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 ot = this.target.el.calcOffsetsTo(scrollable);
8068 var scrollTo = ot[1] - 100;
8070 var maxScroll = Roo.lib.Dom.getDocumentHeight() - Roo.lib.Dom.getViewportHeight();
8072 scrollTo = Math.min(scrollTo, maxScroll);
8074 scrollable.scrollTo('top', scrollTo);
8076 var box = this.target.el.getBox();
8078 var zIndex = Roo.bootstrap.Modal.zIndex++;
8080 this.maskEl.top.setStyle('position', 'fixed');
8081 this.maskEl.top.setStyle('z-index', zIndex);
8082 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8083 this.maskEl.top.setXY([0, 0]);
8084 this.maskEl.top.show();
8086 this.maskEl.left.setStyle('position', 'fixed');
8087 this.maskEl.left.setStyle('z-index', zIndex);
8088 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8089 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8090 this.maskEl.left.show();
8092 this.maskEl.bottom.setStyle('position', 'fixed');
8093 this.maskEl.bottom.setStyle('z-index', zIndex);
8094 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8095 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8096 this.maskEl.bottom.show();
8098 this.maskEl.right.setStyle('position', 'fixed');
8099 this.maskEl.right.setStyle('z-index', zIndex);
8100 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8101 this.maskEl.right.setXY([0, box.y - this.padding]);
8102 this.maskEl.right.show();
8105 this.toolTip.bindEl = this.target.el;
8107 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8109 var tip = this.target.blankText;
8111 if(this.target.getValue() !== '' && this.target.regexText.length){
8112 tip = this.target.regexText;
8115 this.toolTip.show(tip);
8117 this.intervalID = window.setInterval(function() {
8118 Roo.bootstrap.Form.popover.unmask();
8121 window.onwheel = function(){ return false;};
8123 (function(){ this.isMasked = true; }).defer(500, this);
8131 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8135 this.maskEl.top.setStyle('position', 'absolute');
8136 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8137 this.maskEl.top.hide();
8139 this.maskEl.left.setStyle('position', 'absolute');
8140 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8141 this.maskEl.left.hide();
8143 this.maskEl.bottom.setStyle('position', 'absolute');
8144 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8145 this.maskEl.bottom.hide();
8147 this.maskEl.right.setStyle('position', 'absolute');
8148 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8149 this.maskEl.right.hide();
8151 this.toolTip.hide();
8153 this.toolTip.el.hide();
8155 window.onwheel = function(){ return true;};
8157 if(this.intervalID){
8158 window.clearInterval(this.intervalID);
8159 this.intervalID = false;
8162 this.isMasked = false;
8172 * Ext JS Library 1.1.1
8173 * Copyright(c) 2006-2007, Ext JS, LLC.
8175 * Originally Released Under LGPL - original licence link has changed is not relivant.
8178 * <script type="text/javascript">
8181 * @class Roo.form.VTypes
8182 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8185 Roo.form.VTypes = function(){
8186 // closure these in so they are only created once.
8187 var alpha = /^[a-zA-Z_]+$/;
8188 var alphanum = /^[a-zA-Z0-9_]+$/;
8189 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8190 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8192 // All these messages and functions are configurable
8195 * The function used to validate email addresses
8196 * @param {String} value The email address
8198 'email' : function(v){
8199 return email.test(v);
8202 * The error text to display when the email validation function returns false
8205 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8207 * The keystroke filter mask to be applied on email input
8210 'emailMask' : /[a-z0-9_\.\-@]/i,
8213 * The function used to validate URLs
8214 * @param {String} value The URL
8216 'url' : function(v){
8220 * The error text to display when the url validation function returns false
8223 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8226 * The function used to validate alpha values
8227 * @param {String} value The value
8229 'alpha' : function(v){
8230 return alpha.test(v);
8233 * The error text to display when the alpha validation function returns false
8236 'alphaText' : 'This field should only contain letters and _',
8238 * The keystroke filter mask to be applied on alpha input
8241 'alphaMask' : /[a-z_]/i,
8244 * The function used to validate alphanumeric values
8245 * @param {String} value The value
8247 'alphanum' : function(v){
8248 return alphanum.test(v);
8251 * The error text to display when the alphanumeric validation function returns false
8254 'alphanumText' : 'This field should only contain letters, numbers and _',
8256 * The keystroke filter mask to be applied on alphanumeric input
8259 'alphanumMask' : /[a-z0-9_]/i
8269 * @class Roo.bootstrap.Input
8270 * @extends Roo.bootstrap.Component
8271 * Bootstrap Input class
8272 * @cfg {Boolean} disabled is it disabled
8273 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8274 * @cfg {String} name name of the input
8275 * @cfg {string} fieldLabel - the label associated
8276 * @cfg {string} placeholder - placeholder to put in text.
8277 * @cfg {string} before - input group add on before
8278 * @cfg {string} after - input group add on after
8279 * @cfg {string} size - (lg|sm) or leave empty..
8280 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8281 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8282 * @cfg {Number} md colspan out of 12 for computer-sized screens
8283 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8284 * @cfg {string} value default value of the input
8285 * @cfg {Number} labelWidth set the width of label
8286 * @cfg {Number} labellg set the width of label (1-12)
8287 * @cfg {Number} labelmd set the width of label (1-12)
8288 * @cfg {Number} labelsm set the width of label (1-12)
8289 * @cfg {Number} labelxs set the width of label (1-12)
8290 * @cfg {String} labelAlign (top|left)
8291 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8292 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8293 * @cfg {String} indicatorpos (left|right) default left
8295 * @cfg {String} align (left|center|right) Default left
8296 * @cfg {Boolean} forceFeedback (true|false) Default false
8302 * Create a new Input
8303 * @param {Object} config The config object
8306 Roo.bootstrap.Input = function(config){
8308 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8313 * Fires when this field receives input focus.
8314 * @param {Roo.form.Field} this
8319 * Fires when this field loses input focus.
8320 * @param {Roo.form.Field} this
8325 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8326 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8327 * @param {Roo.form.Field} this
8328 * @param {Roo.EventObject} e The event object
8333 * Fires just before the field blurs if the field value has changed.
8334 * @param {Roo.form.Field} this
8335 * @param {Mixed} newValue The new value
8336 * @param {Mixed} oldValue The original value
8341 * Fires after the field has been marked as invalid.
8342 * @param {Roo.form.Field} this
8343 * @param {String} msg The validation message
8348 * Fires after the field has been validated with no errors.
8349 * @param {Roo.form.Field} this
8354 * Fires after the key up
8355 * @param {Roo.form.Field} this
8356 * @param {Roo.EventObject} e The event Object
8362 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8364 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8365 automatic validation (defaults to "keyup").
8367 validationEvent : "keyup",
8369 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8371 validateOnBlur : true,
8373 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8375 validationDelay : 250,
8377 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8379 focusClass : "x-form-focus", // not needed???
8383 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8385 invalidClass : "has-warning",
8388 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8390 validClass : "has-success",
8393 * @cfg {Boolean} hasFeedback (true|false) default true
8398 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8400 invalidFeedbackClass : "glyphicon-warning-sign",
8403 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8405 validFeedbackClass : "glyphicon-ok",
8408 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8410 selectOnFocus : false,
8413 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8417 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8422 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8424 disableKeyFilter : false,
8427 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8431 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8435 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8437 blankText : "Please complete this mandatory field",
8440 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8444 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8446 maxLength : Number.MAX_VALUE,
8448 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8450 minLengthText : "The minimum length for this field is {0}",
8452 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8454 maxLengthText : "The maximum length for this field is {0}",
8458 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8459 * If available, this function will be called only after the basic validators all return true, and will be passed the
8460 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8464 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8465 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8466 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8470 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8474 autocomplete: false,
8493 formatedValue : false,
8494 forceFeedback : false,
8496 indicatorpos : 'left',
8503 parentLabelAlign : function()
8506 while (parent.parent()) {
8507 parent = parent.parent();
8508 if (typeof(parent.labelAlign) !='undefined') {
8509 return parent.labelAlign;
8516 getAutoCreate : function()
8518 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8524 if(this.inputType != 'hidden'){
8525 cfg.cls = 'form-group' //input-group
8531 type : this.inputType,
8533 cls : 'form-control',
8534 placeholder : this.placeholder || '',
8535 autocomplete : this.autocomplete || 'new-password'
8539 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8542 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8543 input.maxLength = this.maxLength;
8546 if (this.disabled) {
8547 input.disabled=true;
8550 if (this.readOnly) {
8551 input.readonly=true;
8555 input.name = this.name;
8559 input.cls += ' input-' + this.size;
8563 ['xs','sm','md','lg'].map(function(size){
8564 if (settings[size]) {
8565 cfg.cls += ' col-' + size + '-' + settings[size];
8569 var inputblock = input;
8573 cls: 'glyphicon form-control-feedback'
8576 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8579 cls : 'has-feedback',
8587 if (this.before || this.after) {
8590 cls : 'input-group',
8594 if (this.before && typeof(this.before) == 'string') {
8596 inputblock.cn.push({
8598 cls : 'roo-input-before input-group-addon',
8602 if (this.before && typeof(this.before) == 'object') {
8603 this.before = Roo.factory(this.before);
8605 inputblock.cn.push({
8607 cls : 'roo-input-before input-group-' +
8608 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8612 inputblock.cn.push(input);
8614 if (this.after && typeof(this.after) == 'string') {
8615 inputblock.cn.push({
8617 cls : 'roo-input-after input-group-addon',
8621 if (this.after && typeof(this.after) == 'object') {
8622 this.after = Roo.factory(this.after);
8624 inputblock.cn.push({
8626 cls : 'roo-input-after input-group-' +
8627 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8631 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8632 inputblock.cls += ' has-feedback';
8633 inputblock.cn.push(feedback);
8637 if (align ==='left' && this.fieldLabel.length) {
8639 cfg.cls += ' roo-form-group-label-left';
8644 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8645 tooltip : 'This field is required'
8650 cls : 'control-label',
8651 html : this.fieldLabel
8662 var labelCfg = cfg.cn[1];
8663 var contentCfg = cfg.cn[2];
8665 if(this.indicatorpos == 'right'){
8670 cls : 'control-label',
8671 html : this.fieldLabel
8676 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8677 tooltip : 'This field is required'
8688 labelCfg = cfg.cn[0];
8689 contentCfg = cfg.cn[2];
8693 if(this.labelWidth > 12){
8694 labelCfg.style = "width: " + this.labelWidth + 'px';
8697 if(this.labelWidth < 13 && this.labelmd == 0){
8698 this.labelmd = this.labelWidth;
8701 if(this.labellg > 0){
8702 labelCfg.cls += ' col-lg-' + this.labellg;
8703 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8706 if(this.labelmd > 0){
8707 labelCfg.cls += ' col-md-' + this.labelmd;
8708 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8711 if(this.labelsm > 0){
8712 labelCfg.cls += ' col-sm-' + this.labelsm;
8713 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8716 if(this.labelxs > 0){
8717 labelCfg.cls += ' col-xs-' + this.labelxs;
8718 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8722 } else if ( this.fieldLabel.length) {
8727 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8728 tooltip : 'This field is required'
8732 //cls : 'input-group-addon',
8733 html : this.fieldLabel
8741 if(this.indicatorpos == 'right'){
8746 //cls : 'input-group-addon',
8747 html : this.fieldLabel
8752 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8753 tooltip : 'This field is required'
8773 if (this.parentType === 'Navbar' && this.parent().bar) {
8774 cfg.cls += ' navbar-form';
8777 if (this.parentType === 'NavGroup') {
8778 cfg.cls += ' navbar-form';
8786 * return the real input element.
8788 inputEl: function ()
8790 return this.el.select('input.form-control',true).first();
8793 tooltipEl : function()
8795 return this.inputEl();
8798 indicatorEl : function()
8800 var indicator = this.el.select('i.roo-required-indicator',true).first();
8810 setDisabled : function(v)
8812 var i = this.inputEl().dom;
8814 i.removeAttribute('disabled');
8818 i.setAttribute('disabled','true');
8820 initEvents : function()
8823 this.inputEl().on("keydown" , this.fireKey, this);
8824 this.inputEl().on("focus", this.onFocus, this);
8825 this.inputEl().on("blur", this.onBlur, this);
8827 this.inputEl().relayEvent('keyup', this);
8829 this.indicator = this.indicatorEl();
8832 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8833 this.indicator.hide();
8836 // reference to original value for reset
8837 this.originalValue = this.getValue();
8838 //Roo.form.TextField.superclass.initEvents.call(this);
8839 if(this.validationEvent == 'keyup'){
8840 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8841 this.inputEl().on('keyup', this.filterValidation, this);
8843 else if(this.validationEvent !== false){
8844 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8847 if(this.selectOnFocus){
8848 this.on("focus", this.preFocus, this);
8851 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8852 this.inputEl().on("keypress", this.filterKeys, this);
8854 this.inputEl().relayEvent('keypress', this);
8857 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8858 this.el.on("click", this.autoSize, this);
8861 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8862 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8865 if (typeof(this.before) == 'object') {
8866 this.before.render(this.el.select('.roo-input-before',true).first());
8868 if (typeof(this.after) == 'object') {
8869 this.after.render(this.el.select('.roo-input-after',true).first());
8874 filterValidation : function(e){
8875 if(!e.isNavKeyPress()){
8876 this.validationTask.delay(this.validationDelay);
8880 * Validates the field value
8881 * @return {Boolean} True if the value is valid, else false
8883 validate : function(){
8884 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8885 if(this.disabled || this.validateValue(this.getRawValue())){
8896 * Validates a value according to the field's validation rules and marks the field as invalid
8897 * if the validation fails
8898 * @param {Mixed} value The value to validate
8899 * @return {Boolean} True if the value is valid, else false
8901 validateValue : function(value){
8902 if(value.length < 1) { // if it's blank
8903 if(this.allowBlank){
8909 if(value.length < this.minLength){
8912 if(value.length > this.maxLength){
8916 var vt = Roo.form.VTypes;
8917 if(!vt[this.vtype](value, this)){
8921 if(typeof this.validator == "function"){
8922 var msg = this.validator(value);
8928 if(this.regex && !this.regex.test(value)){
8938 fireKey : function(e){
8939 //Roo.log('field ' + e.getKey());
8940 if(e.isNavKeyPress()){
8941 this.fireEvent("specialkey", this, e);
8944 focus : function (selectText){
8946 this.inputEl().focus();
8947 if(selectText === true){
8948 this.inputEl().dom.select();
8954 onFocus : function(){
8955 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8956 // this.el.addClass(this.focusClass);
8959 this.hasFocus = true;
8960 this.startValue = this.getValue();
8961 this.fireEvent("focus", this);
8965 beforeBlur : Roo.emptyFn,
8969 onBlur : function(){
8971 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8972 //this.el.removeClass(this.focusClass);
8974 this.hasFocus = false;
8975 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8978 var v = this.getValue();
8979 if(String(v) !== String(this.startValue)){
8980 this.fireEvent('change', this, v, this.startValue);
8982 this.fireEvent("blur", this);
8986 * Resets the current field value to the originally loaded value and clears any validation messages
8989 this.setValue(this.originalValue);
8993 * Returns the name of the field
8994 * @return {Mixed} name The name field
8996 getName: function(){
9000 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9001 * @return {Mixed} value The field value
9003 getValue : function(){
9005 var v = this.inputEl().getValue();
9010 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9011 * @return {Mixed} value The field value
9013 getRawValue : function(){
9014 var v = this.inputEl().getValue();
9020 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9021 * @param {Mixed} value The value to set
9023 setRawValue : function(v){
9024 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9027 selectText : function(start, end){
9028 var v = this.getRawValue();
9030 start = start === undefined ? 0 : start;
9031 end = end === undefined ? v.length : end;
9032 var d = this.inputEl().dom;
9033 if(d.setSelectionRange){
9034 d.setSelectionRange(start, end);
9035 }else if(d.createTextRange){
9036 var range = d.createTextRange();
9037 range.moveStart("character", start);
9038 range.moveEnd("character", v.length-end);
9045 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9046 * @param {Mixed} value The value to set
9048 setValue : function(v){
9051 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9057 processValue : function(value){
9058 if(this.stripCharsRe){
9059 var newValue = value.replace(this.stripCharsRe, '');
9060 if(newValue !== value){
9061 this.setRawValue(newValue);
9068 preFocus : function(){
9070 if(this.selectOnFocus){
9071 this.inputEl().dom.select();
9074 filterKeys : function(e){
9076 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9079 var c = e.getCharCode(), cc = String.fromCharCode(c);
9080 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9083 if(!this.maskRe.test(cc)){
9088 * Clear any invalid styles/messages for this field
9090 clearInvalid : function(){
9092 if(!this.el || this.preventMark){ // not rendered
9098 this.indicator.hide();
9102 this.el.removeClass(this.invalidClass);
9104 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9106 var feedback = this.el.select('.form-control-feedback', true).first();
9109 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9114 this.fireEvent('valid', this);
9118 * Mark this field as valid
9120 markValid : function()
9122 if(!this.el || this.preventMark){ // not rendered...
9126 this.el.removeClass([this.invalidClass, this.validClass]);
9128 var feedback = this.el.select('.form-control-feedback', true).first();
9131 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9138 if(this.allowBlank && !this.getRawValue().length){
9143 this.indicator.hide();
9146 this.el.addClass(this.validClass);
9148 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9150 var feedback = this.el.select('.form-control-feedback', true).first();
9153 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9154 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9159 this.fireEvent('valid', this);
9163 * Mark this field as invalid
9164 * @param {String} msg The validation message
9166 markInvalid : function(msg)
9168 if(!this.el || this.preventMark){ // not rendered
9172 this.el.removeClass([this.invalidClass, this.validClass]);
9174 var feedback = this.el.select('.form-control-feedback', true).first();
9177 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9184 if(this.allowBlank && !this.getRawValue().length){
9189 this.indicator.show();
9192 this.el.addClass(this.invalidClass);
9194 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9196 var feedback = this.el.select('.form-control-feedback', true).first();
9199 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9201 if(this.getValue().length || this.forceFeedback){
9202 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9209 this.fireEvent('invalid', this, msg);
9212 SafariOnKeyDown : function(event)
9214 // this is a workaround for a password hang bug on chrome/ webkit.
9215 if (this.inputEl().dom.type != 'password') {
9219 var isSelectAll = false;
9221 if(this.inputEl().dom.selectionEnd > 0){
9222 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9224 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9225 event.preventDefault();
9230 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9232 event.preventDefault();
9233 // this is very hacky as keydown always get's upper case.
9235 var cc = String.fromCharCode(event.getCharCode());
9236 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9240 adjustWidth : function(tag, w){
9241 tag = tag.toLowerCase();
9242 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9243 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9247 if(tag == 'textarea'){
9250 }else if(Roo.isOpera){
9254 if(tag == 'textarea'){
9273 * @class Roo.bootstrap.TextArea
9274 * @extends Roo.bootstrap.Input
9275 * Bootstrap TextArea class
9276 * @cfg {Number} cols Specifies the visible width of a text area
9277 * @cfg {Number} rows Specifies the visible number of lines in a text area
9278 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9279 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9280 * @cfg {string} html text
9283 * Create a new TextArea
9284 * @param {Object} config The config object
9287 Roo.bootstrap.TextArea = function(config){
9288 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9292 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9302 getAutoCreate : function(){
9304 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9315 value : this.value || '',
9316 html: this.html || '',
9317 cls : 'form-control',
9318 placeholder : this.placeholder || ''
9322 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9323 input.maxLength = this.maxLength;
9327 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9331 input.cols = this.cols;
9334 if (this.readOnly) {
9335 input.readonly = true;
9339 input.name = this.name;
9343 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9347 ['xs','sm','md','lg'].map(function(size){
9348 if (settings[size]) {
9349 cfg.cls += ' col-' + size + '-' + settings[size];
9353 var inputblock = input;
9355 if(this.hasFeedback && !this.allowBlank){
9359 cls: 'glyphicon form-control-feedback'
9363 cls : 'has-feedback',
9372 if (this.before || this.after) {
9375 cls : 'input-group',
9379 inputblock.cn.push({
9381 cls : 'input-group-addon',
9386 inputblock.cn.push(input);
9388 if(this.hasFeedback && !this.allowBlank){
9389 inputblock.cls += ' has-feedback';
9390 inputblock.cn.push(feedback);
9394 inputblock.cn.push({
9396 cls : 'input-group-addon',
9403 if (align ==='left' && this.fieldLabel.length) {
9408 cls : 'control-label',
9409 html : this.fieldLabel
9420 if(this.labelWidth > 12){
9421 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9424 if(this.labelWidth < 13 && this.labelmd == 0){
9425 this.labelmd = this.labelWidth;
9428 if(this.labellg > 0){
9429 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9430 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9433 if(this.labelmd > 0){
9434 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9435 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9438 if(this.labelsm > 0){
9439 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9440 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9443 if(this.labelxs > 0){
9444 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9445 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9448 } else if ( this.fieldLabel.length) {
9453 //cls : 'input-group-addon',
9454 html : this.fieldLabel
9472 if (this.disabled) {
9473 input.disabled=true;
9480 * return the real textarea element.
9482 inputEl: function ()
9484 return this.el.select('textarea.form-control',true).first();
9488 * Clear any invalid styles/messages for this field
9490 clearInvalid : function()
9493 if(!this.el || this.preventMark){ // not rendered
9497 var label = this.el.select('label', true).first();
9498 var icon = this.el.select('i.fa-star', true).first();
9504 this.el.removeClass(this.invalidClass);
9506 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9508 var feedback = this.el.select('.form-control-feedback', true).first();
9511 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9516 this.fireEvent('valid', this);
9520 * Mark this field as valid
9522 markValid : function()
9524 if(!this.el || this.preventMark){ // not rendered
9528 this.el.removeClass([this.invalidClass, this.validClass]);
9530 var feedback = this.el.select('.form-control-feedback', true).first();
9533 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9536 if(this.disabled || this.allowBlank){
9540 var label = this.el.select('label', true).first();
9541 var icon = this.el.select('i.fa-star', true).first();
9547 this.el.addClass(this.validClass);
9549 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9551 var feedback = this.el.select('.form-control-feedback', true).first();
9554 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9555 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9560 this.fireEvent('valid', this);
9564 * Mark this field as invalid
9565 * @param {String} msg The validation message
9567 markInvalid : function(msg)
9569 if(!this.el || this.preventMark){ // not rendered
9573 this.el.removeClass([this.invalidClass, this.validClass]);
9575 var feedback = this.el.select('.form-control-feedback', true).first();
9578 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9581 if(this.disabled || this.allowBlank){
9585 var label = this.el.select('label', true).first();
9586 var icon = this.el.select('i.fa-star', true).first();
9588 if(!this.getValue().length && label && !icon){
9589 this.el.createChild({
9591 cls : 'text-danger fa fa-lg fa-star',
9592 tooltip : 'This field is required',
9593 style : 'margin-right:5px;'
9597 this.el.addClass(this.invalidClass);
9599 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9601 var feedback = this.el.select('.form-control-feedback', true).first();
9604 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9606 if(this.getValue().length || this.forceFeedback){
9607 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9614 this.fireEvent('invalid', this, msg);
9622 * trigger field - base class for combo..
9627 * @class Roo.bootstrap.TriggerField
9628 * @extends Roo.bootstrap.Input
9629 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9630 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9631 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9632 * for which you can provide a custom implementation. For example:
9634 var trigger = new Roo.bootstrap.TriggerField();
9635 trigger.onTriggerClick = myTriggerFn;
9636 trigger.applyTo('my-field');
9639 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9640 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9641 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9642 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9643 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9646 * Create a new TriggerField.
9647 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9648 * to the base TextField)
9650 Roo.bootstrap.TriggerField = function(config){
9651 this.mimicing = false;
9652 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9655 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9657 * @cfg {String} triggerClass A CSS class to apply to the trigger
9660 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9665 * @cfg {Boolean} removable (true|false) special filter default false
9669 /** @cfg {Boolean} grow @hide */
9670 /** @cfg {Number} growMin @hide */
9671 /** @cfg {Number} growMax @hide */
9677 autoSize: Roo.emptyFn,
9684 actionMode : 'wrap',
9689 getAutoCreate : function(){
9691 var align = this.labelAlign || this.parentLabelAlign();
9696 cls: 'form-group' //input-group
9703 type : this.inputType,
9704 cls : 'form-control',
9705 autocomplete: 'new-password',
9706 placeholder : this.placeholder || ''
9710 input.name = this.name;
9713 input.cls += ' input-' + this.size;
9716 if (this.disabled) {
9717 input.disabled=true;
9720 var inputblock = input;
9722 if(this.hasFeedback && !this.allowBlank){
9726 cls: 'glyphicon form-control-feedback'
9729 if(this.removable && !this.editable && !this.tickable){
9731 cls : 'has-feedback',
9737 cls : 'roo-combo-removable-btn close'
9744 cls : 'has-feedback',
9753 if(this.removable && !this.editable && !this.tickable){
9755 cls : 'roo-removable',
9761 cls : 'roo-combo-removable-btn close'
9768 if (this.before || this.after) {
9771 cls : 'input-group',
9775 inputblock.cn.push({
9777 cls : 'input-group-addon',
9782 inputblock.cn.push(input);
9784 if(this.hasFeedback && !this.allowBlank){
9785 inputblock.cls += ' has-feedback';
9786 inputblock.cn.push(feedback);
9790 inputblock.cn.push({
9792 cls : 'input-group-addon',
9805 cls: 'form-hidden-field'
9819 cls: 'form-hidden-field'
9823 cls: 'roo-select2-choices',
9827 cls: 'roo-select2-search-field',
9840 cls: 'roo-select2-container input-group',
9845 // cls: 'typeahead typeahead-long dropdown-menu',
9846 // style: 'display:none'
9851 if(!this.multiple && this.showToggleBtn){
9857 if (this.caret != false) {
9860 cls: 'fa fa-' + this.caret
9867 cls : 'input-group-addon btn dropdown-toggle',
9872 cls: 'combobox-clear',
9886 combobox.cls += ' roo-select2-container-multi';
9889 if (align ==='left' && this.fieldLabel.length) {
9891 cfg.cls += ' roo-form-group-label-left';
9896 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9897 tooltip : 'This field is required'
9902 cls : 'control-label',
9903 html : this.fieldLabel
9915 var labelCfg = cfg.cn[1];
9916 var contentCfg = cfg.cn[2];
9918 if(this.indicatorpos == 'right'){
9923 cls : 'control-label',
9927 html : this.fieldLabel
9931 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9932 tooltip : 'This field is required'
9945 labelCfg = cfg.cn[0];
9946 contentCfg = cfg.cn[1];
9949 if(this.labelWidth > 12){
9950 labelCfg.style = "width: " + this.labelWidth + 'px';
9953 if(this.labelWidth < 13 && this.labelmd == 0){
9954 this.labelmd = this.labelWidth;
9957 if(this.labellg > 0){
9958 labelCfg.cls += ' col-lg-' + this.labellg;
9959 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9962 if(this.labelmd > 0){
9963 labelCfg.cls += ' col-md-' + this.labelmd;
9964 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9967 if(this.labelsm > 0){
9968 labelCfg.cls += ' col-sm-' + this.labelsm;
9969 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9972 if(this.labelxs > 0){
9973 labelCfg.cls += ' col-xs-' + this.labelxs;
9974 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9977 } else if ( this.fieldLabel.length) {
9978 // Roo.log(" label");
9982 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9983 tooltip : 'This field is required'
9987 //cls : 'input-group-addon',
9988 html : this.fieldLabel
9996 if(this.indicatorpos == 'right'){
10004 html : this.fieldLabel
10008 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10009 tooltip : 'This field is required'
10022 // Roo.log(" no label && no align");
10029 ['xs','sm','md','lg'].map(function(size){
10030 if (settings[size]) {
10031 cfg.cls += ' col-' + size + '-' + settings[size];
10042 onResize : function(w, h){
10043 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10044 // if(typeof w == 'number'){
10045 // var x = w - this.trigger.getWidth();
10046 // this.inputEl().setWidth(this.adjustWidth('input', x));
10047 // this.trigger.setStyle('left', x+'px');
10052 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10055 getResizeEl : function(){
10056 return this.inputEl();
10060 getPositionEl : function(){
10061 return this.inputEl();
10065 alignErrorIcon : function(){
10066 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10070 initEvents : function(){
10074 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10075 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10076 if(!this.multiple && this.showToggleBtn){
10077 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10078 if(this.hideTrigger){
10079 this.trigger.setDisplayed(false);
10081 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10085 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10088 if(this.removable && !this.editable && !this.tickable){
10089 var close = this.closeTriggerEl();
10092 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10093 close.on('click', this.removeBtnClick, this, close);
10097 //this.trigger.addClassOnOver('x-form-trigger-over');
10098 //this.trigger.addClassOnClick('x-form-trigger-click');
10101 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10105 closeTriggerEl : function()
10107 var close = this.el.select('.roo-combo-removable-btn', true).first();
10108 return close ? close : false;
10111 removeBtnClick : function(e, h, el)
10113 e.preventDefault();
10115 if(this.fireEvent("remove", this) !== false){
10117 this.fireEvent("afterremove", this)
10121 createList : function()
10123 this.list = Roo.get(document.body).createChild({
10125 cls: 'typeahead typeahead-long dropdown-menu',
10126 style: 'display:none'
10129 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10134 initTrigger : function(){
10139 onDestroy : function(){
10141 this.trigger.removeAllListeners();
10142 // this.trigger.remove();
10145 // this.wrap.remove();
10147 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10151 onFocus : function(){
10152 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10154 if(!this.mimicing){
10155 this.wrap.addClass('x-trigger-wrap-focus');
10156 this.mimicing = true;
10157 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10158 if(this.monitorTab){
10159 this.el.on("keydown", this.checkTab, this);
10166 checkTab : function(e){
10167 if(e.getKey() == e.TAB){
10168 this.triggerBlur();
10173 onBlur : function(){
10178 mimicBlur : function(e, t){
10180 if(!this.wrap.contains(t) && this.validateBlur()){
10181 this.triggerBlur();
10187 triggerBlur : function(){
10188 this.mimicing = false;
10189 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10190 if(this.monitorTab){
10191 this.el.un("keydown", this.checkTab, this);
10193 //this.wrap.removeClass('x-trigger-wrap-focus');
10194 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10198 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10199 validateBlur : function(e, t){
10204 onDisable : function(){
10205 this.inputEl().dom.disabled = true;
10206 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10208 // this.wrap.addClass('x-item-disabled');
10213 onEnable : function(){
10214 this.inputEl().dom.disabled = false;
10215 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10217 // this.el.removeClass('x-item-disabled');
10222 onShow : function(){
10223 var ae = this.getActionEl();
10226 ae.dom.style.display = '';
10227 ae.dom.style.visibility = 'visible';
10233 onHide : function(){
10234 var ae = this.getActionEl();
10235 ae.dom.style.display = 'none';
10239 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10240 * by an implementing function.
10242 * @param {EventObject} e
10244 onTriggerClick : Roo.emptyFn
10248 * Ext JS Library 1.1.1
10249 * Copyright(c) 2006-2007, Ext JS, LLC.
10251 * Originally Released Under LGPL - original licence link has changed is not relivant.
10254 * <script type="text/javascript">
10259 * @class Roo.data.SortTypes
10261 * Defines the default sorting (casting?) comparison functions used when sorting data.
10263 Roo.data.SortTypes = {
10265 * Default sort that does nothing
10266 * @param {Mixed} s The value being converted
10267 * @return {Mixed} The comparison value
10269 none : function(s){
10274 * The regular expression used to strip tags
10278 stripTagsRE : /<\/?[^>]+>/gi,
10281 * Strips all HTML tags to sort on text only
10282 * @param {Mixed} s The value being converted
10283 * @return {String} The comparison value
10285 asText : function(s){
10286 return String(s).replace(this.stripTagsRE, "");
10290 * Strips all HTML tags to sort on text only - Case insensitive
10291 * @param {Mixed} s The value being converted
10292 * @return {String} The comparison value
10294 asUCText : function(s){
10295 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10299 * Case insensitive string
10300 * @param {Mixed} s The value being converted
10301 * @return {String} The comparison value
10303 asUCString : function(s) {
10304 return String(s).toUpperCase();
10309 * @param {Mixed} s The value being converted
10310 * @return {Number} The comparison value
10312 asDate : function(s) {
10316 if(s instanceof Date){
10317 return s.getTime();
10319 return Date.parse(String(s));
10324 * @param {Mixed} s The value being converted
10325 * @return {Float} The comparison value
10327 asFloat : function(s) {
10328 var val = parseFloat(String(s).replace(/,/g, ""));
10337 * @param {Mixed} s The value being converted
10338 * @return {Number} The comparison value
10340 asInt : function(s) {
10341 var val = parseInt(String(s).replace(/,/g, ""));
10349 * Ext JS Library 1.1.1
10350 * Copyright(c) 2006-2007, Ext JS, LLC.
10352 * Originally Released Under LGPL - original licence link has changed is not relivant.
10355 * <script type="text/javascript">
10359 * @class Roo.data.Record
10360 * Instances of this class encapsulate both record <em>definition</em> information, and record
10361 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10362 * to access Records cached in an {@link Roo.data.Store} object.<br>
10364 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10365 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10368 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10370 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10371 * {@link #create}. The parameters are the same.
10372 * @param {Array} data An associative Array of data values keyed by the field name.
10373 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10374 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10375 * not specified an integer id is generated.
10377 Roo.data.Record = function(data, id){
10378 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10383 * Generate a constructor for a specific record layout.
10384 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10385 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10386 * Each field definition object may contain the following properties: <ul>
10387 * <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,
10388 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10389 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10390 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10391 * is being used, then this is a string containing the javascript expression to reference the data relative to
10392 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10393 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10394 * this may be omitted.</p></li>
10395 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10396 * <ul><li>auto (Default, implies no conversion)</li>
10401 * <li>date</li></ul></p></li>
10402 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10403 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10404 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10405 * by the Reader into an object that will be stored in the Record. It is passed the
10406 * following parameters:<ul>
10407 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10409 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10411 * <br>usage:<br><pre><code>
10412 var TopicRecord = Roo.data.Record.create(
10413 {name: 'title', mapping: 'topic_title'},
10414 {name: 'author', mapping: 'username'},
10415 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10416 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10417 {name: 'lastPoster', mapping: 'user2'},
10418 {name: 'excerpt', mapping: 'post_text'}
10421 var myNewRecord = new TopicRecord({
10422 title: 'Do my job please',
10425 lastPost: new Date(),
10426 lastPoster: 'Animal',
10427 excerpt: 'No way dude!'
10429 myStore.add(myNewRecord);
10434 Roo.data.Record.create = function(o){
10435 var f = function(){
10436 f.superclass.constructor.apply(this, arguments);
10438 Roo.extend(f, Roo.data.Record);
10439 var p = f.prototype;
10440 p.fields = new Roo.util.MixedCollection(false, function(field){
10443 for(var i = 0, len = o.length; i < len; i++){
10444 p.fields.add(new Roo.data.Field(o[i]));
10446 f.getField = function(name){
10447 return p.fields.get(name);
10452 Roo.data.Record.AUTO_ID = 1000;
10453 Roo.data.Record.EDIT = 'edit';
10454 Roo.data.Record.REJECT = 'reject';
10455 Roo.data.Record.COMMIT = 'commit';
10457 Roo.data.Record.prototype = {
10459 * Readonly flag - true if this record has been modified.
10468 join : function(store){
10469 this.store = store;
10473 * Set the named field to the specified value.
10474 * @param {String} name The name of the field to set.
10475 * @param {Object} value The value to set the field to.
10477 set : function(name, value){
10478 if(this.data[name] == value){
10482 if(!this.modified){
10483 this.modified = {};
10485 if(typeof this.modified[name] == 'undefined'){
10486 this.modified[name] = this.data[name];
10488 this.data[name] = value;
10489 if(!this.editing && this.store){
10490 this.store.afterEdit(this);
10495 * Get the value of the named field.
10496 * @param {String} name The name of the field to get the value of.
10497 * @return {Object} The value of the field.
10499 get : function(name){
10500 return this.data[name];
10504 beginEdit : function(){
10505 this.editing = true;
10506 this.modified = {};
10510 cancelEdit : function(){
10511 this.editing = false;
10512 delete this.modified;
10516 endEdit : function(){
10517 this.editing = false;
10518 if(this.dirty && this.store){
10519 this.store.afterEdit(this);
10524 * Usually called by the {@link Roo.data.Store} which owns the Record.
10525 * Rejects all changes made to the Record since either creation, or the last commit operation.
10526 * Modified fields are reverted to their original values.
10528 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10529 * of reject operations.
10531 reject : function(){
10532 var m = this.modified;
10534 if(typeof m[n] != "function"){
10535 this.data[n] = m[n];
10538 this.dirty = false;
10539 delete this.modified;
10540 this.editing = false;
10542 this.store.afterReject(this);
10547 * Usually called by the {@link Roo.data.Store} which owns the Record.
10548 * Commits all changes made to the Record since either creation, or the last commit operation.
10550 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10551 * of commit operations.
10553 commit : function(){
10554 this.dirty = false;
10555 delete this.modified;
10556 this.editing = false;
10558 this.store.afterCommit(this);
10563 hasError : function(){
10564 return this.error != null;
10568 clearError : function(){
10573 * Creates a copy of this record.
10574 * @param {String} id (optional) A new record id if you don't want to use this record's id
10577 copy : function(newId) {
10578 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10582 * Ext JS Library 1.1.1
10583 * Copyright(c) 2006-2007, Ext JS, LLC.
10585 * Originally Released Under LGPL - original licence link has changed is not relivant.
10588 * <script type="text/javascript">
10594 * @class Roo.data.Store
10595 * @extends Roo.util.Observable
10596 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10597 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10599 * 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
10600 * has no knowledge of the format of the data returned by the Proxy.<br>
10602 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10603 * instances from the data object. These records are cached and made available through accessor functions.
10605 * Creates a new Store.
10606 * @param {Object} config A config object containing the objects needed for the Store to access data,
10607 * and read the data into Records.
10609 Roo.data.Store = function(config){
10610 this.data = new Roo.util.MixedCollection(false);
10611 this.data.getKey = function(o){
10614 this.baseParams = {};
10616 this.paramNames = {
10621 "multisort" : "_multisort"
10624 if(config && config.data){
10625 this.inlineData = config.data;
10626 delete config.data;
10629 Roo.apply(this, config);
10631 if(this.reader){ // reader passed
10632 this.reader = Roo.factory(this.reader, Roo.data);
10633 this.reader.xmodule = this.xmodule || false;
10634 if(!this.recordType){
10635 this.recordType = this.reader.recordType;
10637 if(this.reader.onMetaChange){
10638 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10642 if(this.recordType){
10643 this.fields = this.recordType.prototype.fields;
10645 this.modified = [];
10649 * @event datachanged
10650 * Fires when the data cache has changed, and a widget which is using this Store
10651 * as a Record cache should refresh its view.
10652 * @param {Store} this
10654 datachanged : true,
10656 * @event metachange
10657 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10658 * @param {Store} this
10659 * @param {Object} meta The JSON metadata
10664 * Fires when Records have been added to the Store
10665 * @param {Store} this
10666 * @param {Roo.data.Record[]} records The array of Records added
10667 * @param {Number} index The index at which the record(s) were added
10672 * Fires when a Record has been removed from the Store
10673 * @param {Store} this
10674 * @param {Roo.data.Record} record The Record that was removed
10675 * @param {Number} index The index at which the record was removed
10680 * Fires when a Record has been updated
10681 * @param {Store} this
10682 * @param {Roo.data.Record} record The Record that was updated
10683 * @param {String} operation The update operation being performed. Value may be one of:
10685 Roo.data.Record.EDIT
10686 Roo.data.Record.REJECT
10687 Roo.data.Record.COMMIT
10693 * Fires when the data cache has been cleared.
10694 * @param {Store} this
10698 * @event beforeload
10699 * Fires before a request is made for a new data object. If the beforeload handler returns false
10700 * the load action will be canceled.
10701 * @param {Store} this
10702 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10706 * @event beforeloadadd
10707 * Fires after a new set of Records has been loaded.
10708 * @param {Store} this
10709 * @param {Roo.data.Record[]} records The Records that were loaded
10710 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10712 beforeloadadd : true,
10715 * Fires after a new set of Records has been loaded, before they are added to the store.
10716 * @param {Store} this
10717 * @param {Roo.data.Record[]} records The Records that were loaded
10718 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10719 * @params {Object} return from reader
10723 * @event loadexception
10724 * Fires if an exception occurs in the Proxy during loading.
10725 * Called with the signature of the Proxy's "loadexception" event.
10726 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10729 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10730 * @param {Object} load options
10731 * @param {Object} jsonData from your request (normally this contains the Exception)
10733 loadexception : true
10737 this.proxy = Roo.factory(this.proxy, Roo.data);
10738 this.proxy.xmodule = this.xmodule || false;
10739 this.relayEvents(this.proxy, ["loadexception"]);
10741 this.sortToggle = {};
10742 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10744 Roo.data.Store.superclass.constructor.call(this);
10746 if(this.inlineData){
10747 this.loadData(this.inlineData);
10748 delete this.inlineData;
10752 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10754 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10755 * without a remote query - used by combo/forms at present.
10759 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10762 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10765 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10766 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10769 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10770 * on any HTTP request
10773 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10776 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10780 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10781 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10783 remoteSort : false,
10786 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10787 * loaded or when a record is removed. (defaults to false).
10789 pruneModifiedRecords : false,
10792 lastOptions : null,
10795 * Add Records to the Store and fires the add event.
10796 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10798 add : function(records){
10799 records = [].concat(records);
10800 for(var i = 0, len = records.length; i < len; i++){
10801 records[i].join(this);
10803 var index = this.data.length;
10804 this.data.addAll(records);
10805 this.fireEvent("add", this, records, index);
10809 * Remove a Record from the Store and fires the remove event.
10810 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10812 remove : function(record){
10813 var index = this.data.indexOf(record);
10814 this.data.removeAt(index);
10815 if(this.pruneModifiedRecords){
10816 this.modified.remove(record);
10818 this.fireEvent("remove", this, record, index);
10822 * Remove all Records from the Store and fires the clear event.
10824 removeAll : function(){
10826 if(this.pruneModifiedRecords){
10827 this.modified = [];
10829 this.fireEvent("clear", this);
10833 * Inserts Records to the Store at the given index and fires the add event.
10834 * @param {Number} index The start index at which to insert the passed Records.
10835 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10837 insert : function(index, records){
10838 records = [].concat(records);
10839 for(var i = 0, len = records.length; i < len; i++){
10840 this.data.insert(index, records[i]);
10841 records[i].join(this);
10843 this.fireEvent("add", this, records, index);
10847 * Get the index within the cache of the passed Record.
10848 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10849 * @return {Number} The index of the passed Record. Returns -1 if not found.
10851 indexOf : function(record){
10852 return this.data.indexOf(record);
10856 * Get the index within the cache of the Record with the passed id.
10857 * @param {String} id The id of the Record to find.
10858 * @return {Number} The index of the Record. Returns -1 if not found.
10860 indexOfId : function(id){
10861 return this.data.indexOfKey(id);
10865 * Get the Record with the specified id.
10866 * @param {String} id The id of the Record to find.
10867 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10869 getById : function(id){
10870 return this.data.key(id);
10874 * Get the Record at the specified index.
10875 * @param {Number} index The index of the Record to find.
10876 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10878 getAt : function(index){
10879 return this.data.itemAt(index);
10883 * Returns a range of Records between specified indices.
10884 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10885 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10886 * @return {Roo.data.Record[]} An array of Records
10888 getRange : function(start, end){
10889 return this.data.getRange(start, end);
10893 storeOptions : function(o){
10894 o = Roo.apply({}, o);
10897 this.lastOptions = o;
10901 * Loads the Record cache from the configured Proxy using the configured Reader.
10903 * If using remote paging, then the first load call must specify the <em>start</em>
10904 * and <em>limit</em> properties in the options.params property to establish the initial
10905 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10907 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10908 * and this call will return before the new data has been loaded. Perform any post-processing
10909 * in a callback function, or in a "load" event handler.</strong>
10911 * @param {Object} options An object containing properties which control loading options:<ul>
10912 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10913 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10914 * passed the following arguments:<ul>
10915 * <li>r : Roo.data.Record[]</li>
10916 * <li>options: Options object from the load call</li>
10917 * <li>success: Boolean success indicator</li></ul></li>
10918 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10919 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10922 load : function(options){
10923 options = options || {};
10924 if(this.fireEvent("beforeload", this, options) !== false){
10925 this.storeOptions(options);
10926 var p = Roo.apply(options.params || {}, this.baseParams);
10927 // if meta was not loaded from remote source.. try requesting it.
10928 if (!this.reader.metaFromRemote) {
10929 p._requestMeta = 1;
10931 if(this.sortInfo && this.remoteSort){
10932 var pn = this.paramNames;
10933 p[pn["sort"]] = this.sortInfo.field;
10934 p[pn["dir"]] = this.sortInfo.direction;
10936 if (this.multiSort) {
10937 var pn = this.paramNames;
10938 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10941 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10946 * Reloads the Record cache from the configured Proxy using the configured Reader and
10947 * the options from the last load operation performed.
10948 * @param {Object} options (optional) An object containing properties which may override the options
10949 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10950 * the most recently used options are reused).
10952 reload : function(options){
10953 this.load(Roo.applyIf(options||{}, this.lastOptions));
10957 // Called as a callback by the Reader during a load operation.
10958 loadRecords : function(o, options, success){
10959 if(!o || success === false){
10960 if(success !== false){
10961 this.fireEvent("load", this, [], options, o);
10963 if(options.callback){
10964 options.callback.call(options.scope || this, [], options, false);
10968 // if data returned failure - throw an exception.
10969 if (o.success === false) {
10970 // show a message if no listener is registered.
10971 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10972 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10974 // loadmask wil be hooked into this..
10975 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10978 var r = o.records, t = o.totalRecords || r.length;
10980 this.fireEvent("beforeloadadd", this, r, options, o);
10982 if(!options || options.add !== true){
10983 if(this.pruneModifiedRecords){
10984 this.modified = [];
10986 for(var i = 0, len = r.length; i < len; i++){
10990 this.data = this.snapshot;
10991 delete this.snapshot;
10994 this.data.addAll(r);
10995 this.totalLength = t;
10997 this.fireEvent("datachanged", this);
10999 this.totalLength = Math.max(t, this.data.length+r.length);
11002 this.fireEvent("load", this, r, options, o);
11003 if(options.callback){
11004 options.callback.call(options.scope || this, r, options, true);
11010 * Loads data from a passed data block. A Reader which understands the format of the data
11011 * must have been configured in the constructor.
11012 * @param {Object} data The data block from which to read the Records. The format of the data expected
11013 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11014 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11016 loadData : function(o, append){
11017 var r = this.reader.readRecords(o);
11018 this.loadRecords(r, {add: append}, true);
11022 * Gets the number of cached records.
11024 * <em>If using paging, this may not be the total size of the dataset. If the data object
11025 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11026 * the data set size</em>
11028 getCount : function(){
11029 return this.data.length || 0;
11033 * Gets the total number of records in the dataset as returned by the server.
11035 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11036 * the dataset size</em>
11038 getTotalCount : function(){
11039 return this.totalLength || 0;
11043 * Returns the sort state of the Store as an object with two properties:
11045 field {String} The name of the field by which the Records are sorted
11046 direction {String} The sort order, "ASC" or "DESC"
11049 getSortState : function(){
11050 return this.sortInfo;
11054 applySort : function(){
11055 if(this.sortInfo && !this.remoteSort){
11056 var s = this.sortInfo, f = s.field;
11057 var st = this.fields.get(f).sortType;
11058 var fn = function(r1, r2){
11059 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11060 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11062 this.data.sort(s.direction, fn);
11063 if(this.snapshot && this.snapshot != this.data){
11064 this.snapshot.sort(s.direction, fn);
11070 * Sets the default sort column and order to be used by the next load operation.
11071 * @param {String} fieldName The name of the field to sort by.
11072 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11074 setDefaultSort : function(field, dir){
11075 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11079 * Sort the Records.
11080 * If remote sorting is used, the sort is performed on the server, and the cache is
11081 * reloaded. If local sorting is used, the cache is sorted internally.
11082 * @param {String} fieldName The name of the field to sort by.
11083 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11085 sort : function(fieldName, dir){
11086 var f = this.fields.get(fieldName);
11088 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11090 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11091 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11096 this.sortToggle[f.name] = dir;
11097 this.sortInfo = {field: f.name, direction: dir};
11098 if(!this.remoteSort){
11100 this.fireEvent("datachanged", this);
11102 this.load(this.lastOptions);
11107 * Calls the specified function for each of the Records in the cache.
11108 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11109 * Returning <em>false</em> aborts and exits the iteration.
11110 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11112 each : function(fn, scope){
11113 this.data.each(fn, scope);
11117 * Gets all records modified since the last commit. Modified records are persisted across load operations
11118 * (e.g., during paging).
11119 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11121 getModifiedRecords : function(){
11122 return this.modified;
11126 createFilterFn : function(property, value, anyMatch){
11127 if(!value.exec){ // not a regex
11128 value = String(value);
11129 if(value.length == 0){
11132 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11134 return function(r){
11135 return value.test(r.data[property]);
11140 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11141 * @param {String} property A field on your records
11142 * @param {Number} start The record index to start at (defaults to 0)
11143 * @param {Number} end The last record index to include (defaults to length - 1)
11144 * @return {Number} The sum
11146 sum : function(property, start, end){
11147 var rs = this.data.items, v = 0;
11148 start = start || 0;
11149 end = (end || end === 0) ? end : rs.length-1;
11151 for(var i = start; i <= end; i++){
11152 v += (rs[i].data[property] || 0);
11158 * Filter the records by a specified property.
11159 * @param {String} field A field on your records
11160 * @param {String/RegExp} value Either a string that the field
11161 * should start with or a RegExp to test against the field
11162 * @param {Boolean} anyMatch True to match any part not just the beginning
11164 filter : function(property, value, anyMatch){
11165 var fn = this.createFilterFn(property, value, anyMatch);
11166 return fn ? this.filterBy(fn) : this.clearFilter();
11170 * Filter by a function. The specified function will be called with each
11171 * record in this data source. If the function returns true the record is included,
11172 * otherwise it is filtered.
11173 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11174 * @param {Object} scope (optional) The scope of the function (defaults to this)
11176 filterBy : function(fn, scope){
11177 this.snapshot = this.snapshot || this.data;
11178 this.data = this.queryBy(fn, scope||this);
11179 this.fireEvent("datachanged", this);
11183 * Query the records by a specified property.
11184 * @param {String} field A field on your records
11185 * @param {String/RegExp} value Either a string that the field
11186 * should start with or a RegExp to test against the field
11187 * @param {Boolean} anyMatch True to match any part not just the beginning
11188 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11190 query : function(property, value, anyMatch){
11191 var fn = this.createFilterFn(property, value, anyMatch);
11192 return fn ? this.queryBy(fn) : this.data.clone();
11196 * Query by a function. The specified function will be called with each
11197 * record in this data source. If the function returns true the record is included
11199 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11200 * @param {Object} scope (optional) The scope of the function (defaults to this)
11201 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11203 queryBy : function(fn, scope){
11204 var data = this.snapshot || this.data;
11205 return data.filterBy(fn, scope||this);
11209 * Collects unique values for a particular dataIndex from this store.
11210 * @param {String} dataIndex The property to collect
11211 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11212 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11213 * @return {Array} An array of the unique values
11215 collect : function(dataIndex, allowNull, bypassFilter){
11216 var d = (bypassFilter === true && this.snapshot) ?
11217 this.snapshot.items : this.data.items;
11218 var v, sv, r = [], l = {};
11219 for(var i = 0, len = d.length; i < len; i++){
11220 v = d[i].data[dataIndex];
11222 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11231 * Revert to a view of the Record cache with no filtering applied.
11232 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11234 clearFilter : function(suppressEvent){
11235 if(this.snapshot && this.snapshot != this.data){
11236 this.data = this.snapshot;
11237 delete this.snapshot;
11238 if(suppressEvent !== true){
11239 this.fireEvent("datachanged", this);
11245 afterEdit : function(record){
11246 if(this.modified.indexOf(record) == -1){
11247 this.modified.push(record);
11249 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11253 afterReject : function(record){
11254 this.modified.remove(record);
11255 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11259 afterCommit : function(record){
11260 this.modified.remove(record);
11261 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11265 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11266 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11268 commitChanges : function(){
11269 var m = this.modified.slice(0);
11270 this.modified = [];
11271 for(var i = 0, len = m.length; i < len; i++){
11277 * Cancel outstanding changes on all changed records.
11279 rejectChanges : function(){
11280 var m = this.modified.slice(0);
11281 this.modified = [];
11282 for(var i = 0, len = m.length; i < len; i++){
11287 onMetaChange : function(meta, rtype, o){
11288 this.recordType = rtype;
11289 this.fields = rtype.prototype.fields;
11290 delete this.snapshot;
11291 this.sortInfo = meta.sortInfo || this.sortInfo;
11292 this.modified = [];
11293 this.fireEvent('metachange', this, this.reader.meta);
11296 moveIndex : function(data, type)
11298 var index = this.indexOf(data);
11300 var newIndex = index + type;
11304 this.insert(newIndex, data);
11309 * Ext JS Library 1.1.1
11310 * Copyright(c) 2006-2007, Ext JS, LLC.
11312 * Originally Released Under LGPL - original licence link has changed is not relivant.
11315 * <script type="text/javascript">
11319 * @class Roo.data.SimpleStore
11320 * @extends Roo.data.Store
11321 * Small helper class to make creating Stores from Array data easier.
11322 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11323 * @cfg {Array} fields An array of field definition objects, or field name strings.
11324 * @cfg {Array} data The multi-dimensional array of data
11326 * @param {Object} config
11328 Roo.data.SimpleStore = function(config){
11329 Roo.data.SimpleStore.superclass.constructor.call(this, {
11331 reader: new Roo.data.ArrayReader({
11334 Roo.data.Record.create(config.fields)
11336 proxy : new Roo.data.MemoryProxy(config.data)
11340 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11342 * Ext JS Library 1.1.1
11343 * Copyright(c) 2006-2007, Ext JS, LLC.
11345 * Originally Released Under LGPL - original licence link has changed is not relivant.
11348 * <script type="text/javascript">
11353 * @extends Roo.data.Store
11354 * @class Roo.data.JsonStore
11355 * Small helper class to make creating Stores for JSON data easier. <br/>
11357 var store = new Roo.data.JsonStore({
11358 url: 'get-images.php',
11360 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11363 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11364 * JsonReader and HttpProxy (unless inline data is provided).</b>
11365 * @cfg {Array} fields An array of field definition objects, or field name strings.
11367 * @param {Object} config
11369 Roo.data.JsonStore = function(c){
11370 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11371 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11372 reader: new Roo.data.JsonReader(c, c.fields)
11375 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11377 * Ext JS Library 1.1.1
11378 * Copyright(c) 2006-2007, Ext JS, LLC.
11380 * Originally Released Under LGPL - original licence link has changed is not relivant.
11383 * <script type="text/javascript">
11387 Roo.data.Field = function(config){
11388 if(typeof config == "string"){
11389 config = {name: config};
11391 Roo.apply(this, config);
11394 this.type = "auto";
11397 var st = Roo.data.SortTypes;
11398 // named sortTypes are supported, here we look them up
11399 if(typeof this.sortType == "string"){
11400 this.sortType = st[this.sortType];
11403 // set default sortType for strings and dates
11404 if(!this.sortType){
11407 this.sortType = st.asUCString;
11410 this.sortType = st.asDate;
11413 this.sortType = st.none;
11418 var stripRe = /[\$,%]/g;
11420 // prebuilt conversion function for this field, instead of
11421 // switching every time we're reading a value
11423 var cv, dateFormat = this.dateFormat;
11428 cv = function(v){ return v; };
11431 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11435 return v !== undefined && v !== null && v !== '' ?
11436 parseInt(String(v).replace(stripRe, ""), 10) : '';
11441 return v !== undefined && v !== null && v !== '' ?
11442 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11447 cv = function(v){ return v === true || v === "true" || v == 1; };
11454 if(v instanceof Date){
11458 if(dateFormat == "timestamp"){
11459 return new Date(v*1000);
11461 return Date.parseDate(v, dateFormat);
11463 var parsed = Date.parse(v);
11464 return parsed ? new Date(parsed) : null;
11473 Roo.data.Field.prototype = {
11481 * Ext JS Library 1.1.1
11482 * Copyright(c) 2006-2007, Ext JS, LLC.
11484 * Originally Released Under LGPL - original licence link has changed is not relivant.
11487 * <script type="text/javascript">
11490 // Base class for reading structured data from a data source. This class is intended to be
11491 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11494 * @class Roo.data.DataReader
11495 * Base class for reading structured data from a data source. This class is intended to be
11496 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11499 Roo.data.DataReader = function(meta, recordType){
11503 this.recordType = recordType instanceof Array ?
11504 Roo.data.Record.create(recordType) : recordType;
11507 Roo.data.DataReader.prototype = {
11509 * Create an empty record
11510 * @param {Object} data (optional) - overlay some values
11511 * @return {Roo.data.Record} record created.
11513 newRow : function(d) {
11515 this.recordType.prototype.fields.each(function(c) {
11517 case 'int' : da[c.name] = 0; break;
11518 case 'date' : da[c.name] = new Date(); break;
11519 case 'float' : da[c.name] = 0.0; break;
11520 case 'boolean' : da[c.name] = false; break;
11521 default : da[c.name] = ""; break;
11525 return new this.recordType(Roo.apply(da, d));
11530 * Ext JS Library 1.1.1
11531 * Copyright(c) 2006-2007, Ext JS, LLC.
11533 * Originally Released Under LGPL - original licence link has changed is not relivant.
11536 * <script type="text/javascript">
11540 * @class Roo.data.DataProxy
11541 * @extends Roo.data.Observable
11542 * This class is an abstract base class for implementations which provide retrieval of
11543 * unformatted data objects.<br>
11545 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11546 * (of the appropriate type which knows how to parse the data object) to provide a block of
11547 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11549 * Custom implementations must implement the load method as described in
11550 * {@link Roo.data.HttpProxy#load}.
11552 Roo.data.DataProxy = function(){
11555 * @event beforeload
11556 * Fires before a network request is made to retrieve a data object.
11557 * @param {Object} This DataProxy object.
11558 * @param {Object} params The params parameter to the load function.
11563 * Fires before the load method's callback is called.
11564 * @param {Object} This DataProxy object.
11565 * @param {Object} o The data object.
11566 * @param {Object} arg The callback argument object passed to the load function.
11570 * @event loadexception
11571 * Fires if an Exception occurs during data retrieval.
11572 * @param {Object} This DataProxy object.
11573 * @param {Object} o The data object.
11574 * @param {Object} arg The callback argument object passed to the load function.
11575 * @param {Object} e The Exception.
11577 loadexception : true
11579 Roo.data.DataProxy.superclass.constructor.call(this);
11582 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11585 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11589 * Ext JS Library 1.1.1
11590 * Copyright(c) 2006-2007, Ext JS, LLC.
11592 * Originally Released Under LGPL - original licence link has changed is not relivant.
11595 * <script type="text/javascript">
11598 * @class Roo.data.MemoryProxy
11599 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11600 * to the Reader when its load method is called.
11602 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11604 Roo.data.MemoryProxy = function(data){
11608 Roo.data.MemoryProxy.superclass.constructor.call(this);
11612 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11615 * Load data from the requested source (in this case an in-memory
11616 * data object passed to the constructor), read the data object into
11617 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11618 * process that block using the passed callback.
11619 * @param {Object} params This parameter is not used by the MemoryProxy class.
11620 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11621 * object into a block of Roo.data.Records.
11622 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11623 * The function must be passed <ul>
11624 * <li>The Record block object</li>
11625 * <li>The "arg" argument from the load function</li>
11626 * <li>A boolean success indicator</li>
11628 * @param {Object} scope The scope in which to call the callback
11629 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11631 load : function(params, reader, callback, scope, arg){
11632 params = params || {};
11635 result = reader.readRecords(this.data);
11637 this.fireEvent("loadexception", this, arg, null, e);
11638 callback.call(scope, null, arg, false);
11641 callback.call(scope, result, arg, true);
11645 update : function(params, records){
11650 * Ext JS Library 1.1.1
11651 * Copyright(c) 2006-2007, Ext JS, LLC.
11653 * Originally Released Under LGPL - original licence link has changed is not relivant.
11656 * <script type="text/javascript">
11659 * @class Roo.data.HttpProxy
11660 * @extends Roo.data.DataProxy
11661 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11662 * configured to reference a certain URL.<br><br>
11664 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11665 * from which the running page was served.<br><br>
11667 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11669 * Be aware that to enable the browser to parse an XML document, the server must set
11670 * the Content-Type header in the HTTP response to "text/xml".
11672 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11673 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11674 * will be used to make the request.
11676 Roo.data.HttpProxy = function(conn){
11677 Roo.data.HttpProxy.superclass.constructor.call(this);
11678 // is conn a conn config or a real conn?
11680 this.useAjax = !conn || !conn.events;
11684 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11685 // thse are take from connection...
11688 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11691 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11692 * extra parameters to each request made by this object. (defaults to undefined)
11695 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11696 * to each request made by this object. (defaults to undefined)
11699 * @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)
11702 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11705 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11711 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11715 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11716 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11717 * a finer-grained basis than the DataProxy events.
11719 getConnection : function(){
11720 return this.useAjax ? Roo.Ajax : this.conn;
11724 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11725 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11726 * process that block using the passed callback.
11727 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11728 * for the request to the remote server.
11729 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11730 * object into a block of Roo.data.Records.
11731 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11732 * The function must be passed <ul>
11733 * <li>The Record block object</li>
11734 * <li>The "arg" argument from the load function</li>
11735 * <li>A boolean success indicator</li>
11737 * @param {Object} scope The scope in which to call the callback
11738 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11740 load : function(params, reader, callback, scope, arg){
11741 if(this.fireEvent("beforeload", this, params) !== false){
11743 params : params || {},
11745 callback : callback,
11750 callback : this.loadResponse,
11754 Roo.applyIf(o, this.conn);
11755 if(this.activeRequest){
11756 Roo.Ajax.abort(this.activeRequest);
11758 this.activeRequest = Roo.Ajax.request(o);
11760 this.conn.request(o);
11763 callback.call(scope||this, null, arg, false);
11768 loadResponse : function(o, success, response){
11769 delete this.activeRequest;
11771 this.fireEvent("loadexception", this, o, response);
11772 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11777 result = o.reader.read(response);
11779 this.fireEvent("loadexception", this, o, response, e);
11780 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11784 this.fireEvent("load", this, o, o.request.arg);
11785 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11789 update : function(dataSet){
11794 updateResponse : function(dataSet){
11799 * Ext JS Library 1.1.1
11800 * Copyright(c) 2006-2007, Ext JS, LLC.
11802 * Originally Released Under LGPL - original licence link has changed is not relivant.
11805 * <script type="text/javascript">
11809 * @class Roo.data.ScriptTagProxy
11810 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11811 * other than the originating domain of the running page.<br><br>
11813 * <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
11814 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11816 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11817 * source code that is used as the source inside a <script> tag.<br><br>
11819 * In order for the browser to process the returned data, the server must wrap the data object
11820 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11821 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11822 * depending on whether the callback name was passed:
11825 boolean scriptTag = false;
11826 String cb = request.getParameter("callback");
11829 response.setContentType("text/javascript");
11831 response.setContentType("application/x-json");
11833 Writer out = response.getWriter();
11835 out.write(cb + "(");
11837 out.print(dataBlock.toJsonString());
11844 * @param {Object} config A configuration object.
11846 Roo.data.ScriptTagProxy = function(config){
11847 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11848 Roo.apply(this, config);
11849 this.head = document.getElementsByTagName("head")[0];
11852 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11854 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11856 * @cfg {String} url The URL from which to request the data object.
11859 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11863 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11864 * the server the name of the callback function set up by the load call to process the returned data object.
11865 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11866 * javascript output which calls this named function passing the data object as its only parameter.
11868 callbackParam : "callback",
11870 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11871 * name to the request.
11876 * Load data from the configured URL, read the data object into
11877 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11878 * process that block using the passed callback.
11879 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11880 * for the request to the remote server.
11881 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11882 * object into a block of Roo.data.Records.
11883 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11884 * The function must be passed <ul>
11885 * <li>The Record block object</li>
11886 * <li>The "arg" argument from the load function</li>
11887 * <li>A boolean success indicator</li>
11889 * @param {Object} scope The scope in which to call the callback
11890 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11892 load : function(params, reader, callback, scope, arg){
11893 if(this.fireEvent("beforeload", this, params) !== false){
11895 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11897 var url = this.url;
11898 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11900 url += "&_dc=" + (new Date().getTime());
11902 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11905 cb : "stcCallback"+transId,
11906 scriptId : "stcScript"+transId,
11910 callback : callback,
11916 window[trans.cb] = function(o){
11917 conn.handleResponse(o, trans);
11920 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11922 if(this.autoAbort !== false){
11926 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11928 var script = document.createElement("script");
11929 script.setAttribute("src", url);
11930 script.setAttribute("type", "text/javascript");
11931 script.setAttribute("id", trans.scriptId);
11932 this.head.appendChild(script);
11934 this.trans = trans;
11936 callback.call(scope||this, null, arg, false);
11941 isLoading : function(){
11942 return this.trans ? true : false;
11946 * Abort the current server request.
11948 abort : function(){
11949 if(this.isLoading()){
11950 this.destroyTrans(this.trans);
11955 destroyTrans : function(trans, isLoaded){
11956 this.head.removeChild(document.getElementById(trans.scriptId));
11957 clearTimeout(trans.timeoutId);
11959 window[trans.cb] = undefined;
11961 delete window[trans.cb];
11964 // if hasn't been loaded, wait for load to remove it to prevent script error
11965 window[trans.cb] = function(){
11966 window[trans.cb] = undefined;
11968 delete window[trans.cb];
11975 handleResponse : function(o, trans){
11976 this.trans = false;
11977 this.destroyTrans(trans, true);
11980 result = trans.reader.readRecords(o);
11982 this.fireEvent("loadexception", this, o, trans.arg, e);
11983 trans.callback.call(trans.scope||window, null, trans.arg, false);
11986 this.fireEvent("load", this, o, trans.arg);
11987 trans.callback.call(trans.scope||window, result, trans.arg, true);
11991 handleFailure : function(trans){
11992 this.trans = false;
11993 this.destroyTrans(trans, false);
11994 this.fireEvent("loadexception", this, null, trans.arg);
11995 trans.callback.call(trans.scope||window, null, trans.arg, false);
11999 * Ext JS Library 1.1.1
12000 * Copyright(c) 2006-2007, Ext JS, LLC.
12002 * Originally Released Under LGPL - original licence link has changed is not relivant.
12005 * <script type="text/javascript">
12009 * @class Roo.data.JsonReader
12010 * @extends Roo.data.DataReader
12011 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12012 * based on mappings in a provided Roo.data.Record constructor.
12014 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12015 * in the reply previously.
12020 var RecordDef = Roo.data.Record.create([
12021 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12022 {name: 'occupation'} // This field will use "occupation" as the mapping.
12024 var myReader = new Roo.data.JsonReader({
12025 totalProperty: "results", // The property which contains the total dataset size (optional)
12026 root: "rows", // The property which contains an Array of row objects
12027 id: "id" // The property within each row object that provides an ID for the record (optional)
12031 * This would consume a JSON file like this:
12033 { 'results': 2, 'rows': [
12034 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12035 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12038 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12039 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12040 * paged from the remote server.
12041 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12042 * @cfg {String} root name of the property which contains the Array of row objects.
12043 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12044 * @cfg {Array} fields Array of field definition objects
12046 * Create a new JsonReader
12047 * @param {Object} meta Metadata configuration options
12048 * @param {Object} recordType Either an Array of field definition objects,
12049 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12051 Roo.data.JsonReader = function(meta, recordType){
12054 // set some defaults:
12055 Roo.applyIf(meta, {
12056 totalProperty: 'total',
12057 successProperty : 'success',
12062 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12064 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12067 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12068 * Used by Store query builder to append _requestMeta to params.
12071 metaFromRemote : false,
12073 * This method is only used by a DataProxy which has retrieved data from a remote server.
12074 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12075 * @return {Object} data A data block which is used by an Roo.data.Store object as
12076 * a cache of Roo.data.Records.
12078 read : function(response){
12079 var json = response.responseText;
12081 var o = /* eval:var:o */ eval("("+json+")");
12083 throw {message: "JsonReader.read: Json object not found"};
12089 this.metaFromRemote = true;
12090 this.meta = o.metaData;
12091 this.recordType = Roo.data.Record.create(o.metaData.fields);
12092 this.onMetaChange(this.meta, this.recordType, o);
12094 return this.readRecords(o);
12097 // private function a store will implement
12098 onMetaChange : function(meta, recordType, o){
12105 simpleAccess: function(obj, subsc) {
12112 getJsonAccessor: function(){
12114 return function(expr) {
12116 return(re.test(expr))
12117 ? new Function("obj", "return obj." + expr)
12122 return Roo.emptyFn;
12127 * Create a data block containing Roo.data.Records from an XML document.
12128 * @param {Object} o An object which contains an Array of row objects in the property specified
12129 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12130 * which contains the total size of the dataset.
12131 * @return {Object} data A data block which is used by an Roo.data.Store object as
12132 * a cache of Roo.data.Records.
12134 readRecords : function(o){
12136 * After any data loads, the raw JSON data is available for further custom processing.
12140 var s = this.meta, Record = this.recordType,
12141 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12143 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12145 if(s.totalProperty) {
12146 this.getTotal = this.getJsonAccessor(s.totalProperty);
12148 if(s.successProperty) {
12149 this.getSuccess = this.getJsonAccessor(s.successProperty);
12151 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12153 var g = this.getJsonAccessor(s.id);
12154 this.getId = function(rec) {
12156 return (r === undefined || r === "") ? null : r;
12159 this.getId = function(){return null;};
12162 for(var jj = 0; jj < fl; jj++){
12164 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12165 this.ef[jj] = this.getJsonAccessor(map);
12169 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12170 if(s.totalProperty){
12171 var vt = parseInt(this.getTotal(o), 10);
12176 if(s.successProperty){
12177 var vs = this.getSuccess(o);
12178 if(vs === false || vs === 'false'){
12183 for(var i = 0; i < c; i++){
12186 var id = this.getId(n);
12187 for(var j = 0; j < fl; j++){
12189 var v = this.ef[j](n);
12191 Roo.log('missing convert for ' + f.name);
12195 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12197 var record = new Record(values, id);
12199 records[i] = record;
12205 totalRecords : totalRecords
12210 * Ext JS Library 1.1.1
12211 * Copyright(c) 2006-2007, Ext JS, LLC.
12213 * Originally Released Under LGPL - original licence link has changed is not relivant.
12216 * <script type="text/javascript">
12220 * @class Roo.data.ArrayReader
12221 * @extends Roo.data.DataReader
12222 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12223 * Each element of that Array represents a row of data fields. The
12224 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12225 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12229 var RecordDef = Roo.data.Record.create([
12230 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12231 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12233 var myReader = new Roo.data.ArrayReader({
12234 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12238 * This would consume an Array like this:
12240 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12242 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12244 * Create a new JsonReader
12245 * @param {Object} meta Metadata configuration options.
12246 * @param {Object} recordType Either an Array of field definition objects
12247 * as specified to {@link Roo.data.Record#create},
12248 * or an {@link Roo.data.Record} object
12249 * created using {@link Roo.data.Record#create}.
12251 Roo.data.ArrayReader = function(meta, recordType){
12252 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12255 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12257 * Create a data block containing Roo.data.Records from an XML document.
12258 * @param {Object} o An Array of row objects which represents the dataset.
12259 * @return {Object} data A data block which is used by an Roo.data.Store object as
12260 * a cache of Roo.data.Records.
12262 readRecords : function(o){
12263 var sid = this.meta ? this.meta.id : null;
12264 var recordType = this.recordType, fields = recordType.prototype.fields;
12267 for(var i = 0; i < root.length; i++){
12270 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12271 for(var j = 0, jlen = fields.length; j < jlen; j++){
12272 var f = fields.items[j];
12273 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12274 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12276 values[f.name] = v;
12278 var record = new recordType(values, id);
12280 records[records.length] = record;
12284 totalRecords : records.length
12293 * @class Roo.bootstrap.ComboBox
12294 * @extends Roo.bootstrap.TriggerField
12295 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12296 * @cfg {Boolean} append (true|false) default false
12297 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12298 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12299 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12300 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12301 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12302 * @cfg {Boolean} animate default true
12303 * @cfg {Boolean} emptyResultText only for touch device
12304 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12306 * Create a new ComboBox.
12307 * @param {Object} config Configuration options
12309 Roo.bootstrap.ComboBox = function(config){
12310 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12314 * Fires when the dropdown list is expanded
12315 * @param {Roo.bootstrap.ComboBox} combo This combo box
12320 * Fires when the dropdown list is collapsed
12321 * @param {Roo.bootstrap.ComboBox} combo This combo box
12325 * @event beforeselect
12326 * Fires before a list item is selected. Return false to cancel the selection.
12327 * @param {Roo.bootstrap.ComboBox} combo This combo box
12328 * @param {Roo.data.Record} record The data record returned from the underlying store
12329 * @param {Number} index The index of the selected item in the dropdown list
12331 'beforeselect' : true,
12334 * Fires when a list item is selected
12335 * @param {Roo.bootstrap.ComboBox} combo This combo box
12336 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12337 * @param {Number} index The index of the selected item in the dropdown list
12341 * @event beforequery
12342 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12343 * The event object passed has these properties:
12344 * @param {Roo.bootstrap.ComboBox} combo This combo box
12345 * @param {String} query The query
12346 * @param {Boolean} forceAll true to force "all" query
12347 * @param {Boolean} cancel true to cancel the query
12348 * @param {Object} e The query event object
12350 'beforequery': true,
12353 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12354 * @param {Roo.bootstrap.ComboBox} combo This combo box
12359 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12360 * @param {Roo.bootstrap.ComboBox} combo This combo box
12361 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12366 * Fires when the remove value from the combobox array
12367 * @param {Roo.bootstrap.ComboBox} combo This combo box
12371 * @event afterremove
12372 * Fires when the remove value from the combobox array
12373 * @param {Roo.bootstrap.ComboBox} combo This combo box
12375 'afterremove' : true,
12377 * @event specialfilter
12378 * Fires when specialfilter
12379 * @param {Roo.bootstrap.ComboBox} combo This combo box
12381 'specialfilter' : true,
12384 * Fires when tick the element
12385 * @param {Roo.bootstrap.ComboBox} combo This combo box
12389 * @event touchviewdisplay
12390 * Fires when touch view require special display (default is using displayField)
12391 * @param {Roo.bootstrap.ComboBox} combo This combo box
12392 * @param {Object} cfg set html .
12394 'touchviewdisplay' : true
12399 this.tickItems = [];
12401 this.selectedIndex = -1;
12402 if(this.mode == 'local'){
12403 if(config.queryDelay === undefined){
12404 this.queryDelay = 10;
12406 if(config.minChars === undefined){
12412 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12415 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12416 * rendering into an Roo.Editor, defaults to false)
12419 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12420 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12423 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12426 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12427 * the dropdown list (defaults to undefined, with no header element)
12431 * @cfg {String/Roo.Template} tpl The template to use to render the output
12435 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12437 listWidth: undefined,
12439 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12440 * mode = 'remote' or 'text' if mode = 'local')
12442 displayField: undefined,
12445 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12446 * mode = 'remote' or 'value' if mode = 'local').
12447 * Note: use of a valueField requires the user make a selection
12448 * in order for a value to be mapped.
12450 valueField: undefined,
12452 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12457 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12458 * field's data value (defaults to the underlying DOM element's name)
12460 hiddenName: undefined,
12462 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12466 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12468 selectedClass: 'active',
12471 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12475 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12476 * anchor positions (defaults to 'tl-bl')
12478 listAlign: 'tl-bl?',
12480 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12484 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12485 * query specified by the allQuery config option (defaults to 'query')
12487 triggerAction: 'query',
12489 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12490 * (defaults to 4, does not apply if editable = false)
12494 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12495 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12499 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12500 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12504 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12505 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12509 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12510 * when editable = true (defaults to false)
12512 selectOnFocus:false,
12514 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12516 queryParam: 'query',
12518 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12519 * when mode = 'remote' (defaults to 'Loading...')
12521 loadingText: 'Loading...',
12523 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12527 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12531 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12532 * traditional select (defaults to true)
12536 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12540 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12544 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12545 * listWidth has a higher value)
12549 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12550 * allow the user to set arbitrary text into the field (defaults to false)
12552 forceSelection:false,
12554 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12555 * if typeAhead = true (defaults to 250)
12557 typeAheadDelay : 250,
12559 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12560 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12562 valueNotFoundText : undefined,
12564 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12566 blockFocus : false,
12569 * @cfg {Boolean} disableClear Disable showing of clear button.
12571 disableClear : false,
12573 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12575 alwaysQuery : false,
12578 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12583 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12585 invalidClass : "has-warning",
12588 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12590 validClass : "has-success",
12593 * @cfg {Boolean} specialFilter (true|false) special filter default false
12595 specialFilter : false,
12598 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12600 mobileTouchView : true,
12603 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12605 useNativeIOS : false,
12607 ios_options : false,
12619 btnPosition : 'right',
12620 triggerList : true,
12621 showToggleBtn : true,
12623 emptyResultText: 'Empty',
12624 triggerText : 'Select',
12626 // element that contains real text value.. (when hidden is used..)
12628 getAutoCreate : function()
12633 * Render classic select for iso
12636 if(Roo.isIOS && this.useNativeIOS){
12637 cfg = this.getAutoCreateNativeIOS();
12645 if(Roo.isTouch && this.mobileTouchView){
12646 cfg = this.getAutoCreateTouchView();
12653 if(!this.tickable){
12654 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12655 if(this.name == 'info_year_invest_id_display_name'){
12656 Roo.log('cfg.................................................');
12663 * ComboBox with tickable selections
12666 var align = this.labelAlign || this.parentLabelAlign();
12669 cls : 'form-group roo-combobox-tickable' //input-group
12672 var btn_text_select = '';
12673 var btn_text_done = '';
12674 var btn_text_cancel = '';
12676 if (this.btn_text_show) {
12677 btn_text_select = 'Select';
12678 btn_text_done = 'Done';
12679 btn_text_cancel = 'Cancel';
12684 cls : 'tickable-buttons',
12689 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12690 //html : this.triggerText
12691 html: btn_text_select
12697 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12699 html: btn_text_done
12705 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12707 html: btn_text_cancel
12713 buttons.cn.unshift({
12715 cls: 'roo-select2-search-field-input'
12721 Roo.each(buttons.cn, function(c){
12723 c.cls += ' btn-' + _this.size;
12726 if (_this.disabled) {
12737 cls: 'form-hidden-field'
12741 cls: 'roo-select2-choices',
12745 cls: 'roo-select2-search-field',
12756 cls: 'roo-select2-container input-group roo-select2-container-multi',
12761 // cls: 'typeahead typeahead-long dropdown-menu',
12762 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12767 if(this.hasFeedback && !this.allowBlank){
12771 cls: 'glyphicon form-control-feedback'
12774 combobox.cn.push(feedback);
12778 if (align ==='left' && this.fieldLabel.length) {
12780 cfg.cls += ' roo-form-group-label-left';
12785 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12786 tooltip : 'This field is required'
12791 cls : 'control-label',
12792 html : this.fieldLabel
12804 var labelCfg = cfg.cn[1];
12805 var contentCfg = cfg.cn[2];
12808 if(this.indicatorpos == 'right'){
12814 cls : 'control-label',
12818 html : this.fieldLabel
12822 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12823 tooltip : 'This field is required'
12838 labelCfg = cfg.cn[0];
12839 contentCfg = cfg.cn[1];
12843 if(this.labelWidth > 12){
12844 labelCfg.style = "width: " + this.labelWidth + 'px';
12847 if(this.labelWidth < 13 && this.labelmd == 0){
12848 this.labelmd = this.labelWidth;
12851 if(this.labellg > 0){
12852 labelCfg.cls += ' col-lg-' + this.labellg;
12853 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12856 if(this.labelmd > 0){
12857 labelCfg.cls += ' col-md-' + this.labelmd;
12858 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12861 if(this.labelsm > 0){
12862 labelCfg.cls += ' col-sm-' + this.labelsm;
12863 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12866 if(this.labelxs > 0){
12867 labelCfg.cls += ' col-xs-' + this.labelxs;
12868 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12872 } else if ( this.fieldLabel.length) {
12873 // Roo.log(" label");
12877 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12878 tooltip : 'This field is required'
12882 //cls : 'input-group-addon',
12883 html : this.fieldLabel
12891 if(this.indicatorpos == 'right'){
12896 //cls : 'input-group-addon',
12900 html : this.fieldLabel
12904 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12905 tooltip : 'This field is required'
12920 // Roo.log(" no label && no align");
12927 ['xs','sm','md','lg'].map(function(size){
12928 if (settings[size]) {
12929 cfg.cls += ' col-' + size + '-' + settings[size];
12937 _initEventsCalled : false,
12940 initEvents: function()
12942 if (this._initEventsCalled) { // as we call render... prevent looping...
12945 this._initEventsCalled = true;
12948 throw "can not find store for combo";
12951 this.store = Roo.factory(this.store, Roo.data);
12953 // if we are building from html. then this element is so complex, that we can not really
12954 // use the rendered HTML.
12955 // so we have to trash and replace the previous code.
12956 if (Roo.XComponent.build_from_html) {
12958 // remove this element....
12959 var e = this.el.dom, k=0;
12960 while (e ) { e = e.previousSibling; ++k;}
12965 this.rendered = false;
12967 this.render(this.parent().getChildContainer(true), k);
12973 if(Roo.isIOS && this.useNativeIOS){
12974 this.initIOSView();
12982 if(Roo.isTouch && this.mobileTouchView){
12983 this.initTouchView();
12988 this.initTickableEvents();
12992 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12994 if(this.hiddenName){
12996 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12998 this.hiddenField.dom.value =
12999 this.hiddenValue !== undefined ? this.hiddenValue :
13000 this.value !== undefined ? this.value : '';
13002 // prevent input submission
13003 this.el.dom.removeAttribute('name');
13004 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13009 // this.el.dom.setAttribute('autocomplete', 'off');
13012 var cls = 'x-combo-list';
13014 //this.list = new Roo.Layer({
13015 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13021 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13022 _this.list.setWidth(lw);
13025 this.list.on('mouseover', this.onViewOver, this);
13026 this.list.on('mousemove', this.onViewMove, this);
13028 this.list.on('scroll', this.onViewScroll, this);
13031 this.list.swallowEvent('mousewheel');
13032 this.assetHeight = 0;
13035 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13036 this.assetHeight += this.header.getHeight();
13039 this.innerList = this.list.createChild({cls:cls+'-inner'});
13040 this.innerList.on('mouseover', this.onViewOver, this);
13041 this.innerList.on('mousemove', this.onViewMove, this);
13042 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13044 if(this.allowBlank && !this.pageSize && !this.disableClear){
13045 this.footer = this.list.createChild({cls:cls+'-ft'});
13046 this.pageTb = new Roo.Toolbar(this.footer);
13050 this.footer = this.list.createChild({cls:cls+'-ft'});
13051 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13052 {pageSize: this.pageSize});
13056 if (this.pageTb && this.allowBlank && !this.disableClear) {
13058 this.pageTb.add(new Roo.Toolbar.Fill(), {
13059 cls: 'x-btn-icon x-btn-clear',
13061 handler: function()
13064 _this.clearValue();
13065 _this.onSelect(false, -1);
13070 this.assetHeight += this.footer.getHeight();
13075 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13078 this.view = new Roo.View(this.list, this.tpl, {
13079 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13081 //this.view.wrapEl.setDisplayed(false);
13082 this.view.on('click', this.onViewClick, this);
13086 this.store.on('beforeload', this.onBeforeLoad, this);
13087 this.store.on('load', this.onLoad, this);
13088 this.store.on('loadexception', this.onLoadException, this);
13090 if(this.resizable){
13091 this.resizer = new Roo.Resizable(this.list, {
13092 pinned:true, handles:'se'
13094 this.resizer.on('resize', function(r, w, h){
13095 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13096 this.listWidth = w;
13097 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13098 this.restrictHeight();
13100 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13103 if(!this.editable){
13104 this.editable = true;
13105 this.setEditable(false);
13110 if (typeof(this.events.add.listeners) != 'undefined') {
13112 this.addicon = this.wrap.createChild(
13113 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13115 this.addicon.on('click', function(e) {
13116 this.fireEvent('add', this);
13119 if (typeof(this.events.edit.listeners) != 'undefined') {
13121 this.editicon = this.wrap.createChild(
13122 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13123 if (this.addicon) {
13124 this.editicon.setStyle('margin-left', '40px');
13126 this.editicon.on('click', function(e) {
13128 // we fire even if inothing is selected..
13129 this.fireEvent('edit', this, this.lastData );
13135 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13136 "up" : function(e){
13137 this.inKeyMode = true;
13141 "down" : function(e){
13142 if(!this.isExpanded()){
13143 this.onTriggerClick();
13145 this.inKeyMode = true;
13150 "enter" : function(e){
13151 // this.onViewClick();
13155 if(this.fireEvent("specialkey", this, e)){
13156 this.onViewClick(false);
13162 "esc" : function(e){
13166 "tab" : function(e){
13169 if(this.fireEvent("specialkey", this, e)){
13170 this.onViewClick(false);
13178 doRelay : function(foo, bar, hname){
13179 if(hname == 'down' || this.scope.isExpanded()){
13180 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13189 this.queryDelay = Math.max(this.queryDelay || 10,
13190 this.mode == 'local' ? 10 : 250);
13193 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13195 if(this.typeAhead){
13196 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13198 if(this.editable !== false){
13199 this.inputEl().on("keyup", this.onKeyUp, this);
13201 if(this.forceSelection){
13202 this.inputEl().on('blur', this.doForce, this);
13206 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13207 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13211 initTickableEvents: function()
13215 if(this.hiddenName){
13217 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13219 this.hiddenField.dom.value =
13220 this.hiddenValue !== undefined ? this.hiddenValue :
13221 this.value !== undefined ? this.value : '';
13223 // prevent input submission
13224 this.el.dom.removeAttribute('name');
13225 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13230 // this.list = this.el.select('ul.dropdown-menu',true).first();
13232 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13233 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13234 if(this.triggerList){
13235 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13238 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13239 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13241 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13242 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13244 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13245 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13247 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13248 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13249 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13252 this.cancelBtn.hide();
13257 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13258 _this.list.setWidth(lw);
13261 this.list.on('mouseover', this.onViewOver, this);
13262 this.list.on('mousemove', this.onViewMove, this);
13264 this.list.on('scroll', this.onViewScroll, this);
13267 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>';
13270 this.view = new Roo.View(this.list, this.tpl, {
13271 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13274 //this.view.wrapEl.setDisplayed(false);
13275 this.view.on('click', this.onViewClick, this);
13279 this.store.on('beforeload', this.onBeforeLoad, this);
13280 this.store.on('load', this.onLoad, this);
13281 this.store.on('loadexception', this.onLoadException, this);
13284 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13285 "up" : function(e){
13286 this.inKeyMode = true;
13290 "down" : function(e){
13291 this.inKeyMode = true;
13295 "enter" : function(e){
13296 if(this.fireEvent("specialkey", this, e)){
13297 this.onViewClick(false);
13303 "esc" : function(e){
13304 this.onTickableFooterButtonClick(e, false, false);
13307 "tab" : function(e){
13308 this.fireEvent("specialkey", this, e);
13310 this.onTickableFooterButtonClick(e, false, false);
13317 doRelay : function(e, fn, key){
13318 if(this.scope.isExpanded()){
13319 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13328 this.queryDelay = Math.max(this.queryDelay || 10,
13329 this.mode == 'local' ? 10 : 250);
13332 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13334 if(this.typeAhead){
13335 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13338 if(this.editable !== false){
13339 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13342 this.indicator = this.indicatorEl();
13344 if(this.indicator){
13345 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13346 this.indicator.hide();
13351 onDestroy : function(){
13353 this.view.setStore(null);
13354 this.view.el.removeAllListeners();
13355 this.view.el.remove();
13356 this.view.purgeListeners();
13359 this.list.dom.innerHTML = '';
13363 this.store.un('beforeload', this.onBeforeLoad, this);
13364 this.store.un('load', this.onLoad, this);
13365 this.store.un('loadexception', this.onLoadException, this);
13367 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13371 fireKey : function(e){
13372 if(e.isNavKeyPress() && !this.list.isVisible()){
13373 this.fireEvent("specialkey", this, e);
13378 onResize: function(w, h){
13379 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13381 // if(typeof w != 'number'){
13382 // // we do not handle it!?!?
13385 // var tw = this.trigger.getWidth();
13386 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13387 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13389 // this.inputEl().setWidth( this.adjustWidth('input', x));
13391 // //this.trigger.setStyle('left', x+'px');
13393 // if(this.list && this.listWidth === undefined){
13394 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13395 // this.list.setWidth(lw);
13396 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13404 * Allow or prevent the user from directly editing the field text. If false is passed,
13405 * the user will only be able to select from the items defined in the dropdown list. This method
13406 * is the runtime equivalent of setting the 'editable' config option at config time.
13407 * @param {Boolean} value True to allow the user to directly edit the field text
13409 setEditable : function(value){
13410 if(value == this.editable){
13413 this.editable = value;
13415 this.inputEl().dom.setAttribute('readOnly', true);
13416 this.inputEl().on('mousedown', this.onTriggerClick, this);
13417 this.inputEl().addClass('x-combo-noedit');
13419 this.inputEl().dom.setAttribute('readOnly', false);
13420 this.inputEl().un('mousedown', this.onTriggerClick, this);
13421 this.inputEl().removeClass('x-combo-noedit');
13427 onBeforeLoad : function(combo,opts){
13428 if(!this.hasFocus){
13432 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13434 this.restrictHeight();
13435 this.selectedIndex = -1;
13439 onLoad : function(){
13441 this.hasQuery = false;
13443 if(!this.hasFocus){
13447 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13448 this.loading.hide();
13451 if(this.store.getCount() > 0){
13453 this.restrictHeight();
13454 if(this.lastQuery == this.allQuery){
13455 if(this.editable && !this.tickable){
13456 this.inputEl().dom.select();
13460 !this.selectByValue(this.value, true) &&
13463 !this.store.lastOptions ||
13464 typeof(this.store.lastOptions.add) == 'undefined' ||
13465 this.store.lastOptions.add != true
13468 this.select(0, true);
13471 if(this.autoFocus){
13474 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13475 this.taTask.delay(this.typeAheadDelay);
13479 this.onEmptyResults();
13485 onLoadException : function()
13487 this.hasQuery = false;
13489 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13490 this.loading.hide();
13493 if(this.tickable && this.editable){
13498 // only causes errors at present
13499 //Roo.log(this.store.reader.jsonData);
13500 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13502 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13508 onTypeAhead : function(){
13509 if(this.store.getCount() > 0){
13510 var r = this.store.getAt(0);
13511 var newValue = r.data[this.displayField];
13512 var len = newValue.length;
13513 var selStart = this.getRawValue().length;
13515 if(selStart != len){
13516 this.setRawValue(newValue);
13517 this.selectText(selStart, newValue.length);
13523 onSelect : function(record, index){
13525 if(this.fireEvent('beforeselect', this, record, index) !== false){
13527 this.setFromData(index > -1 ? record.data : false);
13530 this.fireEvent('select', this, record, index);
13535 * Returns the currently selected field value or empty string if no value is set.
13536 * @return {String} value The selected value
13538 getValue : function()
13540 if(Roo.isIOS && this.useNativeIOS){
13541 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13545 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13548 if(this.valueField){
13549 return typeof this.value != 'undefined' ? this.value : '';
13551 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13555 getRawValue : function()
13557 if(Roo.isIOS && this.useNativeIOS){
13558 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13561 var v = this.inputEl().getValue();
13567 * Clears any text/value currently set in the field
13569 clearValue : function(){
13571 if(this.hiddenField){
13572 this.hiddenField.dom.value = '';
13575 this.setRawValue('');
13576 this.lastSelectionText = '';
13577 this.lastData = false;
13579 var close = this.closeTriggerEl();
13590 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13591 * will be displayed in the field. If the value does not match the data value of an existing item,
13592 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13593 * Otherwise the field will be blank (although the value will still be set).
13594 * @param {String} value The value to match
13596 setValue : function(v)
13598 if(Roo.isIOS && this.useNativeIOS){
13599 this.setIOSValue(v);
13609 if(this.valueField){
13610 var r = this.findRecord(this.valueField, v);
13612 text = r.data[this.displayField];
13613 }else if(this.valueNotFoundText !== undefined){
13614 text = this.valueNotFoundText;
13617 this.lastSelectionText = text;
13618 if(this.hiddenField){
13619 this.hiddenField.dom.value = v;
13621 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13624 var close = this.closeTriggerEl();
13627 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13633 * @property {Object} the last set data for the element
13638 * Sets the value of the field based on a object which is related to the record format for the store.
13639 * @param {Object} value the value to set as. or false on reset?
13641 setFromData : function(o){
13648 var dv = ''; // display value
13649 var vv = ''; // value value..
13651 if (this.displayField) {
13652 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13654 // this is an error condition!!!
13655 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13658 if(this.valueField){
13659 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13662 var close = this.closeTriggerEl();
13665 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13668 if(this.hiddenField){
13669 this.hiddenField.dom.value = vv;
13671 this.lastSelectionText = dv;
13672 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13676 // no hidden field.. - we store the value in 'value', but still display
13677 // display field!!!!
13678 this.lastSelectionText = dv;
13679 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13686 reset : function(){
13687 // overridden so that last data is reset..
13694 this.setValue(this.originalValue);
13695 //this.clearInvalid();
13696 this.lastData = false;
13698 this.view.clearSelections();
13704 findRecord : function(prop, value){
13706 if(this.store.getCount() > 0){
13707 this.store.each(function(r){
13708 if(r.data[prop] == value){
13718 getName: function()
13720 // returns hidden if it's set..
13721 if (!this.rendered) {return ''};
13722 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13726 onViewMove : function(e, t){
13727 this.inKeyMode = false;
13731 onViewOver : function(e, t){
13732 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13735 var item = this.view.findItemFromChild(t);
13738 var index = this.view.indexOf(item);
13739 this.select(index, false);
13744 onViewClick : function(view, doFocus, el, e)
13746 var index = this.view.getSelectedIndexes()[0];
13748 var r = this.store.getAt(index);
13752 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13759 Roo.each(this.tickItems, function(v,k){
13761 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13763 _this.tickItems.splice(k, 1);
13765 if(typeof(e) == 'undefined' && view == false){
13766 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13778 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13779 this.tickItems.push(r.data);
13782 if(typeof(e) == 'undefined' && view == false){
13783 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13790 this.onSelect(r, index);
13792 if(doFocus !== false && !this.blockFocus){
13793 this.inputEl().focus();
13798 restrictHeight : function(){
13799 //this.innerList.dom.style.height = '';
13800 //var inner = this.innerList.dom;
13801 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13802 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13803 //this.list.beginUpdate();
13804 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13805 this.list.alignTo(this.inputEl(), this.listAlign);
13806 this.list.alignTo(this.inputEl(), this.listAlign);
13807 //this.list.endUpdate();
13811 onEmptyResults : function(){
13813 if(this.tickable && this.editable){
13814 this.restrictHeight();
13822 * Returns true if the dropdown list is expanded, else false.
13824 isExpanded : function(){
13825 return this.list.isVisible();
13829 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13830 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13831 * @param {String} value The data value of the item to select
13832 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13833 * selected item if it is not currently in view (defaults to true)
13834 * @return {Boolean} True if the value matched an item in the list, else false
13836 selectByValue : function(v, scrollIntoView){
13837 if(v !== undefined && v !== null){
13838 var r = this.findRecord(this.valueField || this.displayField, v);
13840 this.select(this.store.indexOf(r), scrollIntoView);
13848 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13849 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13850 * @param {Number} index The zero-based index of the list item to select
13851 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13852 * selected item if it is not currently in view (defaults to true)
13854 select : function(index, scrollIntoView){
13855 this.selectedIndex = index;
13856 this.view.select(index);
13857 if(scrollIntoView !== false){
13858 var el = this.view.getNode(index);
13860 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13863 this.list.scrollChildIntoView(el, false);
13869 selectNext : function(){
13870 var ct = this.store.getCount();
13872 if(this.selectedIndex == -1){
13874 }else if(this.selectedIndex < ct-1){
13875 this.select(this.selectedIndex+1);
13881 selectPrev : function(){
13882 var ct = this.store.getCount();
13884 if(this.selectedIndex == -1){
13886 }else if(this.selectedIndex != 0){
13887 this.select(this.selectedIndex-1);
13893 onKeyUp : function(e){
13894 if(this.editable !== false && !e.isSpecialKey()){
13895 this.lastKey = e.getKey();
13896 this.dqTask.delay(this.queryDelay);
13901 validateBlur : function(){
13902 return !this.list || !this.list.isVisible();
13906 initQuery : function(){
13908 var v = this.getRawValue();
13910 if(this.tickable && this.editable){
13911 v = this.tickableInputEl().getValue();
13918 doForce : function(){
13919 if(this.inputEl().dom.value.length > 0){
13920 this.inputEl().dom.value =
13921 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13927 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13928 * query allowing the query action to be canceled if needed.
13929 * @param {String} query The SQL query to execute
13930 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13931 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13932 * saved in the current store (defaults to false)
13934 doQuery : function(q, forceAll){
13936 if(q === undefined || q === null){
13941 forceAll: forceAll,
13945 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13950 forceAll = qe.forceAll;
13951 if(forceAll === true || (q.length >= this.minChars)){
13953 this.hasQuery = true;
13955 if(this.lastQuery != q || this.alwaysQuery){
13956 this.lastQuery = q;
13957 if(this.mode == 'local'){
13958 this.selectedIndex = -1;
13960 this.store.clearFilter();
13963 if(this.specialFilter){
13964 this.fireEvent('specialfilter', this);
13969 this.store.filter(this.displayField, q);
13972 this.store.fireEvent("datachanged", this.store);
13979 this.store.baseParams[this.queryParam] = q;
13981 var options = {params : this.getParams(q)};
13984 options.add = true;
13985 options.params.start = this.page * this.pageSize;
13988 this.store.load(options);
13991 * this code will make the page width larger, at the beginning, the list not align correctly,
13992 * we should expand the list on onLoad
13993 * so command out it
13998 this.selectedIndex = -1;
14003 this.loadNext = false;
14007 getParams : function(q){
14009 //p[this.queryParam] = q;
14013 p.limit = this.pageSize;
14019 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14021 collapse : function(){
14022 if(!this.isExpanded()){
14028 this.hasFocus = false;
14032 this.cancelBtn.hide();
14033 this.trigger.show();
14036 this.tickableInputEl().dom.value = '';
14037 this.tickableInputEl().blur();
14042 Roo.get(document).un('mousedown', this.collapseIf, this);
14043 Roo.get(document).un('mousewheel', this.collapseIf, this);
14044 if (!this.editable) {
14045 Roo.get(document).un('keydown', this.listKeyPress, this);
14047 this.fireEvent('collapse', this);
14053 collapseIf : function(e){
14054 var in_combo = e.within(this.el);
14055 var in_list = e.within(this.list);
14056 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14058 if (in_combo || in_list || is_list) {
14059 //e.stopPropagation();
14064 this.onTickableFooterButtonClick(e, false, false);
14072 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14074 expand : function(){
14076 if(this.isExpanded() || !this.hasFocus){
14080 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14081 this.list.setWidth(lw);
14087 this.restrictHeight();
14091 this.tickItems = Roo.apply([], this.item);
14094 this.cancelBtn.show();
14095 this.trigger.hide();
14098 this.tickableInputEl().focus();
14103 Roo.get(document).on('mousedown', this.collapseIf, this);
14104 Roo.get(document).on('mousewheel', this.collapseIf, this);
14105 if (!this.editable) {
14106 Roo.get(document).on('keydown', this.listKeyPress, this);
14109 this.fireEvent('expand', this);
14113 // Implements the default empty TriggerField.onTriggerClick function
14114 onTriggerClick : function(e)
14116 Roo.log('trigger click');
14118 if(this.disabled || !this.triggerList){
14123 this.loadNext = false;
14125 if(this.isExpanded()){
14127 if (!this.blockFocus) {
14128 this.inputEl().focus();
14132 this.hasFocus = true;
14133 if(this.triggerAction == 'all') {
14134 this.doQuery(this.allQuery, true);
14136 this.doQuery(this.getRawValue());
14138 if (!this.blockFocus) {
14139 this.inputEl().focus();
14144 onTickableTriggerClick : function(e)
14151 this.loadNext = false;
14152 this.hasFocus = true;
14154 if(this.triggerAction == 'all') {
14155 this.doQuery(this.allQuery, true);
14157 this.doQuery(this.getRawValue());
14161 onSearchFieldClick : function(e)
14163 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14164 this.onTickableFooterButtonClick(e, false, false);
14168 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14173 this.loadNext = false;
14174 this.hasFocus = true;
14176 if(this.triggerAction == 'all') {
14177 this.doQuery(this.allQuery, true);
14179 this.doQuery(this.getRawValue());
14183 listKeyPress : function(e)
14185 //Roo.log('listkeypress');
14186 // scroll to first matching element based on key pres..
14187 if (e.isSpecialKey()) {
14190 var k = String.fromCharCode(e.getKey()).toUpperCase();
14193 var csel = this.view.getSelectedNodes();
14194 var cselitem = false;
14196 var ix = this.view.indexOf(csel[0]);
14197 cselitem = this.store.getAt(ix);
14198 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14204 this.store.each(function(v) {
14206 // start at existing selection.
14207 if (cselitem.id == v.id) {
14213 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14214 match = this.store.indexOf(v);
14220 if (match === false) {
14221 return true; // no more action?
14224 this.view.select(match);
14225 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14226 sn.scrollIntoView(sn.dom.parentNode, false);
14229 onViewScroll : function(e, t){
14231 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){
14235 this.hasQuery = true;
14237 this.loading = this.list.select('.loading', true).first();
14239 if(this.loading === null){
14240 this.list.createChild({
14242 cls: 'loading roo-select2-more-results roo-select2-active',
14243 html: 'Loading more results...'
14246 this.loading = this.list.select('.loading', true).first();
14248 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14250 this.loading.hide();
14253 this.loading.show();
14258 this.loadNext = true;
14260 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14265 addItem : function(o)
14267 var dv = ''; // display value
14269 if (this.displayField) {
14270 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14272 // this is an error condition!!!
14273 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14280 var choice = this.choices.createChild({
14282 cls: 'roo-select2-search-choice',
14291 cls: 'roo-select2-search-choice-close',
14296 }, this.searchField);
14298 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14300 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14308 this.inputEl().dom.value = '';
14313 onRemoveItem : function(e, _self, o)
14315 e.preventDefault();
14317 this.lastItem = Roo.apply([], this.item);
14319 var index = this.item.indexOf(o.data) * 1;
14322 Roo.log('not this item?!');
14326 this.item.splice(index, 1);
14331 this.fireEvent('remove', this, e);
14337 syncValue : function()
14339 if(!this.item.length){
14346 Roo.each(this.item, function(i){
14347 if(_this.valueField){
14348 value.push(i[_this.valueField]);
14355 this.value = value.join(',');
14357 if(this.hiddenField){
14358 this.hiddenField.dom.value = this.value;
14361 this.store.fireEvent("datachanged", this.store);
14366 clearItem : function()
14368 if(!this.multiple){
14374 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14382 if(this.tickable && !Roo.isTouch){
14383 this.view.refresh();
14387 inputEl: function ()
14389 if(Roo.isIOS && this.useNativeIOS){
14390 return this.el.select('select.roo-ios-select', true).first();
14393 if(Roo.isTouch && this.mobileTouchView){
14394 return this.el.select('input.form-control',true).first();
14398 return this.searchField;
14401 return this.el.select('input.form-control',true).first();
14404 onTickableFooterButtonClick : function(e, btn, el)
14406 e.preventDefault();
14408 this.lastItem = Roo.apply([], this.item);
14410 if(btn && btn.name == 'cancel'){
14411 this.tickItems = Roo.apply([], this.item);
14420 Roo.each(this.tickItems, function(o){
14428 validate : function()
14430 var v = this.getRawValue();
14433 v = this.getValue();
14436 if(this.disabled || this.allowBlank || v.length){
14441 this.markInvalid();
14445 tickableInputEl : function()
14447 if(!this.tickable || !this.editable){
14448 return this.inputEl();
14451 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14455 getAutoCreateTouchView : function()
14460 cls: 'form-group' //input-group
14466 type : this.inputType,
14467 cls : 'form-control x-combo-noedit',
14468 autocomplete: 'new-password',
14469 placeholder : this.placeholder || '',
14474 input.name = this.name;
14478 input.cls += ' input-' + this.size;
14481 if (this.disabled) {
14482 input.disabled = true;
14493 inputblock.cls += ' input-group';
14495 inputblock.cn.unshift({
14497 cls : 'input-group-addon',
14502 if(this.removable && !this.multiple){
14503 inputblock.cls += ' roo-removable';
14505 inputblock.cn.push({
14508 cls : 'roo-combo-removable-btn close'
14512 if(this.hasFeedback && !this.allowBlank){
14514 inputblock.cls += ' has-feedback';
14516 inputblock.cn.push({
14518 cls: 'glyphicon form-control-feedback'
14525 inputblock.cls += (this.before) ? '' : ' input-group';
14527 inputblock.cn.push({
14529 cls : 'input-group-addon',
14540 cls: 'form-hidden-field'
14554 cls: 'form-hidden-field'
14558 cls: 'roo-select2-choices',
14562 cls: 'roo-select2-search-field',
14575 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14581 if(!this.multiple && this.showToggleBtn){
14588 if (this.caret != false) {
14591 cls: 'fa fa-' + this.caret
14598 cls : 'input-group-addon btn dropdown-toggle',
14603 cls: 'combobox-clear',
14617 combobox.cls += ' roo-select2-container-multi';
14620 var align = this.labelAlign || this.parentLabelAlign();
14622 if (align ==='left' && this.fieldLabel.length) {
14627 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14628 tooltip : 'This field is required'
14632 cls : 'control-label',
14633 html : this.fieldLabel
14644 var labelCfg = cfg.cn[1];
14645 var contentCfg = cfg.cn[2];
14648 if(this.indicatorpos == 'right'){
14652 cls : 'control-label',
14653 html : this.fieldLabel,
14657 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14658 tooltip : 'This field is required'
14671 labelCfg = cfg.cn[0];
14672 contentCfg = cfg.cn[2];
14674 if(this.labelWidth > 12){
14675 labelCfg.style = "width: " + this.labelWidth + 'px';
14678 if(this.labelWidth < 13 && this.labelmd == 0){
14679 this.labelmd = this.labelWidth;
14682 if(this.labellg > 0){
14683 labelCfg.cls += ' col-lg-' + this.labellg;
14684 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14687 if(this.labelmd > 0){
14688 labelCfg.cls += ' col-md-' + this.labelmd;
14689 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14692 if(this.labelsm > 0){
14693 labelCfg.cls += ' col-sm-' + this.labelsm;
14694 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14697 if(this.labelxs > 0){
14698 labelCfg.cls += ' col-xs-' + this.labelxs;
14699 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14703 } else if ( this.fieldLabel.length) {
14707 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14708 tooltip : 'This field is required'
14712 cls : 'control-label',
14713 html : this.fieldLabel
14724 if(this.indicatorpos == 'right'){
14728 cls : 'control-label',
14729 html : this.fieldLabel,
14733 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14734 tooltip : 'This field is required'
14751 var settings = this;
14753 ['xs','sm','md','lg'].map(function(size){
14754 if (settings[size]) {
14755 cfg.cls += ' col-' + size + '-' + settings[size];
14762 initTouchView : function()
14764 this.renderTouchView();
14766 this.touchViewEl.on('scroll', function(){
14767 this.el.dom.scrollTop = 0;
14770 this.originalValue = this.getValue();
14772 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14774 this.inputEl().on("click", this.showTouchView, this);
14775 if (this.triggerEl) {
14776 this.triggerEl.on("click", this.showTouchView, this);
14780 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14781 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14783 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14785 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14786 this.store.on('load', this.onTouchViewLoad, this);
14787 this.store.on('loadexception', this.onTouchViewLoadException, this);
14789 if(this.hiddenName){
14791 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14793 this.hiddenField.dom.value =
14794 this.hiddenValue !== undefined ? this.hiddenValue :
14795 this.value !== undefined ? this.value : '';
14797 this.el.dom.removeAttribute('name');
14798 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14802 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14803 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14806 if(this.removable && !this.multiple){
14807 var close = this.closeTriggerEl();
14809 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14810 close.on('click', this.removeBtnClick, this, close);
14814 * fix the bug in Safari iOS8
14816 this.inputEl().on("focus", function(e){
14817 document.activeElement.blur();
14825 renderTouchView : function()
14827 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14828 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14830 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14831 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14833 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14834 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14835 this.touchViewBodyEl.setStyle('overflow', 'auto');
14837 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14838 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14840 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14841 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14845 showTouchView : function()
14851 this.touchViewHeaderEl.hide();
14853 if(this.modalTitle.length){
14854 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14855 this.touchViewHeaderEl.show();
14858 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14859 this.touchViewEl.show();
14861 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14862 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14863 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14865 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14867 if(this.modalTitle.length){
14868 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14871 this.touchViewBodyEl.setHeight(bodyHeight);
14875 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14877 this.touchViewEl.addClass('in');
14880 this.doTouchViewQuery();
14884 hideTouchView : function()
14886 this.touchViewEl.removeClass('in');
14890 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14892 this.touchViewEl.setStyle('display', 'none');
14897 setTouchViewValue : function()
14904 Roo.each(this.tickItems, function(o){
14909 this.hideTouchView();
14912 doTouchViewQuery : function()
14921 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14925 if(!this.alwaysQuery || this.mode == 'local'){
14926 this.onTouchViewLoad();
14933 onTouchViewBeforeLoad : function(combo,opts)
14939 onTouchViewLoad : function()
14941 if(this.store.getCount() < 1){
14942 this.onTouchViewEmptyResults();
14946 this.clearTouchView();
14948 var rawValue = this.getRawValue();
14950 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14952 this.tickItems = [];
14954 this.store.data.each(function(d, rowIndex){
14955 var row = this.touchViewListGroup.createChild(template);
14957 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14958 row.addClass(d.data.cls);
14961 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14964 html : d.data[this.displayField]
14967 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14968 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14971 row.removeClass('selected');
14972 if(!this.multiple && this.valueField &&
14973 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14976 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14977 row.addClass('selected');
14980 if(this.multiple && this.valueField &&
14981 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14985 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14986 this.tickItems.push(d.data);
14989 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14993 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14995 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14997 if(this.modalTitle.length){
14998 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15001 var listHeight = this.touchViewListGroup.getHeight();
15005 if(firstChecked && listHeight > bodyHeight){
15006 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15011 onTouchViewLoadException : function()
15013 this.hideTouchView();
15016 onTouchViewEmptyResults : function()
15018 this.clearTouchView();
15020 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15022 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15026 clearTouchView : function()
15028 this.touchViewListGroup.dom.innerHTML = '';
15031 onTouchViewClick : function(e, el, o)
15033 e.preventDefault();
15036 var rowIndex = o.rowIndex;
15038 var r = this.store.getAt(rowIndex);
15040 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15042 if(!this.multiple){
15043 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15044 c.dom.removeAttribute('checked');
15047 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15049 this.setFromData(r.data);
15051 var close = this.closeTriggerEl();
15057 this.hideTouchView();
15059 this.fireEvent('select', this, r, rowIndex);
15064 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15065 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15066 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15070 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15071 this.addItem(r.data);
15072 this.tickItems.push(r.data);
15076 getAutoCreateNativeIOS : function()
15079 cls: 'form-group' //input-group,
15084 cls : 'roo-ios-select'
15088 combobox.name = this.name;
15091 if (this.disabled) {
15092 combobox.disabled = true;
15095 var settings = this;
15097 ['xs','sm','md','lg'].map(function(size){
15098 if (settings[size]) {
15099 cfg.cls += ' col-' + size + '-' + settings[size];
15109 initIOSView : function()
15111 this.store.on('load', this.onIOSViewLoad, this);
15116 onIOSViewLoad : function()
15118 if(this.store.getCount() < 1){
15122 this.clearIOSView();
15124 if(this.allowBlank) {
15126 var default_text = '-- SELECT --';
15128 var opt = this.inputEl().createChild({
15131 html : default_text
15135 o[this.valueField] = 0;
15136 o[this.displayField] = default_text;
15138 this.ios_options.push({
15145 this.store.data.each(function(d, rowIndex){
15149 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15150 html = d.data[this.displayField];
15155 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15156 value = d.data[this.valueField];
15165 if(this.value == d.data[this.valueField]){
15166 option['selected'] = true;
15169 var opt = this.inputEl().createChild(option);
15171 this.ios_options.push({
15178 this.inputEl().on('change', function(){
15179 this.fireEvent('select', this);
15184 clearIOSView: function()
15186 this.inputEl().dom.innerHTML = '';
15188 this.ios_options = [];
15191 setIOSValue: function(v)
15195 if(!this.ios_options){
15199 Roo.each(this.ios_options, function(opts){
15201 opts.el.dom.removeAttribute('selected');
15203 if(opts.data[this.valueField] != v){
15207 opts.el.dom.setAttribute('selected', true);
15213 * @cfg {Boolean} grow
15217 * @cfg {Number} growMin
15221 * @cfg {Number} growMax
15230 Roo.apply(Roo.bootstrap.ComboBox, {
15234 cls: 'modal-header',
15256 cls: 'list-group-item',
15260 cls: 'roo-combobox-list-group-item-value'
15264 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15278 listItemCheckbox : {
15280 cls: 'list-group-item',
15284 cls: 'roo-combobox-list-group-item-value'
15288 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15304 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15309 cls: 'modal-footer',
15317 cls: 'col-xs-6 text-left',
15320 cls: 'btn btn-danger roo-touch-view-cancel',
15326 cls: 'col-xs-6 text-right',
15329 cls: 'btn btn-success roo-touch-view-ok',
15340 Roo.apply(Roo.bootstrap.ComboBox, {
15342 touchViewTemplate : {
15344 cls: 'modal fade roo-combobox-touch-view',
15348 cls: 'modal-dialog',
15349 style : 'position:fixed', // we have to fix position....
15353 cls: 'modal-content',
15355 Roo.bootstrap.ComboBox.header,
15356 Roo.bootstrap.ComboBox.body,
15357 Roo.bootstrap.ComboBox.footer
15366 * Ext JS Library 1.1.1
15367 * Copyright(c) 2006-2007, Ext JS, LLC.
15369 * Originally Released Under LGPL - original licence link has changed is not relivant.
15372 * <script type="text/javascript">
15377 * @extends Roo.util.Observable
15378 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15379 * This class also supports single and multi selection modes. <br>
15380 * Create a data model bound view:
15382 var store = new Roo.data.Store(...);
15384 var view = new Roo.View({
15386 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15388 singleSelect: true,
15389 selectedClass: "ydataview-selected",
15393 // listen for node click?
15394 view.on("click", function(vw, index, node, e){
15395 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15399 dataModel.load("foobar.xml");
15401 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15403 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15404 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15406 * Note: old style constructor is still suported (container, template, config)
15409 * Create a new View
15410 * @param {Object} config The config object
15413 Roo.View = function(config, depreciated_tpl, depreciated_config){
15415 this.parent = false;
15417 if (typeof(depreciated_tpl) == 'undefined') {
15418 // new way.. - universal constructor.
15419 Roo.apply(this, config);
15420 this.el = Roo.get(this.el);
15423 this.el = Roo.get(config);
15424 this.tpl = depreciated_tpl;
15425 Roo.apply(this, depreciated_config);
15427 this.wrapEl = this.el.wrap().wrap();
15428 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15431 if(typeof(this.tpl) == "string"){
15432 this.tpl = new Roo.Template(this.tpl);
15434 // support xtype ctors..
15435 this.tpl = new Roo.factory(this.tpl, Roo);
15439 this.tpl.compile();
15444 * @event beforeclick
15445 * Fires before a click is processed. Returns false to cancel the default action.
15446 * @param {Roo.View} this
15447 * @param {Number} index The index of the target node
15448 * @param {HTMLElement} node The target node
15449 * @param {Roo.EventObject} e The raw event object
15451 "beforeclick" : true,
15454 * Fires when a template node is clicked.
15455 * @param {Roo.View} this
15456 * @param {Number} index The index of the target node
15457 * @param {HTMLElement} node The target node
15458 * @param {Roo.EventObject} e The raw event object
15463 * Fires when a template node is double clicked.
15464 * @param {Roo.View} this
15465 * @param {Number} index The index of the target node
15466 * @param {HTMLElement} node The target node
15467 * @param {Roo.EventObject} e The raw event object
15471 * @event contextmenu
15472 * Fires when a template node is right clicked.
15473 * @param {Roo.View} this
15474 * @param {Number} index The index of the target node
15475 * @param {HTMLElement} node The target node
15476 * @param {Roo.EventObject} e The raw event object
15478 "contextmenu" : true,
15480 * @event selectionchange
15481 * Fires when the selected nodes change.
15482 * @param {Roo.View} this
15483 * @param {Array} selections Array of the selected nodes
15485 "selectionchange" : true,
15488 * @event beforeselect
15489 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15490 * @param {Roo.View} this
15491 * @param {HTMLElement} node The node to be selected
15492 * @param {Array} selections Array of currently selected nodes
15494 "beforeselect" : true,
15496 * @event preparedata
15497 * Fires on every row to render, to allow you to change the data.
15498 * @param {Roo.View} this
15499 * @param {Object} data to be rendered (change this)
15501 "preparedata" : true
15509 "click": this.onClick,
15510 "dblclick": this.onDblClick,
15511 "contextmenu": this.onContextMenu,
15515 this.selections = [];
15517 this.cmp = new Roo.CompositeElementLite([]);
15519 this.store = Roo.factory(this.store, Roo.data);
15520 this.setStore(this.store, true);
15523 if ( this.footer && this.footer.xtype) {
15525 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15527 this.footer.dataSource = this.store;
15528 this.footer.container = fctr;
15529 this.footer = Roo.factory(this.footer, Roo);
15530 fctr.insertFirst(this.el);
15532 // this is a bit insane - as the paging toolbar seems to detach the el..
15533 // dom.parentNode.parentNode.parentNode
15534 // they get detached?
15538 Roo.View.superclass.constructor.call(this);
15543 Roo.extend(Roo.View, Roo.util.Observable, {
15546 * @cfg {Roo.data.Store} store Data store to load data from.
15551 * @cfg {String|Roo.Element} el The container element.
15556 * @cfg {String|Roo.Template} tpl The template used by this View
15560 * @cfg {String} dataName the named area of the template to use as the data area
15561 * Works with domtemplates roo-name="name"
15565 * @cfg {String} selectedClass The css class to add to selected nodes
15567 selectedClass : "x-view-selected",
15569 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15574 * @cfg {String} text to display on mask (default Loading)
15578 * @cfg {Boolean} multiSelect Allow multiple selection
15580 multiSelect : false,
15582 * @cfg {Boolean} singleSelect Allow single selection
15584 singleSelect: false,
15587 * @cfg {Boolean} toggleSelect - selecting
15589 toggleSelect : false,
15592 * @cfg {Boolean} tickable - selecting
15597 * Returns the element this view is bound to.
15598 * @return {Roo.Element}
15600 getEl : function(){
15601 return this.wrapEl;
15607 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15609 refresh : function(){
15610 //Roo.log('refresh');
15613 // if we are using something like 'domtemplate', then
15614 // the what gets used is:
15615 // t.applySubtemplate(NAME, data, wrapping data..)
15616 // the outer template then get' applied with
15617 // the store 'extra data'
15618 // and the body get's added to the
15619 // roo-name="data" node?
15620 // <span class='roo-tpl-{name}'></span> ?????
15624 this.clearSelections();
15625 this.el.update("");
15627 var records = this.store.getRange();
15628 if(records.length < 1) {
15630 // is this valid?? = should it render a template??
15632 this.el.update(this.emptyText);
15636 if (this.dataName) {
15637 this.el.update(t.apply(this.store.meta)); //????
15638 el = this.el.child('.roo-tpl-' + this.dataName);
15641 for(var i = 0, len = records.length; i < len; i++){
15642 var data = this.prepareData(records[i].data, i, records[i]);
15643 this.fireEvent("preparedata", this, data, i, records[i]);
15645 var d = Roo.apply({}, data);
15648 Roo.apply(d, {'roo-id' : Roo.id()});
15652 Roo.each(this.parent.item, function(item){
15653 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15656 Roo.apply(d, {'roo-data-checked' : 'checked'});
15660 html[html.length] = Roo.util.Format.trim(
15662 t.applySubtemplate(this.dataName, d, this.store.meta) :
15669 el.update(html.join(""));
15670 this.nodes = el.dom.childNodes;
15671 this.updateIndexes(0);
15676 * Function to override to reformat the data that is sent to
15677 * the template for each node.
15678 * DEPRICATED - use the preparedata event handler.
15679 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15680 * a JSON object for an UpdateManager bound view).
15682 prepareData : function(data, index, record)
15684 this.fireEvent("preparedata", this, data, index, record);
15688 onUpdate : function(ds, record){
15689 // Roo.log('on update');
15690 this.clearSelections();
15691 var index = this.store.indexOf(record);
15692 var n = this.nodes[index];
15693 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15694 n.parentNode.removeChild(n);
15695 this.updateIndexes(index, index);
15701 onAdd : function(ds, records, index)
15703 //Roo.log(['on Add', ds, records, index] );
15704 this.clearSelections();
15705 if(this.nodes.length == 0){
15709 var n = this.nodes[index];
15710 for(var i = 0, len = records.length; i < len; i++){
15711 var d = this.prepareData(records[i].data, i, records[i]);
15713 this.tpl.insertBefore(n, d);
15716 this.tpl.append(this.el, d);
15719 this.updateIndexes(index);
15722 onRemove : function(ds, record, index){
15723 // Roo.log('onRemove');
15724 this.clearSelections();
15725 var el = this.dataName ?
15726 this.el.child('.roo-tpl-' + this.dataName) :
15729 el.dom.removeChild(this.nodes[index]);
15730 this.updateIndexes(index);
15734 * Refresh an individual node.
15735 * @param {Number} index
15737 refreshNode : function(index){
15738 this.onUpdate(this.store, this.store.getAt(index));
15741 updateIndexes : function(startIndex, endIndex){
15742 var ns = this.nodes;
15743 startIndex = startIndex || 0;
15744 endIndex = endIndex || ns.length - 1;
15745 for(var i = startIndex; i <= endIndex; i++){
15746 ns[i].nodeIndex = i;
15751 * Changes the data store this view uses and refresh the view.
15752 * @param {Store} store
15754 setStore : function(store, initial){
15755 if(!initial && this.store){
15756 this.store.un("datachanged", this.refresh);
15757 this.store.un("add", this.onAdd);
15758 this.store.un("remove", this.onRemove);
15759 this.store.un("update", this.onUpdate);
15760 this.store.un("clear", this.refresh);
15761 this.store.un("beforeload", this.onBeforeLoad);
15762 this.store.un("load", this.onLoad);
15763 this.store.un("loadexception", this.onLoad);
15767 store.on("datachanged", this.refresh, this);
15768 store.on("add", this.onAdd, this);
15769 store.on("remove", this.onRemove, this);
15770 store.on("update", this.onUpdate, this);
15771 store.on("clear", this.refresh, this);
15772 store.on("beforeload", this.onBeforeLoad, this);
15773 store.on("load", this.onLoad, this);
15774 store.on("loadexception", this.onLoad, this);
15782 * onbeforeLoad - masks the loading area.
15785 onBeforeLoad : function(store,opts)
15787 //Roo.log('onBeforeLoad');
15789 this.el.update("");
15791 this.el.mask(this.mask ? this.mask : "Loading" );
15793 onLoad : function ()
15800 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15801 * @param {HTMLElement} node
15802 * @return {HTMLElement} The template node
15804 findItemFromChild : function(node){
15805 var el = this.dataName ?
15806 this.el.child('.roo-tpl-' + this.dataName,true) :
15809 if(!node || node.parentNode == el){
15812 var p = node.parentNode;
15813 while(p && p != el){
15814 if(p.parentNode == el){
15823 onClick : function(e){
15824 var item = this.findItemFromChild(e.getTarget());
15826 var index = this.indexOf(item);
15827 if(this.onItemClick(item, index, e) !== false){
15828 this.fireEvent("click", this, index, item, e);
15831 this.clearSelections();
15836 onContextMenu : function(e){
15837 var item = this.findItemFromChild(e.getTarget());
15839 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15844 onDblClick : function(e){
15845 var item = this.findItemFromChild(e.getTarget());
15847 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15851 onItemClick : function(item, index, e)
15853 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15856 if (this.toggleSelect) {
15857 var m = this.isSelected(item) ? 'unselect' : 'select';
15860 _t[m](item, true, false);
15863 if(this.multiSelect || this.singleSelect){
15864 if(this.multiSelect && e.shiftKey && this.lastSelection){
15865 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15867 this.select(item, this.multiSelect && e.ctrlKey);
15868 this.lastSelection = item;
15871 if(!this.tickable){
15872 e.preventDefault();
15880 * Get the number of selected nodes.
15883 getSelectionCount : function(){
15884 return this.selections.length;
15888 * Get the currently selected nodes.
15889 * @return {Array} An array of HTMLElements
15891 getSelectedNodes : function(){
15892 return this.selections;
15896 * Get the indexes of the selected nodes.
15899 getSelectedIndexes : function(){
15900 var indexes = [], s = this.selections;
15901 for(var i = 0, len = s.length; i < len; i++){
15902 indexes.push(s[i].nodeIndex);
15908 * Clear all selections
15909 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15911 clearSelections : function(suppressEvent){
15912 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15913 this.cmp.elements = this.selections;
15914 this.cmp.removeClass(this.selectedClass);
15915 this.selections = [];
15916 if(!suppressEvent){
15917 this.fireEvent("selectionchange", this, this.selections);
15923 * Returns true if the passed node is selected
15924 * @param {HTMLElement/Number} node The node or node index
15925 * @return {Boolean}
15927 isSelected : function(node){
15928 var s = this.selections;
15932 node = this.getNode(node);
15933 return s.indexOf(node) !== -1;
15938 * @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
15939 * @param {Boolean} keepExisting (optional) true to keep existing selections
15940 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15942 select : function(nodeInfo, keepExisting, suppressEvent){
15943 if(nodeInfo instanceof Array){
15945 this.clearSelections(true);
15947 for(var i = 0, len = nodeInfo.length; i < len; i++){
15948 this.select(nodeInfo[i], true, true);
15952 var node = this.getNode(nodeInfo);
15953 if(!node || this.isSelected(node)){
15954 return; // already selected.
15957 this.clearSelections(true);
15960 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15961 Roo.fly(node).addClass(this.selectedClass);
15962 this.selections.push(node);
15963 if(!suppressEvent){
15964 this.fireEvent("selectionchange", this, this.selections);
15972 * @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
15973 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15974 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15976 unselect : function(nodeInfo, keepExisting, suppressEvent)
15978 if(nodeInfo instanceof Array){
15979 Roo.each(this.selections, function(s) {
15980 this.unselect(s, nodeInfo);
15984 var node = this.getNode(nodeInfo);
15985 if(!node || !this.isSelected(node)){
15986 //Roo.log("not selected");
15987 return; // not selected.
15991 Roo.each(this.selections, function(s) {
15993 Roo.fly(node).removeClass(this.selectedClass);
16000 this.selections= ns;
16001 this.fireEvent("selectionchange", this, this.selections);
16005 * Gets a template node.
16006 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16007 * @return {HTMLElement} The node or null if it wasn't found
16009 getNode : function(nodeInfo){
16010 if(typeof nodeInfo == "string"){
16011 return document.getElementById(nodeInfo);
16012 }else if(typeof nodeInfo == "number"){
16013 return this.nodes[nodeInfo];
16019 * Gets a range template nodes.
16020 * @param {Number} startIndex
16021 * @param {Number} endIndex
16022 * @return {Array} An array of nodes
16024 getNodes : function(start, end){
16025 var ns = this.nodes;
16026 start = start || 0;
16027 end = typeof end == "undefined" ? ns.length - 1 : end;
16030 for(var i = start; i <= end; i++){
16034 for(var i = start; i >= end; i--){
16042 * Finds the index of the passed node
16043 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16044 * @return {Number} The index of the node or -1
16046 indexOf : function(node){
16047 node = this.getNode(node);
16048 if(typeof node.nodeIndex == "number"){
16049 return node.nodeIndex;
16051 var ns = this.nodes;
16052 for(var i = 0, len = ns.length; i < len; i++){
16063 * based on jquery fullcalendar
16067 Roo.bootstrap = Roo.bootstrap || {};
16069 * @class Roo.bootstrap.Calendar
16070 * @extends Roo.bootstrap.Component
16071 * Bootstrap Calendar class
16072 * @cfg {Boolean} loadMask (true|false) default false
16073 * @cfg {Object} header generate the user specific header of the calendar, default false
16076 * Create a new Container
16077 * @param {Object} config The config object
16082 Roo.bootstrap.Calendar = function(config){
16083 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16087 * Fires when a date is selected
16088 * @param {DatePicker} this
16089 * @param {Date} date The selected date
16093 * @event monthchange
16094 * Fires when the displayed month changes
16095 * @param {DatePicker} this
16096 * @param {Date} date The selected month
16098 'monthchange': true,
16100 * @event evententer
16101 * Fires when mouse over an event
16102 * @param {Calendar} this
16103 * @param {event} Event
16105 'evententer': true,
16107 * @event eventleave
16108 * Fires when the mouse leaves an
16109 * @param {Calendar} this
16112 'eventleave': true,
16114 * @event eventclick
16115 * Fires when the mouse click an
16116 * @param {Calendar} this
16125 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16128 * @cfg {Number} startDay
16129 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16137 getAutoCreate : function(){
16140 var fc_button = function(name, corner, style, content ) {
16141 return Roo.apply({},{
16143 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16145 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16148 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16159 style : 'width:100%',
16166 cls : 'fc-header-left',
16168 fc_button('prev', 'left', 'arrow', '‹' ),
16169 fc_button('next', 'right', 'arrow', '›' ),
16170 { tag: 'span', cls: 'fc-header-space' },
16171 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16179 cls : 'fc-header-center',
16183 cls: 'fc-header-title',
16186 html : 'month / year'
16194 cls : 'fc-header-right',
16196 /* fc_button('month', 'left', '', 'month' ),
16197 fc_button('week', '', '', 'week' ),
16198 fc_button('day', 'right', '', 'day' )
16210 header = this.header;
16213 var cal_heads = function() {
16215 // fixme - handle this.
16217 for (var i =0; i < Date.dayNames.length; i++) {
16218 var d = Date.dayNames[i];
16221 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16222 html : d.substring(0,3)
16226 ret[0].cls += ' fc-first';
16227 ret[6].cls += ' fc-last';
16230 var cal_cell = function(n) {
16233 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16238 cls: 'fc-day-number',
16242 cls: 'fc-day-content',
16246 style: 'position: relative;' // height: 17px;
16258 var cal_rows = function() {
16261 for (var r = 0; r < 6; r++) {
16268 for (var i =0; i < Date.dayNames.length; i++) {
16269 var d = Date.dayNames[i];
16270 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16273 row.cn[0].cls+=' fc-first';
16274 row.cn[0].cn[0].style = 'min-height:90px';
16275 row.cn[6].cls+=' fc-last';
16279 ret[0].cls += ' fc-first';
16280 ret[4].cls += ' fc-prev-last';
16281 ret[5].cls += ' fc-last';
16288 cls: 'fc-border-separate',
16289 style : 'width:100%',
16297 cls : 'fc-first fc-last',
16315 cls : 'fc-content',
16316 style : "position: relative;",
16319 cls : 'fc-view fc-view-month fc-grid',
16320 style : 'position: relative',
16321 unselectable : 'on',
16324 cls : 'fc-event-container',
16325 style : 'position:absolute;z-index:8;top:0;left:0;'
16343 initEvents : function()
16346 throw "can not find store for calendar";
16352 style: "text-align:center",
16356 style: "background-color:white;width:50%;margin:250 auto",
16360 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16371 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16373 var size = this.el.select('.fc-content', true).first().getSize();
16374 this.maskEl.setSize(size.width, size.height);
16375 this.maskEl.enableDisplayMode("block");
16376 if(!this.loadMask){
16377 this.maskEl.hide();
16380 this.store = Roo.factory(this.store, Roo.data);
16381 this.store.on('load', this.onLoad, this);
16382 this.store.on('beforeload', this.onBeforeLoad, this);
16386 this.cells = this.el.select('.fc-day',true);
16387 //Roo.log(this.cells);
16388 this.textNodes = this.el.query('.fc-day-number');
16389 this.cells.addClassOnOver('fc-state-hover');
16391 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16392 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16393 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16394 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16396 this.on('monthchange', this.onMonthChange, this);
16398 this.update(new Date().clearTime());
16401 resize : function() {
16402 var sz = this.el.getSize();
16404 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16405 this.el.select('.fc-day-content div',true).setHeight(34);
16410 showPrevMonth : function(e){
16411 this.update(this.activeDate.add("mo", -1));
16413 showToday : function(e){
16414 this.update(new Date().clearTime());
16417 showNextMonth : function(e){
16418 this.update(this.activeDate.add("mo", 1));
16422 showPrevYear : function(){
16423 this.update(this.activeDate.add("y", -1));
16427 showNextYear : function(){
16428 this.update(this.activeDate.add("y", 1));
16433 update : function(date)
16435 var vd = this.activeDate;
16436 this.activeDate = date;
16437 // if(vd && this.el){
16438 // var t = date.getTime();
16439 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16440 // Roo.log('using add remove');
16442 // this.fireEvent('monthchange', this, date);
16444 // this.cells.removeClass("fc-state-highlight");
16445 // this.cells.each(function(c){
16446 // if(c.dateValue == t){
16447 // c.addClass("fc-state-highlight");
16448 // setTimeout(function(){
16449 // try{c.dom.firstChild.focus();}catch(e){}
16459 var days = date.getDaysInMonth();
16461 var firstOfMonth = date.getFirstDateOfMonth();
16462 var startingPos = firstOfMonth.getDay()-this.startDay;
16464 if(startingPos < this.startDay){
16468 var pm = date.add(Date.MONTH, -1);
16469 var prevStart = pm.getDaysInMonth()-startingPos;
16471 this.cells = this.el.select('.fc-day',true);
16472 this.textNodes = this.el.query('.fc-day-number');
16473 this.cells.addClassOnOver('fc-state-hover');
16475 var cells = this.cells.elements;
16476 var textEls = this.textNodes;
16478 Roo.each(cells, function(cell){
16479 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16482 days += startingPos;
16484 // convert everything to numbers so it's fast
16485 var day = 86400000;
16486 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16489 //Roo.log(prevStart);
16491 var today = new Date().clearTime().getTime();
16492 var sel = date.clearTime().getTime();
16493 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16494 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16495 var ddMatch = this.disabledDatesRE;
16496 var ddText = this.disabledDatesText;
16497 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16498 var ddaysText = this.disabledDaysText;
16499 var format = this.format;
16501 var setCellClass = function(cal, cell){
16505 //Roo.log('set Cell Class');
16507 var t = d.getTime();
16511 cell.dateValue = t;
16513 cell.className += " fc-today";
16514 cell.className += " fc-state-highlight";
16515 cell.title = cal.todayText;
16518 // disable highlight in other month..
16519 //cell.className += " fc-state-highlight";
16524 cell.className = " fc-state-disabled";
16525 cell.title = cal.minText;
16529 cell.className = " fc-state-disabled";
16530 cell.title = cal.maxText;
16534 if(ddays.indexOf(d.getDay()) != -1){
16535 cell.title = ddaysText;
16536 cell.className = " fc-state-disabled";
16539 if(ddMatch && format){
16540 var fvalue = d.dateFormat(format);
16541 if(ddMatch.test(fvalue)){
16542 cell.title = ddText.replace("%0", fvalue);
16543 cell.className = " fc-state-disabled";
16547 if (!cell.initialClassName) {
16548 cell.initialClassName = cell.dom.className;
16551 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16556 for(; i < startingPos; i++) {
16557 textEls[i].innerHTML = (++prevStart);
16558 d.setDate(d.getDate()+1);
16560 cells[i].className = "fc-past fc-other-month";
16561 setCellClass(this, cells[i]);
16566 for(; i < days; i++){
16567 intDay = i - startingPos + 1;
16568 textEls[i].innerHTML = (intDay);
16569 d.setDate(d.getDate()+1);
16571 cells[i].className = ''; // "x-date-active";
16572 setCellClass(this, cells[i]);
16576 for(; i < 42; i++) {
16577 textEls[i].innerHTML = (++extraDays);
16578 d.setDate(d.getDate()+1);
16580 cells[i].className = "fc-future fc-other-month";
16581 setCellClass(this, cells[i]);
16584 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16586 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16588 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16589 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16591 if(totalRows != 6){
16592 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16593 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16596 this.fireEvent('monthchange', this, date);
16600 if(!this.internalRender){
16601 var main = this.el.dom.firstChild;
16602 var w = main.offsetWidth;
16603 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16604 Roo.fly(main).setWidth(w);
16605 this.internalRender = true;
16606 // opera does not respect the auto grow header center column
16607 // then, after it gets a width opera refuses to recalculate
16608 // without a second pass
16609 if(Roo.isOpera && !this.secondPass){
16610 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16611 this.secondPass = true;
16612 this.update.defer(10, this, [date]);
16619 findCell : function(dt) {
16620 dt = dt.clearTime().getTime();
16622 this.cells.each(function(c){
16623 //Roo.log("check " +c.dateValue + '?=' + dt);
16624 if(c.dateValue == dt){
16634 findCells : function(ev) {
16635 var s = ev.start.clone().clearTime().getTime();
16637 var e= ev.end.clone().clearTime().getTime();
16640 this.cells.each(function(c){
16641 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16643 if(c.dateValue > e){
16646 if(c.dateValue < s){
16655 // findBestRow: function(cells)
16659 // for (var i =0 ; i < cells.length;i++) {
16660 // ret = Math.max(cells[i].rows || 0,ret);
16667 addItem : function(ev)
16669 // look for vertical location slot in
16670 var cells = this.findCells(ev);
16672 // ev.row = this.findBestRow(cells);
16674 // work out the location.
16678 for(var i =0; i < cells.length; i++) {
16680 cells[i].row = cells[0].row;
16683 cells[i].row = cells[i].row + 1;
16693 if (crow.start.getY() == cells[i].getY()) {
16695 crow.end = cells[i];
16712 cells[0].events.push(ev);
16714 this.calevents.push(ev);
16717 clearEvents: function() {
16719 if(!this.calevents){
16723 Roo.each(this.cells.elements, function(c){
16729 Roo.each(this.calevents, function(e) {
16730 Roo.each(e.els, function(el) {
16731 el.un('mouseenter' ,this.onEventEnter, this);
16732 el.un('mouseleave' ,this.onEventLeave, this);
16737 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16743 renderEvents: function()
16747 this.cells.each(function(c) {
16756 if(c.row != c.events.length){
16757 r = 4 - (4 - (c.row - c.events.length));
16760 c.events = ev.slice(0, r);
16761 c.more = ev.slice(r);
16763 if(c.more.length && c.more.length == 1){
16764 c.events.push(c.more.pop());
16767 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16771 this.cells.each(function(c) {
16773 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16776 for (var e = 0; e < c.events.length; e++){
16777 var ev = c.events[e];
16778 var rows = ev.rows;
16780 for(var i = 0; i < rows.length; i++) {
16782 // how many rows should it span..
16785 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16786 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16788 unselectable : "on",
16791 cls: 'fc-event-inner',
16795 // cls: 'fc-event-time',
16796 // html : cells.length > 1 ? '' : ev.time
16800 cls: 'fc-event-title',
16801 html : String.format('{0}', ev.title)
16808 cls: 'ui-resizable-handle ui-resizable-e',
16809 html : '  '
16816 cfg.cls += ' fc-event-start';
16818 if ((i+1) == rows.length) {
16819 cfg.cls += ' fc-event-end';
16822 var ctr = _this.el.select('.fc-event-container',true).first();
16823 var cg = ctr.createChild(cfg);
16825 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16826 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16828 var r = (c.more.length) ? 1 : 0;
16829 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16830 cg.setWidth(ebox.right - sbox.x -2);
16832 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16833 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16834 cg.on('click', _this.onEventClick, _this, ev);
16845 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16846 style : 'position: absolute',
16847 unselectable : "on",
16850 cls: 'fc-event-inner',
16854 cls: 'fc-event-title',
16862 cls: 'ui-resizable-handle ui-resizable-e',
16863 html : '  '
16869 var ctr = _this.el.select('.fc-event-container',true).first();
16870 var cg = ctr.createChild(cfg);
16872 var sbox = c.select('.fc-day-content',true).first().getBox();
16873 var ebox = c.select('.fc-day-content',true).first().getBox();
16875 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16876 cg.setWidth(ebox.right - sbox.x -2);
16878 cg.on('click', _this.onMoreEventClick, _this, c.more);
16888 onEventEnter: function (e, el,event,d) {
16889 this.fireEvent('evententer', this, el, event);
16892 onEventLeave: function (e, el,event,d) {
16893 this.fireEvent('eventleave', this, el, event);
16896 onEventClick: function (e, el,event,d) {
16897 this.fireEvent('eventclick', this, el, event);
16900 onMonthChange: function () {
16904 onMoreEventClick: function(e, el, more)
16908 this.calpopover.placement = 'right';
16909 this.calpopover.setTitle('More');
16911 this.calpopover.setContent('');
16913 var ctr = this.calpopover.el.select('.popover-content', true).first();
16915 Roo.each(more, function(m){
16917 cls : 'fc-event-hori fc-event-draggable',
16920 var cg = ctr.createChild(cfg);
16922 cg.on('click', _this.onEventClick, _this, m);
16925 this.calpopover.show(el);
16930 onLoad: function ()
16932 this.calevents = [];
16935 if(this.store.getCount() > 0){
16936 this.store.data.each(function(d){
16939 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16940 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16941 time : d.data.start_time,
16942 title : d.data.title,
16943 description : d.data.description,
16944 venue : d.data.venue
16949 this.renderEvents();
16951 if(this.calevents.length && this.loadMask){
16952 this.maskEl.hide();
16956 onBeforeLoad: function()
16958 this.clearEvents();
16960 this.maskEl.show();
16974 * @class Roo.bootstrap.Popover
16975 * @extends Roo.bootstrap.Component
16976 * Bootstrap Popover class
16977 * @cfg {String} html contents of the popover (or false to use children..)
16978 * @cfg {String} title of popover (or false to hide)
16979 * @cfg {String} placement how it is placed
16980 * @cfg {String} trigger click || hover (or false to trigger manually)
16981 * @cfg {String} over what (parent or false to trigger manually.)
16982 * @cfg {Number} delay - delay before showing
16985 * Create a new Popover
16986 * @param {Object} config The config object
16989 Roo.bootstrap.Popover = function(config){
16990 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16996 * After the popover show
16998 * @param {Roo.bootstrap.Popover} this
17003 * After the popover hide
17005 * @param {Roo.bootstrap.Popover} this
17011 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17013 title: 'Fill in a title',
17016 placement : 'right',
17017 trigger : 'hover', // hover
17023 can_build_overlaid : false,
17025 getChildContainer : function()
17027 return this.el.select('.popover-content',true).first();
17030 getAutoCreate : function(){
17033 cls : 'popover roo-dynamic',
17034 style: 'display:block',
17040 cls : 'popover-inner',
17044 cls: 'popover-title',
17048 cls : 'popover-content',
17059 setTitle: function(str)
17062 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17064 setContent: function(str)
17067 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17069 // as it get's added to the bottom of the page.
17070 onRender : function(ct, position)
17072 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17074 var cfg = Roo.apply({}, this.getAutoCreate());
17078 cfg.cls += ' ' + this.cls;
17081 cfg.style = this.style;
17083 //Roo.log("adding to ");
17084 this.el = Roo.get(document.body).createChild(cfg, position);
17085 // Roo.log(this.el);
17090 initEvents : function()
17092 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17093 this.el.enableDisplayMode('block');
17095 if (this.over === false) {
17098 if (this.triggers === false) {
17101 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17102 var triggers = this.trigger ? this.trigger.split(' ') : [];
17103 Roo.each(triggers, function(trigger) {
17105 if (trigger == 'click') {
17106 on_el.on('click', this.toggle, this);
17107 } else if (trigger != 'manual') {
17108 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17109 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17111 on_el.on(eventIn ,this.enter, this);
17112 on_el.on(eventOut, this.leave, this);
17123 toggle : function () {
17124 this.hoverState == 'in' ? this.leave() : this.enter();
17127 enter : function () {
17129 clearTimeout(this.timeout);
17131 this.hoverState = 'in';
17133 if (!this.delay || !this.delay.show) {
17138 this.timeout = setTimeout(function () {
17139 if (_t.hoverState == 'in') {
17142 }, this.delay.show)
17145 leave : function() {
17146 clearTimeout(this.timeout);
17148 this.hoverState = 'out';
17150 if (!this.delay || !this.delay.hide) {
17155 this.timeout = setTimeout(function () {
17156 if (_t.hoverState == 'out') {
17159 }, this.delay.hide)
17162 show : function (on_el)
17165 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17169 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17170 if (this.html !== false) {
17171 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17173 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17174 if (!this.title.length) {
17175 this.el.select('.popover-title',true).hide();
17178 var placement = typeof this.placement == 'function' ?
17179 this.placement.call(this, this.el, on_el) :
17182 var autoToken = /\s?auto?\s?/i;
17183 var autoPlace = autoToken.test(placement);
17185 placement = placement.replace(autoToken, '') || 'top';
17189 //this.el.setXY([0,0]);
17191 this.el.dom.style.display='block';
17192 this.el.addClass(placement);
17194 //this.el.appendTo(on_el);
17196 var p = this.getPosition();
17197 var box = this.el.getBox();
17202 var align = Roo.bootstrap.Popover.alignment[placement];
17203 this.el.alignTo(on_el, align[0],align[1]);
17204 //var arrow = this.el.select('.arrow',true).first();
17205 //arrow.set(align[2],
17207 this.el.addClass('in');
17210 if (this.el.hasClass('fade')) {
17214 this.hoverState = 'in';
17216 this.fireEvent('show', this);
17221 this.el.setXY([0,0]);
17222 this.el.removeClass('in');
17224 this.hoverState = null;
17226 this.fireEvent('hide', this);
17231 Roo.bootstrap.Popover.alignment = {
17232 'left' : ['r-l', [-10,0], 'right'],
17233 'right' : ['l-r', [10,0], 'left'],
17234 'bottom' : ['t-b', [0,10], 'top'],
17235 'top' : [ 'b-t', [0,-10], 'bottom']
17246 * @class Roo.bootstrap.Progress
17247 * @extends Roo.bootstrap.Component
17248 * Bootstrap Progress class
17249 * @cfg {Boolean} striped striped of the progress bar
17250 * @cfg {Boolean} active animated of the progress bar
17254 * Create a new Progress
17255 * @param {Object} config The config object
17258 Roo.bootstrap.Progress = function(config){
17259 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17262 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17267 getAutoCreate : function(){
17275 cfg.cls += ' progress-striped';
17279 cfg.cls += ' active';
17298 * @class Roo.bootstrap.ProgressBar
17299 * @extends Roo.bootstrap.Component
17300 * Bootstrap ProgressBar class
17301 * @cfg {Number} aria_valuenow aria-value now
17302 * @cfg {Number} aria_valuemin aria-value min
17303 * @cfg {Number} aria_valuemax aria-value max
17304 * @cfg {String} label label for the progress bar
17305 * @cfg {String} panel (success | info | warning | danger )
17306 * @cfg {String} role role of the progress bar
17307 * @cfg {String} sr_only text
17311 * Create a new ProgressBar
17312 * @param {Object} config The config object
17315 Roo.bootstrap.ProgressBar = function(config){
17316 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17319 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17323 aria_valuemax : 100,
17329 getAutoCreate : function()
17334 cls: 'progress-bar',
17335 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17347 cfg.role = this.role;
17350 if(this.aria_valuenow){
17351 cfg['aria-valuenow'] = this.aria_valuenow;
17354 if(this.aria_valuemin){
17355 cfg['aria-valuemin'] = this.aria_valuemin;
17358 if(this.aria_valuemax){
17359 cfg['aria-valuemax'] = this.aria_valuemax;
17362 if(this.label && !this.sr_only){
17363 cfg.html = this.label;
17367 cfg.cls += ' progress-bar-' + this.panel;
17373 update : function(aria_valuenow)
17375 this.aria_valuenow = aria_valuenow;
17377 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17392 * @class Roo.bootstrap.TabGroup
17393 * @extends Roo.bootstrap.Column
17394 * Bootstrap Column class
17395 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17396 * @cfg {Boolean} carousel true to make the group behave like a carousel
17397 * @cfg {Boolean} bullets show bullets for the panels
17398 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17399 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17400 * @cfg {Boolean} showarrow (true|false) show arrow default true
17403 * Create a new TabGroup
17404 * @param {Object} config The config object
17407 Roo.bootstrap.TabGroup = function(config){
17408 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17410 this.navId = Roo.id();
17413 Roo.bootstrap.TabGroup.register(this);
17417 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17420 transition : false,
17425 slideOnTouch : false,
17428 getAutoCreate : function()
17430 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17432 cfg.cls += ' tab-content';
17434 if (this.carousel) {
17435 cfg.cls += ' carousel slide';
17438 cls : 'carousel-inner',
17442 if(this.bullets && !Roo.isTouch){
17445 cls : 'carousel-bullets',
17449 if(this.bullets_cls){
17450 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17457 cfg.cn[0].cn.push(bullets);
17460 if(this.showarrow){
17461 cfg.cn[0].cn.push({
17463 class : 'carousel-arrow',
17467 class : 'carousel-prev',
17471 class : 'fa fa-chevron-left'
17477 class : 'carousel-next',
17481 class : 'fa fa-chevron-right'
17494 initEvents: function()
17496 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17497 // this.el.on("touchstart", this.onTouchStart, this);
17500 if(this.autoslide){
17503 this.slideFn = window.setInterval(function() {
17504 _this.showPanelNext();
17508 if(this.showarrow){
17509 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17510 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17516 // onTouchStart : function(e, el, o)
17518 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17522 // this.showPanelNext();
17526 getChildContainer : function()
17528 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17532 * register a Navigation item
17533 * @param {Roo.bootstrap.NavItem} the navitem to add
17535 register : function(item)
17537 this.tabs.push( item);
17538 item.navId = this.navId; // not really needed..
17543 getActivePanel : function()
17546 Roo.each(this.tabs, function(t) {
17556 getPanelByName : function(n)
17559 Roo.each(this.tabs, function(t) {
17560 if (t.tabId == n) {
17568 indexOfPanel : function(p)
17571 Roo.each(this.tabs, function(t,i) {
17572 if (t.tabId == p.tabId) {
17581 * show a specific panel
17582 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17583 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17585 showPanel : function (pan)
17587 if(this.transition || typeof(pan) == 'undefined'){
17588 Roo.log("waiting for the transitionend");
17592 if (typeof(pan) == 'number') {
17593 pan = this.tabs[pan];
17596 if (typeof(pan) == 'string') {
17597 pan = this.getPanelByName(pan);
17600 var cur = this.getActivePanel();
17603 Roo.log('pan or acitve pan is undefined');
17607 if (pan.tabId == this.getActivePanel().tabId) {
17611 if (false === cur.fireEvent('beforedeactivate')) {
17615 if(this.bullets > 0 && !Roo.isTouch){
17616 this.setActiveBullet(this.indexOfPanel(pan));
17619 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17621 this.transition = true;
17622 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17623 var lr = dir == 'next' ? 'left' : 'right';
17624 pan.el.addClass(dir); // or prev
17625 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17626 cur.el.addClass(lr); // or right
17627 pan.el.addClass(lr);
17630 cur.el.on('transitionend', function() {
17631 Roo.log("trans end?");
17633 pan.el.removeClass([lr,dir]);
17634 pan.setActive(true);
17636 cur.el.removeClass([lr]);
17637 cur.setActive(false);
17639 _this.transition = false;
17641 }, this, { single: true } );
17646 cur.setActive(false);
17647 pan.setActive(true);
17652 showPanelNext : function()
17654 var i = this.indexOfPanel(this.getActivePanel());
17656 if (i >= this.tabs.length - 1 && !this.autoslide) {
17660 if (i >= this.tabs.length - 1 && this.autoslide) {
17664 this.showPanel(this.tabs[i+1]);
17667 showPanelPrev : function()
17669 var i = this.indexOfPanel(this.getActivePanel());
17671 if (i < 1 && !this.autoslide) {
17675 if (i < 1 && this.autoslide) {
17676 i = this.tabs.length;
17679 this.showPanel(this.tabs[i-1]);
17683 addBullet: function()
17685 if(!this.bullets || Roo.isTouch){
17688 var ctr = this.el.select('.carousel-bullets',true).first();
17689 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17690 var bullet = ctr.createChild({
17691 cls : 'bullet bullet-' + i
17692 },ctr.dom.lastChild);
17697 bullet.on('click', (function(e, el, o, ii, t){
17699 e.preventDefault();
17701 this.showPanel(ii);
17703 if(this.autoslide && this.slideFn){
17704 clearInterval(this.slideFn);
17705 this.slideFn = window.setInterval(function() {
17706 _this.showPanelNext();
17710 }).createDelegate(this, [i, bullet], true));
17715 setActiveBullet : function(i)
17721 Roo.each(this.el.select('.bullet', true).elements, function(el){
17722 el.removeClass('selected');
17725 var bullet = this.el.select('.bullet-' + i, true).first();
17731 bullet.addClass('selected');
17742 Roo.apply(Roo.bootstrap.TabGroup, {
17746 * register a Navigation Group
17747 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17749 register : function(navgrp)
17751 this.groups[navgrp.navId] = navgrp;
17755 * fetch a Navigation Group based on the navigation ID
17756 * if one does not exist , it will get created.
17757 * @param {string} the navgroup to add
17758 * @returns {Roo.bootstrap.NavGroup} the navgroup
17760 get: function(navId) {
17761 if (typeof(this.groups[navId]) == 'undefined') {
17762 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17764 return this.groups[navId] ;
17779 * @class Roo.bootstrap.TabPanel
17780 * @extends Roo.bootstrap.Component
17781 * Bootstrap TabPanel class
17782 * @cfg {Boolean} active panel active
17783 * @cfg {String} html panel content
17784 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17785 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17786 * @cfg {String} href click to link..
17790 * Create a new TabPanel
17791 * @param {Object} config The config object
17794 Roo.bootstrap.TabPanel = function(config){
17795 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17799 * Fires when the active status changes
17800 * @param {Roo.bootstrap.TabPanel} this
17801 * @param {Boolean} state the new state
17806 * @event beforedeactivate
17807 * Fires before a tab is de-activated - can be used to do validation on a form.
17808 * @param {Roo.bootstrap.TabPanel} this
17809 * @return {Boolean} false if there is an error
17812 'beforedeactivate': true
17815 this.tabId = this.tabId || Roo.id();
17819 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17827 getAutoCreate : function(){
17830 // item is needed for carousel - not sure if it has any effect otherwise
17831 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17832 html: this.html || ''
17836 cfg.cls += ' active';
17840 cfg.tabId = this.tabId;
17847 initEvents: function()
17849 var p = this.parent();
17851 this.navId = this.navId || p.navId;
17853 if (typeof(this.navId) != 'undefined') {
17854 // not really needed.. but just in case.. parent should be a NavGroup.
17855 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17859 var i = tg.tabs.length - 1;
17861 if(this.active && tg.bullets > 0 && i < tg.bullets){
17862 tg.setActiveBullet(i);
17866 this.el.on('click', this.onClick, this);
17869 this.el.on("touchstart", this.onTouchStart, this);
17870 this.el.on("touchmove", this.onTouchMove, this);
17871 this.el.on("touchend", this.onTouchEnd, this);
17876 onRender : function(ct, position)
17878 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17881 setActive : function(state)
17883 Roo.log("panel - set active " + this.tabId + "=" + state);
17885 this.active = state;
17887 this.el.removeClass('active');
17889 } else if (!this.el.hasClass('active')) {
17890 this.el.addClass('active');
17893 this.fireEvent('changed', this, state);
17896 onClick : function(e)
17898 e.preventDefault();
17900 if(!this.href.length){
17904 window.location.href = this.href;
17913 onTouchStart : function(e)
17915 this.swiping = false;
17917 this.startX = e.browserEvent.touches[0].clientX;
17918 this.startY = e.browserEvent.touches[0].clientY;
17921 onTouchMove : function(e)
17923 this.swiping = true;
17925 this.endX = e.browserEvent.touches[0].clientX;
17926 this.endY = e.browserEvent.touches[0].clientY;
17929 onTouchEnd : function(e)
17936 var tabGroup = this.parent();
17938 if(this.endX > this.startX){ // swiping right
17939 tabGroup.showPanelPrev();
17943 if(this.startX > this.endX){ // swiping left
17944 tabGroup.showPanelNext();
17963 * @class Roo.bootstrap.DateField
17964 * @extends Roo.bootstrap.Input
17965 * Bootstrap DateField class
17966 * @cfg {Number} weekStart default 0
17967 * @cfg {String} viewMode default empty, (months|years)
17968 * @cfg {String} minViewMode default empty, (months|years)
17969 * @cfg {Number} startDate default -Infinity
17970 * @cfg {Number} endDate default Infinity
17971 * @cfg {Boolean} todayHighlight default false
17972 * @cfg {Boolean} todayBtn default false
17973 * @cfg {Boolean} calendarWeeks default false
17974 * @cfg {Object} daysOfWeekDisabled default empty
17975 * @cfg {Boolean} singleMode default false (true | false)
17977 * @cfg {Boolean} keyboardNavigation default true
17978 * @cfg {String} language default en
17981 * Create a new DateField
17982 * @param {Object} config The config object
17985 Roo.bootstrap.DateField = function(config){
17986 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17990 * Fires when this field show.
17991 * @param {Roo.bootstrap.DateField} this
17992 * @param {Mixed} date The date value
17997 * Fires when this field hide.
17998 * @param {Roo.bootstrap.DateField} this
17999 * @param {Mixed} date The date value
18004 * Fires when select a date.
18005 * @param {Roo.bootstrap.DateField} this
18006 * @param {Mixed} date The date value
18010 * @event beforeselect
18011 * Fires when before select a date.
18012 * @param {Roo.bootstrap.DateField} this
18013 * @param {Mixed} date The date value
18015 beforeselect : true
18019 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18022 * @cfg {String} format
18023 * The default date format string which can be overriden for localization support. The format must be
18024 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18028 * @cfg {String} altFormats
18029 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18030 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18032 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18040 todayHighlight : false,
18046 keyboardNavigation: true,
18048 calendarWeeks: false,
18050 startDate: -Infinity,
18054 daysOfWeekDisabled: [],
18058 singleMode : false,
18060 UTCDate: function()
18062 return new Date(Date.UTC.apply(Date, arguments));
18065 UTCToday: function()
18067 var today = new Date();
18068 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18071 getDate: function() {
18072 var d = this.getUTCDate();
18073 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18076 getUTCDate: function() {
18080 setDate: function(d) {
18081 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18084 setUTCDate: function(d) {
18086 this.setValue(this.formatDate(this.date));
18089 onRender: function(ct, position)
18092 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18094 this.language = this.language || 'en';
18095 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18096 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18098 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18099 this.format = this.format || 'm/d/y';
18100 this.isInline = false;
18101 this.isInput = true;
18102 this.component = this.el.select('.add-on', true).first() || false;
18103 this.component = (this.component && this.component.length === 0) ? false : this.component;
18104 this.hasInput = this.component && this.inputEl().length;
18106 if (typeof(this.minViewMode === 'string')) {
18107 switch (this.minViewMode) {
18109 this.minViewMode = 1;
18112 this.minViewMode = 2;
18115 this.minViewMode = 0;
18120 if (typeof(this.viewMode === 'string')) {
18121 switch (this.viewMode) {
18134 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18136 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18138 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18140 this.picker().on('mousedown', this.onMousedown, this);
18141 this.picker().on('click', this.onClick, this);
18143 this.picker().addClass('datepicker-dropdown');
18145 this.startViewMode = this.viewMode;
18147 if(this.singleMode){
18148 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18149 v.setVisibilityMode(Roo.Element.DISPLAY);
18153 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18154 v.setStyle('width', '189px');
18158 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18159 if(!this.calendarWeeks){
18164 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18165 v.attr('colspan', function(i, val){
18166 return parseInt(val) + 1;
18171 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18173 this.setStartDate(this.startDate);
18174 this.setEndDate(this.endDate);
18176 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18183 if(this.isInline) {
18188 picker : function()
18190 return this.pickerEl;
18191 // return this.el.select('.datepicker', true).first();
18194 fillDow: function()
18196 var dowCnt = this.weekStart;
18205 if(this.calendarWeeks){
18213 while (dowCnt < this.weekStart + 7) {
18217 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18221 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18224 fillMonths: function()
18227 var months = this.picker().select('>.datepicker-months td', true).first();
18229 months.dom.innerHTML = '';
18235 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18238 months.createChild(month);
18245 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;
18247 if (this.date < this.startDate) {
18248 this.viewDate = new Date(this.startDate);
18249 } else if (this.date > this.endDate) {
18250 this.viewDate = new Date(this.endDate);
18252 this.viewDate = new Date(this.date);
18260 var d = new Date(this.viewDate),
18261 year = d.getUTCFullYear(),
18262 month = d.getUTCMonth(),
18263 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18264 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18265 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18266 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18267 currentDate = this.date && this.date.valueOf(),
18268 today = this.UTCToday();
18270 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18272 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18274 // this.picker.select('>tfoot th.today').
18275 // .text(dates[this.language].today)
18276 // .toggle(this.todayBtn !== false);
18278 this.updateNavArrows();
18281 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18283 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18285 prevMonth.setUTCDate(day);
18287 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18289 var nextMonth = new Date(prevMonth);
18291 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18293 nextMonth = nextMonth.valueOf();
18295 var fillMonths = false;
18297 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18299 while(prevMonth.valueOf() < nextMonth) {
18302 if (prevMonth.getUTCDay() === this.weekStart) {
18304 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18312 if(this.calendarWeeks){
18313 // ISO 8601: First week contains first thursday.
18314 // ISO also states week starts on Monday, but we can be more abstract here.
18316 // Start of current week: based on weekstart/current date
18317 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18318 // Thursday of this week
18319 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18320 // First Thursday of year, year from thursday
18321 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18322 // Calendar week: ms between thursdays, div ms per day, div 7 days
18323 calWeek = (th - yth) / 864e5 / 7 + 1;
18325 fillMonths.cn.push({
18333 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18335 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18338 if (this.todayHighlight &&
18339 prevMonth.getUTCFullYear() == today.getFullYear() &&
18340 prevMonth.getUTCMonth() == today.getMonth() &&
18341 prevMonth.getUTCDate() == today.getDate()) {
18342 clsName += ' today';
18345 if (currentDate && prevMonth.valueOf() === currentDate) {
18346 clsName += ' active';
18349 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18350 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18351 clsName += ' disabled';
18354 fillMonths.cn.push({
18356 cls: 'day ' + clsName,
18357 html: prevMonth.getDate()
18360 prevMonth.setDate(prevMonth.getDate()+1);
18363 var currentYear = this.date && this.date.getUTCFullYear();
18364 var currentMonth = this.date && this.date.getUTCMonth();
18366 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18368 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18369 v.removeClass('active');
18371 if(currentYear === year && k === currentMonth){
18372 v.addClass('active');
18375 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18376 v.addClass('disabled');
18382 year = parseInt(year/10, 10) * 10;
18384 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18386 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18389 for (var i = -1; i < 11; i++) {
18390 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18392 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18400 showMode: function(dir)
18403 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18406 Roo.each(this.picker().select('>div',true).elements, function(v){
18407 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18410 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18415 if(this.isInline) {
18419 this.picker().removeClass(['bottom', 'top']);
18421 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18423 * place to the top of element!
18427 this.picker().addClass('top');
18428 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18433 this.picker().addClass('bottom');
18435 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18438 parseDate : function(value)
18440 if(!value || value instanceof Date){
18443 var v = Date.parseDate(value, this.format);
18444 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18445 v = Date.parseDate(value, 'Y-m-d');
18447 if(!v && this.altFormats){
18448 if(!this.altFormatsArray){
18449 this.altFormatsArray = this.altFormats.split("|");
18451 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18452 v = Date.parseDate(value, this.altFormatsArray[i]);
18458 formatDate : function(date, fmt)
18460 return (!date || !(date instanceof Date)) ?
18461 date : date.dateFormat(fmt || this.format);
18464 onFocus : function()
18466 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18470 onBlur : function()
18472 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18474 var d = this.inputEl().getValue();
18483 this.picker().show();
18487 this.fireEvent('show', this, this.date);
18492 if(this.isInline) {
18495 this.picker().hide();
18496 this.viewMode = this.startViewMode;
18499 this.fireEvent('hide', this, this.date);
18503 onMousedown: function(e)
18505 e.stopPropagation();
18506 e.preventDefault();
18511 Roo.bootstrap.DateField.superclass.keyup.call(this);
18515 setValue: function(v)
18517 if(this.fireEvent('beforeselect', this, v) !== false){
18518 var d = new Date(this.parseDate(v) ).clearTime();
18520 if(isNaN(d.getTime())){
18521 this.date = this.viewDate = '';
18522 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18526 v = this.formatDate(d);
18528 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18530 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18534 this.fireEvent('select', this, this.date);
18538 getValue: function()
18540 return this.formatDate(this.date);
18543 fireKey: function(e)
18545 if (!this.picker().isVisible()){
18546 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18552 var dateChanged = false,
18554 newDate, newViewDate;
18559 e.preventDefault();
18563 if (!this.keyboardNavigation) {
18566 dir = e.keyCode == 37 ? -1 : 1;
18569 newDate = this.moveYear(this.date, dir);
18570 newViewDate = this.moveYear(this.viewDate, dir);
18571 } else if (e.shiftKey){
18572 newDate = this.moveMonth(this.date, dir);
18573 newViewDate = this.moveMonth(this.viewDate, dir);
18575 newDate = new Date(this.date);
18576 newDate.setUTCDate(this.date.getUTCDate() + dir);
18577 newViewDate = new Date(this.viewDate);
18578 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18580 if (this.dateWithinRange(newDate)){
18581 this.date = newDate;
18582 this.viewDate = newViewDate;
18583 this.setValue(this.formatDate(this.date));
18585 e.preventDefault();
18586 dateChanged = true;
18591 if (!this.keyboardNavigation) {
18594 dir = e.keyCode == 38 ? -1 : 1;
18596 newDate = this.moveYear(this.date, dir);
18597 newViewDate = this.moveYear(this.viewDate, dir);
18598 } else if (e.shiftKey){
18599 newDate = this.moveMonth(this.date, dir);
18600 newViewDate = this.moveMonth(this.viewDate, dir);
18602 newDate = new Date(this.date);
18603 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18604 newViewDate = new Date(this.viewDate);
18605 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18607 if (this.dateWithinRange(newDate)){
18608 this.date = newDate;
18609 this.viewDate = newViewDate;
18610 this.setValue(this.formatDate(this.date));
18612 e.preventDefault();
18613 dateChanged = true;
18617 this.setValue(this.formatDate(this.date));
18619 e.preventDefault();
18622 this.setValue(this.formatDate(this.date));
18636 onClick: function(e)
18638 e.stopPropagation();
18639 e.preventDefault();
18641 var target = e.getTarget();
18643 if(target.nodeName.toLowerCase() === 'i'){
18644 target = Roo.get(target).dom.parentNode;
18647 var nodeName = target.nodeName;
18648 var className = target.className;
18649 var html = target.innerHTML;
18650 //Roo.log(nodeName);
18652 switch(nodeName.toLowerCase()) {
18654 switch(className) {
18660 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18661 switch(this.viewMode){
18663 this.viewDate = this.moveMonth(this.viewDate, dir);
18667 this.viewDate = this.moveYear(this.viewDate, dir);
18673 var date = new Date();
18674 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18676 this.setValue(this.formatDate(this.date));
18683 if (className.indexOf('disabled') < 0) {
18684 this.viewDate.setUTCDate(1);
18685 if (className.indexOf('month') > -1) {
18686 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18688 var year = parseInt(html, 10) || 0;
18689 this.viewDate.setUTCFullYear(year);
18693 if(this.singleMode){
18694 this.setValue(this.formatDate(this.viewDate));
18705 //Roo.log(className);
18706 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18707 var day = parseInt(html, 10) || 1;
18708 var year = this.viewDate.getUTCFullYear(),
18709 month = this.viewDate.getUTCMonth();
18711 if (className.indexOf('old') > -1) {
18718 } else if (className.indexOf('new') > -1) {
18726 //Roo.log([year,month,day]);
18727 this.date = this.UTCDate(year, month, day,0,0,0,0);
18728 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18730 //Roo.log(this.formatDate(this.date));
18731 this.setValue(this.formatDate(this.date));
18738 setStartDate: function(startDate)
18740 this.startDate = startDate || -Infinity;
18741 if (this.startDate !== -Infinity) {
18742 this.startDate = this.parseDate(this.startDate);
18745 this.updateNavArrows();
18748 setEndDate: function(endDate)
18750 this.endDate = endDate || Infinity;
18751 if (this.endDate !== Infinity) {
18752 this.endDate = this.parseDate(this.endDate);
18755 this.updateNavArrows();
18758 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18760 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18761 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18762 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18764 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18765 return parseInt(d, 10);
18768 this.updateNavArrows();
18771 updateNavArrows: function()
18773 if(this.singleMode){
18777 var d = new Date(this.viewDate),
18778 year = d.getUTCFullYear(),
18779 month = d.getUTCMonth();
18781 Roo.each(this.picker().select('.prev', true).elements, function(v){
18783 switch (this.viewMode) {
18786 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18792 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18799 Roo.each(this.picker().select('.next', true).elements, function(v){
18801 switch (this.viewMode) {
18804 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18810 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18818 moveMonth: function(date, dir)
18823 var new_date = new Date(date.valueOf()),
18824 day = new_date.getUTCDate(),
18825 month = new_date.getUTCMonth(),
18826 mag = Math.abs(dir),
18828 dir = dir > 0 ? 1 : -1;
18831 // If going back one month, make sure month is not current month
18832 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18834 return new_date.getUTCMonth() == month;
18836 // If going forward one month, make sure month is as expected
18837 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18839 return new_date.getUTCMonth() != new_month;
18841 new_month = month + dir;
18842 new_date.setUTCMonth(new_month);
18843 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18844 if (new_month < 0 || new_month > 11) {
18845 new_month = (new_month + 12) % 12;
18848 // For magnitudes >1, move one month at a time...
18849 for (var i=0; i<mag; i++) {
18850 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18851 new_date = this.moveMonth(new_date, dir);
18853 // ...then reset the day, keeping it in the new month
18854 new_month = new_date.getUTCMonth();
18855 new_date.setUTCDate(day);
18857 return new_month != new_date.getUTCMonth();
18860 // Common date-resetting loop -- if date is beyond end of month, make it
18863 new_date.setUTCDate(--day);
18864 new_date.setUTCMonth(new_month);
18869 moveYear: function(date, dir)
18871 return this.moveMonth(date, dir*12);
18874 dateWithinRange: function(date)
18876 return date >= this.startDate && date <= this.endDate;
18882 this.picker().remove();
18885 validateValue : function(value)
18887 if(value.length < 1) {
18888 if(this.allowBlank){
18894 if(value.length < this.minLength){
18897 if(value.length > this.maxLength){
18901 var vt = Roo.form.VTypes;
18902 if(!vt[this.vtype](value, this)){
18906 if(typeof this.validator == "function"){
18907 var msg = this.validator(value);
18913 if(this.regex && !this.regex.test(value)){
18917 if(typeof(this.parseDate(value)) == 'undefined'){
18921 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18925 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18935 Roo.apply(Roo.bootstrap.DateField, {
18946 html: '<i class="fa fa-arrow-left"/>'
18956 html: '<i class="fa fa-arrow-right"/>'
18998 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18999 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19000 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19001 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19002 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19015 navFnc: 'FullYear',
19020 navFnc: 'FullYear',
19025 Roo.apply(Roo.bootstrap.DateField, {
19029 cls: 'datepicker dropdown-menu roo-dynamic',
19033 cls: 'datepicker-days',
19037 cls: 'table-condensed',
19039 Roo.bootstrap.DateField.head,
19043 Roo.bootstrap.DateField.footer
19050 cls: 'datepicker-months',
19054 cls: 'table-condensed',
19056 Roo.bootstrap.DateField.head,
19057 Roo.bootstrap.DateField.content,
19058 Roo.bootstrap.DateField.footer
19065 cls: 'datepicker-years',
19069 cls: 'table-condensed',
19071 Roo.bootstrap.DateField.head,
19072 Roo.bootstrap.DateField.content,
19073 Roo.bootstrap.DateField.footer
19092 * @class Roo.bootstrap.TimeField
19093 * @extends Roo.bootstrap.Input
19094 * Bootstrap DateField class
19098 * Create a new TimeField
19099 * @param {Object} config The config object
19102 Roo.bootstrap.TimeField = function(config){
19103 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19107 * Fires when this field show.
19108 * @param {Roo.bootstrap.DateField} thisthis
19109 * @param {Mixed} date The date value
19114 * Fires when this field hide.
19115 * @param {Roo.bootstrap.DateField} this
19116 * @param {Mixed} date The date value
19121 * Fires when select a date.
19122 * @param {Roo.bootstrap.DateField} this
19123 * @param {Mixed} date The date value
19129 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19132 * @cfg {String} format
19133 * The default time format string which can be overriden for localization support. The format must be
19134 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19138 onRender: function(ct, position)
19141 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19143 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19145 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19147 this.pop = this.picker().select('>.datepicker-time',true).first();
19148 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19150 this.picker().on('mousedown', this.onMousedown, this);
19151 this.picker().on('click', this.onClick, this);
19153 this.picker().addClass('datepicker-dropdown');
19158 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19159 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19160 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19161 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19162 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19163 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19167 fireKey: function(e){
19168 if (!this.picker().isVisible()){
19169 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19175 e.preventDefault();
19183 this.onTogglePeriod();
19186 this.onIncrementMinutes();
19189 this.onDecrementMinutes();
19198 onClick: function(e) {
19199 e.stopPropagation();
19200 e.preventDefault();
19203 picker : function()
19205 return this.el.select('.datepicker', true).first();
19208 fillTime: function()
19210 var time = this.pop.select('tbody', true).first();
19212 time.dom.innerHTML = '';
19227 cls: 'hours-up glyphicon glyphicon-chevron-up'
19247 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19268 cls: 'timepicker-hour',
19283 cls: 'timepicker-minute',
19298 cls: 'btn btn-primary period',
19320 cls: 'hours-down glyphicon glyphicon-chevron-down'
19340 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19358 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19365 var hours = this.time.getHours();
19366 var minutes = this.time.getMinutes();
19379 hours = hours - 12;
19383 hours = '0' + hours;
19387 minutes = '0' + minutes;
19390 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19391 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19392 this.pop.select('button', true).first().dom.innerHTML = period;
19398 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19400 var cls = ['bottom'];
19402 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19409 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19414 this.picker().addClass(cls.join('-'));
19418 Roo.each(cls, function(c){
19420 _this.picker().setTop(_this.inputEl().getHeight());
19424 _this.picker().setTop(0 - _this.picker().getHeight());
19429 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19433 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19440 onFocus : function()
19442 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19446 onBlur : function()
19448 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19454 this.picker().show();
19459 this.fireEvent('show', this, this.date);
19464 this.picker().hide();
19467 this.fireEvent('hide', this, this.date);
19470 setTime : function()
19473 this.setValue(this.time.format(this.format));
19475 this.fireEvent('select', this, this.date);
19480 onMousedown: function(e){
19481 e.stopPropagation();
19482 e.preventDefault();
19485 onIncrementHours: function()
19487 Roo.log('onIncrementHours');
19488 this.time = this.time.add(Date.HOUR, 1);
19493 onDecrementHours: function()
19495 Roo.log('onDecrementHours');
19496 this.time = this.time.add(Date.HOUR, -1);
19500 onIncrementMinutes: function()
19502 Roo.log('onIncrementMinutes');
19503 this.time = this.time.add(Date.MINUTE, 1);
19507 onDecrementMinutes: function()
19509 Roo.log('onDecrementMinutes');
19510 this.time = this.time.add(Date.MINUTE, -1);
19514 onTogglePeriod: function()
19516 Roo.log('onTogglePeriod');
19517 this.time = this.time.add(Date.HOUR, 12);
19524 Roo.apply(Roo.bootstrap.TimeField, {
19554 cls: 'btn btn-info ok',
19566 Roo.apply(Roo.bootstrap.TimeField, {
19570 cls: 'datepicker dropdown-menu',
19574 cls: 'datepicker-time',
19578 cls: 'table-condensed',
19580 Roo.bootstrap.TimeField.content,
19581 Roo.bootstrap.TimeField.footer
19600 * @class Roo.bootstrap.MonthField
19601 * @extends Roo.bootstrap.Input
19602 * Bootstrap MonthField class
19604 * @cfg {String} language default en
19607 * Create a new MonthField
19608 * @param {Object} config The config object
19611 Roo.bootstrap.MonthField = function(config){
19612 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19617 * Fires when this field show.
19618 * @param {Roo.bootstrap.MonthField} this
19619 * @param {Mixed} date The date value
19624 * Fires when this field hide.
19625 * @param {Roo.bootstrap.MonthField} this
19626 * @param {Mixed} date The date value
19631 * Fires when select a date.
19632 * @param {Roo.bootstrap.MonthField} this
19633 * @param {String} oldvalue The old value
19634 * @param {String} newvalue The new value
19640 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19642 onRender: function(ct, position)
19645 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19647 this.language = this.language || 'en';
19648 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19649 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19651 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19652 this.isInline = false;
19653 this.isInput = true;
19654 this.component = this.el.select('.add-on', true).first() || false;
19655 this.component = (this.component && this.component.length === 0) ? false : this.component;
19656 this.hasInput = this.component && this.inputEL().length;
19658 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19660 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19662 this.picker().on('mousedown', this.onMousedown, this);
19663 this.picker().on('click', this.onClick, this);
19665 this.picker().addClass('datepicker-dropdown');
19667 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19668 v.setStyle('width', '189px');
19675 if(this.isInline) {
19681 setValue: function(v, suppressEvent)
19683 var o = this.getValue();
19685 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19689 if(suppressEvent !== true){
19690 this.fireEvent('select', this, o, v);
19695 getValue: function()
19700 onClick: function(e)
19702 e.stopPropagation();
19703 e.preventDefault();
19705 var target = e.getTarget();
19707 if(target.nodeName.toLowerCase() === 'i'){
19708 target = Roo.get(target).dom.parentNode;
19711 var nodeName = target.nodeName;
19712 var className = target.className;
19713 var html = target.innerHTML;
19715 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19719 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19721 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19727 picker : function()
19729 return this.pickerEl;
19732 fillMonths: function()
19735 var months = this.picker().select('>.datepicker-months td', true).first();
19737 months.dom.innerHTML = '';
19743 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19746 months.createChild(month);
19755 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19756 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19759 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19760 e.removeClass('active');
19762 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19763 e.addClass('active');
19770 if(this.isInline) {
19774 this.picker().removeClass(['bottom', 'top']);
19776 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19778 * place to the top of element!
19782 this.picker().addClass('top');
19783 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19788 this.picker().addClass('bottom');
19790 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19793 onFocus : function()
19795 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19799 onBlur : function()
19801 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19803 var d = this.inputEl().getValue();
19812 this.picker().show();
19813 this.picker().select('>.datepicker-months', true).first().show();
19817 this.fireEvent('show', this, this.date);
19822 if(this.isInline) {
19825 this.picker().hide();
19826 this.fireEvent('hide', this, this.date);
19830 onMousedown: function(e)
19832 e.stopPropagation();
19833 e.preventDefault();
19838 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19842 fireKey: function(e)
19844 if (!this.picker().isVisible()){
19845 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19856 e.preventDefault();
19860 dir = e.keyCode == 37 ? -1 : 1;
19862 this.vIndex = this.vIndex + dir;
19864 if(this.vIndex < 0){
19868 if(this.vIndex > 11){
19872 if(isNaN(this.vIndex)){
19876 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19882 dir = e.keyCode == 38 ? -1 : 1;
19884 this.vIndex = this.vIndex + dir * 4;
19886 if(this.vIndex < 0){
19890 if(this.vIndex > 11){
19894 if(isNaN(this.vIndex)){
19898 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19903 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19904 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19908 e.preventDefault();
19911 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19912 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19928 this.picker().remove();
19933 Roo.apply(Roo.bootstrap.MonthField, {
19952 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19953 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19958 Roo.apply(Roo.bootstrap.MonthField, {
19962 cls: 'datepicker dropdown-menu roo-dynamic',
19966 cls: 'datepicker-months',
19970 cls: 'table-condensed',
19972 Roo.bootstrap.DateField.content
19992 * @class Roo.bootstrap.CheckBox
19993 * @extends Roo.bootstrap.Input
19994 * Bootstrap CheckBox class
19996 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19997 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19998 * @cfg {String} boxLabel The text that appears beside the checkbox
19999 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20000 * @cfg {Boolean} checked initnal the element
20001 * @cfg {Boolean} inline inline the element (default false)
20002 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20005 * Create a new CheckBox
20006 * @param {Object} config The config object
20009 Roo.bootstrap.CheckBox = function(config){
20010 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20015 * Fires when the element is checked or unchecked.
20016 * @param {Roo.bootstrap.CheckBox} this This input
20017 * @param {Boolean} checked The new checked value
20024 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20026 inputType: 'checkbox',
20034 getAutoCreate : function()
20036 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20042 cfg.cls = 'form-group ' + this.inputType; //input-group
20045 cfg.cls += ' ' + this.inputType + '-inline';
20051 type : this.inputType,
20052 value : this.inputValue,
20053 cls : 'roo-' + this.inputType, //'form-box',
20054 placeholder : this.placeholder || ''
20058 if(this.inputType != 'radio'){
20062 cls : 'roo-hidden-value',
20063 value : this.checked ? this.valueOff : this.inputValue
20068 if (this.weight) { // Validity check?
20069 cfg.cls += " " + this.inputType + "-" + this.weight;
20072 if (this.disabled) {
20073 input.disabled=true;
20077 input.checked = this.checked;
20084 input.name = this.name;
20086 if(this.inputType != 'radio'){
20087 hidden.name = this.name;
20088 input.name = '_hidden_' + this.name;
20093 input.cls += ' input-' + this.size;
20098 ['xs','sm','md','lg'].map(function(size){
20099 if (settings[size]) {
20100 cfg.cls += ' col-' + size + '-' + settings[size];
20104 var inputblock = input;
20106 if (this.before || this.after) {
20109 cls : 'input-group',
20114 inputblock.cn.push({
20116 cls : 'input-group-addon',
20121 inputblock.cn.push(input);
20123 if(this.inputType != 'radio'){
20124 inputblock.cn.push(hidden);
20128 inputblock.cn.push({
20130 cls : 'input-group-addon',
20137 if (align ==='left' && this.fieldLabel.length) {
20138 // Roo.log("left and has label");
20143 cls : 'control-label',
20144 html : this.fieldLabel
20155 if(this.labelWidth > 12){
20156 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20159 if(this.labelWidth < 13 && this.labelmd == 0){
20160 this.labelmd = this.labelWidth;
20163 if(this.labellg > 0){
20164 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20165 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20168 if(this.labelmd > 0){
20169 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20170 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20173 if(this.labelsm > 0){
20174 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20175 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20178 if(this.labelxs > 0){
20179 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20180 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20183 } else if ( this.fieldLabel.length) {
20184 // Roo.log(" label");
20188 tag: this.boxLabel ? 'span' : 'label',
20190 cls: 'control-label box-input-label',
20191 //cls : 'input-group-addon',
20192 html : this.fieldLabel
20202 // Roo.log(" no label && no align");
20203 cfg.cn = [ inputblock ] ;
20209 var boxLabelCfg = {
20211 //'for': id, // box label is handled by onclick - so no for...
20213 html: this.boxLabel
20217 boxLabelCfg.tooltip = this.tooltip;
20220 cfg.cn.push(boxLabelCfg);
20223 if(this.inputType != 'radio'){
20224 cfg.cn.push(hidden);
20232 * return the real input element.
20234 inputEl: function ()
20236 return this.el.select('input.roo-' + this.inputType,true).first();
20238 hiddenEl: function ()
20240 return this.el.select('input.roo-hidden-value',true).first();
20243 labelEl: function()
20245 return this.el.select('label.control-label',true).first();
20247 /* depricated... */
20251 return this.labelEl();
20254 boxLabelEl: function()
20256 return this.el.select('label.box-label',true).first();
20259 initEvents : function()
20261 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20263 this.inputEl().on('click', this.onClick, this);
20265 if (this.boxLabel) {
20266 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20269 this.startValue = this.getValue();
20272 Roo.bootstrap.CheckBox.register(this);
20276 onClick : function()
20278 this.setChecked(!this.checked);
20281 setChecked : function(state,suppressEvent)
20283 this.startValue = this.getValue();
20285 if(this.inputType == 'radio'){
20287 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20288 e.dom.checked = false;
20291 this.inputEl().dom.checked = true;
20293 this.inputEl().dom.value = this.inputValue;
20295 if(suppressEvent !== true){
20296 this.fireEvent('check', this, true);
20304 this.checked = state;
20306 this.inputEl().dom.checked = state;
20309 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20311 if(suppressEvent !== true){
20312 this.fireEvent('check', this, state);
20318 getValue : function()
20320 if(this.inputType == 'radio'){
20321 return this.getGroupValue();
20324 return this.hiddenEl().dom.value;
20328 getGroupValue : function()
20330 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20334 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20337 setValue : function(v,suppressEvent)
20339 if(this.inputType == 'radio'){
20340 this.setGroupValue(v, suppressEvent);
20344 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20349 setGroupValue : function(v, suppressEvent)
20351 this.startValue = this.getValue();
20353 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20354 e.dom.checked = false;
20356 if(e.dom.value == v){
20357 e.dom.checked = true;
20361 if(suppressEvent !== true){
20362 this.fireEvent('check', this, true);
20370 validate : function()
20374 (this.inputType == 'radio' && this.validateRadio()) ||
20375 (this.inputType == 'checkbox' && this.validateCheckbox())
20381 this.markInvalid();
20385 validateRadio : function()
20387 if(this.allowBlank){
20393 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20394 if(!e.dom.checked){
20406 validateCheckbox : function()
20409 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20410 //return (this.getValue() == this.inputValue) ? true : false;
20413 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20421 for(var i in group){
20426 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20433 * Mark this field as valid
20435 markValid : function()
20439 this.fireEvent('valid', this);
20441 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20444 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20451 if(this.inputType == 'radio'){
20452 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20453 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20454 e.findParent('.form-group', false, true).addClass(_this.validClass);
20461 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20462 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20466 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20472 for(var i in group){
20473 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20474 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20479 * Mark this field as invalid
20480 * @param {String} msg The validation message
20482 markInvalid : function(msg)
20484 if(this.allowBlank){
20490 this.fireEvent('invalid', this, msg);
20492 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20495 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20499 label.markInvalid();
20502 if(this.inputType == 'radio'){
20503 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20504 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20505 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20512 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20513 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20517 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20523 for(var i in group){
20524 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20525 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20530 clearInvalid : function()
20532 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20534 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20536 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20539 label.iconEl.removeClass(label.validClass);
20540 label.iconEl.removeClass(label.invalidClass);
20544 disable : function()
20546 if(this.inputType != 'radio'){
20547 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20554 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20555 _this.getActionEl().addClass(this.disabledClass);
20556 e.dom.disabled = true;
20560 this.disabled = true;
20561 this.fireEvent("disable", this);
20565 enable : function()
20567 if(this.inputType != 'radio'){
20568 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20575 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20576 _this.getActionEl().removeClass(this.disabledClass);
20577 e.dom.disabled = false;
20581 this.disabled = false;
20582 this.fireEvent("enable", this);
20588 Roo.apply(Roo.bootstrap.CheckBox, {
20593 * register a CheckBox Group
20594 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20596 register : function(checkbox)
20598 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20599 this.groups[checkbox.groupId] = {};
20602 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20606 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20610 * fetch a CheckBox Group based on the group ID
20611 * @param {string} the group ID
20612 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20614 get: function(groupId) {
20615 if (typeof(this.groups[groupId]) == 'undefined') {
20619 return this.groups[groupId] ;
20632 * @class Roo.bootstrap.Radio
20633 * @extends Roo.bootstrap.Component
20634 * Bootstrap Radio class
20635 * @cfg {String} boxLabel - the label associated
20636 * @cfg {String} value - the value of radio
20639 * Create a new Radio
20640 * @param {Object} config The config object
20642 Roo.bootstrap.Radio = function(config){
20643 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20647 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20653 getAutoCreate : function()
20657 cls : 'form-group radio',
20662 html : this.boxLabel
20670 initEvents : function()
20672 this.parent().register(this);
20674 this.el.on('click', this.onClick, this);
20678 onClick : function()
20680 this.setChecked(true);
20683 setChecked : function(state, suppressEvent)
20685 this.parent().setValue(this.value, suppressEvent);
20700 * @class Roo.bootstrap.SecurePass
20701 * @extends Roo.bootstrap.Input
20702 * Bootstrap SecurePass class
20706 * Create a new SecurePass
20707 * @param {Object} config The config object
20710 Roo.bootstrap.SecurePass = function (config) {
20711 // these go here, so the translation tool can replace them..
20713 PwdEmpty: "Please type a password, and then retype it to confirm.",
20714 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20715 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20716 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20717 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20718 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20719 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20720 TooWeak: "Your password is Too Weak."
20722 this.meterLabel = "Password strength:";
20723 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20724 this.meterClass = ["roo-password-meter-tooweak",
20725 "roo-password-meter-weak",
20726 "roo-password-meter-medium",
20727 "roo-password-meter-strong",
20728 "roo-password-meter-grey"],
20729 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20732 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20734 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20736 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20737 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20738 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20739 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20740 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20741 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20742 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20752 * @cfg {String/Object} Label for the strength meter (defaults to
20753 * 'Password strength:')
20758 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20759 * ['Weak', 'Medium', 'Strong'])
20775 initEvents: function () {
20776 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20778 if (this.el.is('input[type=password]') && Roo.isSafari) {
20779 this.el.on('keydown', this.SafariOnKeyDown, this);
20782 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20785 onRender: function (ct, position) {
20786 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20787 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20788 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20790 this.trigger.createChild({
20795 cls: 'roo-password-meter-grey col-xs-12',
20798 //width: this.meterWidth + 'px'
20802 cls: 'roo-password-meter-text'
20808 this.trigger.createChild({
20810 cls: 'roo-password-meter-container col-xs-12',
20812 //width: this.meterWidth + 'px'
20816 cls: 'roo-password-meter-grey',
20818 //width: this.meterWidth + 'px'
20824 cls: 'roo-password-meter-grey col-xs-12',
20827 //width: this.meterWidth + 'px'
20831 cls: 'roo-password-meter-text'
20837 if (this.hideTrigger) {
20838 this.trigger.setDisplayed(false);
20840 this.setSize(this.width || '', this.height || '');
20843 onDestroy: function () {
20844 if (this.trigger) {
20845 this.trigger.removeAllListeners();
20846 this.trigger.remove();
20849 this.wrap.remove();
20851 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20854 checkStrength: function () {
20855 var pwd = this.inputEl().getValue();
20856 if (pwd == this._lastPwd) {
20861 if (this.ClientSideStrongPassword(pwd)) {
20863 } else if (this.ClientSideMediumPassword(pwd)) {
20865 } else if (this.ClientSideWeakPassword(pwd)) {
20871 console.log('strength1: ' + strength);
20873 //var pm = this.trigger.child('div/div/div').dom;
20874 var pm = this.trigger.child('div/div');
20875 pm.removeClass(this.meterClass);
20876 pm.addClass(this.meterClass[strength]);
20879 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20881 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20883 this._lastPwd = pwd;
20885 reset: function () {
20886 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20888 this._lastPwd = '';
20890 var pm = this.trigger.child('div/div');
20891 pm.removeClass(this.meterClass);
20892 pm.addClass('roo-password-meter-grey');
20895 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20898 this.inputEl().dom.type='password';
20901 validateValue: function (value) {
20903 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20906 if (value.length == 0) {
20907 if (this.allowBlank) {
20908 this.clearInvalid();
20912 this.markInvalid(this.errors.PwdEmpty);
20913 this.errorMsg = this.errors.PwdEmpty;
20921 if ('[\x21-\x7e]*'.match(value)) {
20922 this.markInvalid(this.errors.PwdBadChar);
20923 this.errorMsg = this.errors.PwdBadChar;
20926 if (value.length < 6) {
20927 this.markInvalid(this.errors.PwdShort);
20928 this.errorMsg = this.errors.PwdShort;
20931 if (value.length > 16) {
20932 this.markInvalid(this.errors.PwdLong);
20933 this.errorMsg = this.errors.PwdLong;
20937 if (this.ClientSideStrongPassword(value)) {
20939 } else if (this.ClientSideMediumPassword(value)) {
20941 } else if (this.ClientSideWeakPassword(value)) {
20948 if (strength < 2) {
20949 //this.markInvalid(this.errors.TooWeak);
20950 this.errorMsg = this.errors.TooWeak;
20955 console.log('strength2: ' + strength);
20957 //var pm = this.trigger.child('div/div/div').dom;
20959 var pm = this.trigger.child('div/div');
20960 pm.removeClass(this.meterClass);
20961 pm.addClass(this.meterClass[strength]);
20963 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20965 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20967 this.errorMsg = '';
20971 CharacterSetChecks: function (type) {
20973 this.fResult = false;
20976 isctype: function (character, type) {
20977 switch (type) { //why needed break after return in js ? very odd bug
20978 case this.kCapitalLetter:
20979 if (character >= 'A' && character <= 'Z') {
20983 case this.kSmallLetter:
20984 if (character >= 'a' && character <= 'z') {
20989 if (character >= '0' && character <= '9') {
20993 case this.kPunctuation:
20994 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21004 IsLongEnough: function (pwd, size) {
21005 return !(pwd == null || isNaN(size) || pwd.length < size);
21008 SpansEnoughCharacterSets: function (word, nb) {
21009 if (!this.IsLongEnough(word, nb))
21014 var characterSetChecks = new Array(
21015 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21016 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
21017 for (var index = 0; index < word.length; ++index) {
21018 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21019 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21020 characterSetChecks[nCharSet].fResult = true;
21027 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21028 if (characterSetChecks[nCharSet].fResult) {
21033 if (nCharSets < nb) {
21039 ClientSideStrongPassword: function (pwd) {
21040 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21043 ClientSideMediumPassword: function (pwd) {
21044 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21047 ClientSideWeakPassword: function (pwd) {
21048 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21051 })//<script type="text/javascript">
21054 * Based Ext JS Library 1.1.1
21055 * Copyright(c) 2006-2007, Ext JS, LLC.
21061 * @class Roo.HtmlEditorCore
21062 * @extends Roo.Component
21063 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21065 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21068 Roo.HtmlEditorCore = function(config){
21071 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21076 * @event initialize
21077 * Fires when the editor is fully initialized (including the iframe)
21078 * @param {Roo.HtmlEditorCore} this
21083 * Fires when the editor is first receives the focus. Any insertion must wait
21084 * until after this event.
21085 * @param {Roo.HtmlEditorCore} this
21089 * @event beforesync
21090 * Fires before the textarea is updated with content from the editor iframe. Return false
21091 * to cancel the sync.
21092 * @param {Roo.HtmlEditorCore} this
21093 * @param {String} html
21097 * @event beforepush
21098 * Fires before the iframe editor is updated with content from the textarea. Return false
21099 * to cancel the push.
21100 * @param {Roo.HtmlEditorCore} this
21101 * @param {String} html
21106 * Fires when the textarea is updated with content from the editor iframe.
21107 * @param {Roo.HtmlEditorCore} this
21108 * @param {String} html
21113 * Fires when the iframe editor is updated with content from the textarea.
21114 * @param {Roo.HtmlEditorCore} this
21115 * @param {String} html
21120 * @event editorevent
21121 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21122 * @param {Roo.HtmlEditorCore} this
21128 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21130 // defaults : white / black...
21131 this.applyBlacklists();
21138 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21142 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21148 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21153 * @cfg {Number} height (in pixels)
21157 * @cfg {Number} width (in pixels)
21162 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21165 stylesheets: false,
21170 // private properties
21171 validationEvent : false,
21173 initialized : false,
21175 sourceEditMode : false,
21176 onFocus : Roo.emptyFn,
21178 hideMode:'offsets',
21182 // blacklist + whitelisted elements..
21189 * Protected method that will not generally be called directly. It
21190 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21191 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21193 getDocMarkup : function(){
21197 // inherit styels from page...??
21198 if (this.stylesheets === false) {
21200 Roo.get(document.head).select('style').each(function(node) {
21201 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21204 Roo.get(document.head).select('link').each(function(node) {
21205 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21208 } else if (!this.stylesheets.length) {
21210 st = '<style type="text/css">' +
21211 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21217 st += '<style type="text/css">' +
21218 'IMG { cursor: pointer } ' +
21222 return '<html><head>' + st +
21223 //<style type="text/css">' +
21224 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21226 ' </head><body class="roo-htmleditor-body"></body></html>';
21230 onRender : function(ct, position)
21233 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21234 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21237 this.el.dom.style.border = '0 none';
21238 this.el.dom.setAttribute('tabIndex', -1);
21239 this.el.addClass('x-hidden hide');
21243 if(Roo.isIE){ // fix IE 1px bogus margin
21244 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21248 this.frameId = Roo.id();
21252 var iframe = this.owner.wrap.createChild({
21254 cls: 'form-control', // bootstrap..
21256 name: this.frameId,
21257 frameBorder : 'no',
21258 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21263 this.iframe = iframe.dom;
21265 this.assignDocWin();
21267 this.doc.designMode = 'on';
21270 this.doc.write(this.getDocMarkup());
21274 var task = { // must defer to wait for browser to be ready
21276 //console.log("run task?" + this.doc.readyState);
21277 this.assignDocWin();
21278 if(this.doc.body || this.doc.readyState == 'complete'){
21280 this.doc.designMode="on";
21284 Roo.TaskMgr.stop(task);
21285 this.initEditor.defer(10, this);
21292 Roo.TaskMgr.start(task);
21297 onResize : function(w, h)
21299 Roo.log('resize: ' +w + ',' + h );
21300 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21304 if(typeof w == 'number'){
21306 this.iframe.style.width = w + 'px';
21308 if(typeof h == 'number'){
21310 this.iframe.style.height = h + 'px';
21312 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21319 * Toggles the editor between standard and source edit mode.
21320 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21322 toggleSourceEdit : function(sourceEditMode){
21324 this.sourceEditMode = sourceEditMode === true;
21326 if(this.sourceEditMode){
21328 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21331 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21332 //this.iframe.className = '';
21335 //this.setSize(this.owner.wrap.getSize());
21336 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21343 * Protected method that will not generally be called directly. If you need/want
21344 * custom HTML cleanup, this is the method you should override.
21345 * @param {String} html The HTML to be cleaned
21346 * return {String} The cleaned HTML
21348 cleanHtml : function(html){
21349 html = String(html);
21350 if(html.length > 5){
21351 if(Roo.isSafari){ // strip safari nonsense
21352 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21355 if(html == ' '){
21362 * HTML Editor -> Textarea
21363 * Protected method that will not generally be called directly. Syncs the contents
21364 * of the editor iframe with the textarea.
21366 syncValue : function(){
21367 if(this.initialized){
21368 var bd = (this.doc.body || this.doc.documentElement);
21369 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21370 var html = bd.innerHTML;
21372 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21373 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21375 html = '<div style="'+m[0]+'">' + html + '</div>';
21378 html = this.cleanHtml(html);
21379 // fix up the special chars.. normaly like back quotes in word...
21380 // however we do not want to do this with chinese..
21381 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21382 var cc = b.charCodeAt();
21384 (cc >= 0x4E00 && cc < 0xA000 ) ||
21385 (cc >= 0x3400 && cc < 0x4E00 ) ||
21386 (cc >= 0xf900 && cc < 0xfb00 )
21392 if(this.owner.fireEvent('beforesync', this, html) !== false){
21393 this.el.dom.value = html;
21394 this.owner.fireEvent('sync', this, html);
21400 * Protected method that will not generally be called directly. Pushes the value of the textarea
21401 * into the iframe editor.
21403 pushValue : function(){
21404 if(this.initialized){
21405 var v = this.el.dom.value.trim();
21407 // if(v.length < 1){
21411 if(this.owner.fireEvent('beforepush', this, v) !== false){
21412 var d = (this.doc.body || this.doc.documentElement);
21414 this.cleanUpPaste();
21415 this.el.dom.value = d.innerHTML;
21416 this.owner.fireEvent('push', this, v);
21422 deferFocus : function(){
21423 this.focus.defer(10, this);
21427 focus : function(){
21428 if(this.win && !this.sourceEditMode){
21435 assignDocWin: function()
21437 var iframe = this.iframe;
21440 this.doc = iframe.contentWindow.document;
21441 this.win = iframe.contentWindow;
21443 // if (!Roo.get(this.frameId)) {
21446 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21447 // this.win = Roo.get(this.frameId).dom.contentWindow;
21449 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21453 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21454 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21459 initEditor : function(){
21460 //console.log("INIT EDITOR");
21461 this.assignDocWin();
21465 this.doc.designMode="on";
21467 this.doc.write(this.getDocMarkup());
21470 var dbody = (this.doc.body || this.doc.documentElement);
21471 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21472 // this copies styles from the containing element into thsi one..
21473 // not sure why we need all of this..
21474 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21476 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21477 //ss['background-attachment'] = 'fixed'; // w3c
21478 dbody.bgProperties = 'fixed'; // ie
21479 //Roo.DomHelper.applyStyles(dbody, ss);
21480 Roo.EventManager.on(this.doc, {
21481 //'mousedown': this.onEditorEvent,
21482 'mouseup': this.onEditorEvent,
21483 'dblclick': this.onEditorEvent,
21484 'click': this.onEditorEvent,
21485 'keyup': this.onEditorEvent,
21490 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21492 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21493 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21495 this.initialized = true;
21497 this.owner.fireEvent('initialize', this);
21502 onDestroy : function(){
21508 //for (var i =0; i < this.toolbars.length;i++) {
21509 // // fixme - ask toolbars for heights?
21510 // this.toolbars[i].onDestroy();
21513 //this.wrap.dom.innerHTML = '';
21514 //this.wrap.remove();
21519 onFirstFocus : function(){
21521 this.assignDocWin();
21524 this.activated = true;
21527 if(Roo.isGecko){ // prevent silly gecko errors
21529 var s = this.win.getSelection();
21530 if(!s.focusNode || s.focusNode.nodeType != 3){
21531 var r = s.getRangeAt(0);
21532 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21537 this.execCmd('useCSS', true);
21538 this.execCmd('styleWithCSS', false);
21541 this.owner.fireEvent('activate', this);
21545 adjustFont: function(btn){
21546 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21547 //if(Roo.isSafari){ // safari
21550 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21551 if(Roo.isSafari){ // safari
21552 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21553 v = (v < 10) ? 10 : v;
21554 v = (v > 48) ? 48 : v;
21555 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21560 v = Math.max(1, v+adjust);
21562 this.execCmd('FontSize', v );
21565 onEditorEvent : function(e)
21567 this.owner.fireEvent('editorevent', this, e);
21568 // this.updateToolbar();
21569 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21572 insertTag : function(tg)
21574 // could be a bit smarter... -> wrap the current selected tRoo..
21575 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21577 range = this.createRange(this.getSelection());
21578 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21579 wrappingNode.appendChild(range.extractContents());
21580 range.insertNode(wrappingNode);
21587 this.execCmd("formatblock", tg);
21591 insertText : function(txt)
21595 var range = this.createRange();
21596 range.deleteContents();
21597 //alert(Sender.getAttribute('label'));
21599 range.insertNode(this.doc.createTextNode(txt));
21605 * Executes a Midas editor command on the editor document and performs necessary focus and
21606 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21607 * @param {String} cmd The Midas command
21608 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21610 relayCmd : function(cmd, value){
21612 this.execCmd(cmd, value);
21613 this.owner.fireEvent('editorevent', this);
21614 //this.updateToolbar();
21615 this.owner.deferFocus();
21619 * Executes a Midas editor command directly on the editor document.
21620 * For visual commands, you should use {@link #relayCmd} instead.
21621 * <b>This should only be called after the editor is initialized.</b>
21622 * @param {String} cmd The Midas command
21623 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21625 execCmd : function(cmd, value){
21626 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21633 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21635 * @param {String} text | dom node..
21637 insertAtCursor : function(text)
21642 if(!this.activated){
21648 var r = this.doc.selection.createRange();
21659 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21663 // from jquery ui (MIT licenced)
21665 var win = this.win;
21667 if (win.getSelection && win.getSelection().getRangeAt) {
21668 range = win.getSelection().getRangeAt(0);
21669 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21670 range.insertNode(node);
21671 } else if (win.document.selection && win.document.selection.createRange) {
21672 // no firefox support
21673 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21674 win.document.selection.createRange().pasteHTML(txt);
21676 // no firefox support
21677 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21678 this.execCmd('InsertHTML', txt);
21687 mozKeyPress : function(e){
21689 var c = e.getCharCode(), cmd;
21692 c = String.fromCharCode(c).toLowerCase();
21706 this.cleanUpPaste.defer(100, this);
21714 e.preventDefault();
21722 fixKeys : function(){ // load time branching for fastest keydown performance
21724 return function(e){
21725 var k = e.getKey(), r;
21728 r = this.doc.selection.createRange();
21731 r.pasteHTML('    ');
21738 r = this.doc.selection.createRange();
21740 var target = r.parentElement();
21741 if(!target || target.tagName.toLowerCase() != 'li'){
21743 r.pasteHTML('<br />');
21749 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21750 this.cleanUpPaste.defer(100, this);
21756 }else if(Roo.isOpera){
21757 return function(e){
21758 var k = e.getKey();
21762 this.execCmd('InsertHTML','    ');
21765 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21766 this.cleanUpPaste.defer(100, this);
21771 }else if(Roo.isSafari){
21772 return function(e){
21773 var k = e.getKey();
21777 this.execCmd('InsertText','\t');
21781 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21782 this.cleanUpPaste.defer(100, this);
21790 getAllAncestors: function()
21792 var p = this.getSelectedNode();
21795 a.push(p); // push blank onto stack..
21796 p = this.getParentElement();
21800 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21804 a.push(this.doc.body);
21808 lastSelNode : false,
21811 getSelection : function()
21813 this.assignDocWin();
21814 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21817 getSelectedNode: function()
21819 // this may only work on Gecko!!!
21821 // should we cache this!!!!
21826 var range = this.createRange(this.getSelection()).cloneRange();
21829 var parent = range.parentElement();
21831 var testRange = range.duplicate();
21832 testRange.moveToElementText(parent);
21833 if (testRange.inRange(range)) {
21836 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21839 parent = parent.parentElement;
21844 // is ancestor a text element.
21845 var ac = range.commonAncestorContainer;
21846 if (ac.nodeType == 3) {
21847 ac = ac.parentNode;
21850 var ar = ac.childNodes;
21853 var other_nodes = [];
21854 var has_other_nodes = false;
21855 for (var i=0;i<ar.length;i++) {
21856 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21859 // fullly contained node.
21861 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21866 // probably selected..
21867 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21868 other_nodes.push(ar[i]);
21872 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21877 has_other_nodes = true;
21879 if (!nodes.length && other_nodes.length) {
21880 nodes= other_nodes;
21882 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21888 createRange: function(sel)
21890 // this has strange effects when using with
21891 // top toolbar - not sure if it's a great idea.
21892 //this.editor.contentWindow.focus();
21893 if (typeof sel != "undefined") {
21895 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21897 return this.doc.createRange();
21900 return this.doc.createRange();
21903 getParentElement: function()
21906 this.assignDocWin();
21907 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21909 var range = this.createRange(sel);
21912 var p = range.commonAncestorContainer;
21913 while (p.nodeType == 3) { // text node
21924 * Range intersection.. the hard stuff...
21928 * [ -- selected range --- ]
21932 * if end is before start or hits it. fail.
21933 * if start is after end or hits it fail.
21935 * if either hits (but other is outside. - then it's not
21941 // @see http://www.thismuchiknow.co.uk/?p=64.
21942 rangeIntersectsNode : function(range, node)
21944 var nodeRange = node.ownerDocument.createRange();
21946 nodeRange.selectNode(node);
21948 nodeRange.selectNodeContents(node);
21951 var rangeStartRange = range.cloneRange();
21952 rangeStartRange.collapse(true);
21954 var rangeEndRange = range.cloneRange();
21955 rangeEndRange.collapse(false);
21957 var nodeStartRange = nodeRange.cloneRange();
21958 nodeStartRange.collapse(true);
21960 var nodeEndRange = nodeRange.cloneRange();
21961 nodeEndRange.collapse(false);
21963 return rangeStartRange.compareBoundaryPoints(
21964 Range.START_TO_START, nodeEndRange) == -1 &&
21965 rangeEndRange.compareBoundaryPoints(
21966 Range.START_TO_START, nodeStartRange) == 1;
21970 rangeCompareNode : function(range, node)
21972 var nodeRange = node.ownerDocument.createRange();
21974 nodeRange.selectNode(node);
21976 nodeRange.selectNodeContents(node);
21980 range.collapse(true);
21982 nodeRange.collapse(true);
21984 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21985 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21987 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21989 var nodeIsBefore = ss == 1;
21990 var nodeIsAfter = ee == -1;
21992 if (nodeIsBefore && nodeIsAfter) {
21995 if (!nodeIsBefore && nodeIsAfter) {
21996 return 1; //right trailed.
21999 if (nodeIsBefore && !nodeIsAfter) {
22000 return 2; // left trailed.
22006 // private? - in a new class?
22007 cleanUpPaste : function()
22009 // cleans up the whole document..
22010 Roo.log('cleanuppaste');
22012 this.cleanUpChildren(this.doc.body);
22013 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22014 if (clean != this.doc.body.innerHTML) {
22015 this.doc.body.innerHTML = clean;
22020 cleanWordChars : function(input) {// change the chars to hex code
22021 var he = Roo.HtmlEditorCore;
22023 var output = input;
22024 Roo.each(he.swapCodes, function(sw) {
22025 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22027 output = output.replace(swapper, sw[1]);
22034 cleanUpChildren : function (n)
22036 if (!n.childNodes.length) {
22039 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22040 this.cleanUpChild(n.childNodes[i]);
22047 cleanUpChild : function (node)
22050 //console.log(node);
22051 if (node.nodeName == "#text") {
22052 // clean up silly Windows -- stuff?
22055 if (node.nodeName == "#comment") {
22056 node.parentNode.removeChild(node);
22057 // clean up silly Windows -- stuff?
22060 var lcname = node.tagName.toLowerCase();
22061 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22062 // whitelist of tags..
22064 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22066 node.parentNode.removeChild(node);
22071 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22073 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22074 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22076 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22077 // remove_keep_children = true;
22080 if (remove_keep_children) {
22081 this.cleanUpChildren(node);
22082 // inserts everything just before this node...
22083 while (node.childNodes.length) {
22084 var cn = node.childNodes[0];
22085 node.removeChild(cn);
22086 node.parentNode.insertBefore(cn, node);
22088 node.parentNode.removeChild(node);
22092 if (!node.attributes || !node.attributes.length) {
22093 this.cleanUpChildren(node);
22097 function cleanAttr(n,v)
22100 if (v.match(/^\./) || v.match(/^\//)) {
22103 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22106 if (v.match(/^#/)) {
22109 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22110 node.removeAttribute(n);
22114 var cwhite = this.cwhite;
22115 var cblack = this.cblack;
22117 function cleanStyle(n,v)
22119 if (v.match(/expression/)) { //XSS?? should we even bother..
22120 node.removeAttribute(n);
22124 var parts = v.split(/;/);
22127 Roo.each(parts, function(p) {
22128 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22132 var l = p.split(':').shift().replace(/\s+/g,'');
22133 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22135 if ( cwhite.length && cblack.indexOf(l) > -1) {
22136 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22137 //node.removeAttribute(n);
22141 // only allow 'c whitelisted system attributes'
22142 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22143 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22144 //node.removeAttribute(n);
22154 if (clean.length) {
22155 node.setAttribute(n, clean.join(';'));
22157 node.removeAttribute(n);
22163 for (var i = node.attributes.length-1; i > -1 ; i--) {
22164 var a = node.attributes[i];
22167 if (a.name.toLowerCase().substr(0,2)=='on') {
22168 node.removeAttribute(a.name);
22171 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22172 node.removeAttribute(a.name);
22175 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22176 cleanAttr(a.name,a.value); // fixme..
22179 if (a.name == 'style') {
22180 cleanStyle(a.name,a.value);
22183 /// clean up MS crap..
22184 // tecnically this should be a list of valid class'es..
22187 if (a.name == 'class') {
22188 if (a.value.match(/^Mso/)) {
22189 node.className = '';
22192 if (a.value.match(/body/)) {
22193 node.className = '';
22204 this.cleanUpChildren(node);
22210 * Clean up MS wordisms...
22212 cleanWord : function(node)
22217 this.cleanWord(this.doc.body);
22220 if (node.nodeName == "#text") {
22221 // clean up silly Windows -- stuff?
22224 if (node.nodeName == "#comment") {
22225 node.parentNode.removeChild(node);
22226 // clean up silly Windows -- stuff?
22230 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22231 node.parentNode.removeChild(node);
22235 // remove - but keep children..
22236 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22237 while (node.childNodes.length) {
22238 var cn = node.childNodes[0];
22239 node.removeChild(cn);
22240 node.parentNode.insertBefore(cn, node);
22242 node.parentNode.removeChild(node);
22243 this.iterateChildren(node, this.cleanWord);
22247 if (node.className.length) {
22249 var cn = node.className.split(/\W+/);
22251 Roo.each(cn, function(cls) {
22252 if (cls.match(/Mso[a-zA-Z]+/)) {
22257 node.className = cna.length ? cna.join(' ') : '';
22259 node.removeAttribute("class");
22263 if (node.hasAttribute("lang")) {
22264 node.removeAttribute("lang");
22267 if (node.hasAttribute("style")) {
22269 var styles = node.getAttribute("style").split(";");
22271 Roo.each(styles, function(s) {
22272 if (!s.match(/:/)) {
22275 var kv = s.split(":");
22276 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22279 // what ever is left... we allow.
22282 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22283 if (!nstyle.length) {
22284 node.removeAttribute('style');
22287 this.iterateChildren(node, this.cleanWord);
22293 * iterateChildren of a Node, calling fn each time, using this as the scole..
22294 * @param {DomNode} node node to iterate children of.
22295 * @param {Function} fn method of this class to call on each item.
22297 iterateChildren : function(node, fn)
22299 if (!node.childNodes.length) {
22302 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22303 fn.call(this, node.childNodes[i])
22309 * cleanTableWidths.
22311 * Quite often pasting from word etc.. results in tables with column and widths.
22312 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22315 cleanTableWidths : function(node)
22320 this.cleanTableWidths(this.doc.body);
22325 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22328 Roo.log(node.tagName);
22329 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22330 this.iterateChildren(node, this.cleanTableWidths);
22333 if (node.hasAttribute('width')) {
22334 node.removeAttribute('width');
22338 if (node.hasAttribute("style")) {
22341 var styles = node.getAttribute("style").split(";");
22343 Roo.each(styles, function(s) {
22344 if (!s.match(/:/)) {
22347 var kv = s.split(":");
22348 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22351 // what ever is left... we allow.
22354 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22355 if (!nstyle.length) {
22356 node.removeAttribute('style');
22360 this.iterateChildren(node, this.cleanTableWidths);
22368 domToHTML : function(currentElement, depth, nopadtext) {
22370 depth = depth || 0;
22371 nopadtext = nopadtext || false;
22373 if (!currentElement) {
22374 return this.domToHTML(this.doc.body);
22377 //Roo.log(currentElement);
22379 var allText = false;
22380 var nodeName = currentElement.nodeName;
22381 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22383 if (nodeName == '#text') {
22385 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22390 if (nodeName != 'BODY') {
22393 // Prints the node tagName, such as <A>, <IMG>, etc
22396 for(i = 0; i < currentElement.attributes.length;i++) {
22398 var aname = currentElement.attributes.item(i).name;
22399 if (!currentElement.attributes.item(i).value.length) {
22402 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22405 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22414 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22417 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22422 // Traverse the tree
22424 var currentElementChild = currentElement.childNodes.item(i);
22425 var allText = true;
22426 var innerHTML = '';
22428 while (currentElementChild) {
22429 // Formatting code (indent the tree so it looks nice on the screen)
22430 var nopad = nopadtext;
22431 if (lastnode == 'SPAN') {
22435 if (currentElementChild.nodeName == '#text') {
22436 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22437 toadd = nopadtext ? toadd : toadd.trim();
22438 if (!nopad && toadd.length > 80) {
22439 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22441 innerHTML += toadd;
22444 currentElementChild = currentElement.childNodes.item(i);
22450 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22452 // Recursively traverse the tree structure of the child node
22453 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22454 lastnode = currentElementChild.nodeName;
22456 currentElementChild=currentElement.childNodes.item(i);
22462 // The remaining code is mostly for formatting the tree
22463 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22468 ret+= "</"+tagName+">";
22474 applyBlacklists : function()
22476 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22477 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22481 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22482 if (b.indexOf(tag) > -1) {
22485 this.white.push(tag);
22489 Roo.each(w, function(tag) {
22490 if (b.indexOf(tag) > -1) {
22493 if (this.white.indexOf(tag) > -1) {
22496 this.white.push(tag);
22501 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22502 if (w.indexOf(tag) > -1) {
22505 this.black.push(tag);
22509 Roo.each(b, function(tag) {
22510 if (w.indexOf(tag) > -1) {
22513 if (this.black.indexOf(tag) > -1) {
22516 this.black.push(tag);
22521 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22522 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22526 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22527 if (b.indexOf(tag) > -1) {
22530 this.cwhite.push(tag);
22534 Roo.each(w, function(tag) {
22535 if (b.indexOf(tag) > -1) {
22538 if (this.cwhite.indexOf(tag) > -1) {
22541 this.cwhite.push(tag);
22546 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22547 if (w.indexOf(tag) > -1) {
22550 this.cblack.push(tag);
22554 Roo.each(b, function(tag) {
22555 if (w.indexOf(tag) > -1) {
22558 if (this.cblack.indexOf(tag) > -1) {
22561 this.cblack.push(tag);
22566 setStylesheets : function(stylesheets)
22568 if(typeof(stylesheets) == 'string'){
22569 Roo.get(this.iframe.contentDocument.head).createChild({
22571 rel : 'stylesheet',
22580 Roo.each(stylesheets, function(s) {
22585 Roo.get(_this.iframe.contentDocument.head).createChild({
22587 rel : 'stylesheet',
22596 removeStylesheets : function()
22600 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22605 // hide stuff that is not compatible
22619 * @event specialkey
22623 * @cfg {String} fieldClass @hide
22626 * @cfg {String} focusClass @hide
22629 * @cfg {String} autoCreate @hide
22632 * @cfg {String} inputType @hide
22635 * @cfg {String} invalidClass @hide
22638 * @cfg {String} invalidText @hide
22641 * @cfg {String} msgFx @hide
22644 * @cfg {String} validateOnBlur @hide
22648 Roo.HtmlEditorCore.white = [
22649 'area', 'br', 'img', 'input', 'hr', 'wbr',
22651 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22652 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22653 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22654 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22655 'table', 'ul', 'xmp',
22657 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22660 'dir', 'menu', 'ol', 'ul', 'dl',
22666 Roo.HtmlEditorCore.black = [
22667 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22669 'base', 'basefont', 'bgsound', 'blink', 'body',
22670 'frame', 'frameset', 'head', 'html', 'ilayer',
22671 'iframe', 'layer', 'link', 'meta', 'object',
22672 'script', 'style' ,'title', 'xml' // clean later..
22674 Roo.HtmlEditorCore.clean = [
22675 'script', 'style', 'title', 'xml'
22677 Roo.HtmlEditorCore.remove = [
22682 Roo.HtmlEditorCore.ablack = [
22686 Roo.HtmlEditorCore.aclean = [
22687 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22691 Roo.HtmlEditorCore.pwhite= [
22692 'http', 'https', 'mailto'
22695 // white listed style attributes.
22696 Roo.HtmlEditorCore.cwhite= [
22697 // 'text-align', /// default is to allow most things..
22703 // black listed style attributes.
22704 Roo.HtmlEditorCore.cblack= [
22705 // 'font-size' -- this can be set by the project
22709 Roo.HtmlEditorCore.swapCodes =[
22728 * @class Roo.bootstrap.HtmlEditor
22729 * @extends Roo.bootstrap.TextArea
22730 * Bootstrap HtmlEditor class
22733 * Create a new HtmlEditor
22734 * @param {Object} config The config object
22737 Roo.bootstrap.HtmlEditor = function(config){
22738 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22739 if (!this.toolbars) {
22740 this.toolbars = [];
22742 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22745 * @event initialize
22746 * Fires when the editor is fully initialized (including the iframe)
22747 * @param {HtmlEditor} this
22752 * Fires when the editor is first receives the focus. Any insertion must wait
22753 * until after this event.
22754 * @param {HtmlEditor} this
22758 * @event beforesync
22759 * Fires before the textarea is updated with content from the editor iframe. Return false
22760 * to cancel the sync.
22761 * @param {HtmlEditor} this
22762 * @param {String} html
22766 * @event beforepush
22767 * Fires before the iframe editor is updated with content from the textarea. Return false
22768 * to cancel the push.
22769 * @param {HtmlEditor} this
22770 * @param {String} html
22775 * Fires when the textarea is updated with content from the editor iframe.
22776 * @param {HtmlEditor} this
22777 * @param {String} html
22782 * Fires when the iframe editor is updated with content from the textarea.
22783 * @param {HtmlEditor} this
22784 * @param {String} html
22788 * @event editmodechange
22789 * Fires when the editor switches edit modes
22790 * @param {HtmlEditor} this
22791 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22793 editmodechange: true,
22795 * @event editorevent
22796 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22797 * @param {HtmlEditor} this
22801 * @event firstfocus
22802 * Fires when on first focus - needed by toolbars..
22803 * @param {HtmlEditor} this
22808 * Auto save the htmlEditor value as a file into Events
22809 * @param {HtmlEditor} this
22813 * @event savedpreview
22814 * preview the saved version of htmlEditor
22815 * @param {HtmlEditor} this
22822 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22826 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22831 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22836 * @cfg {Number} height (in pixels)
22840 * @cfg {Number} width (in pixels)
22845 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22848 stylesheets: false,
22853 // private properties
22854 validationEvent : false,
22856 initialized : false,
22859 onFocus : Roo.emptyFn,
22861 hideMode:'offsets',
22864 tbContainer : false,
22866 toolbarContainer :function() {
22867 return this.wrap.select('.x-html-editor-tb',true).first();
22871 * Protected method that will not generally be called directly. It
22872 * is called when the editor creates its toolbar. Override this method if you need to
22873 * add custom toolbar buttons.
22874 * @param {HtmlEditor} editor
22876 createToolbar : function(){
22878 Roo.log("create toolbars");
22880 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22881 this.toolbars[0].render(this.toolbarContainer());
22885 // if (!editor.toolbars || !editor.toolbars.length) {
22886 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22889 // for (var i =0 ; i < editor.toolbars.length;i++) {
22890 // editor.toolbars[i] = Roo.factory(
22891 // typeof(editor.toolbars[i]) == 'string' ?
22892 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22893 // Roo.bootstrap.HtmlEditor);
22894 // editor.toolbars[i].init(editor);
22900 onRender : function(ct, position)
22902 // Roo.log("Call onRender: " + this.xtype);
22904 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22906 this.wrap = this.inputEl().wrap({
22907 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22910 this.editorcore.onRender(ct, position);
22912 if (this.resizable) {
22913 this.resizeEl = new Roo.Resizable(this.wrap, {
22917 minHeight : this.height,
22918 height: this.height,
22919 handles : this.resizable,
22922 resize : function(r, w, h) {
22923 _t.onResize(w,h); // -something
22929 this.createToolbar(this);
22932 if(!this.width && this.resizable){
22933 this.setSize(this.wrap.getSize());
22935 if (this.resizeEl) {
22936 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22937 // should trigger onReize..
22943 onResize : function(w, h)
22945 Roo.log('resize: ' +w + ',' + h );
22946 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22950 if(this.inputEl() ){
22951 if(typeof w == 'number'){
22952 var aw = w - this.wrap.getFrameWidth('lr');
22953 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22956 if(typeof h == 'number'){
22957 var tbh = -11; // fixme it needs to tool bar size!
22958 for (var i =0; i < this.toolbars.length;i++) {
22959 // fixme - ask toolbars for heights?
22960 tbh += this.toolbars[i].el.getHeight();
22961 //if (this.toolbars[i].footer) {
22962 // tbh += this.toolbars[i].footer.el.getHeight();
22970 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22971 ah -= 5; // knock a few pixes off for look..
22972 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22976 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22977 this.editorcore.onResize(ew,eh);
22982 * Toggles the editor between standard and source edit mode.
22983 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22985 toggleSourceEdit : function(sourceEditMode)
22987 this.editorcore.toggleSourceEdit(sourceEditMode);
22989 if(this.editorcore.sourceEditMode){
22990 Roo.log('editor - showing textarea');
22993 // Roo.log(this.syncValue());
22995 this.inputEl().removeClass(['hide', 'x-hidden']);
22996 this.inputEl().dom.removeAttribute('tabIndex');
22997 this.inputEl().focus();
22999 Roo.log('editor - hiding textarea');
23001 // Roo.log(this.pushValue());
23004 this.inputEl().addClass(['hide', 'x-hidden']);
23005 this.inputEl().dom.setAttribute('tabIndex', -1);
23006 //this.deferFocus();
23009 if(this.resizable){
23010 this.setSize(this.wrap.getSize());
23013 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23016 // private (for BoxComponent)
23017 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23019 // private (for BoxComponent)
23020 getResizeEl : function(){
23024 // private (for BoxComponent)
23025 getPositionEl : function(){
23030 initEvents : function(){
23031 this.originalValue = this.getValue();
23035 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23038 // markInvalid : Roo.emptyFn,
23040 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23043 // clearInvalid : Roo.emptyFn,
23045 setValue : function(v){
23046 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23047 this.editorcore.pushValue();
23052 deferFocus : function(){
23053 this.focus.defer(10, this);
23057 focus : function(){
23058 this.editorcore.focus();
23064 onDestroy : function(){
23070 for (var i =0; i < this.toolbars.length;i++) {
23071 // fixme - ask toolbars for heights?
23072 this.toolbars[i].onDestroy();
23075 this.wrap.dom.innerHTML = '';
23076 this.wrap.remove();
23081 onFirstFocus : function(){
23082 //Roo.log("onFirstFocus");
23083 this.editorcore.onFirstFocus();
23084 for (var i =0; i < this.toolbars.length;i++) {
23085 this.toolbars[i].onFirstFocus();
23091 syncValue : function()
23093 this.editorcore.syncValue();
23096 pushValue : function()
23098 this.editorcore.pushValue();
23102 // hide stuff that is not compatible
23116 * @event specialkey
23120 * @cfg {String} fieldClass @hide
23123 * @cfg {String} focusClass @hide
23126 * @cfg {String} autoCreate @hide
23129 * @cfg {String} inputType @hide
23132 * @cfg {String} invalidClass @hide
23135 * @cfg {String} invalidText @hide
23138 * @cfg {String} msgFx @hide
23141 * @cfg {String} validateOnBlur @hide
23150 Roo.namespace('Roo.bootstrap.htmleditor');
23152 * @class Roo.bootstrap.HtmlEditorToolbar1
23157 new Roo.bootstrap.HtmlEditor({
23160 new Roo.bootstrap.HtmlEditorToolbar1({
23161 disable : { fonts: 1 , format: 1, ..., ... , ...],
23167 * @cfg {Object} disable List of elements to disable..
23168 * @cfg {Array} btns List of additional buttons.
23172 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23175 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23178 Roo.apply(this, config);
23180 // default disabled, based on 'good practice'..
23181 this.disable = this.disable || {};
23182 Roo.applyIf(this.disable, {
23185 specialElements : true
23187 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23189 this.editor = config.editor;
23190 this.editorcore = config.editor.editorcore;
23192 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23194 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23195 // dont call parent... till later.
23197 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23202 editorcore : false,
23207 "h1","h2","h3","h4","h5","h6",
23209 "abbr", "acronym", "address", "cite", "samp", "var",
23213 onRender : function(ct, position)
23215 // Roo.log("Call onRender: " + this.xtype);
23217 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23219 this.el.dom.style.marginBottom = '0';
23221 var editorcore = this.editorcore;
23222 var editor= this.editor;
23225 var btn = function(id,cmd , toggle, handler){
23227 var event = toggle ? 'toggle' : 'click';
23232 xns: Roo.bootstrap,
23235 enableToggle:toggle !== false,
23237 pressed : toggle ? false : null,
23240 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23241 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23250 xns: Roo.bootstrap,
23251 glyphicon : 'font',
23255 xns: Roo.bootstrap,
23259 Roo.each(this.formats, function(f) {
23260 style.menu.items.push({
23262 xns: Roo.bootstrap,
23263 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23268 editorcore.insertTag(this.tagname);
23275 children.push(style);
23278 btn('bold',false,true);
23279 btn('italic',false,true);
23280 btn('align-left', 'justifyleft',true);
23281 btn('align-center', 'justifycenter',true);
23282 btn('align-right' , 'justifyright',true);
23283 btn('link', false, false, function(btn) {
23284 //Roo.log("create link?");
23285 var url = prompt(this.createLinkText, this.defaultLinkValue);
23286 if(url && url != 'http:/'+'/'){
23287 this.editorcore.relayCmd('createlink', url);
23290 btn('list','insertunorderedlist',true);
23291 btn('pencil', false,true, function(btn){
23294 this.toggleSourceEdit(btn.pressed);
23300 xns: Roo.bootstrap,
23305 xns: Roo.bootstrap,
23310 cog.menu.items.push({
23312 xns: Roo.bootstrap,
23313 html : Clean styles,
23318 editorcore.insertTag(this.tagname);
23327 this.xtype = 'NavSimplebar';
23329 for(var i=0;i< children.length;i++) {
23331 this.buttons.add(this.addxtypeChild(children[i]));
23335 editor.on('editorevent', this.updateToolbar, this);
23337 onBtnClick : function(id)
23339 this.editorcore.relayCmd(id);
23340 this.editorcore.focus();
23344 * Protected method that will not generally be called directly. It triggers
23345 * a toolbar update by reading the markup state of the current selection in the editor.
23347 updateToolbar: function(){
23349 if(!this.editorcore.activated){
23350 this.editor.onFirstFocus(); // is this neeed?
23354 var btns = this.buttons;
23355 var doc = this.editorcore.doc;
23356 btns.get('bold').setActive(doc.queryCommandState('bold'));
23357 btns.get('italic').setActive(doc.queryCommandState('italic'));
23358 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23360 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23361 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23362 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23364 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23365 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23368 var ans = this.editorcore.getAllAncestors();
23369 if (this.formatCombo) {
23372 var store = this.formatCombo.store;
23373 this.formatCombo.setValue("");
23374 for (var i =0; i < ans.length;i++) {
23375 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23377 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23385 // hides menus... - so this cant be on a menu...
23386 Roo.bootstrap.MenuMgr.hideAll();
23388 Roo.bootstrap.MenuMgr.hideAll();
23389 //this.editorsyncValue();
23391 onFirstFocus: function() {
23392 this.buttons.each(function(item){
23396 toggleSourceEdit : function(sourceEditMode){
23399 if(sourceEditMode){
23400 Roo.log("disabling buttons");
23401 this.buttons.each( function(item){
23402 if(item.cmd != 'pencil'){
23408 Roo.log("enabling buttons");
23409 if(this.editorcore.initialized){
23410 this.buttons.each( function(item){
23416 Roo.log("calling toggole on editor");
23417 // tell the editor that it's been pressed..
23418 this.editor.toggleSourceEdit(sourceEditMode);
23428 * @class Roo.bootstrap.Table.AbstractSelectionModel
23429 * @extends Roo.util.Observable
23430 * Abstract base class for grid SelectionModels. It provides the interface that should be
23431 * implemented by descendant classes. This class should not be directly instantiated.
23434 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23435 this.locked = false;
23436 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23440 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23441 /** @ignore Called by the grid automatically. Do not call directly. */
23442 init : function(grid){
23448 * Locks the selections.
23451 this.locked = true;
23455 * Unlocks the selections.
23457 unlock : function(){
23458 this.locked = false;
23462 * Returns true if the selections are locked.
23463 * @return {Boolean}
23465 isLocked : function(){
23466 return this.locked;
23470 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23471 * @class Roo.bootstrap.Table.RowSelectionModel
23472 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23473 * It supports multiple selections and keyboard selection/navigation.
23475 * @param {Object} config
23478 Roo.bootstrap.Table.RowSelectionModel = function(config){
23479 Roo.apply(this, config);
23480 this.selections = new Roo.util.MixedCollection(false, function(o){
23485 this.lastActive = false;
23489 * @event selectionchange
23490 * Fires when the selection changes
23491 * @param {SelectionModel} this
23493 "selectionchange" : true,
23495 * @event afterselectionchange
23496 * Fires after the selection changes (eg. by key press or clicking)
23497 * @param {SelectionModel} this
23499 "afterselectionchange" : true,
23501 * @event beforerowselect
23502 * Fires when a row is selected being selected, return false to cancel.
23503 * @param {SelectionModel} this
23504 * @param {Number} rowIndex The selected index
23505 * @param {Boolean} keepExisting False if other selections will be cleared
23507 "beforerowselect" : true,
23510 * Fires when a row is selected.
23511 * @param {SelectionModel} this
23512 * @param {Number} rowIndex The selected index
23513 * @param {Roo.data.Record} r The record
23515 "rowselect" : true,
23517 * @event rowdeselect
23518 * Fires when a row is deselected.
23519 * @param {SelectionModel} this
23520 * @param {Number} rowIndex The selected index
23522 "rowdeselect" : true
23524 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23525 this.locked = false;
23528 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23530 * @cfg {Boolean} singleSelect
23531 * True to allow selection of only one row at a time (defaults to false)
23533 singleSelect : false,
23536 initEvents : function()
23539 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23540 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23541 //}else{ // allow click to work like normal
23542 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23544 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23545 this.grid.on("rowclick", this.handleMouseDown, this);
23547 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23548 "up" : function(e){
23550 this.selectPrevious(e.shiftKey);
23551 }else if(this.last !== false && this.lastActive !== false){
23552 var last = this.last;
23553 this.selectRange(this.last, this.lastActive-1);
23554 this.grid.getView().focusRow(this.lastActive);
23555 if(last !== false){
23559 this.selectFirstRow();
23561 this.fireEvent("afterselectionchange", this);
23563 "down" : function(e){
23565 this.selectNext(e.shiftKey);
23566 }else if(this.last !== false && this.lastActive !== false){
23567 var last = this.last;
23568 this.selectRange(this.last, this.lastActive+1);
23569 this.grid.getView().focusRow(this.lastActive);
23570 if(last !== false){
23574 this.selectFirstRow();
23576 this.fireEvent("afterselectionchange", this);
23580 this.grid.store.on('load', function(){
23581 this.selections.clear();
23584 var view = this.grid.view;
23585 view.on("refresh", this.onRefresh, this);
23586 view.on("rowupdated", this.onRowUpdated, this);
23587 view.on("rowremoved", this.onRemove, this);
23592 onRefresh : function()
23594 var ds = this.grid.store, i, v = this.grid.view;
23595 var s = this.selections;
23596 s.each(function(r){
23597 if((i = ds.indexOfId(r.id)) != -1){
23606 onRemove : function(v, index, r){
23607 this.selections.remove(r);
23611 onRowUpdated : function(v, index, r){
23612 if(this.isSelected(r)){
23613 v.onRowSelect(index);
23619 * @param {Array} records The records to select
23620 * @param {Boolean} keepExisting (optional) True to keep existing selections
23622 selectRecords : function(records, keepExisting)
23625 this.clearSelections();
23627 var ds = this.grid.store;
23628 for(var i = 0, len = records.length; i < len; i++){
23629 this.selectRow(ds.indexOf(records[i]), true);
23634 * Gets the number of selected rows.
23637 getCount : function(){
23638 return this.selections.length;
23642 * Selects the first row in the grid.
23644 selectFirstRow : function(){
23649 * Select the last row.
23650 * @param {Boolean} keepExisting (optional) True to keep existing selections
23652 selectLastRow : function(keepExisting){
23653 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23654 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23658 * Selects the row immediately following the last selected row.
23659 * @param {Boolean} keepExisting (optional) True to keep existing selections
23661 selectNext : function(keepExisting)
23663 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23664 this.selectRow(this.last+1, keepExisting);
23665 this.grid.getView().focusRow(this.last);
23670 * Selects the row that precedes the last selected row.
23671 * @param {Boolean} keepExisting (optional) True to keep existing selections
23673 selectPrevious : function(keepExisting){
23675 this.selectRow(this.last-1, keepExisting);
23676 this.grid.getView().focusRow(this.last);
23681 * Returns the selected records
23682 * @return {Array} Array of selected records
23684 getSelections : function(){
23685 return [].concat(this.selections.items);
23689 * Returns the first selected record.
23692 getSelected : function(){
23693 return this.selections.itemAt(0);
23698 * Clears all selections.
23700 clearSelections : function(fast)
23706 var ds = this.grid.store;
23707 var s = this.selections;
23708 s.each(function(r){
23709 this.deselectRow(ds.indexOfId(r.id));
23713 this.selections.clear();
23720 * Selects all rows.
23722 selectAll : function(){
23726 this.selections.clear();
23727 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23728 this.selectRow(i, true);
23733 * Returns True if there is a selection.
23734 * @return {Boolean}
23736 hasSelection : function(){
23737 return this.selections.length > 0;
23741 * Returns True if the specified row is selected.
23742 * @param {Number/Record} record The record or index of the record to check
23743 * @return {Boolean}
23745 isSelected : function(index){
23746 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23747 return (r && this.selections.key(r.id) ? true : false);
23751 * Returns True if the specified record id is selected.
23752 * @param {String} id The id of record to check
23753 * @return {Boolean}
23755 isIdSelected : function(id){
23756 return (this.selections.key(id) ? true : false);
23761 handleMouseDBClick : function(e, t){
23765 handleMouseDown : function(e, t)
23767 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23768 if(this.isLocked() || rowIndex < 0 ){
23771 if(e.shiftKey && this.last !== false){
23772 var last = this.last;
23773 this.selectRange(last, rowIndex, e.ctrlKey);
23774 this.last = last; // reset the last
23778 var isSelected = this.isSelected(rowIndex);
23779 //Roo.log("select row:" + rowIndex);
23781 this.deselectRow(rowIndex);
23783 this.selectRow(rowIndex, true);
23787 if(e.button !== 0 && isSelected){
23788 alert('rowIndex 2: ' + rowIndex);
23789 view.focusRow(rowIndex);
23790 }else if(e.ctrlKey && isSelected){
23791 this.deselectRow(rowIndex);
23792 }else if(!isSelected){
23793 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23794 view.focusRow(rowIndex);
23798 this.fireEvent("afterselectionchange", this);
23801 handleDragableRowClick : function(grid, rowIndex, e)
23803 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23804 this.selectRow(rowIndex, false);
23805 grid.view.focusRow(rowIndex);
23806 this.fireEvent("afterselectionchange", this);
23811 * Selects multiple rows.
23812 * @param {Array} rows Array of the indexes of the row to select
23813 * @param {Boolean} keepExisting (optional) True to keep existing selections
23815 selectRows : function(rows, keepExisting){
23817 this.clearSelections();
23819 for(var i = 0, len = rows.length; i < len; i++){
23820 this.selectRow(rows[i], true);
23825 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23826 * @param {Number} startRow The index of the first row in the range
23827 * @param {Number} endRow The index of the last row in the range
23828 * @param {Boolean} keepExisting (optional) True to retain existing selections
23830 selectRange : function(startRow, endRow, keepExisting){
23835 this.clearSelections();
23837 if(startRow <= endRow){
23838 for(var i = startRow; i <= endRow; i++){
23839 this.selectRow(i, true);
23842 for(var i = startRow; i >= endRow; i--){
23843 this.selectRow(i, true);
23849 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23850 * @param {Number} startRow The index of the first row in the range
23851 * @param {Number} endRow The index of the last row in the range
23853 deselectRange : function(startRow, endRow, preventViewNotify){
23857 for(var i = startRow; i <= endRow; i++){
23858 this.deselectRow(i, preventViewNotify);
23864 * @param {Number} row The index of the row to select
23865 * @param {Boolean} keepExisting (optional) True to keep existing selections
23867 selectRow : function(index, keepExisting, preventViewNotify)
23869 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23872 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23873 if(!keepExisting || this.singleSelect){
23874 this.clearSelections();
23877 var r = this.grid.store.getAt(index);
23878 //console.log('selectRow - record id :' + r.id);
23880 this.selections.add(r);
23881 this.last = this.lastActive = index;
23882 if(!preventViewNotify){
23883 var proxy = new Roo.Element(
23884 this.grid.getRowDom(index)
23886 proxy.addClass('bg-info info');
23888 this.fireEvent("rowselect", this, index, r);
23889 this.fireEvent("selectionchange", this);
23895 * @param {Number} row The index of the row to deselect
23897 deselectRow : function(index, preventViewNotify)
23902 if(this.last == index){
23905 if(this.lastActive == index){
23906 this.lastActive = false;
23909 var r = this.grid.store.getAt(index);
23914 this.selections.remove(r);
23915 //.console.log('deselectRow - record id :' + r.id);
23916 if(!preventViewNotify){
23918 var proxy = new Roo.Element(
23919 this.grid.getRowDom(index)
23921 proxy.removeClass('bg-info info');
23923 this.fireEvent("rowdeselect", this, index);
23924 this.fireEvent("selectionchange", this);
23928 restoreLast : function(){
23930 this.last = this._last;
23935 acceptsNav : function(row, col, cm){
23936 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23940 onEditorKey : function(field, e){
23941 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23946 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23948 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23950 }else if(k == e.ENTER && !e.ctrlKey){
23954 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23956 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23958 }else if(k == e.ESC){
23962 g.startEditing(newCell[0], newCell[1]);
23968 * Ext JS Library 1.1.1
23969 * Copyright(c) 2006-2007, Ext JS, LLC.
23971 * Originally Released Under LGPL - original licence link has changed is not relivant.
23974 * <script type="text/javascript">
23978 * @class Roo.bootstrap.PagingToolbar
23979 * @extends Roo.bootstrap.NavSimplebar
23980 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23982 * Create a new PagingToolbar
23983 * @param {Object} config The config object
23984 * @param {Roo.data.Store} store
23986 Roo.bootstrap.PagingToolbar = function(config)
23988 // old args format still supported... - xtype is prefered..
23989 // created from xtype...
23991 this.ds = config.dataSource;
23993 if (config.store && !this.ds) {
23994 this.store= Roo.factory(config.store, Roo.data);
23995 this.ds = this.store;
23996 this.ds.xmodule = this.xmodule || false;
23999 this.toolbarItems = [];
24000 if (config.items) {
24001 this.toolbarItems = config.items;
24004 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24009 this.bind(this.ds);
24012 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24016 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24018 * @cfg {Roo.data.Store} dataSource
24019 * The underlying data store providing the paged data
24022 * @cfg {String/HTMLElement/Element} container
24023 * container The id or element that will contain the toolbar
24026 * @cfg {Boolean} displayInfo
24027 * True to display the displayMsg (defaults to false)
24030 * @cfg {Number} pageSize
24031 * The number of records to display per page (defaults to 20)
24035 * @cfg {String} displayMsg
24036 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24038 displayMsg : 'Displaying {0} - {1} of {2}',
24040 * @cfg {String} emptyMsg
24041 * The message to display when no records are found (defaults to "No data to display")
24043 emptyMsg : 'No data to display',
24045 * Customizable piece of the default paging text (defaults to "Page")
24048 beforePageText : "Page",
24050 * Customizable piece of the default paging text (defaults to "of %0")
24053 afterPageText : "of {0}",
24055 * Customizable piece of the default paging text (defaults to "First Page")
24058 firstText : "First Page",
24060 * Customizable piece of the default paging text (defaults to "Previous Page")
24063 prevText : "Previous Page",
24065 * Customizable piece of the default paging text (defaults to "Next Page")
24068 nextText : "Next Page",
24070 * Customizable piece of the default paging text (defaults to "Last Page")
24073 lastText : "Last Page",
24075 * Customizable piece of the default paging text (defaults to "Refresh")
24078 refreshText : "Refresh",
24082 onRender : function(ct, position)
24084 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24085 this.navgroup.parentId = this.id;
24086 this.navgroup.onRender(this.el, null);
24087 // add the buttons to the navgroup
24089 if(this.displayInfo){
24090 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24091 this.displayEl = this.el.select('.x-paging-info', true).first();
24092 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24093 // this.displayEl = navel.el.select('span',true).first();
24099 Roo.each(_this.buttons, function(e){ // this might need to use render????
24100 Roo.factory(e).onRender(_this.el, null);
24104 Roo.each(_this.toolbarItems, function(e) {
24105 _this.navgroup.addItem(e);
24109 this.first = this.navgroup.addItem({
24110 tooltip: this.firstText,
24112 icon : 'fa fa-backward',
24114 preventDefault: true,
24115 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24118 this.prev = this.navgroup.addItem({
24119 tooltip: this.prevText,
24121 icon : 'fa fa-step-backward',
24123 preventDefault: true,
24124 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24126 //this.addSeparator();
24129 var field = this.navgroup.addItem( {
24131 cls : 'x-paging-position',
24133 html : this.beforePageText +
24134 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24135 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24138 this.field = field.el.select('input', true).first();
24139 this.field.on("keydown", this.onPagingKeydown, this);
24140 this.field.on("focus", function(){this.dom.select();});
24143 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24144 //this.field.setHeight(18);
24145 //this.addSeparator();
24146 this.next = this.navgroup.addItem({
24147 tooltip: this.nextText,
24149 html : ' <i class="fa fa-step-forward">',
24151 preventDefault: true,
24152 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24154 this.last = this.navgroup.addItem({
24155 tooltip: this.lastText,
24156 icon : 'fa fa-forward',
24159 preventDefault: true,
24160 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24162 //this.addSeparator();
24163 this.loading = this.navgroup.addItem({
24164 tooltip: this.refreshText,
24165 icon: 'fa fa-refresh',
24166 preventDefault: true,
24167 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24173 updateInfo : function(){
24174 if(this.displayEl){
24175 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24176 var msg = count == 0 ?
24180 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24182 this.displayEl.update(msg);
24187 onLoad : function(ds, r, o){
24188 this.cursor = o.params ? o.params.start : 0;
24189 var d = this.getPageData(),
24193 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24194 this.field.dom.value = ap;
24195 this.first.setDisabled(ap == 1);
24196 this.prev.setDisabled(ap == 1);
24197 this.next.setDisabled(ap == ps);
24198 this.last.setDisabled(ap == ps);
24199 this.loading.enable();
24204 getPageData : function(){
24205 var total = this.ds.getTotalCount();
24208 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24209 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24214 onLoadError : function(){
24215 this.loading.enable();
24219 onPagingKeydown : function(e){
24220 var k = e.getKey();
24221 var d = this.getPageData();
24223 var v = this.field.dom.value, pageNum;
24224 if(!v || isNaN(pageNum = parseInt(v, 10))){
24225 this.field.dom.value = d.activePage;
24228 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24229 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24232 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))
24234 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24235 this.field.dom.value = pageNum;
24236 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24239 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24241 var v = this.field.dom.value, pageNum;
24242 var increment = (e.shiftKey) ? 10 : 1;
24243 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24246 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24247 this.field.dom.value = d.activePage;
24250 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24252 this.field.dom.value = parseInt(v, 10) + increment;
24253 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24254 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24261 beforeLoad : function(){
24263 this.loading.disable();
24268 onClick : function(which){
24277 ds.load({params:{start: 0, limit: this.pageSize}});
24280 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24283 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24286 var total = ds.getTotalCount();
24287 var extra = total % this.pageSize;
24288 var lastStart = extra ? (total - extra) : total-this.pageSize;
24289 ds.load({params:{start: lastStart, limit: this.pageSize}});
24292 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24298 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24299 * @param {Roo.data.Store} store The data store to unbind
24301 unbind : function(ds){
24302 ds.un("beforeload", this.beforeLoad, this);
24303 ds.un("load", this.onLoad, this);
24304 ds.un("loadexception", this.onLoadError, this);
24305 ds.un("remove", this.updateInfo, this);
24306 ds.un("add", this.updateInfo, this);
24307 this.ds = undefined;
24311 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24312 * @param {Roo.data.Store} store The data store to bind
24314 bind : function(ds){
24315 ds.on("beforeload", this.beforeLoad, this);
24316 ds.on("load", this.onLoad, this);
24317 ds.on("loadexception", this.onLoadError, this);
24318 ds.on("remove", this.updateInfo, this);
24319 ds.on("add", this.updateInfo, this);
24330 * @class Roo.bootstrap.MessageBar
24331 * @extends Roo.bootstrap.Component
24332 * Bootstrap MessageBar class
24333 * @cfg {String} html contents of the MessageBar
24334 * @cfg {String} weight (info | success | warning | danger) default info
24335 * @cfg {String} beforeClass insert the bar before the given class
24336 * @cfg {Boolean} closable (true | false) default false
24337 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24340 * Create a new Element
24341 * @param {Object} config The config object
24344 Roo.bootstrap.MessageBar = function(config){
24345 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24348 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24354 beforeClass: 'bootstrap-sticky-wrap',
24356 getAutoCreate : function(){
24360 cls: 'alert alert-dismissable alert-' + this.weight,
24365 html: this.html || ''
24371 cfg.cls += ' alert-messages-fixed';
24385 onRender : function(ct, position)
24387 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24390 var cfg = Roo.apply({}, this.getAutoCreate());
24394 cfg.cls += ' ' + this.cls;
24397 cfg.style = this.style;
24399 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24401 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24404 this.el.select('>button.close').on('click', this.hide, this);
24410 if (!this.rendered) {
24416 this.fireEvent('show', this);
24422 if (!this.rendered) {
24428 this.fireEvent('hide', this);
24431 update : function()
24433 // var e = this.el.dom.firstChild;
24435 // if(this.closable){
24436 // e = e.nextSibling;
24439 // e.data = this.html || '';
24441 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24457 * @class Roo.bootstrap.Graph
24458 * @extends Roo.bootstrap.Component
24459 * Bootstrap Graph class
24463 @cfg {String} graphtype bar | vbar | pie
24464 @cfg {number} g_x coodinator | centre x (pie)
24465 @cfg {number} g_y coodinator | centre y (pie)
24466 @cfg {number} g_r radius (pie)
24467 @cfg {number} g_height height of the chart (respected by all elements in the set)
24468 @cfg {number} g_width width of the chart (respected by all elements in the set)
24469 @cfg {Object} title The title of the chart
24472 -opts (object) options for the chart
24474 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24475 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24477 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.
24478 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24480 o stretch (boolean)
24482 -opts (object) options for the pie
24485 o startAngle (number)
24486 o endAngle (number)
24490 * Create a new Input
24491 * @param {Object} config The config object
24494 Roo.bootstrap.Graph = function(config){
24495 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24501 * The img click event for the img.
24502 * @param {Roo.EventObject} e
24508 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24519 //g_colors: this.colors,
24526 getAutoCreate : function(){
24537 onRender : function(ct,position){
24540 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24542 if (typeof(Raphael) == 'undefined') {
24543 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24547 this.raphael = Raphael(this.el.dom);
24549 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24550 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24551 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24552 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24554 r.text(160, 10, "Single Series Chart").attr(txtattr);
24555 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24556 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24557 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24559 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24560 r.barchart(330, 10, 300, 220, data1);
24561 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24562 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24565 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24566 // r.barchart(30, 30, 560, 250, xdata, {
24567 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24568 // axis : "0 0 1 1",
24569 // axisxlabels : xdata
24570 // //yvalues : cols,
24573 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24575 // this.load(null,xdata,{
24576 // axis : "0 0 1 1",
24577 // axisxlabels : xdata
24582 load : function(graphtype,xdata,opts)
24584 this.raphael.clear();
24586 graphtype = this.graphtype;
24591 var r = this.raphael,
24592 fin = function () {
24593 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24595 fout = function () {
24596 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24598 pfin = function() {
24599 this.sector.stop();
24600 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24603 this.label[0].stop();
24604 this.label[0].attr({ r: 7.5 });
24605 this.label[1].attr({ "font-weight": 800 });
24608 pfout = function() {
24609 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24612 this.label[0].animate({ r: 5 }, 500, "bounce");
24613 this.label[1].attr({ "font-weight": 400 });
24619 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24622 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24625 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24626 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24628 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24635 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24640 setTitle: function(o)
24645 initEvents: function() {
24648 this.el.on('click', this.onClick, this);
24652 onClick : function(e)
24654 Roo.log('img onclick');
24655 this.fireEvent('click', this, e);
24667 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24670 * @class Roo.bootstrap.dash.NumberBox
24671 * @extends Roo.bootstrap.Component
24672 * Bootstrap NumberBox class
24673 * @cfg {String} headline Box headline
24674 * @cfg {String} content Box content
24675 * @cfg {String} icon Box icon
24676 * @cfg {String} footer Footer text
24677 * @cfg {String} fhref Footer href
24680 * Create a new NumberBox
24681 * @param {Object} config The config object
24685 Roo.bootstrap.dash.NumberBox = function(config){
24686 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24690 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24699 getAutoCreate : function(){
24703 cls : 'small-box ',
24711 cls : 'roo-headline',
24712 html : this.headline
24716 cls : 'roo-content',
24717 html : this.content
24731 cls : 'ion ' + this.icon
24740 cls : 'small-box-footer',
24741 href : this.fhref || '#',
24745 cfg.cn.push(footer);
24752 onRender : function(ct,position){
24753 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24760 setHeadline: function (value)
24762 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24765 setFooter: function (value, href)
24767 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24770 this.el.select('a.small-box-footer',true).first().attr('href', href);
24775 setContent: function (value)
24777 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24780 initEvents: function()
24794 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24797 * @class Roo.bootstrap.dash.TabBox
24798 * @extends Roo.bootstrap.Component
24799 * Bootstrap TabBox class
24800 * @cfg {String} title Title of the TabBox
24801 * @cfg {String} icon Icon of the TabBox
24802 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24803 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24806 * Create a new TabBox
24807 * @param {Object} config The config object
24811 Roo.bootstrap.dash.TabBox = function(config){
24812 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24817 * When a pane is added
24818 * @param {Roo.bootstrap.dash.TabPane} pane
24822 * @event activatepane
24823 * When a pane is activated
24824 * @param {Roo.bootstrap.dash.TabPane} pane
24826 "activatepane" : true
24834 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24839 tabScrollable : false,
24841 getChildContainer : function()
24843 return this.el.select('.tab-content', true).first();
24846 getAutoCreate : function(){
24850 cls: 'pull-left header',
24858 cls: 'fa ' + this.icon
24864 cls: 'nav nav-tabs pull-right',
24870 if(this.tabScrollable){
24877 cls: 'nav nav-tabs pull-right',
24888 cls: 'nav-tabs-custom',
24893 cls: 'tab-content no-padding',
24901 initEvents : function()
24903 //Roo.log('add add pane handler');
24904 this.on('addpane', this.onAddPane, this);
24907 * Updates the box title
24908 * @param {String} html to set the title to.
24910 setTitle : function(value)
24912 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24914 onAddPane : function(pane)
24916 this.panes.push(pane);
24917 //Roo.log('addpane');
24919 // tabs are rendere left to right..
24920 if(!this.showtabs){
24924 var ctr = this.el.select('.nav-tabs', true).first();
24927 var existing = ctr.select('.nav-tab',true);
24928 var qty = existing.getCount();;
24931 var tab = ctr.createChild({
24933 cls : 'nav-tab' + (qty ? '' : ' active'),
24941 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24944 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24946 pane.el.addClass('active');
24951 onTabClick : function(ev,un,ob,pane)
24953 //Roo.log('tab - prev default');
24954 ev.preventDefault();
24957 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24958 pane.tab.addClass('active');
24959 //Roo.log(pane.title);
24960 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24961 // technically we should have a deactivate event.. but maybe add later.
24962 // and it should not de-activate the selected tab...
24963 this.fireEvent('activatepane', pane);
24964 pane.el.addClass('active');
24965 pane.fireEvent('activate');
24970 getActivePane : function()
24973 Roo.each(this.panes, function(p) {
24974 if(p.el.hasClass('active')){
24995 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24997 * @class Roo.bootstrap.TabPane
24998 * @extends Roo.bootstrap.Component
24999 * Bootstrap TabPane class
25000 * @cfg {Boolean} active (false | true) Default false
25001 * @cfg {String} title title of panel
25005 * Create a new TabPane
25006 * @param {Object} config The config object
25009 Roo.bootstrap.dash.TabPane = function(config){
25010 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25016 * When a pane is activated
25017 * @param {Roo.bootstrap.dash.TabPane} pane
25024 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25029 // the tabBox that this is attached to.
25032 getAutoCreate : function()
25040 cfg.cls += ' active';
25045 initEvents : function()
25047 //Roo.log('trigger add pane handler');
25048 this.parent().fireEvent('addpane', this)
25052 * Updates the tab title
25053 * @param {String} html to set the title to.
25055 setTitle: function(str)
25061 this.tab.select('a', true).first().dom.innerHTML = str;
25078 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25081 * @class Roo.bootstrap.menu.Menu
25082 * @extends Roo.bootstrap.Component
25083 * Bootstrap Menu class - container for Menu
25084 * @cfg {String} html Text of the menu
25085 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25086 * @cfg {String} icon Font awesome icon
25087 * @cfg {String} pos Menu align to (top | bottom) default bottom
25091 * Create a new Menu
25092 * @param {Object} config The config object
25096 Roo.bootstrap.menu.Menu = function(config){
25097 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25101 * @event beforeshow
25102 * Fires before this menu is displayed
25103 * @param {Roo.bootstrap.menu.Menu} this
25107 * @event beforehide
25108 * Fires before this menu is hidden
25109 * @param {Roo.bootstrap.menu.Menu} this
25114 * Fires after this menu is displayed
25115 * @param {Roo.bootstrap.menu.Menu} this
25120 * Fires after this menu is hidden
25121 * @param {Roo.bootstrap.menu.Menu} this
25126 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25127 * @param {Roo.bootstrap.menu.Menu} this
25128 * @param {Roo.EventObject} e
25135 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25139 weight : 'default',
25144 getChildContainer : function() {
25145 if(this.isSubMenu){
25149 return this.el.select('ul.dropdown-menu', true).first();
25152 getAutoCreate : function()
25157 cls : 'roo-menu-text',
25165 cls : 'fa ' + this.icon
25176 cls : 'dropdown-button btn btn-' + this.weight,
25181 cls : 'dropdown-toggle btn btn-' + this.weight,
25191 cls : 'dropdown-menu'
25197 if(this.pos == 'top'){
25198 cfg.cls += ' dropup';
25201 if(this.isSubMenu){
25204 cls : 'dropdown-menu'
25211 onRender : function(ct, position)
25213 this.isSubMenu = ct.hasClass('dropdown-submenu');
25215 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25218 initEvents : function()
25220 if(this.isSubMenu){
25224 this.hidden = true;
25226 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25227 this.triggerEl.on('click', this.onTriggerPress, this);
25229 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25230 this.buttonEl.on('click', this.onClick, this);
25236 if(this.isSubMenu){
25240 return this.el.select('ul.dropdown-menu', true).first();
25243 onClick : function(e)
25245 this.fireEvent("click", this, e);
25248 onTriggerPress : function(e)
25250 if (this.isVisible()) {
25257 isVisible : function(){
25258 return !this.hidden;
25263 this.fireEvent("beforeshow", this);
25265 this.hidden = false;
25266 this.el.addClass('open');
25268 Roo.get(document).on("mouseup", this.onMouseUp, this);
25270 this.fireEvent("show", this);
25277 this.fireEvent("beforehide", this);
25279 this.hidden = true;
25280 this.el.removeClass('open');
25282 Roo.get(document).un("mouseup", this.onMouseUp);
25284 this.fireEvent("hide", this);
25287 onMouseUp : function()
25301 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25304 * @class Roo.bootstrap.menu.Item
25305 * @extends Roo.bootstrap.Component
25306 * Bootstrap MenuItem class
25307 * @cfg {Boolean} submenu (true | false) default false
25308 * @cfg {String} html text of the item
25309 * @cfg {String} href the link
25310 * @cfg {Boolean} disable (true | false) default false
25311 * @cfg {Boolean} preventDefault (true | false) default true
25312 * @cfg {String} icon Font awesome icon
25313 * @cfg {String} pos Submenu align to (left | right) default right
25317 * Create a new Item
25318 * @param {Object} config The config object
25322 Roo.bootstrap.menu.Item = function(config){
25323 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25327 * Fires when the mouse is hovering over this menu
25328 * @param {Roo.bootstrap.menu.Item} this
25329 * @param {Roo.EventObject} e
25334 * Fires when the mouse exits this menu
25335 * @param {Roo.bootstrap.menu.Item} this
25336 * @param {Roo.EventObject} e
25342 * The raw click event for the entire grid.
25343 * @param {Roo.EventObject} e
25349 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25354 preventDefault: true,
25359 getAutoCreate : function()
25364 cls : 'roo-menu-item-text',
25372 cls : 'fa ' + this.icon
25381 href : this.href || '#',
25388 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25392 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25394 if(this.pos == 'left'){
25395 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25402 initEvents : function()
25404 this.el.on('mouseover', this.onMouseOver, this);
25405 this.el.on('mouseout', this.onMouseOut, this);
25407 this.el.select('a', true).first().on('click', this.onClick, this);
25411 onClick : function(e)
25413 if(this.preventDefault){
25414 e.preventDefault();
25417 this.fireEvent("click", this, e);
25420 onMouseOver : function(e)
25422 if(this.submenu && this.pos == 'left'){
25423 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25426 this.fireEvent("mouseover", this, e);
25429 onMouseOut : function(e)
25431 this.fireEvent("mouseout", this, e);
25443 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25446 * @class Roo.bootstrap.menu.Separator
25447 * @extends Roo.bootstrap.Component
25448 * Bootstrap Separator class
25451 * Create a new Separator
25452 * @param {Object} config The config object
25456 Roo.bootstrap.menu.Separator = function(config){
25457 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25460 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25462 getAutoCreate : function(){
25483 * @class Roo.bootstrap.Tooltip
25484 * Bootstrap Tooltip class
25485 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25486 * to determine which dom element triggers the tooltip.
25488 * It needs to add support for additional attributes like tooltip-position
25491 * Create a new Toolti
25492 * @param {Object} config The config object
25495 Roo.bootstrap.Tooltip = function(config){
25496 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25498 this.alignment = Roo.bootstrap.Tooltip.alignment;
25500 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25501 this.alignment = config.alignment;
25506 Roo.apply(Roo.bootstrap.Tooltip, {
25508 * @function init initialize tooltip monitoring.
25512 currentTip : false,
25513 currentRegion : false,
25519 Roo.get(document).on('mouseover', this.enter ,this);
25520 Roo.get(document).on('mouseout', this.leave, this);
25523 this.currentTip = new Roo.bootstrap.Tooltip();
25526 enter : function(ev)
25528 var dom = ev.getTarget();
25530 //Roo.log(['enter',dom]);
25531 var el = Roo.fly(dom);
25532 if (this.currentEl) {
25534 //Roo.log(this.currentEl);
25535 //Roo.log(this.currentEl.contains(dom));
25536 if (this.currentEl == el) {
25539 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25545 if (this.currentTip.el) {
25546 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25550 if(!el || el.dom == document){
25556 // you can not look for children, as if el is the body.. then everythign is the child..
25557 if (!el.attr('tooltip')) { //
25558 if (!el.select("[tooltip]").elements.length) {
25561 // is the mouse over this child...?
25562 bindEl = el.select("[tooltip]").first();
25563 var xy = ev.getXY();
25564 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25565 //Roo.log("not in region.");
25568 //Roo.log("child element over..");
25571 this.currentEl = bindEl;
25572 this.currentTip.bind(bindEl);
25573 this.currentRegion = Roo.lib.Region.getRegion(dom);
25574 this.currentTip.enter();
25577 leave : function(ev)
25579 var dom = ev.getTarget();
25580 //Roo.log(['leave',dom]);
25581 if (!this.currentEl) {
25586 if (dom != this.currentEl.dom) {
25589 var xy = ev.getXY();
25590 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25593 // only activate leave if mouse cursor is outside... bounding box..
25598 if (this.currentTip) {
25599 this.currentTip.leave();
25601 //Roo.log('clear currentEl');
25602 this.currentEl = false;
25607 'left' : ['r-l', [-2,0], 'right'],
25608 'right' : ['l-r', [2,0], 'left'],
25609 'bottom' : ['t-b', [0,2], 'top'],
25610 'top' : [ 'b-t', [0,-2], 'bottom']
25616 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25621 delay : null, // can be { show : 300 , hide: 500}
25625 hoverState : null, //???
25627 placement : 'bottom',
25631 getAutoCreate : function(){
25638 cls : 'tooltip-arrow'
25641 cls : 'tooltip-inner'
25648 bind : function(el)
25654 enter : function () {
25656 if (this.timeout != null) {
25657 clearTimeout(this.timeout);
25660 this.hoverState = 'in';
25661 //Roo.log("enter - show");
25662 if (!this.delay || !this.delay.show) {
25667 this.timeout = setTimeout(function () {
25668 if (_t.hoverState == 'in') {
25671 }, this.delay.show);
25675 clearTimeout(this.timeout);
25677 this.hoverState = 'out';
25678 if (!this.delay || !this.delay.hide) {
25684 this.timeout = setTimeout(function () {
25685 //Roo.log("leave - timeout");
25687 if (_t.hoverState == 'out') {
25689 Roo.bootstrap.Tooltip.currentEl = false;
25694 show : function (msg)
25697 this.render(document.body);
25700 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25702 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25704 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25706 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25708 var placement = typeof this.placement == 'function' ?
25709 this.placement.call(this, this.el, on_el) :
25712 var autoToken = /\s?auto?\s?/i;
25713 var autoPlace = autoToken.test(placement);
25715 placement = placement.replace(autoToken, '') || 'top';
25719 //this.el.setXY([0,0]);
25721 //this.el.dom.style.display='block';
25723 //this.el.appendTo(on_el);
25725 var p = this.getPosition();
25726 var box = this.el.getBox();
25732 var align = this.alignment[placement];
25734 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25736 if(placement == 'top' || placement == 'bottom'){
25738 placement = 'right';
25741 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25742 placement = 'left';
25745 var scroll = Roo.select('body', true).first().getScroll();
25747 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25753 this.el.alignTo(this.bindEl, align[0],align[1]);
25754 //var arrow = this.el.select('.arrow',true).first();
25755 //arrow.set(align[2],
25757 this.el.addClass(placement);
25759 this.el.addClass('in fade');
25761 this.hoverState = null;
25763 if (this.el.hasClass('fade')) {
25774 //this.el.setXY([0,0]);
25775 this.el.removeClass('in');
25791 * @class Roo.bootstrap.LocationPicker
25792 * @extends Roo.bootstrap.Component
25793 * Bootstrap LocationPicker class
25794 * @cfg {Number} latitude Position when init default 0
25795 * @cfg {Number} longitude Position when init default 0
25796 * @cfg {Number} zoom default 15
25797 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25798 * @cfg {Boolean} mapTypeControl default false
25799 * @cfg {Boolean} disableDoubleClickZoom default false
25800 * @cfg {Boolean} scrollwheel default true
25801 * @cfg {Boolean} streetViewControl default false
25802 * @cfg {Number} radius default 0
25803 * @cfg {String} locationName
25804 * @cfg {Boolean} draggable default true
25805 * @cfg {Boolean} enableAutocomplete default false
25806 * @cfg {Boolean} enableReverseGeocode default true
25807 * @cfg {String} markerTitle
25810 * Create a new LocationPicker
25811 * @param {Object} config The config object
25815 Roo.bootstrap.LocationPicker = function(config){
25817 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25822 * Fires when the picker initialized.
25823 * @param {Roo.bootstrap.LocationPicker} this
25824 * @param {Google Location} location
25828 * @event positionchanged
25829 * Fires when the picker position changed.
25830 * @param {Roo.bootstrap.LocationPicker} this
25831 * @param {Google Location} location
25833 positionchanged : true,
25836 * Fires when the map resize.
25837 * @param {Roo.bootstrap.LocationPicker} this
25842 * Fires when the map show.
25843 * @param {Roo.bootstrap.LocationPicker} this
25848 * Fires when the map hide.
25849 * @param {Roo.bootstrap.LocationPicker} this
25854 * Fires when click the map.
25855 * @param {Roo.bootstrap.LocationPicker} this
25856 * @param {Map event} e
25860 * @event mapRightClick
25861 * Fires when right click the map.
25862 * @param {Roo.bootstrap.LocationPicker} this
25863 * @param {Map event} e
25865 mapRightClick : true,
25867 * @event markerClick
25868 * Fires when click the marker.
25869 * @param {Roo.bootstrap.LocationPicker} this
25870 * @param {Map event} e
25872 markerClick : true,
25874 * @event markerRightClick
25875 * Fires when right click the marker.
25876 * @param {Roo.bootstrap.LocationPicker} this
25877 * @param {Map event} e
25879 markerRightClick : true,
25881 * @event OverlayViewDraw
25882 * Fires when OverlayView Draw
25883 * @param {Roo.bootstrap.LocationPicker} this
25885 OverlayViewDraw : true,
25887 * @event OverlayViewOnAdd
25888 * Fires when OverlayView Draw
25889 * @param {Roo.bootstrap.LocationPicker} this
25891 OverlayViewOnAdd : true,
25893 * @event OverlayViewOnRemove
25894 * Fires when OverlayView Draw
25895 * @param {Roo.bootstrap.LocationPicker} this
25897 OverlayViewOnRemove : true,
25899 * @event OverlayViewShow
25900 * Fires when OverlayView Draw
25901 * @param {Roo.bootstrap.LocationPicker} this
25902 * @param {Pixel} cpx
25904 OverlayViewShow : true,
25906 * @event OverlayViewHide
25907 * Fires when OverlayView Draw
25908 * @param {Roo.bootstrap.LocationPicker} this
25910 OverlayViewHide : true,
25912 * @event loadexception
25913 * Fires when load google lib failed.
25914 * @param {Roo.bootstrap.LocationPicker} this
25916 loadexception : true
25921 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25923 gMapContext: false,
25929 mapTypeControl: false,
25930 disableDoubleClickZoom: false,
25932 streetViewControl: false,
25936 enableAutocomplete: false,
25937 enableReverseGeocode: true,
25940 getAutoCreate: function()
25945 cls: 'roo-location-picker'
25951 initEvents: function(ct, position)
25953 if(!this.el.getWidth() || this.isApplied()){
25957 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25962 initial: function()
25964 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25965 this.fireEvent('loadexception', this);
25969 if(!this.mapTypeId){
25970 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25973 this.gMapContext = this.GMapContext();
25975 this.initOverlayView();
25977 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25981 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25982 _this.setPosition(_this.gMapContext.marker.position);
25985 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25986 _this.fireEvent('mapClick', this, event);
25990 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25991 _this.fireEvent('mapRightClick', this, event);
25995 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25996 _this.fireEvent('markerClick', this, event);
26000 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26001 _this.fireEvent('markerRightClick', this, event);
26005 this.setPosition(this.gMapContext.location);
26007 this.fireEvent('initial', this, this.gMapContext.location);
26010 initOverlayView: function()
26014 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26018 _this.fireEvent('OverlayViewDraw', _this);
26023 _this.fireEvent('OverlayViewOnAdd', _this);
26026 onRemove: function()
26028 _this.fireEvent('OverlayViewOnRemove', _this);
26031 show: function(cpx)
26033 _this.fireEvent('OverlayViewShow', _this, cpx);
26038 _this.fireEvent('OverlayViewHide', _this);
26044 fromLatLngToContainerPixel: function(event)
26046 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26049 isApplied: function()
26051 return this.getGmapContext() == false ? false : true;
26054 getGmapContext: function()
26056 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26059 GMapContext: function()
26061 var position = new google.maps.LatLng(this.latitude, this.longitude);
26063 var _map = new google.maps.Map(this.el.dom, {
26066 mapTypeId: this.mapTypeId,
26067 mapTypeControl: this.mapTypeControl,
26068 disableDoubleClickZoom: this.disableDoubleClickZoom,
26069 scrollwheel: this.scrollwheel,
26070 streetViewControl: this.streetViewControl,
26071 locationName: this.locationName,
26072 draggable: this.draggable,
26073 enableAutocomplete: this.enableAutocomplete,
26074 enableReverseGeocode: this.enableReverseGeocode
26077 var _marker = new google.maps.Marker({
26078 position: position,
26080 title: this.markerTitle,
26081 draggable: this.draggable
26088 location: position,
26089 radius: this.radius,
26090 locationName: this.locationName,
26091 addressComponents: {
26092 formatted_address: null,
26093 addressLine1: null,
26094 addressLine2: null,
26096 streetNumber: null,
26100 stateOrProvince: null
26103 domContainer: this.el.dom,
26104 geodecoder: new google.maps.Geocoder()
26108 drawCircle: function(center, radius, options)
26110 if (this.gMapContext.circle != null) {
26111 this.gMapContext.circle.setMap(null);
26115 options = Roo.apply({}, options, {
26116 strokeColor: "#0000FF",
26117 strokeOpacity: .35,
26119 fillColor: "#0000FF",
26123 options.map = this.gMapContext.map;
26124 options.radius = radius;
26125 options.center = center;
26126 this.gMapContext.circle = new google.maps.Circle(options);
26127 return this.gMapContext.circle;
26133 setPosition: function(location)
26135 this.gMapContext.location = location;
26136 this.gMapContext.marker.setPosition(location);
26137 this.gMapContext.map.panTo(location);
26138 this.drawCircle(location, this.gMapContext.radius, {});
26142 if (this.gMapContext.settings.enableReverseGeocode) {
26143 this.gMapContext.geodecoder.geocode({
26144 latLng: this.gMapContext.location
26145 }, function(results, status) {
26147 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26148 _this.gMapContext.locationName = results[0].formatted_address;
26149 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26151 _this.fireEvent('positionchanged', this, location);
26158 this.fireEvent('positionchanged', this, location);
26163 google.maps.event.trigger(this.gMapContext.map, "resize");
26165 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26167 this.fireEvent('resize', this);
26170 setPositionByLatLng: function(latitude, longitude)
26172 this.setPosition(new google.maps.LatLng(latitude, longitude));
26175 getCurrentPosition: function()
26178 latitude: this.gMapContext.location.lat(),
26179 longitude: this.gMapContext.location.lng()
26183 getAddressName: function()
26185 return this.gMapContext.locationName;
26188 getAddressComponents: function()
26190 return this.gMapContext.addressComponents;
26193 address_component_from_google_geocode: function(address_components)
26197 for (var i = 0; i < address_components.length; i++) {
26198 var component = address_components[i];
26199 if (component.types.indexOf("postal_code") >= 0) {
26200 result.postalCode = component.short_name;
26201 } else if (component.types.indexOf("street_number") >= 0) {
26202 result.streetNumber = component.short_name;
26203 } else if (component.types.indexOf("route") >= 0) {
26204 result.streetName = component.short_name;
26205 } else if (component.types.indexOf("neighborhood") >= 0) {
26206 result.city = component.short_name;
26207 } else if (component.types.indexOf("locality") >= 0) {
26208 result.city = component.short_name;
26209 } else if (component.types.indexOf("sublocality") >= 0) {
26210 result.district = component.short_name;
26211 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26212 result.stateOrProvince = component.short_name;
26213 } else if (component.types.indexOf("country") >= 0) {
26214 result.country = component.short_name;
26218 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26219 result.addressLine2 = "";
26223 setZoomLevel: function(zoom)
26225 this.gMapContext.map.setZoom(zoom);
26238 this.fireEvent('show', this);
26249 this.fireEvent('hide', this);
26254 Roo.apply(Roo.bootstrap.LocationPicker, {
26256 OverlayView : function(map, options)
26258 options = options || {};
26272 * @class Roo.bootstrap.Alert
26273 * @extends Roo.bootstrap.Component
26274 * Bootstrap Alert class
26275 * @cfg {String} title The title of alert
26276 * @cfg {String} html The content of alert
26277 * @cfg {String} weight ( success | info | warning | danger )
26278 * @cfg {String} faicon font-awesomeicon
26281 * Create a new alert
26282 * @param {Object} config The config object
26286 Roo.bootstrap.Alert = function(config){
26287 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26291 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26298 getAutoCreate : function()
26307 cls : 'roo-alert-icon'
26312 cls : 'roo-alert-title',
26317 cls : 'roo-alert-text',
26324 cfg.cn[0].cls += ' fa ' + this.faicon;
26328 cfg.cls += ' alert-' + this.weight;
26334 initEvents: function()
26336 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26339 setTitle : function(str)
26341 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26344 setText : function(str)
26346 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26349 setWeight : function(weight)
26352 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26355 this.weight = weight;
26357 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26360 setIcon : function(icon)
26363 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26366 this.faicon = icon;
26368 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26389 * @class Roo.bootstrap.UploadCropbox
26390 * @extends Roo.bootstrap.Component
26391 * Bootstrap UploadCropbox class
26392 * @cfg {String} emptyText show when image has been loaded
26393 * @cfg {String} rotateNotify show when image too small to rotate
26394 * @cfg {Number} errorTimeout default 3000
26395 * @cfg {Number} minWidth default 300
26396 * @cfg {Number} minHeight default 300
26397 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26398 * @cfg {Boolean} isDocument (true|false) default false
26399 * @cfg {String} url action url
26400 * @cfg {String} paramName default 'imageUpload'
26401 * @cfg {String} method default POST
26402 * @cfg {Boolean} loadMask (true|false) default true
26403 * @cfg {Boolean} loadingText default 'Loading...'
26406 * Create a new UploadCropbox
26407 * @param {Object} config The config object
26410 Roo.bootstrap.UploadCropbox = function(config){
26411 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26415 * @event beforeselectfile
26416 * Fire before select file
26417 * @param {Roo.bootstrap.UploadCropbox} this
26419 "beforeselectfile" : true,
26422 * Fire after initEvent
26423 * @param {Roo.bootstrap.UploadCropbox} this
26428 * Fire after initEvent
26429 * @param {Roo.bootstrap.UploadCropbox} this
26430 * @param {String} data
26435 * Fire when preparing the file data
26436 * @param {Roo.bootstrap.UploadCropbox} this
26437 * @param {Object} file
26442 * Fire when get exception
26443 * @param {Roo.bootstrap.UploadCropbox} this
26444 * @param {XMLHttpRequest} xhr
26446 "exception" : true,
26448 * @event beforeloadcanvas
26449 * Fire before load the canvas
26450 * @param {Roo.bootstrap.UploadCropbox} this
26451 * @param {String} src
26453 "beforeloadcanvas" : true,
26456 * Fire when trash image
26457 * @param {Roo.bootstrap.UploadCropbox} this
26462 * Fire when download the image
26463 * @param {Roo.bootstrap.UploadCropbox} this
26467 * @event footerbuttonclick
26468 * Fire when footerbuttonclick
26469 * @param {Roo.bootstrap.UploadCropbox} this
26470 * @param {String} type
26472 "footerbuttonclick" : true,
26476 * @param {Roo.bootstrap.UploadCropbox} this
26481 * Fire when rotate the image
26482 * @param {Roo.bootstrap.UploadCropbox} this
26483 * @param {String} pos
26488 * Fire when inspect the file
26489 * @param {Roo.bootstrap.UploadCropbox} this
26490 * @param {Object} file
26495 * Fire when xhr upload the file
26496 * @param {Roo.bootstrap.UploadCropbox} this
26497 * @param {Object} data
26502 * Fire when arrange the file data
26503 * @param {Roo.bootstrap.UploadCropbox} this
26504 * @param {Object} formData
26509 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26512 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26514 emptyText : 'Click to upload image',
26515 rotateNotify : 'Image is too small to rotate',
26516 errorTimeout : 3000,
26530 cropType : 'image/jpeg',
26532 canvasLoaded : false,
26533 isDocument : false,
26535 paramName : 'imageUpload',
26537 loadingText : 'Loading...',
26540 getAutoCreate : function()
26544 cls : 'roo-upload-cropbox',
26548 cls : 'roo-upload-cropbox-selector',
26553 cls : 'roo-upload-cropbox-body',
26554 style : 'cursor:pointer',
26558 cls : 'roo-upload-cropbox-preview'
26562 cls : 'roo-upload-cropbox-thumb'
26566 cls : 'roo-upload-cropbox-empty-notify',
26567 html : this.emptyText
26571 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26572 html : this.rotateNotify
26578 cls : 'roo-upload-cropbox-footer',
26581 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26591 onRender : function(ct, position)
26593 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26595 if (this.buttons.length) {
26597 Roo.each(this.buttons, function(bb) {
26599 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26601 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26607 this.maskEl = this.el;
26611 initEvents : function()
26613 this.urlAPI = (window.createObjectURL && window) ||
26614 (window.URL && URL.revokeObjectURL && URL) ||
26615 (window.webkitURL && webkitURL);
26617 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26618 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26620 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26621 this.selectorEl.hide();
26623 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26624 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26626 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26627 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26628 this.thumbEl.hide();
26630 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26631 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26633 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26634 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26635 this.errorEl.hide();
26637 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26638 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26639 this.footerEl.hide();
26641 this.setThumbBoxSize();
26647 this.fireEvent('initial', this);
26654 window.addEventListener("resize", function() { _this.resize(); } );
26656 this.bodyEl.on('click', this.beforeSelectFile, this);
26659 this.bodyEl.on('touchstart', this.onTouchStart, this);
26660 this.bodyEl.on('touchmove', this.onTouchMove, this);
26661 this.bodyEl.on('touchend', this.onTouchEnd, this);
26665 this.bodyEl.on('mousedown', this.onMouseDown, this);
26666 this.bodyEl.on('mousemove', this.onMouseMove, this);
26667 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26668 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26669 Roo.get(document).on('mouseup', this.onMouseUp, this);
26672 this.selectorEl.on('change', this.onFileSelected, this);
26678 this.baseScale = 1;
26680 this.baseRotate = 1;
26681 this.dragable = false;
26682 this.pinching = false;
26685 this.cropData = false;
26686 this.notifyEl.dom.innerHTML = this.emptyText;
26688 this.selectorEl.dom.value = '';
26692 resize : function()
26694 if(this.fireEvent('resize', this) != false){
26695 this.setThumbBoxPosition();
26696 this.setCanvasPosition();
26700 onFooterButtonClick : function(e, el, o, type)
26703 case 'rotate-left' :
26704 this.onRotateLeft(e);
26706 case 'rotate-right' :
26707 this.onRotateRight(e);
26710 this.beforeSelectFile(e);
26725 this.fireEvent('footerbuttonclick', this, type);
26728 beforeSelectFile : function(e)
26730 e.preventDefault();
26732 if(this.fireEvent('beforeselectfile', this) != false){
26733 this.selectorEl.dom.click();
26737 onFileSelected : function(e)
26739 e.preventDefault();
26741 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26745 var file = this.selectorEl.dom.files[0];
26747 if(this.fireEvent('inspect', this, file) != false){
26748 this.prepare(file);
26753 trash : function(e)
26755 this.fireEvent('trash', this);
26758 download : function(e)
26760 this.fireEvent('download', this);
26763 loadCanvas : function(src)
26765 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26769 this.imageEl = document.createElement('img');
26773 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26775 this.imageEl.src = src;
26779 onLoadCanvas : function()
26781 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26782 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26784 this.bodyEl.un('click', this.beforeSelectFile, this);
26786 this.notifyEl.hide();
26787 this.thumbEl.show();
26788 this.footerEl.show();
26790 this.baseRotateLevel();
26792 if(this.isDocument){
26793 this.setThumbBoxSize();
26796 this.setThumbBoxPosition();
26798 this.baseScaleLevel();
26804 this.canvasLoaded = true;
26807 this.maskEl.unmask();
26812 setCanvasPosition : function()
26814 if(!this.canvasEl){
26818 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26819 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26821 this.previewEl.setLeft(pw);
26822 this.previewEl.setTop(ph);
26826 onMouseDown : function(e)
26830 this.dragable = true;
26831 this.pinching = false;
26833 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26834 this.dragable = false;
26838 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26839 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26843 onMouseMove : function(e)
26847 if(!this.canvasLoaded){
26851 if (!this.dragable){
26855 var minX = Math.ceil(this.thumbEl.getLeft(true));
26856 var minY = Math.ceil(this.thumbEl.getTop(true));
26858 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26859 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26861 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26862 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26864 x = x - this.mouseX;
26865 y = y - this.mouseY;
26867 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26868 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26870 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26871 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26873 this.previewEl.setLeft(bgX);
26874 this.previewEl.setTop(bgY);
26876 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26877 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26880 onMouseUp : function(e)
26884 this.dragable = false;
26887 onMouseWheel : function(e)
26891 this.startScale = this.scale;
26893 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26895 if(!this.zoomable()){
26896 this.scale = this.startScale;
26905 zoomable : function()
26907 var minScale = this.thumbEl.getWidth() / this.minWidth;
26909 if(this.minWidth < this.minHeight){
26910 minScale = this.thumbEl.getHeight() / this.minHeight;
26913 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26914 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26918 (this.rotate == 0 || this.rotate == 180) &&
26920 width > this.imageEl.OriginWidth ||
26921 height > this.imageEl.OriginHeight ||
26922 (width < this.minWidth && height < this.minHeight)
26930 (this.rotate == 90 || this.rotate == 270) &&
26932 width > this.imageEl.OriginWidth ||
26933 height > this.imageEl.OriginHeight ||
26934 (width < this.minHeight && height < this.minWidth)
26941 !this.isDocument &&
26942 (this.rotate == 0 || this.rotate == 180) &&
26944 width < this.minWidth ||
26945 width > this.imageEl.OriginWidth ||
26946 height < this.minHeight ||
26947 height > this.imageEl.OriginHeight
26954 !this.isDocument &&
26955 (this.rotate == 90 || this.rotate == 270) &&
26957 width < this.minHeight ||
26958 width > this.imageEl.OriginWidth ||
26959 height < this.minWidth ||
26960 height > this.imageEl.OriginHeight
26970 onRotateLeft : function(e)
26972 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26974 var minScale = this.thumbEl.getWidth() / this.minWidth;
26976 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26977 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26979 this.startScale = this.scale;
26981 while (this.getScaleLevel() < minScale){
26983 this.scale = this.scale + 1;
26985 if(!this.zoomable()){
26990 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26991 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26996 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27003 this.scale = this.startScale;
27005 this.onRotateFail();
27010 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27012 if(this.isDocument){
27013 this.setThumbBoxSize();
27014 this.setThumbBoxPosition();
27015 this.setCanvasPosition();
27020 this.fireEvent('rotate', this, 'left');
27024 onRotateRight : function(e)
27026 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27028 var minScale = this.thumbEl.getWidth() / this.minWidth;
27030 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27031 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27033 this.startScale = this.scale;
27035 while (this.getScaleLevel() < minScale){
27037 this.scale = this.scale + 1;
27039 if(!this.zoomable()){
27044 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27045 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27050 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27057 this.scale = this.startScale;
27059 this.onRotateFail();
27064 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27066 if(this.isDocument){
27067 this.setThumbBoxSize();
27068 this.setThumbBoxPosition();
27069 this.setCanvasPosition();
27074 this.fireEvent('rotate', this, 'right');
27077 onRotateFail : function()
27079 this.errorEl.show(true);
27083 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27088 this.previewEl.dom.innerHTML = '';
27090 var canvasEl = document.createElement("canvas");
27092 var contextEl = canvasEl.getContext("2d");
27094 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27095 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27096 var center = this.imageEl.OriginWidth / 2;
27098 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27099 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27100 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27101 center = this.imageEl.OriginHeight / 2;
27104 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27106 contextEl.translate(center, center);
27107 contextEl.rotate(this.rotate * Math.PI / 180);
27109 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27111 this.canvasEl = document.createElement("canvas");
27113 this.contextEl = this.canvasEl.getContext("2d");
27115 switch (this.rotate) {
27118 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27119 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27121 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27126 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27127 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27129 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27130 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);
27134 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27139 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27140 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27142 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27143 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);
27147 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);
27152 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27153 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27155 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27156 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27160 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);
27167 this.previewEl.appendChild(this.canvasEl);
27169 this.setCanvasPosition();
27174 if(!this.canvasLoaded){
27178 var imageCanvas = document.createElement("canvas");
27180 var imageContext = imageCanvas.getContext("2d");
27182 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27183 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27185 var center = imageCanvas.width / 2;
27187 imageContext.translate(center, center);
27189 imageContext.rotate(this.rotate * Math.PI / 180);
27191 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27193 var canvas = document.createElement("canvas");
27195 var context = canvas.getContext("2d");
27197 canvas.width = this.minWidth;
27198 canvas.height = this.minHeight;
27200 switch (this.rotate) {
27203 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27204 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27206 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27207 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27209 var targetWidth = this.minWidth - 2 * x;
27210 var targetHeight = this.minHeight - 2 * y;
27214 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27215 scale = targetWidth / width;
27218 if(x > 0 && y == 0){
27219 scale = targetHeight / height;
27222 if(x > 0 && y > 0){
27223 scale = targetWidth / width;
27225 if(width < height){
27226 scale = targetHeight / height;
27230 context.scale(scale, scale);
27232 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27233 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27235 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27236 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27238 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27243 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27244 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27246 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27247 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27249 var targetWidth = this.minWidth - 2 * x;
27250 var targetHeight = this.minHeight - 2 * y;
27254 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27255 scale = targetWidth / width;
27258 if(x > 0 && y == 0){
27259 scale = targetHeight / height;
27262 if(x > 0 && y > 0){
27263 scale = targetWidth / width;
27265 if(width < height){
27266 scale = targetHeight / height;
27270 context.scale(scale, scale);
27272 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27273 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27275 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27276 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27278 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27280 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27285 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27286 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27288 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27289 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27291 var targetWidth = this.minWidth - 2 * x;
27292 var targetHeight = this.minHeight - 2 * y;
27296 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27297 scale = targetWidth / width;
27300 if(x > 0 && y == 0){
27301 scale = targetHeight / height;
27304 if(x > 0 && y > 0){
27305 scale = targetWidth / width;
27307 if(width < height){
27308 scale = targetHeight / height;
27312 context.scale(scale, scale);
27314 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27315 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27317 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27318 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27320 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27321 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27323 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27328 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27329 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27331 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27332 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27334 var targetWidth = this.minWidth - 2 * x;
27335 var targetHeight = this.minHeight - 2 * y;
27339 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27340 scale = targetWidth / width;
27343 if(x > 0 && y == 0){
27344 scale = targetHeight / height;
27347 if(x > 0 && y > 0){
27348 scale = targetWidth / width;
27350 if(width < height){
27351 scale = targetHeight / height;
27355 context.scale(scale, scale);
27357 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27358 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27360 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27361 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27363 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27365 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27372 this.cropData = canvas.toDataURL(this.cropType);
27374 if(this.fireEvent('crop', this, this.cropData) !== false){
27375 this.process(this.file, this.cropData);
27382 setThumbBoxSize : function()
27386 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27387 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27388 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27390 this.minWidth = width;
27391 this.minHeight = height;
27393 if(this.rotate == 90 || this.rotate == 270){
27394 this.minWidth = height;
27395 this.minHeight = width;
27400 width = Math.ceil(this.minWidth * height / this.minHeight);
27402 if(this.minWidth > this.minHeight){
27404 height = Math.ceil(this.minHeight * width / this.minWidth);
27407 this.thumbEl.setStyle({
27408 width : width + 'px',
27409 height : height + 'px'
27416 setThumbBoxPosition : function()
27418 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27419 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27421 this.thumbEl.setLeft(x);
27422 this.thumbEl.setTop(y);
27426 baseRotateLevel : function()
27428 this.baseRotate = 1;
27431 typeof(this.exif) != 'undefined' &&
27432 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27433 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27435 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27438 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27442 baseScaleLevel : function()
27446 if(this.isDocument){
27448 if(this.baseRotate == 6 || this.baseRotate == 8){
27450 height = this.thumbEl.getHeight();
27451 this.baseScale = height / this.imageEl.OriginWidth;
27453 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27454 width = this.thumbEl.getWidth();
27455 this.baseScale = width / this.imageEl.OriginHeight;
27461 height = this.thumbEl.getHeight();
27462 this.baseScale = height / this.imageEl.OriginHeight;
27464 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27465 width = this.thumbEl.getWidth();
27466 this.baseScale = width / this.imageEl.OriginWidth;
27472 if(this.baseRotate == 6 || this.baseRotate == 8){
27474 width = this.thumbEl.getHeight();
27475 this.baseScale = width / this.imageEl.OriginHeight;
27477 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27478 height = this.thumbEl.getWidth();
27479 this.baseScale = height / this.imageEl.OriginHeight;
27482 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27483 height = this.thumbEl.getWidth();
27484 this.baseScale = height / this.imageEl.OriginHeight;
27486 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27487 width = this.thumbEl.getHeight();
27488 this.baseScale = width / this.imageEl.OriginWidth;
27495 width = this.thumbEl.getWidth();
27496 this.baseScale = width / this.imageEl.OriginWidth;
27498 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27499 height = this.thumbEl.getHeight();
27500 this.baseScale = height / this.imageEl.OriginHeight;
27503 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27505 height = this.thumbEl.getHeight();
27506 this.baseScale = height / this.imageEl.OriginHeight;
27508 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27509 width = this.thumbEl.getWidth();
27510 this.baseScale = width / this.imageEl.OriginWidth;
27518 getScaleLevel : function()
27520 return this.baseScale * Math.pow(1.1, this.scale);
27523 onTouchStart : function(e)
27525 if(!this.canvasLoaded){
27526 this.beforeSelectFile(e);
27530 var touches = e.browserEvent.touches;
27536 if(touches.length == 1){
27537 this.onMouseDown(e);
27541 if(touches.length != 2){
27547 for(var i = 0, finger; finger = touches[i]; i++){
27548 coords.push(finger.pageX, finger.pageY);
27551 var x = Math.pow(coords[0] - coords[2], 2);
27552 var y = Math.pow(coords[1] - coords[3], 2);
27554 this.startDistance = Math.sqrt(x + y);
27556 this.startScale = this.scale;
27558 this.pinching = true;
27559 this.dragable = false;
27563 onTouchMove : function(e)
27565 if(!this.pinching && !this.dragable){
27569 var touches = e.browserEvent.touches;
27576 this.onMouseMove(e);
27582 for(var i = 0, finger; finger = touches[i]; i++){
27583 coords.push(finger.pageX, finger.pageY);
27586 var x = Math.pow(coords[0] - coords[2], 2);
27587 var y = Math.pow(coords[1] - coords[3], 2);
27589 this.endDistance = Math.sqrt(x + y);
27591 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27593 if(!this.zoomable()){
27594 this.scale = this.startScale;
27602 onTouchEnd : function(e)
27604 this.pinching = false;
27605 this.dragable = false;
27609 process : function(file, crop)
27612 this.maskEl.mask(this.loadingText);
27615 this.xhr = new XMLHttpRequest();
27617 file.xhr = this.xhr;
27619 this.xhr.open(this.method, this.url, true);
27622 "Accept": "application/json",
27623 "Cache-Control": "no-cache",
27624 "X-Requested-With": "XMLHttpRequest"
27627 for (var headerName in headers) {
27628 var headerValue = headers[headerName];
27630 this.xhr.setRequestHeader(headerName, headerValue);
27636 this.xhr.onload = function()
27638 _this.xhrOnLoad(_this.xhr);
27641 this.xhr.onerror = function()
27643 _this.xhrOnError(_this.xhr);
27646 var formData = new FormData();
27648 formData.append('returnHTML', 'NO');
27651 formData.append('crop', crop);
27654 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27655 formData.append(this.paramName, file, file.name);
27658 if(typeof(file.filename) != 'undefined'){
27659 formData.append('filename', file.filename);
27662 if(typeof(file.mimetype) != 'undefined'){
27663 formData.append('mimetype', file.mimetype);
27666 if(this.fireEvent('arrange', this, formData) != false){
27667 this.xhr.send(formData);
27671 xhrOnLoad : function(xhr)
27674 this.maskEl.unmask();
27677 if (xhr.readyState !== 4) {
27678 this.fireEvent('exception', this, xhr);
27682 var response = Roo.decode(xhr.responseText);
27684 if(!response.success){
27685 this.fireEvent('exception', this, xhr);
27689 var response = Roo.decode(xhr.responseText);
27691 this.fireEvent('upload', this, response);
27695 xhrOnError : function()
27698 this.maskEl.unmask();
27701 Roo.log('xhr on error');
27703 var response = Roo.decode(xhr.responseText);
27709 prepare : function(file)
27712 this.maskEl.mask(this.loadingText);
27718 if(typeof(file) === 'string'){
27719 this.loadCanvas(file);
27723 if(!file || !this.urlAPI){
27728 this.cropType = file.type;
27732 if(this.fireEvent('prepare', this, this.file) != false){
27734 var reader = new FileReader();
27736 reader.onload = function (e) {
27737 if (e.target.error) {
27738 Roo.log(e.target.error);
27742 var buffer = e.target.result,
27743 dataView = new DataView(buffer),
27745 maxOffset = dataView.byteLength - 4,
27749 if (dataView.getUint16(0) === 0xffd8) {
27750 while (offset < maxOffset) {
27751 markerBytes = dataView.getUint16(offset);
27753 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27754 markerLength = dataView.getUint16(offset + 2) + 2;
27755 if (offset + markerLength > dataView.byteLength) {
27756 Roo.log('Invalid meta data: Invalid segment size.');
27760 if(markerBytes == 0xffe1){
27761 _this.parseExifData(
27768 offset += markerLength;
27778 var url = _this.urlAPI.createObjectURL(_this.file);
27780 _this.loadCanvas(url);
27785 reader.readAsArrayBuffer(this.file);
27791 parseExifData : function(dataView, offset, length)
27793 var tiffOffset = offset + 10,
27797 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27798 // No Exif data, might be XMP data instead
27802 // Check for the ASCII code for "Exif" (0x45786966):
27803 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27804 // No Exif data, might be XMP data instead
27807 if (tiffOffset + 8 > dataView.byteLength) {
27808 Roo.log('Invalid Exif data: Invalid segment size.');
27811 // Check for the two null bytes:
27812 if (dataView.getUint16(offset + 8) !== 0x0000) {
27813 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27816 // Check the byte alignment:
27817 switch (dataView.getUint16(tiffOffset)) {
27819 littleEndian = true;
27822 littleEndian = false;
27825 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27828 // Check for the TIFF tag marker (0x002A):
27829 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27830 Roo.log('Invalid Exif data: Missing TIFF marker.');
27833 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27834 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27836 this.parseExifTags(
27839 tiffOffset + dirOffset,
27844 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27849 if (dirOffset + 6 > dataView.byteLength) {
27850 Roo.log('Invalid Exif data: Invalid directory offset.');
27853 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27854 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27855 if (dirEndOffset + 4 > dataView.byteLength) {
27856 Roo.log('Invalid Exif data: Invalid directory size.');
27859 for (i = 0; i < tagsNumber; i += 1) {
27863 dirOffset + 2 + 12 * i, // tag offset
27867 // Return the offset to the next directory:
27868 return dataView.getUint32(dirEndOffset, littleEndian);
27871 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27873 var tag = dataView.getUint16(offset, littleEndian);
27875 this.exif[tag] = this.getExifValue(
27879 dataView.getUint16(offset + 2, littleEndian), // tag type
27880 dataView.getUint32(offset + 4, littleEndian), // tag length
27885 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27887 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27896 Roo.log('Invalid Exif data: Invalid tag type.');
27900 tagSize = tagType.size * length;
27901 // Determine if the value is contained in the dataOffset bytes,
27902 // or if the value at the dataOffset is a pointer to the actual data:
27903 dataOffset = tagSize > 4 ?
27904 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27905 if (dataOffset + tagSize > dataView.byteLength) {
27906 Roo.log('Invalid Exif data: Invalid data offset.');
27909 if (length === 1) {
27910 return tagType.getValue(dataView, dataOffset, littleEndian);
27913 for (i = 0; i < length; i += 1) {
27914 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27917 if (tagType.ascii) {
27919 // Concatenate the chars:
27920 for (i = 0; i < values.length; i += 1) {
27922 // Ignore the terminating NULL byte(s):
27923 if (c === '\u0000') {
27935 Roo.apply(Roo.bootstrap.UploadCropbox, {
27937 'Orientation': 0x0112
27941 1: 0, //'top-left',
27943 3: 180, //'bottom-right',
27944 // 4: 'bottom-left',
27946 6: 90, //'right-top',
27947 // 7: 'right-bottom',
27948 8: 270 //'left-bottom'
27952 // byte, 8-bit unsigned int:
27954 getValue: function (dataView, dataOffset) {
27955 return dataView.getUint8(dataOffset);
27959 // ascii, 8-bit byte:
27961 getValue: function (dataView, dataOffset) {
27962 return String.fromCharCode(dataView.getUint8(dataOffset));
27967 // short, 16 bit int:
27969 getValue: function (dataView, dataOffset, littleEndian) {
27970 return dataView.getUint16(dataOffset, littleEndian);
27974 // long, 32 bit int:
27976 getValue: function (dataView, dataOffset, littleEndian) {
27977 return dataView.getUint32(dataOffset, littleEndian);
27981 // rational = two long values, first is numerator, second is denominator:
27983 getValue: function (dataView, dataOffset, littleEndian) {
27984 return dataView.getUint32(dataOffset, littleEndian) /
27985 dataView.getUint32(dataOffset + 4, littleEndian);
27989 // slong, 32 bit signed int:
27991 getValue: function (dataView, dataOffset, littleEndian) {
27992 return dataView.getInt32(dataOffset, littleEndian);
27996 // srational, two slongs, first is numerator, second is denominator:
27998 getValue: function (dataView, dataOffset, littleEndian) {
27999 return dataView.getInt32(dataOffset, littleEndian) /
28000 dataView.getInt32(dataOffset + 4, littleEndian);
28010 cls : 'btn-group roo-upload-cropbox-rotate-left',
28011 action : 'rotate-left',
28015 cls : 'btn btn-default',
28016 html : '<i class="fa fa-undo"></i>'
28022 cls : 'btn-group roo-upload-cropbox-picture',
28023 action : 'picture',
28027 cls : 'btn btn-default',
28028 html : '<i class="fa fa-picture-o"></i>'
28034 cls : 'btn-group roo-upload-cropbox-rotate-right',
28035 action : 'rotate-right',
28039 cls : 'btn btn-default',
28040 html : '<i class="fa fa-repeat"></i>'
28048 cls : 'btn-group roo-upload-cropbox-rotate-left',
28049 action : 'rotate-left',
28053 cls : 'btn btn-default',
28054 html : '<i class="fa fa-undo"></i>'
28060 cls : 'btn-group roo-upload-cropbox-download',
28061 action : 'download',
28065 cls : 'btn btn-default',
28066 html : '<i class="fa fa-download"></i>'
28072 cls : 'btn-group roo-upload-cropbox-crop',
28077 cls : 'btn btn-default',
28078 html : '<i class="fa fa-crop"></i>'
28084 cls : 'btn-group roo-upload-cropbox-trash',
28089 cls : 'btn btn-default',
28090 html : '<i class="fa fa-trash"></i>'
28096 cls : 'btn-group roo-upload-cropbox-rotate-right',
28097 action : 'rotate-right',
28101 cls : 'btn btn-default',
28102 html : '<i class="fa fa-repeat"></i>'
28110 cls : 'btn-group roo-upload-cropbox-rotate-left',
28111 action : 'rotate-left',
28115 cls : 'btn btn-default',
28116 html : '<i class="fa fa-undo"></i>'
28122 cls : 'btn-group roo-upload-cropbox-rotate-right',
28123 action : 'rotate-right',
28127 cls : 'btn btn-default',
28128 html : '<i class="fa fa-repeat"></i>'
28141 * @class Roo.bootstrap.DocumentManager
28142 * @extends Roo.bootstrap.Component
28143 * Bootstrap DocumentManager class
28144 * @cfg {String} paramName default 'imageUpload'
28145 * @cfg {String} toolTipName default 'filename'
28146 * @cfg {String} method default POST
28147 * @cfg {String} url action url
28148 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28149 * @cfg {Boolean} multiple multiple upload default true
28150 * @cfg {Number} thumbSize default 300
28151 * @cfg {String} fieldLabel
28152 * @cfg {Number} labelWidth default 4
28153 * @cfg {String} labelAlign (left|top) default left
28154 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28155 * @cfg {Number} labellg set the width of label (1-12)
28156 * @cfg {Number} labelmd set the width of label (1-12)
28157 * @cfg {Number} labelsm set the width of label (1-12)
28158 * @cfg {Number} labelxs set the width of label (1-12)
28161 * Create a new DocumentManager
28162 * @param {Object} config The config object
28165 Roo.bootstrap.DocumentManager = function(config){
28166 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28169 this.delegates = [];
28174 * Fire when initial the DocumentManager
28175 * @param {Roo.bootstrap.DocumentManager} this
28180 * inspect selected file
28181 * @param {Roo.bootstrap.DocumentManager} this
28182 * @param {File} file
28187 * Fire when xhr load exception
28188 * @param {Roo.bootstrap.DocumentManager} this
28189 * @param {XMLHttpRequest} xhr
28191 "exception" : true,
28193 * @event afterupload
28194 * Fire when xhr load exception
28195 * @param {Roo.bootstrap.DocumentManager} this
28196 * @param {XMLHttpRequest} xhr
28198 "afterupload" : true,
28201 * prepare the form data
28202 * @param {Roo.bootstrap.DocumentManager} this
28203 * @param {Object} formData
28208 * Fire when remove the file
28209 * @param {Roo.bootstrap.DocumentManager} this
28210 * @param {Object} file
28215 * Fire after refresh the file
28216 * @param {Roo.bootstrap.DocumentManager} this
28221 * Fire after click the image
28222 * @param {Roo.bootstrap.DocumentManager} this
28223 * @param {Object} file
28228 * Fire when upload a image and editable set to true
28229 * @param {Roo.bootstrap.DocumentManager} this
28230 * @param {Object} file
28234 * @event beforeselectfile
28235 * Fire before select file
28236 * @param {Roo.bootstrap.DocumentManager} this
28238 "beforeselectfile" : true,
28241 * Fire before process file
28242 * @param {Roo.bootstrap.DocumentManager} this
28243 * @param {Object} file
28250 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28259 paramName : 'imageUpload',
28260 toolTipName : 'filename',
28263 labelAlign : 'left',
28273 getAutoCreate : function()
28275 var managerWidget = {
28277 cls : 'roo-document-manager',
28281 cls : 'roo-document-manager-selector',
28286 cls : 'roo-document-manager-uploader',
28290 cls : 'roo-document-manager-upload-btn',
28291 html : '<i class="fa fa-plus"></i>'
28302 cls : 'column col-md-12',
28307 if(this.fieldLabel.length){
28312 cls : 'column col-md-12',
28313 html : this.fieldLabel
28317 cls : 'column col-md-12',
28322 if(this.labelAlign == 'left'){
28327 html : this.fieldLabel
28336 if(this.labelWidth > 12){
28337 content[0].style = "width: " + this.labelWidth + 'px';
28340 if(this.labelWidth < 13 && this.labelmd == 0){
28341 this.labelmd = this.labelWidth;
28344 if(this.labellg > 0){
28345 content[0].cls += ' col-lg-' + this.labellg;
28346 content[1].cls += ' col-lg-' + (12 - this.labellg);
28349 if(this.labelmd > 0){
28350 content[0].cls += ' col-md-' + this.labelmd;
28351 content[1].cls += ' col-md-' + (12 - this.labelmd);
28354 if(this.labelsm > 0){
28355 content[0].cls += ' col-sm-' + this.labelsm;
28356 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28359 if(this.labelxs > 0){
28360 content[0].cls += ' col-xs-' + this.labelxs;
28361 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28369 cls : 'row clearfix',
28377 initEvents : function()
28379 this.managerEl = this.el.select('.roo-document-manager', true).first();
28380 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28382 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28383 this.selectorEl.hide();
28386 this.selectorEl.attr('multiple', 'multiple');
28389 this.selectorEl.on('change', this.onFileSelected, this);
28391 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28392 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28394 this.uploader.on('click', this.onUploaderClick, this);
28396 this.renderProgressDialog();
28400 window.addEventListener("resize", function() { _this.refresh(); } );
28402 this.fireEvent('initial', this);
28405 renderProgressDialog : function()
28409 this.progressDialog = new Roo.bootstrap.Modal({
28410 cls : 'roo-document-manager-progress-dialog',
28411 allow_close : false,
28421 btnclick : function() {
28422 _this.uploadCancel();
28428 this.progressDialog.render(Roo.get(document.body));
28430 this.progress = new Roo.bootstrap.Progress({
28431 cls : 'roo-document-manager-progress',
28436 this.progress.render(this.progressDialog.getChildContainer());
28438 this.progressBar = new Roo.bootstrap.ProgressBar({
28439 cls : 'roo-document-manager-progress-bar',
28442 aria_valuemax : 12,
28446 this.progressBar.render(this.progress.getChildContainer());
28449 onUploaderClick : function(e)
28451 e.preventDefault();
28453 if(this.fireEvent('beforeselectfile', this) != false){
28454 this.selectorEl.dom.click();
28459 onFileSelected : function(e)
28461 e.preventDefault();
28463 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28467 Roo.each(this.selectorEl.dom.files, function(file){
28468 if(this.fireEvent('inspect', this, file) != false){
28469 this.files.push(file);
28479 this.selectorEl.dom.value = '';
28481 if(!this.files.length){
28485 if(this.boxes > 0 && this.files.length > this.boxes){
28486 this.files = this.files.slice(0, this.boxes);
28489 this.uploader.show();
28491 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28492 this.uploader.hide();
28501 Roo.each(this.files, function(file){
28503 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28504 var f = this.renderPreview(file);
28509 if(file.type.indexOf('image') != -1){
28510 this.delegates.push(
28512 _this.process(file);
28513 }).createDelegate(this)
28521 _this.process(file);
28522 }).createDelegate(this)
28527 this.files = files;
28529 this.delegates = this.delegates.concat(docs);
28531 if(!this.delegates.length){
28536 this.progressBar.aria_valuemax = this.delegates.length;
28543 arrange : function()
28545 if(!this.delegates.length){
28546 this.progressDialog.hide();
28551 var delegate = this.delegates.shift();
28553 this.progressDialog.show();
28555 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28557 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28562 refresh : function()
28564 this.uploader.show();
28566 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28567 this.uploader.hide();
28570 Roo.isTouch ? this.closable(false) : this.closable(true);
28572 this.fireEvent('refresh', this);
28575 onRemove : function(e, el, o)
28577 e.preventDefault();
28579 this.fireEvent('remove', this, o);
28583 remove : function(o)
28587 Roo.each(this.files, function(file){
28588 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28597 this.files = files;
28604 Roo.each(this.files, function(file){
28609 file.target.remove();
28618 onClick : function(e, el, o)
28620 e.preventDefault();
28622 this.fireEvent('click', this, o);
28626 closable : function(closable)
28628 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28630 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28642 xhrOnLoad : function(xhr)
28644 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28648 if (xhr.readyState !== 4) {
28650 this.fireEvent('exception', this, xhr);
28654 var response = Roo.decode(xhr.responseText);
28656 if(!response.success){
28658 this.fireEvent('exception', this, xhr);
28662 var file = this.renderPreview(response.data);
28664 this.files.push(file);
28668 this.fireEvent('afterupload', this, xhr);
28672 xhrOnError : function(xhr)
28674 Roo.log('xhr on error');
28676 var response = Roo.decode(xhr.responseText);
28683 process : function(file)
28685 if(this.fireEvent('process', this, file) !== false){
28686 if(this.editable && file.type.indexOf('image') != -1){
28687 this.fireEvent('edit', this, file);
28691 this.uploadStart(file, false);
28698 uploadStart : function(file, crop)
28700 this.xhr = new XMLHttpRequest();
28702 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28707 file.xhr = this.xhr;
28709 this.managerEl.createChild({
28711 cls : 'roo-document-manager-loading',
28715 tooltip : file.name,
28716 cls : 'roo-document-manager-thumb',
28717 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28723 this.xhr.open(this.method, this.url, true);
28726 "Accept": "application/json",
28727 "Cache-Control": "no-cache",
28728 "X-Requested-With": "XMLHttpRequest"
28731 for (var headerName in headers) {
28732 var headerValue = headers[headerName];
28734 this.xhr.setRequestHeader(headerName, headerValue);
28740 this.xhr.onload = function()
28742 _this.xhrOnLoad(_this.xhr);
28745 this.xhr.onerror = function()
28747 _this.xhrOnError(_this.xhr);
28750 var formData = new FormData();
28752 formData.append('returnHTML', 'NO');
28755 formData.append('crop', crop);
28758 formData.append(this.paramName, file, file.name);
28765 if(this.fireEvent('prepare', this, formData, options) != false){
28767 if(options.manually){
28771 this.xhr.send(formData);
28775 this.uploadCancel();
28778 uploadCancel : function()
28784 this.delegates = [];
28786 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28793 renderPreview : function(file)
28795 if(typeof(file.target) != 'undefined' && file.target){
28799 var previewEl = this.managerEl.createChild({
28801 cls : 'roo-document-manager-preview',
28805 tooltip : file[this.toolTipName],
28806 cls : 'roo-document-manager-thumb',
28807 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28812 html : '<i class="fa fa-times-circle"></i>'
28817 var close = previewEl.select('button.close', true).first();
28819 close.on('click', this.onRemove, this, file);
28821 file.target = previewEl;
28823 var image = previewEl.select('img', true).first();
28827 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28829 image.on('click', this.onClick, this, file);
28835 onPreviewLoad : function(file, image)
28837 if(typeof(file.target) == 'undefined' || !file.target){
28841 var width = image.dom.naturalWidth || image.dom.width;
28842 var height = image.dom.naturalHeight || image.dom.height;
28844 if(width > height){
28845 file.target.addClass('wide');
28849 file.target.addClass('tall');
28854 uploadFromSource : function(file, crop)
28856 this.xhr = new XMLHttpRequest();
28858 this.managerEl.createChild({
28860 cls : 'roo-document-manager-loading',
28864 tooltip : file.name,
28865 cls : 'roo-document-manager-thumb',
28866 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28872 this.xhr.open(this.method, this.url, true);
28875 "Accept": "application/json",
28876 "Cache-Control": "no-cache",
28877 "X-Requested-With": "XMLHttpRequest"
28880 for (var headerName in headers) {
28881 var headerValue = headers[headerName];
28883 this.xhr.setRequestHeader(headerName, headerValue);
28889 this.xhr.onload = function()
28891 _this.xhrOnLoad(_this.xhr);
28894 this.xhr.onerror = function()
28896 _this.xhrOnError(_this.xhr);
28899 var formData = new FormData();
28901 formData.append('returnHTML', 'NO');
28903 formData.append('crop', crop);
28905 if(typeof(file.filename) != 'undefined'){
28906 formData.append('filename', file.filename);
28909 if(typeof(file.mimetype) != 'undefined'){
28910 formData.append('mimetype', file.mimetype);
28915 if(this.fireEvent('prepare', this, formData) != false){
28916 this.xhr.send(formData);
28926 * @class Roo.bootstrap.DocumentViewer
28927 * @extends Roo.bootstrap.Component
28928 * Bootstrap DocumentViewer class
28929 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28930 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28933 * Create a new DocumentViewer
28934 * @param {Object} config The config object
28937 Roo.bootstrap.DocumentViewer = function(config){
28938 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28943 * Fire after initEvent
28944 * @param {Roo.bootstrap.DocumentViewer} this
28950 * @param {Roo.bootstrap.DocumentViewer} this
28955 * Fire after download button
28956 * @param {Roo.bootstrap.DocumentViewer} this
28961 * Fire after trash button
28962 * @param {Roo.bootstrap.DocumentViewer} this
28969 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28971 showDownload : true,
28975 getAutoCreate : function()
28979 cls : 'roo-document-viewer',
28983 cls : 'roo-document-viewer-body',
28987 cls : 'roo-document-viewer-thumb',
28991 cls : 'roo-document-viewer-image'
28999 cls : 'roo-document-viewer-footer',
29002 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29006 cls : 'btn-group roo-document-viewer-download',
29010 cls : 'btn btn-default',
29011 html : '<i class="fa fa-download"></i>'
29017 cls : 'btn-group roo-document-viewer-trash',
29021 cls : 'btn btn-default',
29022 html : '<i class="fa fa-trash"></i>'
29035 initEvents : function()
29037 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29038 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29040 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29041 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29043 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29044 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29046 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29047 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29049 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29050 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29052 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29053 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29055 this.bodyEl.on('click', this.onClick, this);
29056 this.downloadBtn.on('click', this.onDownload, this);
29057 this.trashBtn.on('click', this.onTrash, this);
29059 this.downloadBtn.hide();
29060 this.trashBtn.hide();
29062 if(this.showDownload){
29063 this.downloadBtn.show();
29066 if(this.showTrash){
29067 this.trashBtn.show();
29070 if(!this.showDownload && !this.showTrash) {
29071 this.footerEl.hide();
29076 initial : function()
29078 this.fireEvent('initial', this);
29082 onClick : function(e)
29084 e.preventDefault();
29086 this.fireEvent('click', this);
29089 onDownload : function(e)
29091 e.preventDefault();
29093 this.fireEvent('download', this);
29096 onTrash : function(e)
29098 e.preventDefault();
29100 this.fireEvent('trash', this);
29112 * @class Roo.bootstrap.NavProgressBar
29113 * @extends Roo.bootstrap.Component
29114 * Bootstrap NavProgressBar class
29117 * Create a new nav progress bar
29118 * @param {Object} config The config object
29121 Roo.bootstrap.NavProgressBar = function(config){
29122 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29124 this.bullets = this.bullets || [];
29126 // Roo.bootstrap.NavProgressBar.register(this);
29130 * Fires when the active item changes
29131 * @param {Roo.bootstrap.NavProgressBar} this
29132 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29133 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29140 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29145 getAutoCreate : function()
29147 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29151 cls : 'roo-navigation-bar-group',
29155 cls : 'roo-navigation-top-bar'
29159 cls : 'roo-navigation-bullets-bar',
29163 cls : 'roo-navigation-bar'
29170 cls : 'roo-navigation-bottom-bar'
29180 initEvents: function()
29185 onRender : function(ct, position)
29187 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29189 if(this.bullets.length){
29190 Roo.each(this.bullets, function(b){
29199 addItem : function(cfg)
29201 var item = new Roo.bootstrap.NavProgressItem(cfg);
29203 item.parentId = this.id;
29204 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29207 var top = new Roo.bootstrap.Element({
29209 cls : 'roo-navigation-bar-text'
29212 var bottom = new Roo.bootstrap.Element({
29214 cls : 'roo-navigation-bar-text'
29217 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29218 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29220 var topText = new Roo.bootstrap.Element({
29222 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29225 var bottomText = new Roo.bootstrap.Element({
29227 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29230 topText.onRender(top.el, null);
29231 bottomText.onRender(bottom.el, null);
29234 item.bottomEl = bottom;
29237 this.barItems.push(item);
29242 getActive : function()
29244 var active = false;
29246 Roo.each(this.barItems, function(v){
29248 if (!v.isActive()) {
29260 setActiveItem : function(item)
29264 Roo.each(this.barItems, function(v){
29265 if (v.rid == item.rid) {
29269 if (v.isActive()) {
29270 v.setActive(false);
29275 item.setActive(true);
29277 this.fireEvent('changed', this, item, prev);
29280 getBarItem: function(rid)
29284 Roo.each(this.barItems, function(e) {
29285 if (e.rid != rid) {
29296 indexOfItem : function(item)
29300 Roo.each(this.barItems, function(v, i){
29302 if (v.rid != item.rid) {
29313 setActiveNext : function()
29315 var i = this.indexOfItem(this.getActive());
29317 if (i > this.barItems.length) {
29321 this.setActiveItem(this.barItems[i+1]);
29324 setActivePrev : function()
29326 var i = this.indexOfItem(this.getActive());
29332 this.setActiveItem(this.barItems[i-1]);
29335 format : function()
29337 if(!this.barItems.length){
29341 var width = 100 / this.barItems.length;
29343 Roo.each(this.barItems, function(i){
29344 i.el.setStyle('width', width + '%');
29345 i.topEl.el.setStyle('width', width + '%');
29346 i.bottomEl.el.setStyle('width', width + '%');
29355 * Nav Progress Item
29360 * @class Roo.bootstrap.NavProgressItem
29361 * @extends Roo.bootstrap.Component
29362 * Bootstrap NavProgressItem class
29363 * @cfg {String} rid the reference id
29364 * @cfg {Boolean} active (true|false) Is item active default false
29365 * @cfg {Boolean} disabled (true|false) Is item active default false
29366 * @cfg {String} html
29367 * @cfg {String} position (top|bottom) text position default bottom
29368 * @cfg {String} icon show icon instead of number
29371 * Create a new NavProgressItem
29372 * @param {Object} config The config object
29374 Roo.bootstrap.NavProgressItem = function(config){
29375 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29380 * The raw click event for the entire grid.
29381 * @param {Roo.bootstrap.NavProgressItem} this
29382 * @param {Roo.EventObject} e
29389 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29395 position : 'bottom',
29398 getAutoCreate : function()
29400 var iconCls = 'roo-navigation-bar-item-icon';
29402 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29406 cls: 'roo-navigation-bar-item',
29416 cfg.cls += ' active';
29419 cfg.cls += ' disabled';
29425 disable : function()
29427 this.setDisabled(true);
29430 enable : function()
29432 this.setDisabled(false);
29435 initEvents: function()
29437 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29439 this.iconEl.on('click', this.onClick, this);
29442 onClick : function(e)
29444 e.preventDefault();
29450 if(this.fireEvent('click', this, e) === false){
29454 this.parent().setActiveItem(this);
29457 isActive: function ()
29459 return this.active;
29462 setActive : function(state)
29464 if(this.active == state){
29468 this.active = state;
29471 this.el.addClass('active');
29475 this.el.removeClass('active');
29480 setDisabled : function(state)
29482 if(this.disabled == state){
29486 this.disabled = state;
29489 this.el.addClass('disabled');
29493 this.el.removeClass('disabled');
29496 tooltipEl : function()
29498 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29511 * @class Roo.bootstrap.FieldLabel
29512 * @extends Roo.bootstrap.Component
29513 * Bootstrap FieldLabel class
29514 * @cfg {String} html contents of the element
29515 * @cfg {String} tag tag of the element default label
29516 * @cfg {String} cls class of the element
29517 * @cfg {String} target label target
29518 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29519 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29520 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29521 * @cfg {String} iconTooltip default "This field is required"
29524 * Create a new FieldLabel
29525 * @param {Object} config The config object
29528 Roo.bootstrap.FieldLabel = function(config){
29529 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29534 * Fires after the field has been marked as invalid.
29535 * @param {Roo.form.FieldLabel} this
29536 * @param {String} msg The validation message
29541 * Fires after the field has been validated with no errors.
29542 * @param {Roo.form.FieldLabel} this
29548 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29555 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29556 validClass : 'text-success fa fa-lg fa-check',
29557 iconTooltip : 'This field is required',
29559 getAutoCreate : function(){
29563 cls : 'roo-bootstrap-field-label ' + this.cls,
29569 tooltip : this.iconTooltip
29581 initEvents: function()
29583 Roo.bootstrap.Element.superclass.initEvents.call(this);
29585 this.iconEl = this.el.select('i', true).first();
29587 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29589 Roo.bootstrap.FieldLabel.register(this);
29593 * Mark this field as valid
29595 markValid : function()
29597 this.iconEl.show();
29599 this.iconEl.removeClass(this.invalidClass);
29601 this.iconEl.addClass(this.validClass);
29603 this.fireEvent('valid', this);
29607 * Mark this field as invalid
29608 * @param {String} msg The validation message
29610 markInvalid : function(msg)
29612 this.iconEl.show();
29614 this.iconEl.removeClass(this.validClass);
29616 this.iconEl.addClass(this.invalidClass);
29618 this.fireEvent('invalid', this, msg);
29624 Roo.apply(Roo.bootstrap.FieldLabel, {
29629 * register a FieldLabel Group
29630 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29632 register : function(label)
29634 if(this.groups.hasOwnProperty(label.target)){
29638 this.groups[label.target] = label;
29642 * fetch a FieldLabel Group based on the target
29643 * @param {string} target
29644 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29646 get: function(target) {
29647 if (typeof(this.groups[target]) == 'undefined') {
29651 return this.groups[target] ;
29660 * page DateSplitField.
29666 * @class Roo.bootstrap.DateSplitField
29667 * @extends Roo.bootstrap.Component
29668 * Bootstrap DateSplitField class
29669 * @cfg {string} fieldLabel - the label associated
29670 * @cfg {Number} labelWidth set the width of label (0-12)
29671 * @cfg {String} labelAlign (top|left)
29672 * @cfg {Boolean} dayAllowBlank (true|false) default false
29673 * @cfg {Boolean} monthAllowBlank (true|false) default false
29674 * @cfg {Boolean} yearAllowBlank (true|false) default false
29675 * @cfg {string} dayPlaceholder
29676 * @cfg {string} monthPlaceholder
29677 * @cfg {string} yearPlaceholder
29678 * @cfg {string} dayFormat default 'd'
29679 * @cfg {string} monthFormat default 'm'
29680 * @cfg {string} yearFormat default 'Y'
29681 * @cfg {Number} labellg set the width of label (1-12)
29682 * @cfg {Number} labelmd set the width of label (1-12)
29683 * @cfg {Number} labelsm set the width of label (1-12)
29684 * @cfg {Number} labelxs set the width of label (1-12)
29688 * Create a new DateSplitField
29689 * @param {Object} config The config object
29692 Roo.bootstrap.DateSplitField = function(config){
29693 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29699 * getting the data of years
29700 * @param {Roo.bootstrap.DateSplitField} this
29701 * @param {Object} years
29706 * getting the data of days
29707 * @param {Roo.bootstrap.DateSplitField} this
29708 * @param {Object} days
29713 * Fires after the field has been marked as invalid.
29714 * @param {Roo.form.Field} this
29715 * @param {String} msg The validation message
29720 * Fires after the field has been validated with no errors.
29721 * @param {Roo.form.Field} this
29727 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29730 labelAlign : 'top',
29732 dayAllowBlank : false,
29733 monthAllowBlank : false,
29734 yearAllowBlank : false,
29735 dayPlaceholder : '',
29736 monthPlaceholder : '',
29737 yearPlaceholder : '',
29741 isFormField : true,
29747 getAutoCreate : function()
29751 cls : 'row roo-date-split-field-group',
29756 cls : 'form-hidden-field roo-date-split-field-group-value',
29762 var labelCls = 'col-md-12';
29763 var contentCls = 'col-md-4';
29765 if(this.fieldLabel){
29769 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29773 html : this.fieldLabel
29778 if(this.labelAlign == 'left'){
29780 if(this.labelWidth > 12){
29781 label.style = "width: " + this.labelWidth + 'px';
29784 if(this.labelWidth < 13 && this.labelmd == 0){
29785 this.labelmd = this.labelWidth;
29788 if(this.labellg > 0){
29789 labelCls = ' col-lg-' + this.labellg;
29790 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29793 if(this.labelmd > 0){
29794 labelCls = ' col-md-' + this.labelmd;
29795 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29798 if(this.labelsm > 0){
29799 labelCls = ' col-sm-' + this.labelsm;
29800 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29803 if(this.labelxs > 0){
29804 labelCls = ' col-xs-' + this.labelxs;
29805 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29809 label.cls += ' ' + labelCls;
29811 cfg.cn.push(label);
29814 Roo.each(['day', 'month', 'year'], function(t){
29817 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29824 inputEl: function ()
29826 return this.el.select('.roo-date-split-field-group-value', true).first();
29829 onRender : function(ct, position)
29833 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29835 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29837 this.dayField = new Roo.bootstrap.ComboBox({
29838 allowBlank : this.dayAllowBlank,
29839 alwaysQuery : true,
29840 displayField : 'value',
29843 forceSelection : true,
29845 placeholder : this.dayPlaceholder,
29846 selectOnFocus : true,
29847 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29848 triggerAction : 'all',
29850 valueField : 'value',
29851 store : new Roo.data.SimpleStore({
29852 data : (function() {
29854 _this.fireEvent('days', _this, days);
29857 fields : [ 'value' ]
29860 select : function (_self, record, index)
29862 _this.setValue(_this.getValue());
29867 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29869 this.monthField = new Roo.bootstrap.MonthField({
29870 after : '<i class=\"fa fa-calendar\"></i>',
29871 allowBlank : this.monthAllowBlank,
29872 placeholder : this.monthPlaceholder,
29875 render : function (_self)
29877 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29878 e.preventDefault();
29882 select : function (_self, oldvalue, newvalue)
29884 _this.setValue(_this.getValue());
29889 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29891 this.yearField = new Roo.bootstrap.ComboBox({
29892 allowBlank : this.yearAllowBlank,
29893 alwaysQuery : true,
29894 displayField : 'value',
29897 forceSelection : true,
29899 placeholder : this.yearPlaceholder,
29900 selectOnFocus : true,
29901 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29902 triggerAction : 'all',
29904 valueField : 'value',
29905 store : new Roo.data.SimpleStore({
29906 data : (function() {
29908 _this.fireEvent('years', _this, years);
29911 fields : [ 'value' ]
29914 select : function (_self, record, index)
29916 _this.setValue(_this.getValue());
29921 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29924 setValue : function(v, format)
29926 this.inputEl.dom.value = v;
29928 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29930 var d = Date.parseDate(v, f);
29937 this.setDay(d.format(this.dayFormat));
29938 this.setMonth(d.format(this.monthFormat));
29939 this.setYear(d.format(this.yearFormat));
29946 setDay : function(v)
29948 this.dayField.setValue(v);
29949 this.inputEl.dom.value = this.getValue();
29954 setMonth : function(v)
29956 this.monthField.setValue(v, true);
29957 this.inputEl.dom.value = this.getValue();
29962 setYear : function(v)
29964 this.yearField.setValue(v);
29965 this.inputEl.dom.value = this.getValue();
29970 getDay : function()
29972 return this.dayField.getValue();
29975 getMonth : function()
29977 return this.monthField.getValue();
29980 getYear : function()
29982 return this.yearField.getValue();
29985 getValue : function()
29987 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29989 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29999 this.inputEl.dom.value = '';
30004 validate : function()
30006 var d = this.dayField.validate();
30007 var m = this.monthField.validate();
30008 var y = this.yearField.validate();
30013 (!this.dayAllowBlank && !d) ||
30014 (!this.monthAllowBlank && !m) ||
30015 (!this.yearAllowBlank && !y)
30020 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30029 this.markInvalid();
30034 markValid : function()
30037 var label = this.el.select('label', true).first();
30038 var icon = this.el.select('i.fa-star', true).first();
30044 this.fireEvent('valid', this);
30048 * Mark this field as invalid
30049 * @param {String} msg The validation message
30051 markInvalid : function(msg)
30054 var label = this.el.select('label', true).first();
30055 var icon = this.el.select('i.fa-star', true).first();
30057 if(label && !icon){
30058 this.el.select('.roo-date-split-field-label', true).createChild({
30060 cls : 'text-danger fa fa-lg fa-star',
30061 tooltip : 'This field is required',
30062 style : 'margin-right:5px;'
30066 this.fireEvent('invalid', this, msg);
30069 clearInvalid : function()
30071 var label = this.el.select('label', true).first();
30072 var icon = this.el.select('i.fa-star', true).first();
30078 this.fireEvent('valid', this);
30081 getName: function()
30091 * http://masonry.desandro.com
30093 * The idea is to render all the bricks based on vertical width...
30095 * The original code extends 'outlayer' - we might need to use that....
30101 * @class Roo.bootstrap.LayoutMasonry
30102 * @extends Roo.bootstrap.Component
30103 * Bootstrap Layout Masonry class
30106 * Create a new Element
30107 * @param {Object} config The config object
30110 Roo.bootstrap.LayoutMasonry = function(config){
30112 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30116 Roo.bootstrap.LayoutMasonry.register(this);
30122 * Fire after layout the items
30123 * @param {Roo.bootstrap.LayoutMasonry} this
30124 * @param {Roo.EventObject} e
30131 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30134 * @cfg {Boolean} isLayoutInstant = no animation?
30136 isLayoutInstant : false, // needed?
30139 * @cfg {Number} boxWidth width of the columns
30144 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30149 * @cfg {Number} padWidth padding below box..
30154 * @cfg {Number} gutter gutter width..
30159 * @cfg {Number} maxCols maximum number of columns
30165 * @cfg {Boolean} isAutoInitial defalut true
30167 isAutoInitial : true,
30172 * @cfg {Boolean} isHorizontal defalut false
30174 isHorizontal : false,
30176 currentSize : null,
30182 bricks: null, //CompositeElement
30186 _isLayoutInited : false,
30188 // isAlternative : false, // only use for vertical layout...
30191 * @cfg {Number} alternativePadWidth padding below box..
30193 alternativePadWidth : 50,
30195 selectedBrick : [],
30197 getAutoCreate : function(){
30199 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30203 cls: 'blog-masonary-wrapper ' + this.cls,
30205 cls : 'mas-boxes masonary'
30212 getChildContainer: function( )
30214 if (this.boxesEl) {
30215 return this.boxesEl;
30218 this.boxesEl = this.el.select('.mas-boxes').first();
30220 return this.boxesEl;
30224 initEvents : function()
30228 if(this.isAutoInitial){
30229 Roo.log('hook children rendered');
30230 this.on('childrenrendered', function() {
30231 Roo.log('children rendered');
30237 initial : function()
30239 this.currentSize = this.el.getBox(true);
30241 Roo.EventManager.onWindowResize(this.resize, this);
30243 if(!this.isAutoInitial){
30251 //this.layout.defer(500,this);
30255 resize : function()
30257 var cs = this.el.getBox(true);
30260 this.currentSize.width == cs.width &&
30261 this.currentSize.x == cs.x &&
30262 this.currentSize.height == cs.height &&
30263 this.currentSize.y == cs.y
30265 Roo.log("no change in with or X or Y");
30269 this.currentSize = cs;
30275 layout : function()
30277 this._resetLayout();
30279 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30281 this.layoutItems( isInstant );
30283 this._isLayoutInited = true;
30285 this.fireEvent('layout', this);
30289 _resetLayout : function()
30291 if(this.isHorizontal){
30292 this.horizontalMeasureColumns();
30296 this.verticalMeasureColumns();
30300 verticalMeasureColumns : function()
30302 this.getContainerWidth();
30304 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30305 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30309 var boxWidth = this.boxWidth + this.padWidth;
30311 if(this.containerWidth < this.boxWidth){
30312 boxWidth = this.containerWidth
30315 var containerWidth = this.containerWidth;
30317 var cols = Math.floor(containerWidth / boxWidth);
30319 this.cols = Math.max( cols, 1 );
30321 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30323 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30325 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30327 this.colWidth = boxWidth + avail - this.padWidth;
30329 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
30330 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30333 horizontalMeasureColumns : function()
30335 this.getContainerWidth();
30337 var boxWidth = this.boxWidth;
30339 if(this.containerWidth < boxWidth){
30340 boxWidth = this.containerWidth;
30343 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30345 this.el.setHeight(boxWidth);
30349 getContainerWidth : function()
30351 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30354 layoutItems : function( isInstant )
30356 Roo.log(this.bricks);
30358 var items = Roo.apply([], this.bricks);
30360 if(this.isHorizontal){
30361 this._horizontalLayoutItems( items , isInstant );
30365 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30366 // this._verticalAlternativeLayoutItems( items , isInstant );
30370 this._verticalLayoutItems( items , isInstant );
30374 _verticalLayoutItems : function ( items , isInstant)
30376 if ( !items || !items.length ) {
30381 ['xs', 'xs', 'xs', 'tall'],
30382 ['xs', 'xs', 'tall'],
30383 ['xs', 'xs', 'sm'],
30384 ['xs', 'xs', 'xs'],
30390 ['sm', 'xs', 'xs'],
30394 ['tall', 'xs', 'xs', 'xs'],
30395 ['tall', 'xs', 'xs'],
30407 Roo.each(items, function(item, k){
30409 switch (item.size) {
30410 // these layouts take up a full box,
30421 boxes.push([item]);
30444 var filterPattern = function(box, length)
30452 var pattern = box.slice(0, length);
30456 Roo.each(pattern, function(i){
30457 format.push(i.size);
30460 Roo.each(standard, function(s){
30462 if(String(s) != String(format)){
30471 if(!match && length == 1){
30476 filterPattern(box, length - 1);
30480 queue.push(pattern);
30482 box = box.slice(length, box.length);
30484 filterPattern(box, 4);
30490 Roo.each(boxes, function(box, k){
30496 if(box.length == 1){
30501 filterPattern(box, 4);
30505 this._processVerticalLayoutQueue( queue, isInstant );
30509 // _verticalAlternativeLayoutItems : function( items , isInstant )
30511 // if ( !items || !items.length ) {
30515 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30519 _horizontalLayoutItems : function ( items , isInstant)
30521 if ( !items || !items.length || items.length < 3) {
30527 var eItems = items.slice(0, 3);
30529 items = items.slice(3, items.length);
30532 ['xs', 'xs', 'xs', 'wide'],
30533 ['xs', 'xs', 'wide'],
30534 ['xs', 'xs', 'sm'],
30535 ['xs', 'xs', 'xs'],
30541 ['sm', 'xs', 'xs'],
30545 ['wide', 'xs', 'xs', 'xs'],
30546 ['wide', 'xs', 'xs'],
30559 Roo.each(items, function(item, k){
30561 switch (item.size) {
30572 boxes.push([item]);
30596 var filterPattern = function(box, length)
30604 var pattern = box.slice(0, length);
30608 Roo.each(pattern, function(i){
30609 format.push(i.size);
30612 Roo.each(standard, function(s){
30614 if(String(s) != String(format)){
30623 if(!match && length == 1){
30628 filterPattern(box, length - 1);
30632 queue.push(pattern);
30634 box = box.slice(length, box.length);
30636 filterPattern(box, 4);
30642 Roo.each(boxes, function(box, k){
30648 if(box.length == 1){
30653 filterPattern(box, 4);
30660 var pos = this.el.getBox(true);
30664 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30666 var hit_end = false;
30668 Roo.each(queue, function(box){
30672 Roo.each(box, function(b){
30674 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30684 Roo.each(box, function(b){
30686 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30689 mx = Math.max(mx, b.x);
30693 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30697 Roo.each(box, function(b){
30699 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30713 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30716 /** Sets position of item in DOM
30717 * @param {Element} item
30718 * @param {Number} x - horizontal position
30719 * @param {Number} y - vertical position
30720 * @param {Boolean} isInstant - disables transitions
30722 _processVerticalLayoutQueue : function( queue, isInstant )
30724 var pos = this.el.getBox(true);
30729 for (var i = 0; i < this.cols; i++){
30733 Roo.each(queue, function(box, k){
30735 var col = k % this.cols;
30737 Roo.each(box, function(b,kk){
30739 b.el.position('absolute');
30741 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30742 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30744 if(b.size == 'md-left' || b.size == 'md-right'){
30745 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30746 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30749 b.el.setWidth(width);
30750 b.el.setHeight(height);
30752 b.el.select('iframe',true).setSize(width,height);
30756 for (var i = 0; i < this.cols; i++){
30758 if(maxY[i] < maxY[col]){
30763 col = Math.min(col, i);
30767 x = pos.x + col * (this.colWidth + this.padWidth);
30771 var positions = [];
30773 switch (box.length){
30775 positions = this.getVerticalOneBoxColPositions(x, y, box);
30778 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30781 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30784 positions = this.getVerticalFourBoxColPositions(x, y, box);
30790 Roo.each(box, function(b,kk){
30792 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30794 var sz = b.el.getSize();
30796 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30804 for (var i = 0; i < this.cols; i++){
30805 mY = Math.max(mY, maxY[i]);
30808 this.el.setHeight(mY - pos.y);
30812 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30814 // var pos = this.el.getBox(true);
30817 // var maxX = pos.right;
30819 // var maxHeight = 0;
30821 // Roo.each(items, function(item, k){
30825 // item.el.position('absolute');
30827 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30829 // item.el.setWidth(width);
30831 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30833 // item.el.setHeight(height);
30836 // item.el.setXY([x, y], isInstant ? false : true);
30838 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30841 // y = y + height + this.alternativePadWidth;
30843 // maxHeight = maxHeight + height + this.alternativePadWidth;
30847 // this.el.setHeight(maxHeight);
30851 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30853 var pos = this.el.getBox(true);
30858 var maxX = pos.right;
30860 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30862 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30864 Roo.each(queue, function(box, k){
30866 Roo.each(box, function(b, kk){
30868 b.el.position('absolute');
30870 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30871 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30873 if(b.size == 'md-left' || b.size == 'md-right'){
30874 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30875 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30878 b.el.setWidth(width);
30879 b.el.setHeight(height);
30887 var positions = [];
30889 switch (box.length){
30891 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30894 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30897 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30900 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30906 Roo.each(box, function(b,kk){
30908 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30910 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30918 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30920 Roo.each(eItems, function(b,k){
30922 b.size = (k == 0) ? 'sm' : 'xs';
30923 b.x = (k == 0) ? 2 : 1;
30924 b.y = (k == 0) ? 2 : 1;
30926 b.el.position('absolute');
30928 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30930 b.el.setWidth(width);
30932 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30934 b.el.setHeight(height);
30938 var positions = [];
30941 x : maxX - this.unitWidth * 2 - this.gutter,
30946 x : maxX - this.unitWidth,
30947 y : minY + (this.unitWidth + this.gutter) * 2
30951 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30955 Roo.each(eItems, function(b,k){
30957 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30963 getVerticalOneBoxColPositions : function(x, y, box)
30967 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30969 if(box[0].size == 'md-left'){
30973 if(box[0].size == 'md-right'){
30978 x : x + (this.unitWidth + this.gutter) * rand,
30985 getVerticalTwoBoxColPositions : function(x, y, box)
30989 if(box[0].size == 'xs'){
30993 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30997 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31011 x : x + (this.unitWidth + this.gutter) * 2,
31012 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31019 getVerticalThreeBoxColPositions : function(x, y, box)
31023 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31031 x : x + (this.unitWidth + this.gutter) * 1,
31036 x : x + (this.unitWidth + this.gutter) * 2,
31044 if(box[0].size == 'xs' && box[1].size == 'xs'){
31053 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31057 x : x + (this.unitWidth + this.gutter) * 1,
31071 x : x + (this.unitWidth + this.gutter) * 2,
31076 x : x + (this.unitWidth + this.gutter) * 2,
31077 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31084 getVerticalFourBoxColPositions : function(x, y, box)
31088 if(box[0].size == 'xs'){
31097 y : y + (this.unitHeight + this.gutter) * 1
31102 y : y + (this.unitHeight + this.gutter) * 2
31106 x : x + (this.unitWidth + this.gutter) * 1,
31120 x : x + (this.unitWidth + this.gutter) * 2,
31125 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31126 y : y + (this.unitHeight + this.gutter) * 1
31130 x : x + (this.unitWidth + this.gutter) * 2,
31131 y : y + (this.unitWidth + this.gutter) * 2
31138 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31142 if(box[0].size == 'md-left'){
31144 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31151 if(box[0].size == 'md-right'){
31153 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31154 y : minY + (this.unitWidth + this.gutter) * 1
31160 var rand = Math.floor(Math.random() * (4 - box[0].y));
31163 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31164 y : minY + (this.unitWidth + this.gutter) * rand
31171 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31175 if(box[0].size == 'xs'){
31178 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31183 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31184 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31192 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31197 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31198 y : minY + (this.unitWidth + this.gutter) * 2
31205 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31209 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31212 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31217 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31218 y : minY + (this.unitWidth + this.gutter) * 1
31222 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31223 y : minY + (this.unitWidth + this.gutter) * 2
31230 if(box[0].size == 'xs' && box[1].size == 'xs'){
31233 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31238 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31243 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31244 y : minY + (this.unitWidth + this.gutter) * 1
31252 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31257 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31258 y : minY + (this.unitWidth + this.gutter) * 2
31262 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31263 y : minY + (this.unitWidth + this.gutter) * 2
31270 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31274 if(box[0].size == 'xs'){
31277 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31282 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31287 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),
31292 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31293 y : minY + (this.unitWidth + this.gutter) * 1
31301 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31306 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31307 y : minY + (this.unitWidth + this.gutter) * 2
31311 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31312 y : minY + (this.unitWidth + this.gutter) * 2
31316 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31317 y : minY + (this.unitWidth + this.gutter) * 2
31325 * remove a Masonry Brick
31326 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31328 removeBrick : function(brick_id)
31334 for (var i = 0; i<this.bricks.length; i++) {
31335 if (this.bricks[i].id == brick_id) {
31336 this.bricks.splice(i,1);
31337 this.el.dom.removeChild(Roo.get(brick_id).dom);
31344 * adds a Masonry Brick
31345 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31347 addBrick : function(cfg)
31349 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31350 //this.register(cn);
31351 cn.parentId = this.id;
31352 cn.onRender(this.el, null);
31357 * register a Masonry Brick
31358 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31361 register : function(brick)
31363 this.bricks.push(brick);
31364 brick.masonryId = this.id;
31368 * clear all the Masonry Brick
31370 clearAll : function()
31373 //this.getChildContainer().dom.innerHTML = "";
31374 this.el.dom.innerHTML = '';
31377 getSelected : function()
31379 if (!this.selectedBrick) {
31383 return this.selectedBrick;
31387 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31391 * register a Masonry Layout
31392 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31395 register : function(layout)
31397 this.groups[layout.id] = layout;
31400 * fetch a Masonry Layout based on the masonry layout ID
31401 * @param {string} the masonry layout to add
31402 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31405 get: function(layout_id) {
31406 if (typeof(this.groups[layout_id]) == 'undefined') {
31409 return this.groups[layout_id] ;
31421 * http://masonry.desandro.com
31423 * The idea is to render all the bricks based on vertical width...
31425 * The original code extends 'outlayer' - we might need to use that....
31431 * @class Roo.bootstrap.LayoutMasonryAuto
31432 * @extends Roo.bootstrap.Component
31433 * Bootstrap Layout Masonry class
31436 * Create a new Element
31437 * @param {Object} config The config object
31440 Roo.bootstrap.LayoutMasonryAuto = function(config){
31441 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31444 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31447 * @cfg {Boolean} isFitWidth - resize the width..
31449 isFitWidth : false, // options..
31451 * @cfg {Boolean} isOriginLeft = left align?
31453 isOriginLeft : true,
31455 * @cfg {Boolean} isOriginTop = top align?
31457 isOriginTop : false,
31459 * @cfg {Boolean} isLayoutInstant = no animation?
31461 isLayoutInstant : false, // needed?
31463 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31465 isResizingContainer : true,
31467 * @cfg {Number} columnWidth width of the columns
31473 * @cfg {Number} maxCols maximum number of columns
31478 * @cfg {Number} padHeight padding below box..
31484 * @cfg {Boolean} isAutoInitial defalut true
31487 isAutoInitial : true,
31493 initialColumnWidth : 0,
31494 currentSize : null,
31496 colYs : null, // array.
31503 bricks: null, //CompositeElement
31504 cols : 0, // array?
31505 // element : null, // wrapped now this.el
31506 _isLayoutInited : null,
31509 getAutoCreate : function(){
31513 cls: 'blog-masonary-wrapper ' + this.cls,
31515 cls : 'mas-boxes masonary'
31522 getChildContainer: function( )
31524 if (this.boxesEl) {
31525 return this.boxesEl;
31528 this.boxesEl = this.el.select('.mas-boxes').first();
31530 return this.boxesEl;
31534 initEvents : function()
31538 if(this.isAutoInitial){
31539 Roo.log('hook children rendered');
31540 this.on('childrenrendered', function() {
31541 Roo.log('children rendered');
31548 initial : function()
31550 this.reloadItems();
31552 this.currentSize = this.el.getBox(true);
31554 /// was window resize... - let's see if this works..
31555 Roo.EventManager.onWindowResize(this.resize, this);
31557 if(!this.isAutoInitial){
31562 this.layout.defer(500,this);
31565 reloadItems: function()
31567 this.bricks = this.el.select('.masonry-brick', true);
31569 this.bricks.each(function(b) {
31570 //Roo.log(b.getSize());
31571 if (!b.attr('originalwidth')) {
31572 b.attr('originalwidth', b.getSize().width);
31577 Roo.log(this.bricks.elements.length);
31580 resize : function()
31583 var cs = this.el.getBox(true);
31585 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31586 Roo.log("no change in with or X");
31589 this.currentSize = cs;
31593 layout : function()
31596 this._resetLayout();
31597 //this._manageStamps();
31599 // don't animate first layout
31600 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31601 this.layoutItems( isInstant );
31603 // flag for initalized
31604 this._isLayoutInited = true;
31607 layoutItems : function( isInstant )
31609 //var items = this._getItemsForLayout( this.items );
31610 // original code supports filtering layout items.. we just ignore it..
31612 this._layoutItems( this.bricks , isInstant );
31614 this._postLayout();
31616 _layoutItems : function ( items , isInstant)
31618 //this.fireEvent( 'layout', this, items );
31621 if ( !items || !items.elements.length ) {
31622 // no items, emit event with empty array
31627 items.each(function(item) {
31628 Roo.log("layout item");
31630 // get x/y object from method
31631 var position = this._getItemLayoutPosition( item );
31633 position.item = item;
31634 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31635 queue.push( position );
31638 this._processLayoutQueue( queue );
31640 /** Sets position of item in DOM
31641 * @param {Element} item
31642 * @param {Number} x - horizontal position
31643 * @param {Number} y - vertical position
31644 * @param {Boolean} isInstant - disables transitions
31646 _processLayoutQueue : function( queue )
31648 for ( var i=0, len = queue.length; i < len; i++ ) {
31649 var obj = queue[i];
31650 obj.item.position('absolute');
31651 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31657 * Any logic you want to do after each layout,
31658 * i.e. size the container
31660 _postLayout : function()
31662 this.resizeContainer();
31665 resizeContainer : function()
31667 if ( !this.isResizingContainer ) {
31670 var size = this._getContainerSize();
31672 this.el.setSize(size.width,size.height);
31673 this.boxesEl.setSize(size.width,size.height);
31679 _resetLayout : function()
31681 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31682 this.colWidth = this.el.getWidth();
31683 //this.gutter = this.el.getWidth();
31685 this.measureColumns();
31691 this.colYs.push( 0 );
31697 measureColumns : function()
31699 this.getContainerWidth();
31700 // if columnWidth is 0, default to outerWidth of first item
31701 if ( !this.columnWidth ) {
31702 var firstItem = this.bricks.first();
31703 Roo.log(firstItem);
31704 this.columnWidth = this.containerWidth;
31705 if (firstItem && firstItem.attr('originalwidth') ) {
31706 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31708 // columnWidth fall back to item of first element
31709 Roo.log("set column width?");
31710 this.initialColumnWidth = this.columnWidth ;
31712 // if first elem has no width, default to size of container
31717 if (this.initialColumnWidth) {
31718 this.columnWidth = this.initialColumnWidth;
31723 // column width is fixed at the top - however if container width get's smaller we should
31726 // this bit calcs how man columns..
31728 var columnWidth = this.columnWidth += this.gutter;
31730 // calculate columns
31731 var containerWidth = this.containerWidth + this.gutter;
31733 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31734 // fix rounding errors, typically with gutters
31735 var excess = columnWidth - containerWidth % columnWidth;
31738 // if overshoot is less than a pixel, round up, otherwise floor it
31739 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31740 cols = Math[ mathMethod ]( cols );
31741 this.cols = Math.max( cols, 1 );
31742 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31744 // padding positioning..
31745 var totalColWidth = this.cols * this.columnWidth;
31746 var padavail = this.containerWidth - totalColWidth;
31747 // so for 2 columns - we need 3 'pads'
31749 var padNeeded = (1+this.cols) * this.padWidth;
31751 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31753 this.columnWidth += padExtra
31754 //this.padWidth = Math.floor(padavail / ( this.cols));
31756 // adjust colum width so that padding is fixed??
31758 // we have 3 columns ... total = width * 3
31759 // we have X left over... that should be used by
31761 //if (this.expandC) {
31769 getContainerWidth : function()
31771 /* // container is parent if fit width
31772 var container = this.isFitWidth ? this.element.parentNode : this.element;
31773 // check that this.size and size are there
31774 // IE8 triggers resize on body size change, so they might not be
31776 var size = getSize( container ); //FIXME
31777 this.containerWidth = size && size.innerWidth; //FIXME
31780 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31784 _getItemLayoutPosition : function( item ) // what is item?
31786 // we resize the item to our columnWidth..
31788 item.setWidth(this.columnWidth);
31789 item.autoBoxAdjust = false;
31791 var sz = item.getSize();
31793 // how many columns does this brick span
31794 var remainder = this.containerWidth % this.columnWidth;
31796 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31797 // round if off by 1 pixel, otherwise use ceil
31798 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31799 colSpan = Math.min( colSpan, this.cols );
31801 // normally this should be '1' as we dont' currently allow multi width columns..
31803 var colGroup = this._getColGroup( colSpan );
31804 // get the minimum Y value from the columns
31805 var minimumY = Math.min.apply( Math, colGroup );
31806 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31808 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31810 // position the brick
31812 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31813 y: this.currentSize.y + minimumY + this.padHeight
31817 // apply setHeight to necessary columns
31818 var setHeight = minimumY + sz.height + this.padHeight;
31819 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31821 var setSpan = this.cols + 1 - colGroup.length;
31822 for ( var i = 0; i < setSpan; i++ ) {
31823 this.colYs[ shortColIndex + i ] = setHeight ;
31830 * @param {Number} colSpan - number of columns the element spans
31831 * @returns {Array} colGroup
31833 _getColGroup : function( colSpan )
31835 if ( colSpan < 2 ) {
31836 // if brick spans only one column, use all the column Ys
31841 // how many different places could this brick fit horizontally
31842 var groupCount = this.cols + 1 - colSpan;
31843 // for each group potential horizontal position
31844 for ( var i = 0; i < groupCount; i++ ) {
31845 // make an array of colY values for that one group
31846 var groupColYs = this.colYs.slice( i, i + colSpan );
31847 // and get the max value of the array
31848 colGroup[i] = Math.max.apply( Math, groupColYs );
31853 _manageStamp : function( stamp )
31855 var stampSize = stamp.getSize();
31856 var offset = stamp.getBox();
31857 // get the columns that this stamp affects
31858 var firstX = this.isOriginLeft ? offset.x : offset.right;
31859 var lastX = firstX + stampSize.width;
31860 var firstCol = Math.floor( firstX / this.columnWidth );
31861 firstCol = Math.max( 0, firstCol );
31863 var lastCol = Math.floor( lastX / this.columnWidth );
31864 // lastCol should not go over if multiple of columnWidth #425
31865 lastCol -= lastX % this.columnWidth ? 0 : 1;
31866 lastCol = Math.min( this.cols - 1, lastCol );
31868 // set colYs to bottom of the stamp
31869 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31872 for ( var i = firstCol; i <= lastCol; i++ ) {
31873 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31878 _getContainerSize : function()
31880 this.maxY = Math.max.apply( Math, this.colYs );
31885 if ( this.isFitWidth ) {
31886 size.width = this._getContainerFitWidth();
31892 _getContainerFitWidth : function()
31894 var unusedCols = 0;
31895 // count unused columns
31898 if ( this.colYs[i] !== 0 ) {
31903 // fit container to columns that have been used
31904 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31907 needsResizeLayout : function()
31909 var previousWidth = this.containerWidth;
31910 this.getContainerWidth();
31911 return previousWidth !== this.containerWidth;
31926 * @class Roo.bootstrap.MasonryBrick
31927 * @extends Roo.bootstrap.Component
31928 * Bootstrap MasonryBrick class
31931 * Create a new MasonryBrick
31932 * @param {Object} config The config object
31935 Roo.bootstrap.MasonryBrick = function(config){
31936 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31942 * When a MasonryBrick is clcik
31943 * @param {Roo.bootstrap.MasonryBrick} this
31944 * @param {Roo.EventObject} e
31950 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31953 * @cfg {String} title
31957 * @cfg {String} html
31961 * @cfg {String} bgimage
31965 * @cfg {String} videourl
31969 * @cfg {String} cls
31973 * @cfg {String} href
31977 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31982 * @cfg {String} placetitle (center|bottom)
31987 * @cfg {Boolean} isFitContainer defalut true
31989 isFitContainer : true,
31992 * @cfg {Boolean} preventDefault defalut false
31994 preventDefault : false,
31997 * @cfg {Boolean} inverse defalut false
31999 maskInverse : false,
32001 getAutoCreate : function()
32003 if(!this.isFitContainer){
32004 return this.getSplitAutoCreate();
32007 var cls = 'masonry-brick masonry-brick-full';
32009 if(this.href.length){
32010 cls += ' masonry-brick-link';
32013 if(this.bgimage.length){
32014 cls += ' masonry-brick-image';
32017 if(this.maskInverse){
32018 cls += ' mask-inverse';
32021 if(!this.html.length && !this.maskInverse){
32022 cls += ' enable-mask';
32026 cls += ' masonry-' + this.size + '-brick';
32029 if(this.placetitle.length){
32031 switch (this.placetitle) {
32033 cls += ' masonry-center-title';
32036 cls += ' masonry-bottom-title';
32043 if(!this.html.length && !this.bgimage.length){
32044 cls += ' masonry-center-title';
32047 if(!this.html.length && this.bgimage.length){
32048 cls += ' masonry-bottom-title';
32053 cls += ' ' + this.cls;
32057 tag: (this.href.length) ? 'a' : 'div',
32062 cls: 'masonry-brick-paragraph',
32068 if(this.href.length){
32069 cfg.href = this.href;
32072 var cn = cfg.cn[0].cn;
32074 if(this.title.length){
32077 cls: 'masonry-brick-title',
32082 if(this.html.length){
32085 cls: 'masonry-brick-text',
32089 if (!this.title.length && !this.html.length) {
32090 cfg.cn[0].cls += ' hide';
32093 if(this.bgimage.length){
32096 cls: 'masonry-brick-image-view',
32101 if(this.videourl.length){
32102 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32103 // youtube support only?
32106 cls: 'masonry-brick-image-view',
32109 allowfullscreen : true
32117 cls: 'masonry-brick-mask'
32124 getSplitAutoCreate : function()
32126 var cls = 'masonry-brick masonry-brick-split';
32128 if(this.href.length){
32129 cls += ' masonry-brick-link';
32132 if(this.bgimage.length){
32133 cls += ' masonry-brick-image';
32137 cls += ' masonry-' + this.size + '-brick';
32140 switch (this.placetitle) {
32142 cls += ' masonry-center-title';
32145 cls += ' masonry-bottom-title';
32148 if(!this.bgimage.length){
32149 cls += ' masonry-center-title';
32152 if(this.bgimage.length){
32153 cls += ' masonry-bottom-title';
32159 cls += ' ' + this.cls;
32163 tag: (this.href.length) ? 'a' : 'div',
32168 cls: 'masonry-brick-split-head',
32172 cls: 'masonry-brick-paragraph',
32179 cls: 'masonry-brick-split-body',
32185 if(this.href.length){
32186 cfg.href = this.href;
32189 if(this.title.length){
32190 cfg.cn[0].cn[0].cn.push({
32192 cls: 'masonry-brick-title',
32197 if(this.html.length){
32198 cfg.cn[1].cn.push({
32200 cls: 'masonry-brick-text',
32205 if(this.bgimage.length){
32206 cfg.cn[0].cn.push({
32208 cls: 'masonry-brick-image-view',
32213 if(this.videourl.length){
32214 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32215 // youtube support only?
32216 cfg.cn[0].cn.cn.push({
32218 cls: 'masonry-brick-image-view',
32221 allowfullscreen : true
32228 initEvents: function()
32230 switch (this.size) {
32263 this.el.on('touchstart', this.onTouchStart, this);
32264 this.el.on('touchmove', this.onTouchMove, this);
32265 this.el.on('touchend', this.onTouchEnd, this);
32266 this.el.on('contextmenu', this.onContextMenu, this);
32268 this.el.on('mouseenter' ,this.enter, this);
32269 this.el.on('mouseleave', this.leave, this);
32270 this.el.on('click', this.onClick, this);
32273 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32274 this.parent().bricks.push(this);
32279 onClick: function(e, el)
32281 var time = this.endTimer - this.startTimer;
32282 // Roo.log(e.preventDefault());
32285 e.preventDefault();
32290 if(!this.preventDefault){
32294 e.preventDefault();
32296 if (this.activcClass != '') {
32297 this.selectBrick();
32300 this.fireEvent('click', this);
32303 enter: function(e, el)
32305 e.preventDefault();
32307 if(!this.isFitContainer || this.maskInverse){
32311 if(this.bgimage.length && this.html.length){
32312 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32316 leave: function(e, el)
32318 e.preventDefault();
32320 if(!this.isFitContainer || this.maskInverse){
32324 if(this.bgimage.length && this.html.length){
32325 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32329 onTouchStart: function(e, el)
32331 // e.preventDefault();
32333 this.touchmoved = false;
32335 if(!this.isFitContainer){
32339 if(!this.bgimage.length || !this.html.length){
32343 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32345 this.timer = new Date().getTime();
32349 onTouchMove: function(e, el)
32351 this.touchmoved = true;
32354 onContextMenu : function(e,el)
32356 e.preventDefault();
32357 e.stopPropagation();
32361 onTouchEnd: function(e, el)
32363 // e.preventDefault();
32365 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32372 if(!this.bgimage.length || !this.html.length){
32374 if(this.href.length){
32375 window.location.href = this.href;
32381 if(!this.isFitContainer){
32385 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32387 window.location.href = this.href;
32390 selectBrick : function() {
32392 if (!this.parentId) {
32396 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32397 var index = m.selectedBrick.indexOf(this.id);
32400 m.selectedBrick.splice(index,1);
32401 this.el.removeClass(this.activeClass);
32405 m.selectedBrick.push(this.id);
32406 this.el.addClass(this.activeClass);
32422 * @class Roo.bootstrap.Brick
32423 * @extends Roo.bootstrap.Component
32424 * Bootstrap Brick class
32427 * Create a new Brick
32428 * @param {Object} config The config object
32431 Roo.bootstrap.Brick = function(config){
32432 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32438 * When a Brick is click
32439 * @param {Roo.bootstrap.Brick} this
32440 * @param {Roo.EventObject} e
32446 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32449 * @cfg {String} title
32453 * @cfg {String} html
32457 * @cfg {String} bgimage
32461 * @cfg {String} cls
32465 * @cfg {String} href
32469 * @cfg {String} video
32473 * @cfg {Boolean} square
32477 getAutoCreate : function()
32479 var cls = 'roo-brick';
32481 if(this.href.length){
32482 cls += ' roo-brick-link';
32485 if(this.bgimage.length){
32486 cls += ' roo-brick-image';
32489 if(!this.html.length && !this.bgimage.length){
32490 cls += ' roo-brick-center-title';
32493 if(!this.html.length && this.bgimage.length){
32494 cls += ' roo-brick-bottom-title';
32498 cls += ' ' + this.cls;
32502 tag: (this.href.length) ? 'a' : 'div',
32507 cls: 'roo-brick-paragraph',
32513 if(this.href.length){
32514 cfg.href = this.href;
32517 var cn = cfg.cn[0].cn;
32519 if(this.title.length){
32522 cls: 'roo-brick-title',
32527 if(this.html.length){
32530 cls: 'roo-brick-text',
32537 if(this.bgimage.length){
32540 cls: 'roo-brick-image-view',
32548 initEvents: function()
32550 if(this.title.length || this.html.length){
32551 this.el.on('mouseenter' ,this.enter, this);
32552 this.el.on('mouseleave', this.leave, this);
32556 Roo.EventManager.onWindowResize(this.resize, this);
32561 resize : function()
32563 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32565 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32567 if(this.bgimage.length){
32568 var image = this.el.select('.roo-brick-image-view', true).first();
32569 image.setWidth(paragraph.getWidth());
32570 image.setHeight(paragraph.getWidth());
32572 this.el.setHeight(paragraph.getWidth());
32578 enter: function(e, el)
32580 e.preventDefault();
32582 if(this.bgimage.length){
32583 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32584 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32588 leave: function(e, el)
32590 e.preventDefault();
32592 if(this.bgimage.length){
32593 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32594 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32610 * @class Roo.bootstrap.NumberField
32611 * @extends Roo.bootstrap.Input
32612 * Bootstrap NumberField class
32618 * Create a new NumberField
32619 * @param {Object} config The config object
32622 Roo.bootstrap.NumberField = function(config){
32623 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32626 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32629 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32631 allowDecimals : true,
32633 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32635 decimalSeparator : ".",
32637 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32639 decimalPrecision : 2,
32641 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32643 allowNegative : true,
32645 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32647 minValue : Number.NEGATIVE_INFINITY,
32649 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32651 maxValue : Number.MAX_VALUE,
32653 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32655 minText : "The minimum value for this field is {0}",
32657 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32659 maxText : "The maximum value for this field is {0}",
32661 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32662 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32664 nanText : "{0} is not a valid number",
32666 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32671 initEvents : function()
32673 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32675 var allowed = "0123456789";
32677 if(this.allowDecimals){
32678 allowed += this.decimalSeparator;
32681 if(this.allowNegative){
32685 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32687 var keyPress = function(e){
32689 var k = e.getKey();
32691 var c = e.getCharCode();
32694 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32695 allowed.indexOf(String.fromCharCode(c)) === -1
32701 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32705 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32710 this.el.on("keypress", keyPress, this);
32713 validateValue : function(value)
32716 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32720 var num = this.parseValue(value);
32723 this.markInvalid(String.format(this.nanText, value));
32727 if(num < this.minValue){
32728 this.markInvalid(String.format(this.minText, this.minValue));
32732 if(num > this.maxValue){
32733 this.markInvalid(String.format(this.maxText, this.maxValue));
32740 getValue : function()
32742 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32745 parseValue : function(value)
32747 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32748 return isNaN(value) ? '' : value;
32751 fixPrecision : function(value)
32753 var nan = isNaN(value);
32755 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32756 return nan ? '' : value;
32758 return parseFloat(value).toFixed(this.decimalPrecision);
32761 setValue : function(v)
32763 v = this.fixPrecision(v);
32764 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32767 decimalPrecisionFcn : function(v)
32769 return Math.floor(v);
32772 beforeBlur : function()
32778 var v = this.parseValue(this.getRawValue());
32793 * @class Roo.bootstrap.DocumentSlider
32794 * @extends Roo.bootstrap.Component
32795 * Bootstrap DocumentSlider class
32798 * Create a new DocumentViewer
32799 * @param {Object} config The config object
32802 Roo.bootstrap.DocumentSlider = function(config){
32803 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32810 * Fire after initEvent
32811 * @param {Roo.bootstrap.DocumentSlider} this
32816 * Fire after update
32817 * @param {Roo.bootstrap.DocumentSlider} this
32823 * @param {Roo.bootstrap.DocumentSlider} this
32829 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32835 getAutoCreate : function()
32839 cls : 'roo-document-slider',
32843 cls : 'roo-document-slider-header',
32847 cls : 'roo-document-slider-header-title'
32853 cls : 'roo-document-slider-body',
32857 cls : 'roo-document-slider-prev',
32861 cls : 'fa fa-chevron-left'
32867 cls : 'roo-document-slider-thumb',
32871 cls : 'roo-document-slider-image'
32877 cls : 'roo-document-slider-next',
32881 cls : 'fa fa-chevron-right'
32893 initEvents : function()
32895 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32896 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32898 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32899 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32901 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32902 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32904 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32905 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32907 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32908 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32910 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32911 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32913 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32914 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32916 this.thumbEl.on('click', this.onClick, this);
32918 this.prevIndicator.on('click', this.prev, this);
32920 this.nextIndicator.on('click', this.next, this);
32924 initial : function()
32926 if(this.files.length){
32927 this.indicator = 1;
32931 this.fireEvent('initial', this);
32934 update : function()
32936 this.imageEl.attr('src', this.files[this.indicator - 1]);
32938 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32940 this.prevIndicator.show();
32942 if(this.indicator == 1){
32943 this.prevIndicator.hide();
32946 this.nextIndicator.show();
32948 if(this.indicator == this.files.length){
32949 this.nextIndicator.hide();
32952 this.thumbEl.scrollTo('top');
32954 this.fireEvent('update', this);
32957 onClick : function(e)
32959 e.preventDefault();
32961 this.fireEvent('click', this);
32966 e.preventDefault();
32968 this.indicator = Math.max(1, this.indicator - 1);
32975 e.preventDefault();
32977 this.indicator = Math.min(this.files.length, this.indicator + 1);
32991 * @class Roo.bootstrap.RadioSet
32992 * @extends Roo.bootstrap.Input
32993 * Bootstrap RadioSet class
32994 * @cfg {String} indicatorpos (left|right) default left
32995 * @cfg {Boolean} inline (true|false) inline the element (default true)
32996 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32998 * Create a new RadioSet
32999 * @param {Object} config The config object
33002 Roo.bootstrap.RadioSet = function(config){
33004 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33008 Roo.bootstrap.RadioSet.register(this);
33013 * Fires when the element is checked or unchecked.
33014 * @param {Roo.bootstrap.RadioSet} this This radio
33015 * @param {Roo.bootstrap.Radio} item The checked item
33022 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33030 indicatorpos : 'left',
33032 getAutoCreate : function()
33036 cls : 'roo-radio-set-label',
33040 html : this.fieldLabel
33045 if(this.indicatorpos == 'left'){
33048 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33049 tooltip : 'This field is required'
33054 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33055 tooltip : 'This field is required'
33061 cls : 'roo-radio-set-items'
33064 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33066 if (align === 'left' && this.fieldLabel.length) {
33069 cls : "roo-radio-set-right",
33075 if(this.labelWidth > 12){
33076 label.style = "width: " + this.labelWidth + 'px';
33079 if(this.labelWidth < 13 && this.labelmd == 0){
33080 this.labelmd = this.labelWidth;
33083 if(this.labellg > 0){
33084 label.cls += ' col-lg-' + this.labellg;
33085 items.cls += ' col-lg-' + (12 - this.labellg);
33088 if(this.labelmd > 0){
33089 label.cls += ' col-md-' + this.labelmd;
33090 items.cls += ' col-md-' + (12 - this.labelmd);
33093 if(this.labelsm > 0){
33094 label.cls += ' col-sm-' + this.labelsm;
33095 items.cls += ' col-sm-' + (12 - this.labelsm);
33098 if(this.labelxs > 0){
33099 label.cls += ' col-xs-' + this.labelxs;
33100 items.cls += ' col-xs-' + (12 - this.labelxs);
33106 cls : 'roo-radio-set',
33110 cls : 'roo-radio-set-input',
33113 value : this.value ? this.value : ''
33120 if(this.weight.length){
33121 cfg.cls += ' roo-radio-' + this.weight;
33125 cfg.cls += ' roo-radio-set-inline';
33132 initEvents : function()
33134 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33135 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33137 if(!this.fieldLabel.length){
33138 this.labelEl.hide();
33141 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33142 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33144 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33145 this.indicatorEl().hide();
33147 this.originalValue = this.getValue();
33151 inputEl: function ()
33153 return this.el.select('.roo-radio-set-input', true).first();
33156 getChildContainer : function()
33158 return this.itemsEl;
33161 register : function(item)
33163 this.radioes.push(item);
33167 validate : function()
33171 Roo.each(this.radioes, function(i){
33180 if(this.allowBlank) {
33184 if(this.disabled || valid){
33189 this.markInvalid();
33194 markValid : function()
33196 if(this.labelEl.isVisible(true)){
33197 this.indicatorEl().hide();
33200 this.el.removeClass([this.invalidClass, this.validClass]);
33201 this.el.addClass(this.validClass);
33203 this.fireEvent('valid', this);
33206 markInvalid : function(msg)
33208 if(this.allowBlank || this.disabled){
33212 if(this.labelEl.isVisible(true)){
33213 this.indicatorEl().show();
33216 this.el.removeClass([this.invalidClass, this.validClass]);
33217 this.el.addClass(this.invalidClass);
33219 this.fireEvent('invalid', this, msg);
33223 setValue : function(v, suppressEvent)
33225 Roo.each(this.radioes, function(i){
33228 i.el.removeClass('checked');
33230 if(i.value === v || i.value.toString() === v.toString()){
33232 i.el.addClass('checked');
33234 if(suppressEvent !== true){
33235 this.fireEvent('check', this, i);
33241 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
33245 clearInvalid : function(){
33247 if(!this.el || this.preventMark){
33252 if(this.labelEl.isVisible(true)){
33253 this.indicatorEl().hide();
33257 this.el.removeClass([this.invalidClass]);
33259 this.fireEvent('valid', this);
33264 Roo.apply(Roo.bootstrap.RadioSet, {
33268 register : function(set)
33270 this.groups[set.name] = set;
33273 get: function(name)
33275 if (typeof(this.groups[name]) == 'undefined') {
33279 return this.groups[name] ;
33285 * Ext JS Library 1.1.1
33286 * Copyright(c) 2006-2007, Ext JS, LLC.
33288 * Originally Released Under LGPL - original licence link has changed is not relivant.
33291 * <script type="text/javascript">
33296 * @class Roo.bootstrap.SplitBar
33297 * @extends Roo.util.Observable
33298 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33302 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33303 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33304 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33305 split.minSize = 100;
33306 split.maxSize = 600;
33307 split.animate = true;
33308 split.on('moved', splitterMoved);
33311 * Create a new SplitBar
33312 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33313 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33314 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33315 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33316 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33317 position of the SplitBar).
33319 Roo.bootstrap.SplitBar = function(cfg){
33324 // dragElement : elm
33325 // resizingElement: el,
33327 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33328 // placement : Roo.bootstrap.SplitBar.LEFT ,
33329 // existingProxy ???
33332 this.el = Roo.get(cfg.dragElement, true);
33333 this.el.dom.unselectable = "on";
33335 this.resizingEl = Roo.get(cfg.resizingElement, true);
33339 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33340 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33343 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33346 * The minimum size of the resizing element. (Defaults to 0)
33352 * The maximum size of the resizing element. (Defaults to 2000)
33355 this.maxSize = 2000;
33358 * Whether to animate the transition to the new size
33361 this.animate = false;
33364 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33367 this.useShim = false;
33372 if(!cfg.existingProxy){
33374 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33376 this.proxy = Roo.get(cfg.existingProxy).dom;
33379 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33382 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33385 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33388 this.dragSpecs = {};
33391 * @private The adapter to use to positon and resize elements
33393 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33394 this.adapter.init(this);
33396 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33398 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33399 this.el.addClass("roo-splitbar-h");
33402 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33403 this.el.addClass("roo-splitbar-v");
33409 * Fires when the splitter is moved (alias for {@link #event-moved})
33410 * @param {Roo.bootstrap.SplitBar} this
33411 * @param {Number} newSize the new width or height
33416 * Fires when the splitter is moved
33417 * @param {Roo.bootstrap.SplitBar} this
33418 * @param {Number} newSize the new width or height
33422 * @event beforeresize
33423 * Fires before the splitter is dragged
33424 * @param {Roo.bootstrap.SplitBar} this
33426 "beforeresize" : true,
33428 "beforeapply" : true
33431 Roo.util.Observable.call(this);
33434 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33435 onStartProxyDrag : function(x, y){
33436 this.fireEvent("beforeresize", this);
33438 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33440 o.enableDisplayMode("block");
33441 // all splitbars share the same overlay
33442 Roo.bootstrap.SplitBar.prototype.overlay = o;
33444 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33445 this.overlay.show();
33446 Roo.get(this.proxy).setDisplayed("block");
33447 var size = this.adapter.getElementSize(this);
33448 this.activeMinSize = this.getMinimumSize();;
33449 this.activeMaxSize = this.getMaximumSize();;
33450 var c1 = size - this.activeMinSize;
33451 var c2 = Math.max(this.activeMaxSize - size, 0);
33452 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33453 this.dd.resetConstraints();
33454 this.dd.setXConstraint(
33455 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33456 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33458 this.dd.setYConstraint(0, 0);
33460 this.dd.resetConstraints();
33461 this.dd.setXConstraint(0, 0);
33462 this.dd.setYConstraint(
33463 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33464 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33467 this.dragSpecs.startSize = size;
33468 this.dragSpecs.startPoint = [x, y];
33469 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33473 * @private Called after the drag operation by the DDProxy
33475 onEndProxyDrag : function(e){
33476 Roo.get(this.proxy).setDisplayed(false);
33477 var endPoint = Roo.lib.Event.getXY(e);
33479 this.overlay.hide();
33482 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33483 newSize = this.dragSpecs.startSize +
33484 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33485 endPoint[0] - this.dragSpecs.startPoint[0] :
33486 this.dragSpecs.startPoint[0] - endPoint[0]
33489 newSize = this.dragSpecs.startSize +
33490 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33491 endPoint[1] - this.dragSpecs.startPoint[1] :
33492 this.dragSpecs.startPoint[1] - endPoint[1]
33495 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33496 if(newSize != this.dragSpecs.startSize){
33497 if(this.fireEvent('beforeapply', this, newSize) !== false){
33498 this.adapter.setElementSize(this, newSize);
33499 this.fireEvent("moved", this, newSize);
33500 this.fireEvent("resize", this, newSize);
33506 * Get the adapter this SplitBar uses
33507 * @return The adapter object
33509 getAdapter : function(){
33510 return this.adapter;
33514 * Set the adapter this SplitBar uses
33515 * @param {Object} adapter A SplitBar adapter object
33517 setAdapter : function(adapter){
33518 this.adapter = adapter;
33519 this.adapter.init(this);
33523 * Gets the minimum size for the resizing element
33524 * @return {Number} The minimum size
33526 getMinimumSize : function(){
33527 return this.minSize;
33531 * Sets the minimum size for the resizing element
33532 * @param {Number} minSize The minimum size
33534 setMinimumSize : function(minSize){
33535 this.minSize = minSize;
33539 * Gets the maximum size for the resizing element
33540 * @return {Number} The maximum size
33542 getMaximumSize : function(){
33543 return this.maxSize;
33547 * Sets the maximum size for the resizing element
33548 * @param {Number} maxSize The maximum size
33550 setMaximumSize : function(maxSize){
33551 this.maxSize = maxSize;
33555 * Sets the initialize size for the resizing element
33556 * @param {Number} size The initial size
33558 setCurrentSize : function(size){
33559 var oldAnimate = this.animate;
33560 this.animate = false;
33561 this.adapter.setElementSize(this, size);
33562 this.animate = oldAnimate;
33566 * Destroy this splitbar.
33567 * @param {Boolean} removeEl True to remove the element
33569 destroy : function(removeEl){
33571 this.shim.remove();
33574 this.proxy.parentNode.removeChild(this.proxy);
33582 * @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.
33584 Roo.bootstrap.SplitBar.createProxy = function(dir){
33585 var proxy = new Roo.Element(document.createElement("div"));
33586 proxy.unselectable();
33587 var cls = 'roo-splitbar-proxy';
33588 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33589 document.body.appendChild(proxy.dom);
33594 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33595 * Default Adapter. It assumes the splitter and resizing element are not positioned
33596 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33598 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33601 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33602 // do nothing for now
33603 init : function(s){
33607 * Called before drag operations to get the current size of the resizing element.
33608 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33610 getElementSize : function(s){
33611 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33612 return s.resizingEl.getWidth();
33614 return s.resizingEl.getHeight();
33619 * Called after drag operations to set the size of the resizing element.
33620 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33621 * @param {Number} newSize The new size to set
33622 * @param {Function} onComplete A function to be invoked when resizing is complete
33624 setElementSize : function(s, newSize, onComplete){
33625 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33627 s.resizingEl.setWidth(newSize);
33629 onComplete(s, newSize);
33632 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33637 s.resizingEl.setHeight(newSize);
33639 onComplete(s, newSize);
33642 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33649 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33650 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33651 * Adapter that moves the splitter element to align with the resized sizing element.
33652 * Used with an absolute positioned SplitBar.
33653 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33654 * document.body, make sure you assign an id to the body element.
33656 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33657 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33658 this.container = Roo.get(container);
33661 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33662 init : function(s){
33663 this.basic.init(s);
33666 getElementSize : function(s){
33667 return this.basic.getElementSize(s);
33670 setElementSize : function(s, newSize, onComplete){
33671 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33674 moveSplitter : function(s){
33675 var yes = Roo.bootstrap.SplitBar;
33676 switch(s.placement){
33678 s.el.setX(s.resizingEl.getRight());
33681 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33684 s.el.setY(s.resizingEl.getBottom());
33687 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33694 * Orientation constant - Create a vertical SplitBar
33698 Roo.bootstrap.SplitBar.VERTICAL = 1;
33701 * Orientation constant - Create a horizontal SplitBar
33705 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33708 * Placement constant - The resizing element is to the left of the splitter element
33712 Roo.bootstrap.SplitBar.LEFT = 1;
33715 * Placement constant - The resizing element is to the right of the splitter element
33719 Roo.bootstrap.SplitBar.RIGHT = 2;
33722 * Placement constant - The resizing element is positioned above the splitter element
33726 Roo.bootstrap.SplitBar.TOP = 3;
33729 * Placement constant - The resizing element is positioned under splitter element
33733 Roo.bootstrap.SplitBar.BOTTOM = 4;
33734 Roo.namespace("Roo.bootstrap.layout");/*
33736 * Ext JS Library 1.1.1
33737 * Copyright(c) 2006-2007, Ext JS, LLC.
33739 * Originally Released Under LGPL - original licence link has changed is not relivant.
33742 * <script type="text/javascript">
33746 * @class Roo.bootstrap.layout.Manager
33747 * @extends Roo.bootstrap.Component
33748 * Base class for layout managers.
33750 Roo.bootstrap.layout.Manager = function(config)
33752 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33758 /** false to disable window resize monitoring @type Boolean */
33759 this.monitorWindowResize = true;
33764 * Fires when a layout is performed.
33765 * @param {Roo.LayoutManager} this
33769 * @event regionresized
33770 * Fires when the user resizes a region.
33771 * @param {Roo.LayoutRegion} region The resized region
33772 * @param {Number} newSize The new size (width for east/west, height for north/south)
33774 "regionresized" : true,
33776 * @event regioncollapsed
33777 * Fires when a region is collapsed.
33778 * @param {Roo.LayoutRegion} region The collapsed region
33780 "regioncollapsed" : true,
33782 * @event regionexpanded
33783 * Fires when a region is expanded.
33784 * @param {Roo.LayoutRegion} region The expanded region
33786 "regionexpanded" : true
33788 this.updating = false;
33791 this.el = Roo.get(config.el);
33797 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33802 monitorWindowResize : true,
33808 onRender : function(ct, position)
33811 this.el = Roo.get(ct);
33814 //this.fireEvent('render',this);
33818 initEvents: function()
33822 // ie scrollbar fix
33823 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33824 document.body.scroll = "no";
33825 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33826 this.el.position('relative');
33828 this.id = this.el.id;
33829 this.el.addClass("roo-layout-container");
33830 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33831 if(this.el.dom != document.body ) {
33832 this.el.on('resize', this.layout,this);
33833 this.el.on('show', this.layout,this);
33839 * Returns true if this layout is currently being updated
33840 * @return {Boolean}
33842 isUpdating : function(){
33843 return this.updating;
33847 * Suspend the LayoutManager from doing auto-layouts while
33848 * making multiple add or remove calls
33850 beginUpdate : function(){
33851 this.updating = true;
33855 * Restore auto-layouts and optionally disable the manager from performing a layout
33856 * @param {Boolean} noLayout true to disable a layout update
33858 endUpdate : function(noLayout){
33859 this.updating = false;
33865 layout: function(){
33869 onRegionResized : function(region, newSize){
33870 this.fireEvent("regionresized", region, newSize);
33874 onRegionCollapsed : function(region){
33875 this.fireEvent("regioncollapsed", region);
33878 onRegionExpanded : function(region){
33879 this.fireEvent("regionexpanded", region);
33883 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33884 * performs box-model adjustments.
33885 * @return {Object} The size as an object {width: (the width), height: (the height)}
33887 getViewSize : function()
33890 if(this.el.dom != document.body){
33891 size = this.el.getSize();
33893 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33895 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33896 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33901 * Returns the Element this layout is bound to.
33902 * @return {Roo.Element}
33904 getEl : function(){
33909 * Returns the specified region.
33910 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33911 * @return {Roo.LayoutRegion}
33913 getRegion : function(target){
33914 return this.regions[target.toLowerCase()];
33917 onWindowResize : function(){
33918 if(this.monitorWindowResize){
33925 * Ext JS Library 1.1.1
33926 * Copyright(c) 2006-2007, Ext JS, LLC.
33928 * Originally Released Under LGPL - original licence link has changed is not relivant.
33931 * <script type="text/javascript">
33934 * @class Roo.bootstrap.layout.Border
33935 * @extends Roo.bootstrap.layout.Manager
33936 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33937 * please see: examples/bootstrap/nested.html<br><br>
33939 <b>The container the layout is rendered into can be either the body element or any other element.
33940 If it is not the body element, the container needs to either be an absolute positioned element,
33941 or you will need to add "position:relative" to the css of the container. You will also need to specify
33942 the container size if it is not the body element.</b>
33945 * Create a new Border
33946 * @param {Object} config Configuration options
33948 Roo.bootstrap.layout.Border = function(config){
33949 config = config || {};
33950 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33954 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33955 if(config[region]){
33956 config[region].region = region;
33957 this.addRegion(config[region]);
33963 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33965 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33967 * Creates and adds a new region if it doesn't already exist.
33968 * @param {String} target The target region key (north, south, east, west or center).
33969 * @param {Object} config The regions config object
33970 * @return {BorderLayoutRegion} The new region
33972 addRegion : function(config)
33974 if(!this.regions[config.region]){
33975 var r = this.factory(config);
33976 this.bindRegion(r);
33978 return this.regions[config.region];
33982 bindRegion : function(r){
33983 this.regions[r.config.region] = r;
33985 r.on("visibilitychange", this.layout, this);
33986 r.on("paneladded", this.layout, this);
33987 r.on("panelremoved", this.layout, this);
33988 r.on("invalidated", this.layout, this);
33989 r.on("resized", this.onRegionResized, this);
33990 r.on("collapsed", this.onRegionCollapsed, this);
33991 r.on("expanded", this.onRegionExpanded, this);
33995 * Performs a layout update.
33997 layout : function()
33999 if(this.updating) {
34003 // render all the rebions if they have not been done alreayd?
34004 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34005 if(this.regions[region] && !this.regions[region].bodyEl){
34006 this.regions[region].onRender(this.el)
34010 var size = this.getViewSize();
34011 var w = size.width;
34012 var h = size.height;
34017 //var x = 0, y = 0;
34019 var rs = this.regions;
34020 var north = rs["north"];
34021 var south = rs["south"];
34022 var west = rs["west"];
34023 var east = rs["east"];
34024 var center = rs["center"];
34025 //if(this.hideOnLayout){ // not supported anymore
34026 //c.el.setStyle("display", "none");
34028 if(north && north.isVisible()){
34029 var b = north.getBox();
34030 var m = north.getMargins();
34031 b.width = w - (m.left+m.right);
34034 centerY = b.height + b.y + m.bottom;
34035 centerH -= centerY;
34036 north.updateBox(this.safeBox(b));
34038 if(south && south.isVisible()){
34039 var b = south.getBox();
34040 var m = south.getMargins();
34041 b.width = w - (m.left+m.right);
34043 var totalHeight = (b.height + m.top + m.bottom);
34044 b.y = h - totalHeight + m.top;
34045 centerH -= totalHeight;
34046 south.updateBox(this.safeBox(b));
34048 if(west && west.isVisible()){
34049 var b = west.getBox();
34050 var m = west.getMargins();
34051 b.height = centerH - (m.top+m.bottom);
34053 b.y = centerY + m.top;
34054 var totalWidth = (b.width + m.left + m.right);
34055 centerX += totalWidth;
34056 centerW -= totalWidth;
34057 west.updateBox(this.safeBox(b));
34059 if(east && east.isVisible()){
34060 var b = east.getBox();
34061 var m = east.getMargins();
34062 b.height = centerH - (m.top+m.bottom);
34063 var totalWidth = (b.width + m.left + m.right);
34064 b.x = w - totalWidth + m.left;
34065 b.y = centerY + m.top;
34066 centerW -= totalWidth;
34067 east.updateBox(this.safeBox(b));
34070 var m = center.getMargins();
34072 x: centerX + m.left,
34073 y: centerY + m.top,
34074 width: centerW - (m.left+m.right),
34075 height: centerH - (m.top+m.bottom)
34077 //if(this.hideOnLayout){
34078 //center.el.setStyle("display", "block");
34080 center.updateBox(this.safeBox(centerBox));
34083 this.fireEvent("layout", this);
34087 safeBox : function(box){
34088 box.width = Math.max(0, box.width);
34089 box.height = Math.max(0, box.height);
34094 * Adds a ContentPanel (or subclass) to this layout.
34095 * @param {String} target The target region key (north, south, east, west or center).
34096 * @param {Roo.ContentPanel} panel The panel to add
34097 * @return {Roo.ContentPanel} The added panel
34099 add : function(target, panel){
34101 target = target.toLowerCase();
34102 return this.regions[target].add(panel);
34106 * Remove a ContentPanel (or subclass) to this layout.
34107 * @param {String} target The target region key (north, south, east, west or center).
34108 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34109 * @return {Roo.ContentPanel} The removed panel
34111 remove : function(target, panel){
34112 target = target.toLowerCase();
34113 return this.regions[target].remove(panel);
34117 * Searches all regions for a panel with the specified id
34118 * @param {String} panelId
34119 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34121 findPanel : function(panelId){
34122 var rs = this.regions;
34123 for(var target in rs){
34124 if(typeof rs[target] != "function"){
34125 var p = rs[target].getPanel(panelId);
34135 * Searches all regions for a panel with the specified id and activates (shows) it.
34136 * @param {String/ContentPanel} panelId The panels id or the panel itself
34137 * @return {Roo.ContentPanel} The shown panel or null
34139 showPanel : function(panelId) {
34140 var rs = this.regions;
34141 for(var target in rs){
34142 var r = rs[target];
34143 if(typeof r != "function"){
34144 if(r.hasPanel(panelId)){
34145 return r.showPanel(panelId);
34153 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34154 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34157 restoreState : function(provider){
34159 provider = Roo.state.Manager;
34161 var sm = new Roo.LayoutStateManager();
34162 sm.init(this, provider);
34168 * Adds a xtype elements to the layout.
34172 xtype : 'ContentPanel',
34179 xtype : 'NestedLayoutPanel',
34185 items : [ ... list of content panels or nested layout panels.. ]
34189 * @param {Object} cfg Xtype definition of item to add.
34191 addxtype : function(cfg)
34193 // basically accepts a pannel...
34194 // can accept a layout region..!?!?
34195 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34198 // theory? children can only be panels??
34200 //if (!cfg.xtype.match(/Panel$/)) {
34205 if (typeof(cfg.region) == 'undefined') {
34206 Roo.log("Failed to add Panel, region was not set");
34210 var region = cfg.region;
34216 xitems = cfg.items;
34223 case 'Content': // ContentPanel (el, cfg)
34224 case 'Scroll': // ContentPanel (el, cfg)
34226 cfg.autoCreate = true;
34227 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34229 // var el = this.el.createChild();
34230 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34233 this.add(region, ret);
34237 case 'TreePanel': // our new panel!
34238 cfg.el = this.el.createChild();
34239 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34240 this.add(region, ret);
34245 // create a new Layout (which is a Border Layout...
34247 var clayout = cfg.layout;
34248 clayout.el = this.el.createChild();
34249 clayout.items = clayout.items || [];
34253 // replace this exitems with the clayout ones..
34254 xitems = clayout.items;
34256 // force background off if it's in center...
34257 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34258 cfg.background = false;
34260 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34263 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34264 //console.log('adding nested layout panel ' + cfg.toSource());
34265 this.add(region, ret);
34266 nb = {}; /// find first...
34271 // needs grid and region
34273 //var el = this.getRegion(region).el.createChild();
34275 *var el = this.el.createChild();
34276 // create the grid first...
34277 cfg.grid.container = el;
34278 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34281 if (region == 'center' && this.active ) {
34282 cfg.background = false;
34285 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34287 this.add(region, ret);
34289 if (cfg.background) {
34290 // render grid on panel activation (if panel background)
34291 ret.on('activate', function(gp) {
34292 if (!gp.grid.rendered) {
34293 // gp.grid.render(el);
34297 // cfg.grid.render(el);
34303 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34304 // it was the old xcomponent building that caused this before.
34305 // espeically if border is the top element in the tree.
34315 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34317 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34318 this.add(region, ret);
34322 throw "Can not add '" + cfg.xtype + "' to Border";
34328 this.beginUpdate();
34332 Roo.each(xitems, function(i) {
34333 region = nb && i.region ? i.region : false;
34335 var add = ret.addxtype(i);
34338 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34339 if (!i.background) {
34340 abn[region] = nb[region] ;
34347 // make the last non-background panel active..
34348 //if (nb) { Roo.log(abn); }
34351 for(var r in abn) {
34352 region = this.getRegion(r);
34354 // tried using nb[r], but it does not work..
34356 region.showPanel(abn[r]);
34367 factory : function(cfg)
34370 var validRegions = Roo.bootstrap.layout.Border.regions;
34372 var target = cfg.region;
34375 var r = Roo.bootstrap.layout;
34379 return new r.North(cfg);
34381 return new r.South(cfg);
34383 return new r.East(cfg);
34385 return new r.West(cfg);
34387 return new r.Center(cfg);
34389 throw 'Layout region "'+target+'" not supported.';
34396 * Ext JS Library 1.1.1
34397 * Copyright(c) 2006-2007, Ext JS, LLC.
34399 * Originally Released Under LGPL - original licence link has changed is not relivant.
34402 * <script type="text/javascript">
34406 * @class Roo.bootstrap.layout.Basic
34407 * @extends Roo.util.Observable
34408 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34409 * and does not have a titlebar, tabs or any other features. All it does is size and position
34410 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34411 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34412 * @cfg {string} region the region that it inhabits..
34413 * @cfg {bool} skipConfig skip config?
34417 Roo.bootstrap.layout.Basic = function(config){
34419 this.mgr = config.mgr;
34421 this.position = config.region;
34423 var skipConfig = config.skipConfig;
34427 * @scope Roo.BasicLayoutRegion
34431 * @event beforeremove
34432 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34433 * @param {Roo.LayoutRegion} this
34434 * @param {Roo.ContentPanel} panel The panel
34435 * @param {Object} e The cancel event object
34437 "beforeremove" : true,
34439 * @event invalidated
34440 * Fires when the layout for this region is changed.
34441 * @param {Roo.LayoutRegion} this
34443 "invalidated" : true,
34445 * @event visibilitychange
34446 * Fires when this region is shown or hidden
34447 * @param {Roo.LayoutRegion} this
34448 * @param {Boolean} visibility true or false
34450 "visibilitychange" : true,
34452 * @event paneladded
34453 * Fires when a panel is added.
34454 * @param {Roo.LayoutRegion} this
34455 * @param {Roo.ContentPanel} panel The panel
34457 "paneladded" : true,
34459 * @event panelremoved
34460 * Fires when a panel is removed.
34461 * @param {Roo.LayoutRegion} this
34462 * @param {Roo.ContentPanel} panel The panel
34464 "panelremoved" : true,
34466 * @event beforecollapse
34467 * Fires when this region before collapse.
34468 * @param {Roo.LayoutRegion} this
34470 "beforecollapse" : true,
34473 * Fires when this region is collapsed.
34474 * @param {Roo.LayoutRegion} this
34476 "collapsed" : true,
34479 * Fires when this region is expanded.
34480 * @param {Roo.LayoutRegion} this
34485 * Fires when this region is slid into view.
34486 * @param {Roo.LayoutRegion} this
34488 "slideshow" : true,
34491 * Fires when this region slides out of view.
34492 * @param {Roo.LayoutRegion} this
34494 "slidehide" : true,
34496 * @event panelactivated
34497 * Fires when a panel is activated.
34498 * @param {Roo.LayoutRegion} this
34499 * @param {Roo.ContentPanel} panel The activated panel
34501 "panelactivated" : true,
34504 * Fires when the user resizes this region.
34505 * @param {Roo.LayoutRegion} this
34506 * @param {Number} newSize The new size (width for east/west, height for north/south)
34510 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34511 this.panels = new Roo.util.MixedCollection();
34512 this.panels.getKey = this.getPanelId.createDelegate(this);
34514 this.activePanel = null;
34515 // ensure listeners are added...
34517 if (config.listeners || config.events) {
34518 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34519 listeners : config.listeners || {},
34520 events : config.events || {}
34524 if(skipConfig !== true){
34525 this.applyConfig(config);
34529 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34531 getPanelId : function(p){
34535 applyConfig : function(config){
34536 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34537 this.config = config;
34542 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34543 * the width, for horizontal (north, south) the height.
34544 * @param {Number} newSize The new width or height
34546 resizeTo : function(newSize){
34547 var el = this.el ? this.el :
34548 (this.activePanel ? this.activePanel.getEl() : null);
34550 switch(this.position){
34553 el.setWidth(newSize);
34554 this.fireEvent("resized", this, newSize);
34558 el.setHeight(newSize);
34559 this.fireEvent("resized", this, newSize);
34565 getBox : function(){
34566 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34569 getMargins : function(){
34570 return this.margins;
34573 updateBox : function(box){
34575 var el = this.activePanel.getEl();
34576 el.dom.style.left = box.x + "px";
34577 el.dom.style.top = box.y + "px";
34578 this.activePanel.setSize(box.width, box.height);
34582 * Returns the container element for this region.
34583 * @return {Roo.Element}
34585 getEl : function(){
34586 return this.activePanel;
34590 * Returns true if this region is currently visible.
34591 * @return {Boolean}
34593 isVisible : function(){
34594 return this.activePanel ? true : false;
34597 setActivePanel : function(panel){
34598 panel = this.getPanel(panel);
34599 if(this.activePanel && this.activePanel != panel){
34600 this.activePanel.setActiveState(false);
34601 this.activePanel.getEl().setLeftTop(-10000,-10000);
34603 this.activePanel = panel;
34604 panel.setActiveState(true);
34606 panel.setSize(this.box.width, this.box.height);
34608 this.fireEvent("panelactivated", this, panel);
34609 this.fireEvent("invalidated");
34613 * Show the specified panel.
34614 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34615 * @return {Roo.ContentPanel} The shown panel or null
34617 showPanel : function(panel){
34618 panel = this.getPanel(panel);
34620 this.setActivePanel(panel);
34626 * Get the active panel for this region.
34627 * @return {Roo.ContentPanel} The active panel or null
34629 getActivePanel : function(){
34630 return this.activePanel;
34634 * Add the passed ContentPanel(s)
34635 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34636 * @return {Roo.ContentPanel} The panel added (if only one was added)
34638 add : function(panel){
34639 if(arguments.length > 1){
34640 for(var i = 0, len = arguments.length; i < len; i++) {
34641 this.add(arguments[i]);
34645 if(this.hasPanel(panel)){
34646 this.showPanel(panel);
34649 var el = panel.getEl();
34650 if(el.dom.parentNode != this.mgr.el.dom){
34651 this.mgr.el.dom.appendChild(el.dom);
34653 if(panel.setRegion){
34654 panel.setRegion(this);
34656 this.panels.add(panel);
34657 el.setStyle("position", "absolute");
34658 if(!panel.background){
34659 this.setActivePanel(panel);
34660 if(this.config.initialSize && this.panels.getCount()==1){
34661 this.resizeTo(this.config.initialSize);
34664 this.fireEvent("paneladded", this, panel);
34669 * Returns true if the panel is in this region.
34670 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34671 * @return {Boolean}
34673 hasPanel : function(panel){
34674 if(typeof panel == "object"){ // must be panel obj
34675 panel = panel.getId();
34677 return this.getPanel(panel) ? true : false;
34681 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34682 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34683 * @param {Boolean} preservePanel Overrides the config preservePanel option
34684 * @return {Roo.ContentPanel} The panel that was removed
34686 remove : function(panel, preservePanel){
34687 panel = this.getPanel(panel);
34692 this.fireEvent("beforeremove", this, panel, e);
34693 if(e.cancel === true){
34696 var panelId = panel.getId();
34697 this.panels.removeKey(panelId);
34702 * Returns the panel specified or null if it's not in this region.
34703 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34704 * @return {Roo.ContentPanel}
34706 getPanel : function(id){
34707 if(typeof id == "object"){ // must be panel obj
34710 return this.panels.get(id);
34714 * Returns this regions position (north/south/east/west/center).
34717 getPosition: function(){
34718 return this.position;
34722 * Ext JS Library 1.1.1
34723 * Copyright(c) 2006-2007, Ext JS, LLC.
34725 * Originally Released Under LGPL - original licence link has changed is not relivant.
34728 * <script type="text/javascript">
34732 * @class Roo.bootstrap.layout.Region
34733 * @extends Roo.bootstrap.layout.Basic
34734 * This class represents a region in a layout manager.
34736 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34737 * @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})
34738 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34739 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34740 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34741 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34742 * @cfg {String} title The title for the region (overrides panel titles)
34743 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34744 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34745 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34746 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34747 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34748 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34749 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34750 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34751 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34752 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34754 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34755 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34756 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34757 * @cfg {Number} width For East/West panels
34758 * @cfg {Number} height For North/South panels
34759 * @cfg {Boolean} split To show the splitter
34760 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34762 * @cfg {string} cls Extra CSS classes to add to region
34764 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34765 * @cfg {string} region the region that it inhabits..
34768 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34769 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34771 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34772 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34773 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34775 Roo.bootstrap.layout.Region = function(config)
34777 this.applyConfig(config);
34779 var mgr = config.mgr;
34780 var pos = config.region;
34781 config.skipConfig = true;
34782 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34785 this.onRender(mgr.el);
34788 this.visible = true;
34789 this.collapsed = false;
34790 this.unrendered_panels = [];
34793 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34795 position: '', // set by wrapper (eg. north/south etc..)
34796 unrendered_panels : null, // unrendered panels.
34797 createBody : function(){
34798 /** This region's body element
34799 * @type Roo.Element */
34800 this.bodyEl = this.el.createChild({
34802 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34806 onRender: function(ctr, pos)
34808 var dh = Roo.DomHelper;
34809 /** This region's container element
34810 * @type Roo.Element */
34811 this.el = dh.append(ctr.dom, {
34813 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34815 /** This region's title element
34816 * @type Roo.Element */
34818 this.titleEl = dh.append(this.el.dom,
34821 unselectable: "on",
34822 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34824 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34825 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34828 this.titleEl.enableDisplayMode();
34829 /** This region's title text element
34830 * @type HTMLElement */
34831 this.titleTextEl = this.titleEl.dom.firstChild;
34832 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34834 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34835 this.closeBtn.enableDisplayMode();
34836 this.closeBtn.on("click", this.closeClicked, this);
34837 this.closeBtn.hide();
34839 this.createBody(this.config);
34840 if(this.config.hideWhenEmpty){
34842 this.on("paneladded", this.validateVisibility, this);
34843 this.on("panelremoved", this.validateVisibility, this);
34845 if(this.autoScroll){
34846 this.bodyEl.setStyle("overflow", "auto");
34848 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34850 //if(c.titlebar !== false){
34851 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34852 this.titleEl.hide();
34854 this.titleEl.show();
34855 if(this.config.title){
34856 this.titleTextEl.innerHTML = this.config.title;
34860 if(this.config.collapsed){
34861 this.collapse(true);
34863 if(this.config.hidden){
34867 if (this.unrendered_panels && this.unrendered_panels.length) {
34868 for (var i =0;i< this.unrendered_panels.length; i++) {
34869 this.add(this.unrendered_panels[i]);
34871 this.unrendered_panels = null;
34877 applyConfig : function(c)
34880 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34881 var dh = Roo.DomHelper;
34882 if(c.titlebar !== false){
34883 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34884 this.collapseBtn.on("click", this.collapse, this);
34885 this.collapseBtn.enableDisplayMode();
34887 if(c.showPin === true || this.showPin){
34888 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34889 this.stickBtn.enableDisplayMode();
34890 this.stickBtn.on("click", this.expand, this);
34891 this.stickBtn.hide();
34896 /** This region's collapsed element
34897 * @type Roo.Element */
34900 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34901 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34904 if(c.floatable !== false){
34905 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34906 this.collapsedEl.on("click", this.collapseClick, this);
34909 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34910 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34911 id: "message", unselectable: "on", style:{"float":"left"}});
34912 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34914 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34915 this.expandBtn.on("click", this.expand, this);
34919 if(this.collapseBtn){
34920 this.collapseBtn.setVisible(c.collapsible == true);
34923 this.cmargins = c.cmargins || this.cmargins ||
34924 (this.position == "west" || this.position == "east" ?
34925 {top: 0, left: 2, right:2, bottom: 0} :
34926 {top: 2, left: 0, right:0, bottom: 2});
34928 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34931 this.bottomTabs = c.tabPosition != "top";
34933 this.autoScroll = c.autoScroll || false;
34938 this.duration = c.duration || .30;
34939 this.slideDuration = c.slideDuration || .45;
34944 * Returns true if this region is currently visible.
34945 * @return {Boolean}
34947 isVisible : function(){
34948 return this.visible;
34952 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34953 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34955 //setCollapsedTitle : function(title){
34956 // title = title || " ";
34957 // if(this.collapsedTitleTextEl){
34958 // this.collapsedTitleTextEl.innerHTML = title;
34962 getBox : function(){
34964 // if(!this.collapsed){
34965 b = this.el.getBox(false, true);
34967 // b = this.collapsedEl.getBox(false, true);
34972 getMargins : function(){
34973 return this.margins;
34974 //return this.collapsed ? this.cmargins : this.margins;
34977 highlight : function(){
34978 this.el.addClass("x-layout-panel-dragover");
34981 unhighlight : function(){
34982 this.el.removeClass("x-layout-panel-dragover");
34985 updateBox : function(box)
34987 if (!this.bodyEl) {
34988 return; // not rendered yet..
34992 if(!this.collapsed){
34993 this.el.dom.style.left = box.x + "px";
34994 this.el.dom.style.top = box.y + "px";
34995 this.updateBody(box.width, box.height);
34997 this.collapsedEl.dom.style.left = box.x + "px";
34998 this.collapsedEl.dom.style.top = box.y + "px";
34999 this.collapsedEl.setSize(box.width, box.height);
35002 this.tabs.autoSizeTabs();
35006 updateBody : function(w, h)
35009 this.el.setWidth(w);
35010 w -= this.el.getBorderWidth("rl");
35011 if(this.config.adjustments){
35012 w += this.config.adjustments[0];
35015 if(h !== null && h > 0){
35016 this.el.setHeight(h);
35017 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35018 h -= this.el.getBorderWidth("tb");
35019 if(this.config.adjustments){
35020 h += this.config.adjustments[1];
35022 this.bodyEl.setHeight(h);
35024 h = this.tabs.syncHeight(h);
35027 if(this.panelSize){
35028 w = w !== null ? w : this.panelSize.width;
35029 h = h !== null ? h : this.panelSize.height;
35031 if(this.activePanel){
35032 var el = this.activePanel.getEl();
35033 w = w !== null ? w : el.getWidth();
35034 h = h !== null ? h : el.getHeight();
35035 this.panelSize = {width: w, height: h};
35036 this.activePanel.setSize(w, h);
35038 if(Roo.isIE && this.tabs){
35039 this.tabs.el.repaint();
35044 * Returns the container element for this region.
35045 * @return {Roo.Element}
35047 getEl : function(){
35052 * Hides this region.
35055 //if(!this.collapsed){
35056 this.el.dom.style.left = "-2000px";
35059 // this.collapsedEl.dom.style.left = "-2000px";
35060 // this.collapsedEl.hide();
35062 this.visible = false;
35063 this.fireEvent("visibilitychange", this, false);
35067 * Shows this region if it was previously hidden.
35070 //if(!this.collapsed){
35073 // this.collapsedEl.show();
35075 this.visible = true;
35076 this.fireEvent("visibilitychange", this, true);
35079 closeClicked : function(){
35080 if(this.activePanel){
35081 this.remove(this.activePanel);
35085 collapseClick : function(e){
35087 e.stopPropagation();
35090 e.stopPropagation();
35096 * Collapses this region.
35097 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35100 collapse : function(skipAnim, skipCheck = false){
35101 if(this.collapsed) {
35105 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35107 this.collapsed = true;
35109 this.split.el.hide();
35111 if(this.config.animate && skipAnim !== true){
35112 this.fireEvent("invalidated", this);
35113 this.animateCollapse();
35115 this.el.setLocation(-20000,-20000);
35117 this.collapsedEl.show();
35118 this.fireEvent("collapsed", this);
35119 this.fireEvent("invalidated", this);
35125 animateCollapse : function(){
35130 * Expands this region if it was previously collapsed.
35131 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35132 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35135 expand : function(e, skipAnim){
35137 e.stopPropagation();
35139 if(!this.collapsed || this.el.hasActiveFx()) {
35143 this.afterSlideIn();
35146 this.collapsed = false;
35147 if(this.config.animate && skipAnim !== true){
35148 this.animateExpand();
35152 this.split.el.show();
35154 this.collapsedEl.setLocation(-2000,-2000);
35155 this.collapsedEl.hide();
35156 this.fireEvent("invalidated", this);
35157 this.fireEvent("expanded", this);
35161 animateExpand : function(){
35165 initTabs : function()
35167 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35169 var ts = new Roo.bootstrap.panel.Tabs({
35170 el: this.bodyEl.dom,
35171 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35172 disableTooltips: this.config.disableTabTips,
35173 toolbar : this.config.toolbar
35176 if(this.config.hideTabs){
35177 ts.stripWrap.setDisplayed(false);
35180 ts.resizeTabs = this.config.resizeTabs === true;
35181 ts.minTabWidth = this.config.minTabWidth || 40;
35182 ts.maxTabWidth = this.config.maxTabWidth || 250;
35183 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35184 ts.monitorResize = false;
35185 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35186 ts.bodyEl.addClass('roo-layout-tabs-body');
35187 this.panels.each(this.initPanelAsTab, this);
35190 initPanelAsTab : function(panel){
35191 var ti = this.tabs.addTab(
35195 this.config.closeOnTab && panel.isClosable(),
35198 if(panel.tabTip !== undefined){
35199 ti.setTooltip(panel.tabTip);
35201 ti.on("activate", function(){
35202 this.setActivePanel(panel);
35205 if(this.config.closeOnTab){
35206 ti.on("beforeclose", function(t, e){
35208 this.remove(panel);
35212 panel.tabItem = ti;
35217 updatePanelTitle : function(panel, title)
35219 if(this.activePanel == panel){
35220 this.updateTitle(title);
35223 var ti = this.tabs.getTab(panel.getEl().id);
35225 if(panel.tabTip !== undefined){
35226 ti.setTooltip(panel.tabTip);
35231 updateTitle : function(title){
35232 if(this.titleTextEl && !this.config.title){
35233 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35237 setActivePanel : function(panel)
35239 panel = this.getPanel(panel);
35240 if(this.activePanel && this.activePanel != panel){
35241 this.activePanel.setActiveState(false);
35243 this.activePanel = panel;
35244 panel.setActiveState(true);
35245 if(this.panelSize){
35246 panel.setSize(this.panelSize.width, this.panelSize.height);
35249 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35251 this.updateTitle(panel.getTitle());
35253 this.fireEvent("invalidated", this);
35255 this.fireEvent("panelactivated", this, panel);
35259 * Shows the specified panel.
35260 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35261 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35263 showPanel : function(panel)
35265 panel = this.getPanel(panel);
35268 var tab = this.tabs.getTab(panel.getEl().id);
35269 if(tab.isHidden()){
35270 this.tabs.unhideTab(tab.id);
35274 this.setActivePanel(panel);
35281 * Get the active panel for this region.
35282 * @return {Roo.ContentPanel} The active panel or null
35284 getActivePanel : function(){
35285 return this.activePanel;
35288 validateVisibility : function(){
35289 if(this.panels.getCount() < 1){
35290 this.updateTitle(" ");
35291 this.closeBtn.hide();
35294 if(!this.isVisible()){
35301 * Adds the passed ContentPanel(s) to this region.
35302 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35303 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35305 add : function(panel)
35307 if(arguments.length > 1){
35308 for(var i = 0, len = arguments.length; i < len; i++) {
35309 this.add(arguments[i]);
35314 // if we have not been rendered yet, then we can not really do much of this..
35315 if (!this.bodyEl) {
35316 this.unrendered_panels.push(panel);
35323 if(this.hasPanel(panel)){
35324 this.showPanel(panel);
35327 panel.setRegion(this);
35328 this.panels.add(panel);
35329 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35330 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35331 // and hide them... ???
35332 this.bodyEl.dom.appendChild(panel.getEl().dom);
35333 if(panel.background !== true){
35334 this.setActivePanel(panel);
35336 this.fireEvent("paneladded", this, panel);
35343 this.initPanelAsTab(panel);
35347 if(panel.background !== true){
35348 this.tabs.activate(panel.getEl().id);
35350 this.fireEvent("paneladded", this, panel);
35355 * Hides the tab for the specified panel.
35356 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35358 hidePanel : function(panel){
35359 if(this.tabs && (panel = this.getPanel(panel))){
35360 this.tabs.hideTab(panel.getEl().id);
35365 * Unhides the tab for a previously hidden panel.
35366 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35368 unhidePanel : function(panel){
35369 if(this.tabs && (panel = this.getPanel(panel))){
35370 this.tabs.unhideTab(panel.getEl().id);
35374 clearPanels : function(){
35375 while(this.panels.getCount() > 0){
35376 this.remove(this.panels.first());
35381 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35382 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35383 * @param {Boolean} preservePanel Overrides the config preservePanel option
35384 * @return {Roo.ContentPanel} The panel that was removed
35386 remove : function(panel, preservePanel)
35388 panel = this.getPanel(panel);
35393 this.fireEvent("beforeremove", this, panel, e);
35394 if(e.cancel === true){
35397 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35398 var panelId = panel.getId();
35399 this.panels.removeKey(panelId);
35401 document.body.appendChild(panel.getEl().dom);
35404 this.tabs.removeTab(panel.getEl().id);
35405 }else if (!preservePanel){
35406 this.bodyEl.dom.removeChild(panel.getEl().dom);
35408 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35409 var p = this.panels.first();
35410 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35411 tempEl.appendChild(p.getEl().dom);
35412 this.bodyEl.update("");
35413 this.bodyEl.dom.appendChild(p.getEl().dom);
35415 this.updateTitle(p.getTitle());
35417 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35418 this.setActivePanel(p);
35420 panel.setRegion(null);
35421 if(this.activePanel == panel){
35422 this.activePanel = null;
35424 if(this.config.autoDestroy !== false && preservePanel !== true){
35425 try{panel.destroy();}catch(e){}
35427 this.fireEvent("panelremoved", this, panel);
35432 * Returns the TabPanel component used by this region
35433 * @return {Roo.TabPanel}
35435 getTabs : function(){
35439 createTool : function(parentEl, className){
35440 var btn = Roo.DomHelper.append(parentEl, {
35442 cls: "x-layout-tools-button",
35445 cls: "roo-layout-tools-button-inner " + className,
35449 btn.addClassOnOver("roo-layout-tools-button-over");
35454 * Ext JS Library 1.1.1
35455 * Copyright(c) 2006-2007, Ext JS, LLC.
35457 * Originally Released Under LGPL - original licence link has changed is not relivant.
35460 * <script type="text/javascript">
35466 * @class Roo.SplitLayoutRegion
35467 * @extends Roo.LayoutRegion
35468 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35470 Roo.bootstrap.layout.Split = function(config){
35471 this.cursor = config.cursor;
35472 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35475 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35477 splitTip : "Drag to resize.",
35478 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35479 useSplitTips : false,
35481 applyConfig : function(config){
35482 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35485 onRender : function(ctr,pos) {
35487 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35488 if(!this.config.split){
35493 var splitEl = Roo.DomHelper.append(ctr.dom, {
35495 id: this.el.id + "-split",
35496 cls: "roo-layout-split roo-layout-split-"+this.position,
35499 /** The SplitBar for this region
35500 * @type Roo.SplitBar */
35501 // does not exist yet...
35502 Roo.log([this.position, this.orientation]);
35504 this.split = new Roo.bootstrap.SplitBar({
35505 dragElement : splitEl,
35506 resizingElement: this.el,
35507 orientation : this.orientation
35510 this.split.on("moved", this.onSplitMove, this);
35511 this.split.useShim = this.config.useShim === true;
35512 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35513 if(this.useSplitTips){
35514 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35516 //if(config.collapsible){
35517 // this.split.el.on("dblclick", this.collapse, this);
35520 if(typeof this.config.minSize != "undefined"){
35521 this.split.minSize = this.config.minSize;
35523 if(typeof this.config.maxSize != "undefined"){
35524 this.split.maxSize = this.config.maxSize;
35526 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35527 this.hideSplitter();
35532 getHMaxSize : function(){
35533 var cmax = this.config.maxSize || 10000;
35534 var center = this.mgr.getRegion("center");
35535 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35538 getVMaxSize : function(){
35539 var cmax = this.config.maxSize || 10000;
35540 var center = this.mgr.getRegion("center");
35541 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35544 onSplitMove : function(split, newSize){
35545 this.fireEvent("resized", this, newSize);
35549 * Returns the {@link Roo.SplitBar} for this region.
35550 * @return {Roo.SplitBar}
35552 getSplitBar : function(){
35557 this.hideSplitter();
35558 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35561 hideSplitter : function(){
35563 this.split.el.setLocation(-2000,-2000);
35564 this.split.el.hide();
35570 this.split.el.show();
35572 Roo.bootstrap.layout.Split.superclass.show.call(this);
35575 beforeSlide: function(){
35576 if(Roo.isGecko){// firefox overflow auto bug workaround
35577 this.bodyEl.clip();
35579 this.tabs.bodyEl.clip();
35581 if(this.activePanel){
35582 this.activePanel.getEl().clip();
35584 if(this.activePanel.beforeSlide){
35585 this.activePanel.beforeSlide();
35591 afterSlide : function(){
35592 if(Roo.isGecko){// firefox overflow auto bug workaround
35593 this.bodyEl.unclip();
35595 this.tabs.bodyEl.unclip();
35597 if(this.activePanel){
35598 this.activePanel.getEl().unclip();
35599 if(this.activePanel.afterSlide){
35600 this.activePanel.afterSlide();
35606 initAutoHide : function(){
35607 if(this.autoHide !== false){
35608 if(!this.autoHideHd){
35609 var st = new Roo.util.DelayedTask(this.slideIn, this);
35610 this.autoHideHd = {
35611 "mouseout": function(e){
35612 if(!e.within(this.el, true)){
35616 "mouseover" : function(e){
35622 this.el.on(this.autoHideHd);
35626 clearAutoHide : function(){
35627 if(this.autoHide !== false){
35628 this.el.un("mouseout", this.autoHideHd.mouseout);
35629 this.el.un("mouseover", this.autoHideHd.mouseover);
35633 clearMonitor : function(){
35634 Roo.get(document).un("click", this.slideInIf, this);
35637 // these names are backwards but not changed for compat
35638 slideOut : function(){
35639 if(this.isSlid || this.el.hasActiveFx()){
35642 this.isSlid = true;
35643 if(this.collapseBtn){
35644 this.collapseBtn.hide();
35646 this.closeBtnState = this.closeBtn.getStyle('display');
35647 this.closeBtn.hide();
35649 this.stickBtn.show();
35652 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35653 this.beforeSlide();
35654 this.el.setStyle("z-index", 10001);
35655 this.el.slideIn(this.getSlideAnchor(), {
35656 callback: function(){
35658 this.initAutoHide();
35659 Roo.get(document).on("click", this.slideInIf, this);
35660 this.fireEvent("slideshow", this);
35667 afterSlideIn : function(){
35668 this.clearAutoHide();
35669 this.isSlid = false;
35670 this.clearMonitor();
35671 this.el.setStyle("z-index", "");
35672 if(this.collapseBtn){
35673 this.collapseBtn.show();
35675 this.closeBtn.setStyle('display', this.closeBtnState);
35677 this.stickBtn.hide();
35679 this.fireEvent("slidehide", this);
35682 slideIn : function(cb){
35683 if(!this.isSlid || this.el.hasActiveFx()){
35687 this.isSlid = false;
35688 this.beforeSlide();
35689 this.el.slideOut(this.getSlideAnchor(), {
35690 callback: function(){
35691 this.el.setLeftTop(-10000, -10000);
35693 this.afterSlideIn();
35701 slideInIf : function(e){
35702 if(!e.within(this.el)){
35707 animateCollapse : function(){
35708 this.beforeSlide();
35709 this.el.setStyle("z-index", 20000);
35710 var anchor = this.getSlideAnchor();
35711 this.el.slideOut(anchor, {
35712 callback : function(){
35713 this.el.setStyle("z-index", "");
35714 this.collapsedEl.slideIn(anchor, {duration:.3});
35716 this.el.setLocation(-10000,-10000);
35718 this.fireEvent("collapsed", this);
35725 animateExpand : function(){
35726 this.beforeSlide();
35727 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35728 this.el.setStyle("z-index", 20000);
35729 this.collapsedEl.hide({
35732 this.el.slideIn(this.getSlideAnchor(), {
35733 callback : function(){
35734 this.el.setStyle("z-index", "");
35737 this.split.el.show();
35739 this.fireEvent("invalidated", this);
35740 this.fireEvent("expanded", this);
35768 getAnchor : function(){
35769 return this.anchors[this.position];
35772 getCollapseAnchor : function(){
35773 return this.canchors[this.position];
35776 getSlideAnchor : function(){
35777 return this.sanchors[this.position];
35780 getAlignAdj : function(){
35781 var cm = this.cmargins;
35782 switch(this.position){
35798 getExpandAdj : function(){
35799 var c = this.collapsedEl, cm = this.cmargins;
35800 switch(this.position){
35802 return [-(cm.right+c.getWidth()+cm.left), 0];
35805 return [cm.right+c.getWidth()+cm.left, 0];
35808 return [0, -(cm.top+cm.bottom+c.getHeight())];
35811 return [0, cm.top+cm.bottom+c.getHeight()];
35817 * Ext JS Library 1.1.1
35818 * Copyright(c) 2006-2007, Ext JS, LLC.
35820 * Originally Released Under LGPL - original licence link has changed is not relivant.
35823 * <script type="text/javascript">
35826 * These classes are private internal classes
35828 Roo.bootstrap.layout.Center = function(config){
35829 config.region = "center";
35830 Roo.bootstrap.layout.Region.call(this, config);
35831 this.visible = true;
35832 this.minWidth = config.minWidth || 20;
35833 this.minHeight = config.minHeight || 20;
35836 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35838 // center panel can't be hidden
35842 // center panel can't be hidden
35845 getMinWidth: function(){
35846 return this.minWidth;
35849 getMinHeight: function(){
35850 return this.minHeight;
35863 Roo.bootstrap.layout.North = function(config)
35865 config.region = 'north';
35866 config.cursor = 'n-resize';
35868 Roo.bootstrap.layout.Split.call(this, config);
35872 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35873 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35874 this.split.el.addClass("roo-layout-split-v");
35876 var size = config.initialSize || config.height;
35877 if(typeof size != "undefined"){
35878 this.el.setHeight(size);
35881 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35883 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35887 getBox : function(){
35888 if(this.collapsed){
35889 return this.collapsedEl.getBox();
35891 var box = this.el.getBox();
35893 box.height += this.split.el.getHeight();
35898 updateBox : function(box){
35899 if(this.split && !this.collapsed){
35900 box.height -= this.split.el.getHeight();
35901 this.split.el.setLeft(box.x);
35902 this.split.el.setTop(box.y+box.height);
35903 this.split.el.setWidth(box.width);
35905 if(this.collapsed){
35906 this.updateBody(box.width, null);
35908 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35916 Roo.bootstrap.layout.South = function(config){
35917 config.region = 'south';
35918 config.cursor = 's-resize';
35919 Roo.bootstrap.layout.Split.call(this, config);
35921 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35922 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35923 this.split.el.addClass("roo-layout-split-v");
35925 var size = config.initialSize || config.height;
35926 if(typeof size != "undefined"){
35927 this.el.setHeight(size);
35931 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35932 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35933 getBox : function(){
35934 if(this.collapsed){
35935 return this.collapsedEl.getBox();
35937 var box = this.el.getBox();
35939 var sh = this.split.el.getHeight();
35946 updateBox : function(box){
35947 if(this.split && !this.collapsed){
35948 var sh = this.split.el.getHeight();
35951 this.split.el.setLeft(box.x);
35952 this.split.el.setTop(box.y-sh);
35953 this.split.el.setWidth(box.width);
35955 if(this.collapsed){
35956 this.updateBody(box.width, null);
35958 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35962 Roo.bootstrap.layout.East = function(config){
35963 config.region = "east";
35964 config.cursor = "e-resize";
35965 Roo.bootstrap.layout.Split.call(this, config);
35967 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35968 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35969 this.split.el.addClass("roo-layout-split-h");
35971 var size = config.initialSize || config.width;
35972 if(typeof size != "undefined"){
35973 this.el.setWidth(size);
35976 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35977 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35978 getBox : function(){
35979 if(this.collapsed){
35980 return this.collapsedEl.getBox();
35982 var box = this.el.getBox();
35984 var sw = this.split.el.getWidth();
35991 updateBox : function(box){
35992 if(this.split && !this.collapsed){
35993 var sw = this.split.el.getWidth();
35995 this.split.el.setLeft(box.x);
35996 this.split.el.setTop(box.y);
35997 this.split.el.setHeight(box.height);
36000 if(this.collapsed){
36001 this.updateBody(null, box.height);
36003 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36007 Roo.bootstrap.layout.West = function(config){
36008 config.region = "west";
36009 config.cursor = "w-resize";
36011 Roo.bootstrap.layout.Split.call(this, config);
36013 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36014 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36015 this.split.el.addClass("roo-layout-split-h");
36019 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36020 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36022 onRender: function(ctr, pos)
36024 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36025 var size = this.config.initialSize || this.config.width;
36026 if(typeof size != "undefined"){
36027 this.el.setWidth(size);
36031 getBox : function(){
36032 if(this.collapsed){
36033 return this.collapsedEl.getBox();
36035 var box = this.el.getBox();
36037 box.width += this.split.el.getWidth();
36042 updateBox : function(box){
36043 if(this.split && !this.collapsed){
36044 var sw = this.split.el.getWidth();
36046 this.split.el.setLeft(box.x+box.width);
36047 this.split.el.setTop(box.y);
36048 this.split.el.setHeight(box.height);
36050 if(this.collapsed){
36051 this.updateBody(null, box.height);
36053 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36056 Roo.namespace("Roo.bootstrap.panel");/*
36058 * Ext JS Library 1.1.1
36059 * Copyright(c) 2006-2007, Ext JS, LLC.
36061 * Originally Released Under LGPL - original licence link has changed is not relivant.
36064 * <script type="text/javascript">
36067 * @class Roo.ContentPanel
36068 * @extends Roo.util.Observable
36069 * A basic ContentPanel element.
36070 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36071 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36072 * @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
36073 * @cfg {Boolean} closable True if the panel can be closed/removed
36074 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36075 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36076 * @cfg {Toolbar} toolbar A toolbar for this panel
36077 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36078 * @cfg {String} title The title for this panel
36079 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36080 * @cfg {String} url Calls {@link #setUrl} with this value
36081 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36082 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36083 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36084 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36085 * @cfg {Boolean} badges render the badges
36088 * Create a new ContentPanel.
36089 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36090 * @param {String/Object} config A string to set only the title or a config object
36091 * @param {String} content (optional) Set the HTML content for this panel
36092 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36094 Roo.bootstrap.panel.Content = function( config){
36096 this.tpl = config.tpl || false;
36098 var el = config.el;
36099 var content = config.content;
36101 if(config.autoCreate){ // xtype is available if this is called from factory
36104 this.el = Roo.get(el);
36105 if(!this.el && config && config.autoCreate){
36106 if(typeof config.autoCreate == "object"){
36107 if(!config.autoCreate.id){
36108 config.autoCreate.id = config.id||el;
36110 this.el = Roo.DomHelper.append(document.body,
36111 config.autoCreate, true);
36113 var elcfg = { tag: "div",
36114 cls: "roo-layout-inactive-content",
36118 elcfg.html = config.html;
36122 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36125 this.closable = false;
36126 this.loaded = false;
36127 this.active = false;
36130 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36132 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36134 this.wrapEl = this.el; //this.el.wrap();
36136 if (config.toolbar.items) {
36137 ti = config.toolbar.items ;
36138 delete config.toolbar.items ;
36142 this.toolbar.render(this.wrapEl, 'before');
36143 for(var i =0;i < ti.length;i++) {
36144 // Roo.log(['add child', items[i]]);
36145 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36147 this.toolbar.items = nitems;
36148 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36149 delete config.toolbar;
36153 // xtype created footer. - not sure if will work as we normally have to render first..
36154 if (this.footer && !this.footer.el && this.footer.xtype) {
36155 if (!this.wrapEl) {
36156 this.wrapEl = this.el.wrap();
36159 this.footer.container = this.wrapEl.createChild();
36161 this.footer = Roo.factory(this.footer, Roo);
36166 if(typeof config == "string"){
36167 this.title = config;
36169 Roo.apply(this, config);
36173 this.resizeEl = Roo.get(this.resizeEl, true);
36175 this.resizeEl = this.el;
36177 // handle view.xtype
36185 * Fires when this panel is activated.
36186 * @param {Roo.ContentPanel} this
36190 * @event deactivate
36191 * Fires when this panel is activated.
36192 * @param {Roo.ContentPanel} this
36194 "deactivate" : true,
36198 * Fires when this panel is resized if fitToFrame is true.
36199 * @param {Roo.ContentPanel} this
36200 * @param {Number} width The width after any component adjustments
36201 * @param {Number} height The height after any component adjustments
36207 * Fires when this tab is created
36208 * @param {Roo.ContentPanel} this
36219 if(this.autoScroll){
36220 this.resizeEl.setStyle("overflow", "auto");
36222 // fix randome scrolling
36223 //this.el.on('scroll', function() {
36224 // Roo.log('fix random scolling');
36225 // this.scrollTo('top',0);
36228 content = content || this.content;
36230 this.setContent(content);
36232 if(config && config.url){
36233 this.setUrl(this.url, this.params, this.loadOnce);
36238 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36240 if (this.view && typeof(this.view.xtype) != 'undefined') {
36241 this.view.el = this.el.appendChild(document.createElement("div"));
36242 this.view = Roo.factory(this.view);
36243 this.view.render && this.view.render(false, '');
36247 this.fireEvent('render', this);
36250 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36254 setRegion : function(region){
36255 this.region = region;
36256 this.setActiveClass(region && !this.background);
36260 setActiveClass: function(state)
36263 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36264 this.el.setStyle('position','relative');
36266 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36267 this.el.setStyle('position', 'absolute');
36272 * Returns the toolbar for this Panel if one was configured.
36273 * @return {Roo.Toolbar}
36275 getToolbar : function(){
36276 return this.toolbar;
36279 setActiveState : function(active)
36281 this.active = active;
36282 this.setActiveClass(active);
36284 this.fireEvent("deactivate", this);
36286 this.fireEvent("activate", this);
36290 * Updates this panel's element
36291 * @param {String} content The new content
36292 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36294 setContent : function(content, loadScripts){
36295 this.el.update(content, loadScripts);
36298 ignoreResize : function(w, h){
36299 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36302 this.lastSize = {width: w, height: h};
36307 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36308 * @return {Roo.UpdateManager} The UpdateManager
36310 getUpdateManager : function(){
36311 return this.el.getUpdateManager();
36314 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36315 * @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:
36318 url: "your-url.php",
36319 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36320 callback: yourFunction,
36321 scope: yourObject, //(optional scope)
36324 text: "Loading...",
36329 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36330 * 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.
36331 * @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}
36332 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36333 * @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.
36334 * @return {Roo.ContentPanel} this
36337 var um = this.el.getUpdateManager();
36338 um.update.apply(um, arguments);
36344 * 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.
36345 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36346 * @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)
36347 * @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)
36348 * @return {Roo.UpdateManager} The UpdateManager
36350 setUrl : function(url, params, loadOnce){
36351 if(this.refreshDelegate){
36352 this.removeListener("activate", this.refreshDelegate);
36354 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36355 this.on("activate", this.refreshDelegate);
36356 return this.el.getUpdateManager();
36359 _handleRefresh : function(url, params, loadOnce){
36360 if(!loadOnce || !this.loaded){
36361 var updater = this.el.getUpdateManager();
36362 updater.update(url, params, this._setLoaded.createDelegate(this));
36366 _setLoaded : function(){
36367 this.loaded = true;
36371 * Returns this panel's id
36374 getId : function(){
36379 * Returns this panel's element - used by regiosn to add.
36380 * @return {Roo.Element}
36382 getEl : function(){
36383 return this.wrapEl || this.el;
36388 adjustForComponents : function(width, height)
36390 //Roo.log('adjustForComponents ');
36391 if(this.resizeEl != this.el){
36392 width -= this.el.getFrameWidth('lr');
36393 height -= this.el.getFrameWidth('tb');
36396 var te = this.toolbar.getEl();
36397 te.setWidth(width);
36398 height -= te.getHeight();
36401 var te = this.footer.getEl();
36402 te.setWidth(width);
36403 height -= te.getHeight();
36407 if(this.adjustments){
36408 width += this.adjustments[0];
36409 height += this.adjustments[1];
36411 return {"width": width, "height": height};
36414 setSize : function(width, height){
36415 if(this.fitToFrame && !this.ignoreResize(width, height)){
36416 if(this.fitContainer && this.resizeEl != this.el){
36417 this.el.setSize(width, height);
36419 var size = this.adjustForComponents(width, height);
36420 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36421 this.fireEvent('resize', this, size.width, size.height);
36426 * Returns this panel's title
36429 getTitle : function(){
36431 if (typeof(this.title) != 'object') {
36436 for (var k in this.title) {
36437 if (!this.title.hasOwnProperty(k)) {
36441 if (k.indexOf('-') >= 0) {
36442 var s = k.split('-');
36443 for (var i = 0; i<s.length; i++) {
36444 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36447 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36454 * Set this panel's title
36455 * @param {String} title
36457 setTitle : function(title){
36458 this.title = title;
36460 this.region.updatePanelTitle(this, title);
36465 * Returns true is this panel was configured to be closable
36466 * @return {Boolean}
36468 isClosable : function(){
36469 return this.closable;
36472 beforeSlide : function(){
36474 this.resizeEl.clip();
36477 afterSlide : function(){
36479 this.resizeEl.unclip();
36483 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36484 * Will fail silently if the {@link #setUrl} method has not been called.
36485 * This does not activate the panel, just updates its content.
36487 refresh : function(){
36488 if(this.refreshDelegate){
36489 this.loaded = false;
36490 this.refreshDelegate();
36495 * Destroys this panel
36497 destroy : function(){
36498 this.el.removeAllListeners();
36499 var tempEl = document.createElement("span");
36500 tempEl.appendChild(this.el.dom);
36501 tempEl.innerHTML = "";
36507 * form - if the content panel contains a form - this is a reference to it.
36508 * @type {Roo.form.Form}
36512 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36513 * This contains a reference to it.
36519 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36529 * @param {Object} cfg Xtype definition of item to add.
36533 getChildContainer: function () {
36534 return this.getEl();
36539 var ret = new Roo.factory(cfg);
36544 if (cfg.xtype.match(/^Form$/)) {
36547 //if (this.footer) {
36548 // el = this.footer.container.insertSibling(false, 'before');
36550 el = this.el.createChild();
36553 this.form = new Roo.form.Form(cfg);
36556 if ( this.form.allItems.length) {
36557 this.form.render(el.dom);
36561 // should only have one of theses..
36562 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36563 // views.. should not be just added - used named prop 'view''
36565 cfg.el = this.el.appendChild(document.createElement("div"));
36568 var ret = new Roo.factory(cfg);
36570 ret.render && ret.render(false, ''); // render blank..
36580 * @class Roo.bootstrap.panel.Grid
36581 * @extends Roo.bootstrap.panel.Content
36583 * Create a new GridPanel.
36584 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36585 * @param {Object} config A the config object
36591 Roo.bootstrap.panel.Grid = function(config)
36595 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36596 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36598 config.el = this.wrapper;
36599 //this.el = this.wrapper;
36601 if (config.container) {
36602 // ctor'ed from a Border/panel.grid
36605 this.wrapper.setStyle("overflow", "hidden");
36606 this.wrapper.addClass('roo-grid-container');
36611 if(config.toolbar){
36612 var tool_el = this.wrapper.createChild();
36613 this.toolbar = Roo.factory(config.toolbar);
36615 if (config.toolbar.items) {
36616 ti = config.toolbar.items ;
36617 delete config.toolbar.items ;
36621 this.toolbar.render(tool_el);
36622 for(var i =0;i < ti.length;i++) {
36623 // Roo.log(['add child', items[i]]);
36624 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36626 this.toolbar.items = nitems;
36628 delete config.toolbar;
36631 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36632 config.grid.scrollBody = true;;
36633 config.grid.monitorWindowResize = false; // turn off autosizing
36634 config.grid.autoHeight = false;
36635 config.grid.autoWidth = false;
36637 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36639 if (config.background) {
36640 // render grid on panel activation (if panel background)
36641 this.on('activate', function(gp) {
36642 if (!gp.grid.rendered) {
36643 gp.grid.render(this.wrapper);
36644 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36649 this.grid.render(this.wrapper);
36650 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36653 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36654 // ??? needed ??? config.el = this.wrapper;
36659 // xtype created footer. - not sure if will work as we normally have to render first..
36660 if (this.footer && !this.footer.el && this.footer.xtype) {
36662 var ctr = this.grid.getView().getFooterPanel(true);
36663 this.footer.dataSource = this.grid.dataSource;
36664 this.footer = Roo.factory(this.footer, Roo);
36665 this.footer.render(ctr);
36675 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36676 getId : function(){
36677 return this.grid.id;
36681 * Returns the grid for this panel
36682 * @return {Roo.bootstrap.Table}
36684 getGrid : function(){
36688 setSize : function(width, height){
36689 if(!this.ignoreResize(width, height)){
36690 var grid = this.grid;
36691 var size = this.adjustForComponents(width, height);
36692 var gridel = grid.getGridEl();
36693 gridel.setSize(size.width, size.height);
36695 var thd = grid.getGridEl().select('thead',true).first();
36696 var tbd = grid.getGridEl().select('tbody', true).first();
36698 tbd.setSize(width, height - thd.getHeight());
36707 beforeSlide : function(){
36708 this.grid.getView().scroller.clip();
36711 afterSlide : function(){
36712 this.grid.getView().scroller.unclip();
36715 destroy : function(){
36716 this.grid.destroy();
36718 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36723 * @class Roo.bootstrap.panel.Nest
36724 * @extends Roo.bootstrap.panel.Content
36726 * Create a new Panel, that can contain a layout.Border.
36729 * @param {Roo.BorderLayout} layout The layout for this panel
36730 * @param {String/Object} config A string to set only the title or a config object
36732 Roo.bootstrap.panel.Nest = function(config)
36734 // construct with only one argument..
36735 /* FIXME - implement nicer consturctors
36736 if (layout.layout) {
36738 layout = config.layout;
36739 delete config.layout;
36741 if (layout.xtype && !layout.getEl) {
36742 // then layout needs constructing..
36743 layout = Roo.factory(layout, Roo);
36747 config.el = config.layout.getEl();
36749 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36751 config.layout.monitorWindowResize = false; // turn off autosizing
36752 this.layout = config.layout;
36753 this.layout.getEl().addClass("roo-layout-nested-layout");
36760 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36762 setSize : function(width, height){
36763 if(!this.ignoreResize(width, height)){
36764 var size = this.adjustForComponents(width, height);
36765 var el = this.layout.getEl();
36766 if (size.height < 1) {
36767 el.setWidth(size.width);
36769 el.setSize(size.width, size.height);
36771 var touch = el.dom.offsetWidth;
36772 this.layout.layout();
36773 // ie requires a double layout on the first pass
36774 if(Roo.isIE && !this.initialized){
36775 this.initialized = true;
36776 this.layout.layout();
36781 // activate all subpanels if not currently active..
36783 setActiveState : function(active){
36784 this.active = active;
36785 this.setActiveClass(active);
36788 this.fireEvent("deactivate", this);
36792 this.fireEvent("activate", this);
36793 // not sure if this should happen before or after..
36794 if (!this.layout) {
36795 return; // should not happen..
36798 for (var r in this.layout.regions) {
36799 reg = this.layout.getRegion(r);
36800 if (reg.getActivePanel()) {
36801 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36802 reg.setActivePanel(reg.getActivePanel());
36805 if (!reg.panels.length) {
36808 reg.showPanel(reg.getPanel(0));
36817 * Returns the nested BorderLayout for this panel
36818 * @return {Roo.BorderLayout}
36820 getLayout : function(){
36821 return this.layout;
36825 * Adds a xtype elements to the layout of the nested panel
36829 xtype : 'ContentPanel',
36836 xtype : 'NestedLayoutPanel',
36842 items : [ ... list of content panels or nested layout panels.. ]
36846 * @param {Object} cfg Xtype definition of item to add.
36848 addxtype : function(cfg) {
36849 return this.layout.addxtype(cfg);
36854 * Ext JS Library 1.1.1
36855 * Copyright(c) 2006-2007, Ext JS, LLC.
36857 * Originally Released Under LGPL - original licence link has changed is not relivant.
36860 * <script type="text/javascript">
36863 * @class Roo.TabPanel
36864 * @extends Roo.util.Observable
36865 * A lightweight tab container.
36869 // basic tabs 1, built from existing content
36870 var tabs = new Roo.TabPanel("tabs1");
36871 tabs.addTab("script", "View Script");
36872 tabs.addTab("markup", "View Markup");
36873 tabs.activate("script");
36875 // more advanced tabs, built from javascript
36876 var jtabs = new Roo.TabPanel("jtabs");
36877 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36879 // set up the UpdateManager
36880 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36881 var updater = tab2.getUpdateManager();
36882 updater.setDefaultUrl("ajax1.htm");
36883 tab2.on('activate', updater.refresh, updater, true);
36885 // Use setUrl for Ajax loading
36886 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36887 tab3.setUrl("ajax2.htm", null, true);
36890 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36893 jtabs.activate("jtabs-1");
36896 * Create a new TabPanel.
36897 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36898 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36900 Roo.bootstrap.panel.Tabs = function(config){
36902 * The container element for this TabPanel.
36903 * @type Roo.Element
36905 this.el = Roo.get(config.el);
36908 if(typeof config == "boolean"){
36909 this.tabPosition = config ? "bottom" : "top";
36911 Roo.apply(this, config);
36915 if(this.tabPosition == "bottom"){
36916 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36917 this.el.addClass("roo-tabs-bottom");
36919 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36920 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36921 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36923 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36925 if(this.tabPosition != "bottom"){
36926 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36927 * @type Roo.Element
36929 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36930 this.el.addClass("roo-tabs-top");
36934 this.bodyEl.setStyle("position", "relative");
36936 this.active = null;
36937 this.activateDelegate = this.activate.createDelegate(this);
36942 * Fires when the active tab changes
36943 * @param {Roo.TabPanel} this
36944 * @param {Roo.TabPanelItem} activePanel The new active tab
36948 * @event beforetabchange
36949 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36950 * @param {Roo.TabPanel} this
36951 * @param {Object} e Set cancel to true on this object to cancel the tab change
36952 * @param {Roo.TabPanelItem} tab The tab being changed to
36954 "beforetabchange" : true
36957 Roo.EventManager.onWindowResize(this.onResize, this);
36958 this.cpad = this.el.getPadding("lr");
36959 this.hiddenCount = 0;
36962 // toolbar on the tabbar support...
36963 if (this.toolbar) {
36964 alert("no toolbar support yet");
36965 this.toolbar = false;
36967 var tcfg = this.toolbar;
36968 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36969 this.toolbar = new Roo.Toolbar(tcfg);
36970 if (Roo.isSafari) {
36971 var tbl = tcfg.container.child('table', true);
36972 tbl.setAttribute('width', '100%');
36980 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36983 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36985 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36987 tabPosition : "top",
36989 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36991 currentTabWidth : 0,
36993 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36997 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37001 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37003 preferredTabWidth : 175,
37005 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37007 resizeTabs : false,
37009 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37011 monitorResize : true,
37013 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37018 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37019 * @param {String} id The id of the div to use <b>or create</b>
37020 * @param {String} text The text for the tab
37021 * @param {String} content (optional) Content to put in the TabPanelItem body
37022 * @param {Boolean} closable (optional) True to create a close icon on the tab
37023 * @return {Roo.TabPanelItem} The created TabPanelItem
37025 addTab : function(id, text, content, closable, tpl)
37027 var item = new Roo.bootstrap.panel.TabItem({
37031 closable : closable,
37034 this.addTabItem(item);
37036 item.setContent(content);
37042 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37043 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37044 * @return {Roo.TabPanelItem}
37046 getTab : function(id){
37047 return this.items[id];
37051 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37052 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37054 hideTab : function(id){
37055 var t = this.items[id];
37058 this.hiddenCount++;
37059 this.autoSizeTabs();
37064 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37065 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37067 unhideTab : function(id){
37068 var t = this.items[id];
37070 t.setHidden(false);
37071 this.hiddenCount--;
37072 this.autoSizeTabs();
37077 * Adds an existing {@link Roo.TabPanelItem}.
37078 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37080 addTabItem : function(item){
37081 this.items[item.id] = item;
37082 this.items.push(item);
37083 // if(this.resizeTabs){
37084 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37085 // this.autoSizeTabs();
37087 // item.autoSize();
37092 * Removes a {@link Roo.TabPanelItem}.
37093 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37095 removeTab : function(id){
37096 var items = this.items;
37097 var tab = items[id];
37098 if(!tab) { return; }
37099 var index = items.indexOf(tab);
37100 if(this.active == tab && items.length > 1){
37101 var newTab = this.getNextAvailable(index);
37106 this.stripEl.dom.removeChild(tab.pnode.dom);
37107 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37108 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37110 items.splice(index, 1);
37111 delete this.items[tab.id];
37112 tab.fireEvent("close", tab);
37113 tab.purgeListeners();
37114 this.autoSizeTabs();
37117 getNextAvailable : function(start){
37118 var items = this.items;
37120 // look for a next tab that will slide over to
37121 // replace the one being removed
37122 while(index < items.length){
37123 var item = items[++index];
37124 if(item && !item.isHidden()){
37128 // if one isn't found select the previous tab (on the left)
37131 var item = items[--index];
37132 if(item && !item.isHidden()){
37140 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37141 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37143 disableTab : function(id){
37144 var tab = this.items[id];
37145 if(tab && this.active != tab){
37151 * Enables a {@link Roo.TabPanelItem} that is disabled.
37152 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37154 enableTab : function(id){
37155 var tab = this.items[id];
37160 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37161 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37162 * @return {Roo.TabPanelItem} The TabPanelItem.
37164 activate : function(id){
37165 var tab = this.items[id];
37169 if(tab == this.active || tab.disabled){
37173 this.fireEvent("beforetabchange", this, e, tab);
37174 if(e.cancel !== true && !tab.disabled){
37176 this.active.hide();
37178 this.active = this.items[id];
37179 this.active.show();
37180 this.fireEvent("tabchange", this, this.active);
37186 * Gets the active {@link Roo.TabPanelItem}.
37187 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37189 getActiveTab : function(){
37190 return this.active;
37194 * Updates the tab body element to fit the height of the container element
37195 * for overflow scrolling
37196 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37198 syncHeight : function(targetHeight){
37199 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37200 var bm = this.bodyEl.getMargins();
37201 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37202 this.bodyEl.setHeight(newHeight);
37206 onResize : function(){
37207 if(this.monitorResize){
37208 this.autoSizeTabs();
37213 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37215 beginUpdate : function(){
37216 this.updating = true;
37220 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37222 endUpdate : function(){
37223 this.updating = false;
37224 this.autoSizeTabs();
37228 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37230 autoSizeTabs : function(){
37231 var count = this.items.length;
37232 var vcount = count - this.hiddenCount;
37233 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37236 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37237 var availWidth = Math.floor(w / vcount);
37238 var b = this.stripBody;
37239 if(b.getWidth() > w){
37240 var tabs = this.items;
37241 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37242 if(availWidth < this.minTabWidth){
37243 /*if(!this.sleft){ // incomplete scrolling code
37244 this.createScrollButtons();
37247 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37250 if(this.currentTabWidth < this.preferredTabWidth){
37251 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37257 * Returns the number of tabs in this TabPanel.
37260 getCount : function(){
37261 return this.items.length;
37265 * Resizes all the tabs to the passed width
37266 * @param {Number} The new width
37268 setTabWidth : function(width){
37269 this.currentTabWidth = width;
37270 for(var i = 0, len = this.items.length; i < len; i++) {
37271 if(!this.items[i].isHidden()) {
37272 this.items[i].setWidth(width);
37278 * Destroys this TabPanel
37279 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37281 destroy : function(removeEl){
37282 Roo.EventManager.removeResizeListener(this.onResize, this);
37283 for(var i = 0, len = this.items.length; i < len; i++){
37284 this.items[i].purgeListeners();
37286 if(removeEl === true){
37287 this.el.update("");
37292 createStrip : function(container)
37294 var strip = document.createElement("nav");
37295 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37296 container.appendChild(strip);
37300 createStripList : function(strip)
37302 // div wrapper for retard IE
37303 // returns the "tr" element.
37304 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37305 //'<div class="x-tabs-strip-wrap">'+
37306 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37307 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37308 return strip.firstChild; //.firstChild.firstChild.firstChild;
37310 createBody : function(container)
37312 var body = document.createElement("div");
37313 Roo.id(body, "tab-body");
37314 //Roo.fly(body).addClass("x-tabs-body");
37315 Roo.fly(body).addClass("tab-content");
37316 container.appendChild(body);
37319 createItemBody :function(bodyEl, id){
37320 var body = Roo.getDom(id);
37322 body = document.createElement("div");
37325 //Roo.fly(body).addClass("x-tabs-item-body");
37326 Roo.fly(body).addClass("tab-pane");
37327 bodyEl.insertBefore(body, bodyEl.firstChild);
37331 createStripElements : function(stripEl, text, closable, tpl)
37333 var td = document.createElement("li"); // was td..
37336 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37339 stripEl.appendChild(td);
37341 td.className = "x-tabs-closable";
37342 if(!this.closeTpl){
37343 this.closeTpl = new Roo.Template(
37344 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37345 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37346 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37349 var el = this.closeTpl.overwrite(td, {"text": text});
37350 var close = el.getElementsByTagName("div")[0];
37351 var inner = el.getElementsByTagName("em")[0];
37352 return {"el": el, "close": close, "inner": inner};
37355 // not sure what this is..
37356 // if(!this.tabTpl){
37357 //this.tabTpl = new Roo.Template(
37358 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37359 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37361 // this.tabTpl = new Roo.Template(
37362 // '<a href="#">' +
37363 // '<span unselectable="on"' +
37364 // (this.disableTooltips ? '' : ' title="{text}"') +
37365 // ' >{text}</span></a>'
37371 var template = tpl || this.tabTpl || false;
37375 template = new Roo.Template(
37377 '<span unselectable="on"' +
37378 (this.disableTooltips ? '' : ' title="{text}"') +
37379 ' >{text}</span></a>'
37383 switch (typeof(template)) {
37387 template = new Roo.Template(template);
37393 var el = template.overwrite(td, {"text": text});
37395 var inner = el.getElementsByTagName("span")[0];
37397 return {"el": el, "inner": inner};
37405 * @class Roo.TabPanelItem
37406 * @extends Roo.util.Observable
37407 * Represents an individual item (tab plus body) in a TabPanel.
37408 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37409 * @param {String} id The id of this TabPanelItem
37410 * @param {String} text The text for the tab of this TabPanelItem
37411 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37413 Roo.bootstrap.panel.TabItem = function(config){
37415 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37416 * @type Roo.TabPanel
37418 this.tabPanel = config.panel;
37420 * The id for this TabPanelItem
37423 this.id = config.id;
37425 this.disabled = false;
37427 this.text = config.text;
37429 this.loaded = false;
37430 this.closable = config.closable;
37433 * The body element for this TabPanelItem.
37434 * @type Roo.Element
37436 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37437 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37438 this.bodyEl.setStyle("display", "block");
37439 this.bodyEl.setStyle("zoom", "1");
37440 //this.hideAction();
37442 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37444 this.el = Roo.get(els.el);
37445 this.inner = Roo.get(els.inner, true);
37446 this.textEl = Roo.get(this.el.dom.firstChild, true);
37447 this.pnode = Roo.get(els.el.parentNode, true);
37448 this.el.on("mousedown", this.onTabMouseDown, this);
37449 this.el.on("click", this.onTabClick, this);
37451 if(config.closable){
37452 var c = Roo.get(els.close, true);
37453 c.dom.title = this.closeText;
37454 c.addClassOnOver("close-over");
37455 c.on("click", this.closeClick, this);
37461 * Fires when this tab becomes the active tab.
37462 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37463 * @param {Roo.TabPanelItem} this
37467 * @event beforeclose
37468 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37469 * @param {Roo.TabPanelItem} this
37470 * @param {Object} e Set cancel to true on this object to cancel the close.
37472 "beforeclose": true,
37475 * Fires when this tab is closed.
37476 * @param {Roo.TabPanelItem} this
37480 * @event deactivate
37481 * Fires when this tab is no longer the active tab.
37482 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37483 * @param {Roo.TabPanelItem} this
37485 "deactivate" : true
37487 this.hidden = false;
37489 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37492 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37494 purgeListeners : function(){
37495 Roo.util.Observable.prototype.purgeListeners.call(this);
37496 this.el.removeAllListeners();
37499 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37502 this.pnode.addClass("active");
37505 this.tabPanel.stripWrap.repaint();
37507 this.fireEvent("activate", this.tabPanel, this);
37511 * Returns true if this tab is the active tab.
37512 * @return {Boolean}
37514 isActive : function(){
37515 return this.tabPanel.getActiveTab() == this;
37519 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37522 this.pnode.removeClass("active");
37524 this.fireEvent("deactivate", this.tabPanel, this);
37527 hideAction : function(){
37528 this.bodyEl.hide();
37529 this.bodyEl.setStyle("position", "absolute");
37530 this.bodyEl.setLeft("-20000px");
37531 this.bodyEl.setTop("-20000px");
37534 showAction : function(){
37535 this.bodyEl.setStyle("position", "relative");
37536 this.bodyEl.setTop("");
37537 this.bodyEl.setLeft("");
37538 this.bodyEl.show();
37542 * Set the tooltip for the tab.
37543 * @param {String} tooltip The tab's tooltip
37545 setTooltip : function(text){
37546 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37547 this.textEl.dom.qtip = text;
37548 this.textEl.dom.removeAttribute('title');
37550 this.textEl.dom.title = text;
37554 onTabClick : function(e){
37555 e.preventDefault();
37556 this.tabPanel.activate(this.id);
37559 onTabMouseDown : function(e){
37560 e.preventDefault();
37561 this.tabPanel.activate(this.id);
37564 getWidth : function(){
37565 return this.inner.getWidth();
37568 setWidth : function(width){
37569 var iwidth = width - this.pnode.getPadding("lr");
37570 this.inner.setWidth(iwidth);
37571 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37572 this.pnode.setWidth(width);
37576 * Show or hide the tab
37577 * @param {Boolean} hidden True to hide or false to show.
37579 setHidden : function(hidden){
37580 this.hidden = hidden;
37581 this.pnode.setStyle("display", hidden ? "none" : "");
37585 * Returns true if this tab is "hidden"
37586 * @return {Boolean}
37588 isHidden : function(){
37589 return this.hidden;
37593 * Returns the text for this tab
37596 getText : function(){
37600 autoSize : function(){
37601 //this.el.beginMeasure();
37602 this.textEl.setWidth(1);
37604 * #2804 [new] Tabs in Roojs
37605 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37607 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37608 //this.el.endMeasure();
37612 * Sets the text for the tab (Note: this also sets the tooltip text)
37613 * @param {String} text The tab's text and tooltip
37615 setText : function(text){
37617 this.textEl.update(text);
37618 this.setTooltip(text);
37619 //if(!this.tabPanel.resizeTabs){
37620 // this.autoSize();
37624 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37626 activate : function(){
37627 this.tabPanel.activate(this.id);
37631 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37633 disable : function(){
37634 if(this.tabPanel.active != this){
37635 this.disabled = true;
37636 this.pnode.addClass("disabled");
37641 * Enables this TabPanelItem if it was previously disabled.
37643 enable : function(){
37644 this.disabled = false;
37645 this.pnode.removeClass("disabled");
37649 * Sets the content for this TabPanelItem.
37650 * @param {String} content The content
37651 * @param {Boolean} loadScripts true to look for and load scripts
37653 setContent : function(content, loadScripts){
37654 this.bodyEl.update(content, loadScripts);
37658 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37659 * @return {Roo.UpdateManager} The UpdateManager
37661 getUpdateManager : function(){
37662 return this.bodyEl.getUpdateManager();
37666 * Set a URL to be used to load the content for this TabPanelItem.
37667 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37668 * @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)
37669 * @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)
37670 * @return {Roo.UpdateManager} The UpdateManager
37672 setUrl : function(url, params, loadOnce){
37673 if(this.refreshDelegate){
37674 this.un('activate', this.refreshDelegate);
37676 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37677 this.on("activate", this.refreshDelegate);
37678 return this.bodyEl.getUpdateManager();
37682 _handleRefresh : function(url, params, loadOnce){
37683 if(!loadOnce || !this.loaded){
37684 var updater = this.bodyEl.getUpdateManager();
37685 updater.update(url, params, this._setLoaded.createDelegate(this));
37690 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37691 * Will fail silently if the setUrl method has not been called.
37692 * This does not activate the panel, just updates its content.
37694 refresh : function(){
37695 if(this.refreshDelegate){
37696 this.loaded = false;
37697 this.refreshDelegate();
37702 _setLoaded : function(){
37703 this.loaded = true;
37707 closeClick : function(e){
37710 this.fireEvent("beforeclose", this, o);
37711 if(o.cancel !== true){
37712 this.tabPanel.removeTab(this.id);
37716 * The text displayed in the tooltip for the close icon.
37719 closeText : "Close this tab"