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
9097 this.el.removeClass(this.invalidClass);
9099 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9101 var feedback = this.el.select('.form-control-feedback', true).first();
9104 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9109 this.fireEvent('valid', this);
9113 * Mark this field as valid
9115 markValid : function()
9117 if(!this.el || this.preventMark){ // not rendered...
9121 this.el.removeClass([this.invalidClass, this.validClass]);
9123 var feedback = this.el.select('.form-control-feedback', true).first();
9126 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9133 if(this.allowBlank && !this.getRawValue().length){
9138 this.indicator.hide();
9141 this.el.addClass(this.validClass);
9143 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9145 var feedback = this.el.select('.form-control-feedback', true).first();
9148 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9149 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9154 this.fireEvent('valid', this);
9158 * Mark this field as invalid
9159 * @param {String} msg The validation message
9161 markInvalid : function(msg)
9163 if(!this.el || this.preventMark){ // not rendered
9167 this.el.removeClass([this.invalidClass, this.validClass]);
9169 var feedback = this.el.select('.form-control-feedback', true).first();
9172 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9179 if(this.allowBlank && !this.getRawValue().length){
9184 this.indicator.show();
9187 this.el.addClass(this.invalidClass);
9189 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9191 var feedback = this.el.select('.form-control-feedback', true).first();
9194 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9196 if(this.getValue().length || this.forceFeedback){
9197 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9204 this.fireEvent('invalid', this, msg);
9207 SafariOnKeyDown : function(event)
9209 // this is a workaround for a password hang bug on chrome/ webkit.
9210 if (this.inputEl().dom.type != 'password') {
9214 var isSelectAll = false;
9216 if(this.inputEl().dom.selectionEnd > 0){
9217 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9219 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9220 event.preventDefault();
9225 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9227 event.preventDefault();
9228 // this is very hacky as keydown always get's upper case.
9230 var cc = String.fromCharCode(event.getCharCode());
9231 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9235 adjustWidth : function(tag, w){
9236 tag = tag.toLowerCase();
9237 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9238 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9242 if(tag == 'textarea'){
9245 }else if(Roo.isOpera){
9249 if(tag == 'textarea'){
9268 * @class Roo.bootstrap.TextArea
9269 * @extends Roo.bootstrap.Input
9270 * Bootstrap TextArea class
9271 * @cfg {Number} cols Specifies the visible width of a text area
9272 * @cfg {Number} rows Specifies the visible number of lines in a text area
9273 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9274 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9275 * @cfg {string} html text
9278 * Create a new TextArea
9279 * @param {Object} config The config object
9282 Roo.bootstrap.TextArea = function(config){
9283 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9287 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9297 getAutoCreate : function(){
9299 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9310 value : this.value || '',
9311 html: this.html || '',
9312 cls : 'form-control',
9313 placeholder : this.placeholder || ''
9317 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9318 input.maxLength = this.maxLength;
9322 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9326 input.cols = this.cols;
9329 if (this.readOnly) {
9330 input.readonly = true;
9334 input.name = this.name;
9338 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9342 ['xs','sm','md','lg'].map(function(size){
9343 if (settings[size]) {
9344 cfg.cls += ' col-' + size + '-' + settings[size];
9348 var inputblock = input;
9350 if(this.hasFeedback && !this.allowBlank){
9354 cls: 'glyphicon form-control-feedback'
9358 cls : 'has-feedback',
9367 if (this.before || this.after) {
9370 cls : 'input-group',
9374 inputblock.cn.push({
9376 cls : 'input-group-addon',
9381 inputblock.cn.push(input);
9383 if(this.hasFeedback && !this.allowBlank){
9384 inputblock.cls += ' has-feedback';
9385 inputblock.cn.push(feedback);
9389 inputblock.cn.push({
9391 cls : 'input-group-addon',
9398 if (align ==='left' && this.fieldLabel.length) {
9403 cls : 'control-label',
9404 html : this.fieldLabel
9415 if(this.labelWidth > 12){
9416 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9419 if(this.labelWidth < 13 && this.labelmd == 0){
9420 this.labelmd = this.labelWidth;
9423 if(this.labellg > 0){
9424 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9425 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9428 if(this.labelmd > 0){
9429 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9430 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9433 if(this.labelsm > 0){
9434 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9435 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9438 if(this.labelxs > 0){
9439 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9440 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9443 } else if ( this.fieldLabel.length) {
9448 //cls : 'input-group-addon',
9449 html : this.fieldLabel
9467 if (this.disabled) {
9468 input.disabled=true;
9475 * return the real textarea element.
9477 inputEl: function ()
9479 return this.el.select('textarea.form-control',true).first();
9483 * Clear any invalid styles/messages for this field
9485 clearInvalid : function()
9488 if(!this.el || this.preventMark){ // not rendered
9492 var label = this.el.select('label', true).first();
9493 var icon = this.el.select('i.fa-star', true).first();
9499 this.el.removeClass(this.invalidClass);
9501 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9503 var feedback = this.el.select('.form-control-feedback', true).first();
9506 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9511 this.fireEvent('valid', this);
9515 * Mark this field as valid
9517 markValid : function()
9519 if(!this.el || this.preventMark){ // not rendered
9523 this.el.removeClass([this.invalidClass, this.validClass]);
9525 var feedback = this.el.select('.form-control-feedback', true).first();
9528 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9531 if(this.disabled || this.allowBlank){
9535 var label = this.el.select('label', true).first();
9536 var icon = this.el.select('i.fa-star', true).first();
9542 this.el.addClass(this.validClass);
9544 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9546 var feedback = this.el.select('.form-control-feedback', true).first();
9549 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9550 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9555 this.fireEvent('valid', this);
9559 * Mark this field as invalid
9560 * @param {String} msg The validation message
9562 markInvalid : function(msg)
9564 if(!this.el || this.preventMark){ // not rendered
9568 this.el.removeClass([this.invalidClass, this.validClass]);
9570 var feedback = this.el.select('.form-control-feedback', true).first();
9573 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9576 if(this.disabled || this.allowBlank){
9580 var label = this.el.select('label', true).first();
9581 var icon = this.el.select('i.fa-star', true).first();
9583 if(!this.getValue().length && label && !icon){
9584 this.el.createChild({
9586 cls : 'text-danger fa fa-lg fa-star',
9587 tooltip : 'This field is required',
9588 style : 'margin-right:5px;'
9592 this.el.addClass(this.invalidClass);
9594 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9596 var feedback = this.el.select('.form-control-feedback', true).first();
9599 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9601 if(this.getValue().length || this.forceFeedback){
9602 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9609 this.fireEvent('invalid', this, msg);
9617 * trigger field - base class for combo..
9622 * @class Roo.bootstrap.TriggerField
9623 * @extends Roo.bootstrap.Input
9624 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9625 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9626 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9627 * for which you can provide a custom implementation. For example:
9629 var trigger = new Roo.bootstrap.TriggerField();
9630 trigger.onTriggerClick = myTriggerFn;
9631 trigger.applyTo('my-field');
9634 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9635 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9636 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9637 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9638 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9641 * Create a new TriggerField.
9642 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9643 * to the base TextField)
9645 Roo.bootstrap.TriggerField = function(config){
9646 this.mimicing = false;
9647 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9650 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9652 * @cfg {String} triggerClass A CSS class to apply to the trigger
9655 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9660 * @cfg {Boolean} removable (true|false) special filter default false
9664 /** @cfg {Boolean} grow @hide */
9665 /** @cfg {Number} growMin @hide */
9666 /** @cfg {Number} growMax @hide */
9672 autoSize: Roo.emptyFn,
9679 actionMode : 'wrap',
9684 getAutoCreate : function(){
9686 var align = this.labelAlign || this.parentLabelAlign();
9691 cls: 'form-group' //input-group
9698 type : this.inputType,
9699 cls : 'form-control',
9700 autocomplete: 'new-password',
9701 placeholder : this.placeholder || ''
9705 input.name = this.name;
9708 input.cls += ' input-' + this.size;
9711 if (this.disabled) {
9712 input.disabled=true;
9715 var inputblock = input;
9717 if(this.hasFeedback && !this.allowBlank){
9721 cls: 'glyphicon form-control-feedback'
9724 if(this.removable && !this.editable && !this.tickable){
9726 cls : 'has-feedback',
9732 cls : 'roo-combo-removable-btn close'
9739 cls : 'has-feedback',
9748 if(this.removable && !this.editable && !this.tickable){
9750 cls : 'roo-removable',
9756 cls : 'roo-combo-removable-btn close'
9763 if (this.before || this.after) {
9766 cls : 'input-group',
9770 inputblock.cn.push({
9772 cls : 'input-group-addon',
9777 inputblock.cn.push(input);
9779 if(this.hasFeedback && !this.allowBlank){
9780 inputblock.cls += ' has-feedback';
9781 inputblock.cn.push(feedback);
9785 inputblock.cn.push({
9787 cls : 'input-group-addon',
9800 cls: 'form-hidden-field'
9814 cls: 'form-hidden-field'
9818 cls: 'roo-select2-choices',
9822 cls: 'roo-select2-search-field',
9835 cls: 'roo-select2-container input-group',
9840 // cls: 'typeahead typeahead-long dropdown-menu',
9841 // style: 'display:none'
9846 if(!this.multiple && this.showToggleBtn){
9852 if (this.caret != false) {
9855 cls: 'fa fa-' + this.caret
9862 cls : 'input-group-addon btn dropdown-toggle',
9867 cls: 'combobox-clear',
9881 combobox.cls += ' roo-select2-container-multi';
9884 if (align ==='left' && this.fieldLabel.length) {
9886 cfg.cls += ' roo-form-group-label-left';
9891 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9892 tooltip : 'This field is required'
9897 cls : 'control-label',
9898 html : this.fieldLabel
9910 var labelCfg = cfg.cn[1];
9911 var contentCfg = cfg.cn[2];
9913 if(this.indicatorpos == 'right'){
9918 cls : 'control-label',
9922 html : this.fieldLabel
9926 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9927 tooltip : 'This field is required'
9940 labelCfg = cfg.cn[0];
9941 contentCfg = cfg.cn[1];
9944 if(this.labelWidth > 12){
9945 labelCfg.style = "width: " + this.labelWidth + 'px';
9948 if(this.labelWidth < 13 && this.labelmd == 0){
9949 this.labelmd = this.labelWidth;
9952 if(this.labellg > 0){
9953 labelCfg.cls += ' col-lg-' + this.labellg;
9954 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9957 if(this.labelmd > 0){
9958 labelCfg.cls += ' col-md-' + this.labelmd;
9959 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9962 if(this.labelsm > 0){
9963 labelCfg.cls += ' col-sm-' + this.labelsm;
9964 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9967 if(this.labelxs > 0){
9968 labelCfg.cls += ' col-xs-' + this.labelxs;
9969 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9972 } else if ( this.fieldLabel.length) {
9973 // Roo.log(" label");
9977 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9978 tooltip : 'This field is required'
9982 //cls : 'input-group-addon',
9983 html : this.fieldLabel
9991 if(this.indicatorpos == 'right'){
9999 html : this.fieldLabel
10003 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10004 tooltip : 'This field is required'
10017 // Roo.log(" no label && no align");
10024 ['xs','sm','md','lg'].map(function(size){
10025 if (settings[size]) {
10026 cfg.cls += ' col-' + size + '-' + settings[size];
10037 onResize : function(w, h){
10038 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10039 // if(typeof w == 'number'){
10040 // var x = w - this.trigger.getWidth();
10041 // this.inputEl().setWidth(this.adjustWidth('input', x));
10042 // this.trigger.setStyle('left', x+'px');
10047 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10050 getResizeEl : function(){
10051 return this.inputEl();
10055 getPositionEl : function(){
10056 return this.inputEl();
10060 alignErrorIcon : function(){
10061 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10065 initEvents : function(){
10069 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10070 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10071 if(!this.multiple && this.showToggleBtn){
10072 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10073 if(this.hideTrigger){
10074 this.trigger.setDisplayed(false);
10076 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10080 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10083 if(this.removable && !this.editable && !this.tickable){
10084 var close = this.closeTriggerEl();
10087 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10088 close.on('click', this.removeBtnClick, this, close);
10092 //this.trigger.addClassOnOver('x-form-trigger-over');
10093 //this.trigger.addClassOnClick('x-form-trigger-click');
10096 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10100 closeTriggerEl : function()
10102 var close = this.el.select('.roo-combo-removable-btn', true).first();
10103 return close ? close : false;
10106 removeBtnClick : function(e, h, el)
10108 e.preventDefault();
10110 if(this.fireEvent("remove", this) !== false){
10112 this.fireEvent("afterremove", this)
10116 createList : function()
10118 this.list = Roo.get(document.body).createChild({
10120 cls: 'typeahead typeahead-long dropdown-menu',
10121 style: 'display:none'
10124 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10129 initTrigger : function(){
10134 onDestroy : function(){
10136 this.trigger.removeAllListeners();
10137 // this.trigger.remove();
10140 // this.wrap.remove();
10142 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10146 onFocus : function(){
10147 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10149 if(!this.mimicing){
10150 this.wrap.addClass('x-trigger-wrap-focus');
10151 this.mimicing = true;
10152 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10153 if(this.monitorTab){
10154 this.el.on("keydown", this.checkTab, this);
10161 checkTab : function(e){
10162 if(e.getKey() == e.TAB){
10163 this.triggerBlur();
10168 onBlur : function(){
10173 mimicBlur : function(e, t){
10175 if(!this.wrap.contains(t) && this.validateBlur()){
10176 this.triggerBlur();
10182 triggerBlur : function(){
10183 this.mimicing = false;
10184 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10185 if(this.monitorTab){
10186 this.el.un("keydown", this.checkTab, this);
10188 //this.wrap.removeClass('x-trigger-wrap-focus');
10189 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10193 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10194 validateBlur : function(e, t){
10199 onDisable : function(){
10200 this.inputEl().dom.disabled = true;
10201 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10203 // this.wrap.addClass('x-item-disabled');
10208 onEnable : function(){
10209 this.inputEl().dom.disabled = false;
10210 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10212 // this.el.removeClass('x-item-disabled');
10217 onShow : function(){
10218 var ae = this.getActionEl();
10221 ae.dom.style.display = '';
10222 ae.dom.style.visibility = 'visible';
10228 onHide : function(){
10229 var ae = this.getActionEl();
10230 ae.dom.style.display = 'none';
10234 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10235 * by an implementing function.
10237 * @param {EventObject} e
10239 onTriggerClick : Roo.emptyFn
10243 * Ext JS Library 1.1.1
10244 * Copyright(c) 2006-2007, Ext JS, LLC.
10246 * Originally Released Under LGPL - original licence link has changed is not relivant.
10249 * <script type="text/javascript">
10254 * @class Roo.data.SortTypes
10256 * Defines the default sorting (casting?) comparison functions used when sorting data.
10258 Roo.data.SortTypes = {
10260 * Default sort that does nothing
10261 * @param {Mixed} s The value being converted
10262 * @return {Mixed} The comparison value
10264 none : function(s){
10269 * The regular expression used to strip tags
10273 stripTagsRE : /<\/?[^>]+>/gi,
10276 * Strips all HTML tags to sort on text only
10277 * @param {Mixed} s The value being converted
10278 * @return {String} The comparison value
10280 asText : function(s){
10281 return String(s).replace(this.stripTagsRE, "");
10285 * Strips all HTML tags to sort on text only - Case insensitive
10286 * @param {Mixed} s The value being converted
10287 * @return {String} The comparison value
10289 asUCText : function(s){
10290 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10294 * Case insensitive string
10295 * @param {Mixed} s The value being converted
10296 * @return {String} The comparison value
10298 asUCString : function(s) {
10299 return String(s).toUpperCase();
10304 * @param {Mixed} s The value being converted
10305 * @return {Number} The comparison value
10307 asDate : function(s) {
10311 if(s instanceof Date){
10312 return s.getTime();
10314 return Date.parse(String(s));
10319 * @param {Mixed} s The value being converted
10320 * @return {Float} The comparison value
10322 asFloat : function(s) {
10323 var val = parseFloat(String(s).replace(/,/g, ""));
10332 * @param {Mixed} s The value being converted
10333 * @return {Number} The comparison value
10335 asInt : function(s) {
10336 var val = parseInt(String(s).replace(/,/g, ""));
10344 * Ext JS Library 1.1.1
10345 * Copyright(c) 2006-2007, Ext JS, LLC.
10347 * Originally Released Under LGPL - original licence link has changed is not relivant.
10350 * <script type="text/javascript">
10354 * @class Roo.data.Record
10355 * Instances of this class encapsulate both record <em>definition</em> information, and record
10356 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10357 * to access Records cached in an {@link Roo.data.Store} object.<br>
10359 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10360 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10363 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10365 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10366 * {@link #create}. The parameters are the same.
10367 * @param {Array} data An associative Array of data values keyed by the field name.
10368 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10369 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10370 * not specified an integer id is generated.
10372 Roo.data.Record = function(data, id){
10373 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10378 * Generate a constructor for a specific record layout.
10379 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10380 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10381 * Each field definition object may contain the following properties: <ul>
10382 * <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,
10383 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10384 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10385 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10386 * is being used, then this is a string containing the javascript expression to reference the data relative to
10387 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10388 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10389 * this may be omitted.</p></li>
10390 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10391 * <ul><li>auto (Default, implies no conversion)</li>
10396 * <li>date</li></ul></p></li>
10397 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10398 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10399 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10400 * by the Reader into an object that will be stored in the Record. It is passed the
10401 * following parameters:<ul>
10402 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10404 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10406 * <br>usage:<br><pre><code>
10407 var TopicRecord = Roo.data.Record.create(
10408 {name: 'title', mapping: 'topic_title'},
10409 {name: 'author', mapping: 'username'},
10410 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10411 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10412 {name: 'lastPoster', mapping: 'user2'},
10413 {name: 'excerpt', mapping: 'post_text'}
10416 var myNewRecord = new TopicRecord({
10417 title: 'Do my job please',
10420 lastPost: new Date(),
10421 lastPoster: 'Animal',
10422 excerpt: 'No way dude!'
10424 myStore.add(myNewRecord);
10429 Roo.data.Record.create = function(o){
10430 var f = function(){
10431 f.superclass.constructor.apply(this, arguments);
10433 Roo.extend(f, Roo.data.Record);
10434 var p = f.prototype;
10435 p.fields = new Roo.util.MixedCollection(false, function(field){
10438 for(var i = 0, len = o.length; i < len; i++){
10439 p.fields.add(new Roo.data.Field(o[i]));
10441 f.getField = function(name){
10442 return p.fields.get(name);
10447 Roo.data.Record.AUTO_ID = 1000;
10448 Roo.data.Record.EDIT = 'edit';
10449 Roo.data.Record.REJECT = 'reject';
10450 Roo.data.Record.COMMIT = 'commit';
10452 Roo.data.Record.prototype = {
10454 * Readonly flag - true if this record has been modified.
10463 join : function(store){
10464 this.store = store;
10468 * Set the named field to the specified value.
10469 * @param {String} name The name of the field to set.
10470 * @param {Object} value The value to set the field to.
10472 set : function(name, value){
10473 if(this.data[name] == value){
10477 if(!this.modified){
10478 this.modified = {};
10480 if(typeof this.modified[name] == 'undefined'){
10481 this.modified[name] = this.data[name];
10483 this.data[name] = value;
10484 if(!this.editing && this.store){
10485 this.store.afterEdit(this);
10490 * Get the value of the named field.
10491 * @param {String} name The name of the field to get the value of.
10492 * @return {Object} The value of the field.
10494 get : function(name){
10495 return this.data[name];
10499 beginEdit : function(){
10500 this.editing = true;
10501 this.modified = {};
10505 cancelEdit : function(){
10506 this.editing = false;
10507 delete this.modified;
10511 endEdit : function(){
10512 this.editing = false;
10513 if(this.dirty && this.store){
10514 this.store.afterEdit(this);
10519 * Usually called by the {@link Roo.data.Store} which owns the Record.
10520 * Rejects all changes made to the Record since either creation, or the last commit operation.
10521 * Modified fields are reverted to their original values.
10523 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10524 * of reject operations.
10526 reject : function(){
10527 var m = this.modified;
10529 if(typeof m[n] != "function"){
10530 this.data[n] = m[n];
10533 this.dirty = false;
10534 delete this.modified;
10535 this.editing = false;
10537 this.store.afterReject(this);
10542 * Usually called by the {@link Roo.data.Store} which owns the Record.
10543 * Commits all changes made to the Record since either creation, or the last commit operation.
10545 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10546 * of commit operations.
10548 commit : function(){
10549 this.dirty = false;
10550 delete this.modified;
10551 this.editing = false;
10553 this.store.afterCommit(this);
10558 hasError : function(){
10559 return this.error != null;
10563 clearError : function(){
10568 * Creates a copy of this record.
10569 * @param {String} id (optional) A new record id if you don't want to use this record's id
10572 copy : function(newId) {
10573 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10577 * Ext JS Library 1.1.1
10578 * Copyright(c) 2006-2007, Ext JS, LLC.
10580 * Originally Released Under LGPL - original licence link has changed is not relivant.
10583 * <script type="text/javascript">
10589 * @class Roo.data.Store
10590 * @extends Roo.util.Observable
10591 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10592 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10594 * 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
10595 * has no knowledge of the format of the data returned by the Proxy.<br>
10597 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10598 * instances from the data object. These records are cached and made available through accessor functions.
10600 * Creates a new Store.
10601 * @param {Object} config A config object containing the objects needed for the Store to access data,
10602 * and read the data into Records.
10604 Roo.data.Store = function(config){
10605 this.data = new Roo.util.MixedCollection(false);
10606 this.data.getKey = function(o){
10609 this.baseParams = {};
10611 this.paramNames = {
10616 "multisort" : "_multisort"
10619 if(config && config.data){
10620 this.inlineData = config.data;
10621 delete config.data;
10624 Roo.apply(this, config);
10626 if(this.reader){ // reader passed
10627 this.reader = Roo.factory(this.reader, Roo.data);
10628 this.reader.xmodule = this.xmodule || false;
10629 if(!this.recordType){
10630 this.recordType = this.reader.recordType;
10632 if(this.reader.onMetaChange){
10633 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10637 if(this.recordType){
10638 this.fields = this.recordType.prototype.fields;
10640 this.modified = [];
10644 * @event datachanged
10645 * Fires when the data cache has changed, and a widget which is using this Store
10646 * as a Record cache should refresh its view.
10647 * @param {Store} this
10649 datachanged : true,
10651 * @event metachange
10652 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10653 * @param {Store} this
10654 * @param {Object} meta The JSON metadata
10659 * Fires when Records have been added to the Store
10660 * @param {Store} this
10661 * @param {Roo.data.Record[]} records The array of Records added
10662 * @param {Number} index The index at which the record(s) were added
10667 * Fires when a Record has been removed from the Store
10668 * @param {Store} this
10669 * @param {Roo.data.Record} record The Record that was removed
10670 * @param {Number} index The index at which the record was removed
10675 * Fires when a Record has been updated
10676 * @param {Store} this
10677 * @param {Roo.data.Record} record The Record that was updated
10678 * @param {String} operation The update operation being performed. Value may be one of:
10680 Roo.data.Record.EDIT
10681 Roo.data.Record.REJECT
10682 Roo.data.Record.COMMIT
10688 * Fires when the data cache has been cleared.
10689 * @param {Store} this
10693 * @event beforeload
10694 * Fires before a request is made for a new data object. If the beforeload handler returns false
10695 * the load action will be canceled.
10696 * @param {Store} this
10697 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10701 * @event beforeloadadd
10702 * Fires after a new set of Records has been loaded.
10703 * @param {Store} this
10704 * @param {Roo.data.Record[]} records The Records that were loaded
10705 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10707 beforeloadadd : true,
10710 * Fires after a new set of Records has been loaded, before they are added to the store.
10711 * @param {Store} this
10712 * @param {Roo.data.Record[]} records The Records that were loaded
10713 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10714 * @params {Object} return from reader
10718 * @event loadexception
10719 * Fires if an exception occurs in the Proxy during loading.
10720 * Called with the signature of the Proxy's "loadexception" event.
10721 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10724 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10725 * @param {Object} load options
10726 * @param {Object} jsonData from your request (normally this contains the Exception)
10728 loadexception : true
10732 this.proxy = Roo.factory(this.proxy, Roo.data);
10733 this.proxy.xmodule = this.xmodule || false;
10734 this.relayEvents(this.proxy, ["loadexception"]);
10736 this.sortToggle = {};
10737 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10739 Roo.data.Store.superclass.constructor.call(this);
10741 if(this.inlineData){
10742 this.loadData(this.inlineData);
10743 delete this.inlineData;
10747 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10749 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10750 * without a remote query - used by combo/forms at present.
10754 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10757 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10760 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10761 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10764 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10765 * on any HTTP request
10768 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10771 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10775 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10776 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10778 remoteSort : false,
10781 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10782 * loaded or when a record is removed. (defaults to false).
10784 pruneModifiedRecords : false,
10787 lastOptions : null,
10790 * Add Records to the Store and fires the add event.
10791 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10793 add : function(records){
10794 records = [].concat(records);
10795 for(var i = 0, len = records.length; i < len; i++){
10796 records[i].join(this);
10798 var index = this.data.length;
10799 this.data.addAll(records);
10800 this.fireEvent("add", this, records, index);
10804 * Remove a Record from the Store and fires the remove event.
10805 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10807 remove : function(record){
10808 var index = this.data.indexOf(record);
10809 this.data.removeAt(index);
10810 if(this.pruneModifiedRecords){
10811 this.modified.remove(record);
10813 this.fireEvent("remove", this, record, index);
10817 * Remove all Records from the Store and fires the clear event.
10819 removeAll : function(){
10821 if(this.pruneModifiedRecords){
10822 this.modified = [];
10824 this.fireEvent("clear", this);
10828 * Inserts Records to the Store at the given index and fires the add event.
10829 * @param {Number} index The start index at which to insert the passed Records.
10830 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10832 insert : function(index, records){
10833 records = [].concat(records);
10834 for(var i = 0, len = records.length; i < len; i++){
10835 this.data.insert(index, records[i]);
10836 records[i].join(this);
10838 this.fireEvent("add", this, records, index);
10842 * Get the index within the cache of the passed Record.
10843 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10844 * @return {Number} The index of the passed Record. Returns -1 if not found.
10846 indexOf : function(record){
10847 return this.data.indexOf(record);
10851 * Get the index within the cache of the Record with the passed id.
10852 * @param {String} id The id of the Record to find.
10853 * @return {Number} The index of the Record. Returns -1 if not found.
10855 indexOfId : function(id){
10856 return this.data.indexOfKey(id);
10860 * Get the Record with the specified id.
10861 * @param {String} id The id of the Record to find.
10862 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10864 getById : function(id){
10865 return this.data.key(id);
10869 * Get the Record at the specified index.
10870 * @param {Number} index The index of the Record to find.
10871 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10873 getAt : function(index){
10874 return this.data.itemAt(index);
10878 * Returns a range of Records between specified indices.
10879 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10880 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10881 * @return {Roo.data.Record[]} An array of Records
10883 getRange : function(start, end){
10884 return this.data.getRange(start, end);
10888 storeOptions : function(o){
10889 o = Roo.apply({}, o);
10892 this.lastOptions = o;
10896 * Loads the Record cache from the configured Proxy using the configured Reader.
10898 * If using remote paging, then the first load call must specify the <em>start</em>
10899 * and <em>limit</em> properties in the options.params property to establish the initial
10900 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10902 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10903 * and this call will return before the new data has been loaded. Perform any post-processing
10904 * in a callback function, or in a "load" event handler.</strong>
10906 * @param {Object} options An object containing properties which control loading options:<ul>
10907 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10908 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10909 * passed the following arguments:<ul>
10910 * <li>r : Roo.data.Record[]</li>
10911 * <li>options: Options object from the load call</li>
10912 * <li>success: Boolean success indicator</li></ul></li>
10913 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10914 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10917 load : function(options){
10918 options = options || {};
10919 if(this.fireEvent("beforeload", this, options) !== false){
10920 this.storeOptions(options);
10921 var p = Roo.apply(options.params || {}, this.baseParams);
10922 // if meta was not loaded from remote source.. try requesting it.
10923 if (!this.reader.metaFromRemote) {
10924 p._requestMeta = 1;
10926 if(this.sortInfo && this.remoteSort){
10927 var pn = this.paramNames;
10928 p[pn["sort"]] = this.sortInfo.field;
10929 p[pn["dir"]] = this.sortInfo.direction;
10931 if (this.multiSort) {
10932 var pn = this.paramNames;
10933 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10936 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10941 * Reloads the Record cache from the configured Proxy using the configured Reader and
10942 * the options from the last load operation performed.
10943 * @param {Object} options (optional) An object containing properties which may override the options
10944 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10945 * the most recently used options are reused).
10947 reload : function(options){
10948 this.load(Roo.applyIf(options||{}, this.lastOptions));
10952 // Called as a callback by the Reader during a load operation.
10953 loadRecords : function(o, options, success){
10954 if(!o || success === false){
10955 if(success !== false){
10956 this.fireEvent("load", this, [], options, o);
10958 if(options.callback){
10959 options.callback.call(options.scope || this, [], options, false);
10963 // if data returned failure - throw an exception.
10964 if (o.success === false) {
10965 // show a message if no listener is registered.
10966 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10967 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10969 // loadmask wil be hooked into this..
10970 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10973 var r = o.records, t = o.totalRecords || r.length;
10975 this.fireEvent("beforeloadadd", this, r, options, o);
10977 if(!options || options.add !== true){
10978 if(this.pruneModifiedRecords){
10979 this.modified = [];
10981 for(var i = 0, len = r.length; i < len; i++){
10985 this.data = this.snapshot;
10986 delete this.snapshot;
10989 this.data.addAll(r);
10990 this.totalLength = t;
10992 this.fireEvent("datachanged", this);
10994 this.totalLength = Math.max(t, this.data.length+r.length);
10998 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11000 var e = new Roo.data.Record({});
11002 e.set(this.parent.displayField, this.parent.emptyTitle);
11003 e.set(this.parent.valueField, '');
11008 this.fireEvent("load", this, r, options, o);
11009 if(options.callback){
11010 options.callback.call(options.scope || this, r, options, true);
11016 * Loads data from a passed data block. A Reader which understands the format of the data
11017 * must have been configured in the constructor.
11018 * @param {Object} data The data block from which to read the Records. The format of the data expected
11019 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11020 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11022 loadData : function(o, append){
11023 var r = this.reader.readRecords(o);
11024 this.loadRecords(r, {add: append}, true);
11028 * Gets the number of cached records.
11030 * <em>If using paging, this may not be the total size of the dataset. If the data object
11031 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11032 * the data set size</em>
11034 getCount : function(){
11035 return this.data.length || 0;
11039 * Gets the total number of records in the dataset as returned by the server.
11041 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11042 * the dataset size</em>
11044 getTotalCount : function(){
11045 return this.totalLength || 0;
11049 * Returns the sort state of the Store as an object with two properties:
11051 field {String} The name of the field by which the Records are sorted
11052 direction {String} The sort order, "ASC" or "DESC"
11055 getSortState : function(){
11056 return this.sortInfo;
11060 applySort : function(){
11061 if(this.sortInfo && !this.remoteSort){
11062 var s = this.sortInfo, f = s.field;
11063 var st = this.fields.get(f).sortType;
11064 var fn = function(r1, r2){
11065 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11066 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11068 this.data.sort(s.direction, fn);
11069 if(this.snapshot && this.snapshot != this.data){
11070 this.snapshot.sort(s.direction, fn);
11076 * Sets the default sort column and order to be used by the next load operation.
11077 * @param {String} fieldName The name of the field to sort by.
11078 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11080 setDefaultSort : function(field, dir){
11081 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11085 * Sort the Records.
11086 * If remote sorting is used, the sort is performed on the server, and the cache is
11087 * reloaded. If local sorting is used, the cache is sorted internally.
11088 * @param {String} fieldName The name of the field to sort by.
11089 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11091 sort : function(fieldName, dir){
11092 var f = this.fields.get(fieldName);
11094 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11096 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11097 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11102 this.sortToggle[f.name] = dir;
11103 this.sortInfo = {field: f.name, direction: dir};
11104 if(!this.remoteSort){
11106 this.fireEvent("datachanged", this);
11108 this.load(this.lastOptions);
11113 * Calls the specified function for each of the Records in the cache.
11114 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11115 * Returning <em>false</em> aborts and exits the iteration.
11116 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11118 each : function(fn, scope){
11119 this.data.each(fn, scope);
11123 * Gets all records modified since the last commit. Modified records are persisted across load operations
11124 * (e.g., during paging).
11125 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11127 getModifiedRecords : function(){
11128 return this.modified;
11132 createFilterFn : function(property, value, anyMatch){
11133 if(!value.exec){ // not a regex
11134 value = String(value);
11135 if(value.length == 0){
11138 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11140 return function(r){
11141 return value.test(r.data[property]);
11146 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11147 * @param {String} property A field on your records
11148 * @param {Number} start The record index to start at (defaults to 0)
11149 * @param {Number} end The last record index to include (defaults to length - 1)
11150 * @return {Number} The sum
11152 sum : function(property, start, end){
11153 var rs = this.data.items, v = 0;
11154 start = start || 0;
11155 end = (end || end === 0) ? end : rs.length-1;
11157 for(var i = start; i <= end; i++){
11158 v += (rs[i].data[property] || 0);
11164 * Filter the records by a specified property.
11165 * @param {String} field A field on your records
11166 * @param {String/RegExp} value Either a string that the field
11167 * should start with or a RegExp to test against the field
11168 * @param {Boolean} anyMatch True to match any part not just the beginning
11170 filter : function(property, value, anyMatch){
11171 var fn = this.createFilterFn(property, value, anyMatch);
11172 return fn ? this.filterBy(fn) : this.clearFilter();
11176 * Filter by a function. The specified function will be called with each
11177 * record in this data source. If the function returns true the record is included,
11178 * otherwise it is filtered.
11179 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11180 * @param {Object} scope (optional) The scope of the function (defaults to this)
11182 filterBy : function(fn, scope){
11183 this.snapshot = this.snapshot || this.data;
11184 this.data = this.queryBy(fn, scope||this);
11185 this.fireEvent("datachanged", this);
11189 * Query the records by a specified property.
11190 * @param {String} field A field on your records
11191 * @param {String/RegExp} value Either a string that the field
11192 * should start with or a RegExp to test against the field
11193 * @param {Boolean} anyMatch True to match any part not just the beginning
11194 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11196 query : function(property, value, anyMatch){
11197 var fn = this.createFilterFn(property, value, anyMatch);
11198 return fn ? this.queryBy(fn) : this.data.clone();
11202 * Query by a function. The specified function will be called with each
11203 * record in this data source. If the function returns true the record is included
11205 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11206 * @param {Object} scope (optional) The scope of the function (defaults to this)
11207 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11209 queryBy : function(fn, scope){
11210 var data = this.snapshot || this.data;
11211 return data.filterBy(fn, scope||this);
11215 * Collects unique values for a particular dataIndex from this store.
11216 * @param {String} dataIndex The property to collect
11217 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11218 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11219 * @return {Array} An array of the unique values
11221 collect : function(dataIndex, allowNull, bypassFilter){
11222 var d = (bypassFilter === true && this.snapshot) ?
11223 this.snapshot.items : this.data.items;
11224 var v, sv, r = [], l = {};
11225 for(var i = 0, len = d.length; i < len; i++){
11226 v = d[i].data[dataIndex];
11228 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11237 * Revert to a view of the Record cache with no filtering applied.
11238 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11240 clearFilter : function(suppressEvent){
11241 if(this.snapshot && this.snapshot != this.data){
11242 this.data = this.snapshot;
11243 delete this.snapshot;
11244 if(suppressEvent !== true){
11245 this.fireEvent("datachanged", this);
11251 afterEdit : function(record){
11252 if(this.modified.indexOf(record) == -1){
11253 this.modified.push(record);
11255 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11259 afterReject : function(record){
11260 this.modified.remove(record);
11261 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11265 afterCommit : function(record){
11266 this.modified.remove(record);
11267 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11271 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11272 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11274 commitChanges : function(){
11275 var m = this.modified.slice(0);
11276 this.modified = [];
11277 for(var i = 0, len = m.length; i < len; i++){
11283 * Cancel outstanding changes on all changed records.
11285 rejectChanges : function(){
11286 var m = this.modified.slice(0);
11287 this.modified = [];
11288 for(var i = 0, len = m.length; i < len; i++){
11293 onMetaChange : function(meta, rtype, o){
11294 this.recordType = rtype;
11295 this.fields = rtype.prototype.fields;
11296 delete this.snapshot;
11297 this.sortInfo = meta.sortInfo || this.sortInfo;
11298 this.modified = [];
11299 this.fireEvent('metachange', this, this.reader.meta);
11302 moveIndex : function(data, type)
11304 var index = this.indexOf(data);
11306 var newIndex = index + type;
11310 this.insert(newIndex, data);
11315 * Ext JS Library 1.1.1
11316 * Copyright(c) 2006-2007, Ext JS, LLC.
11318 * Originally Released Under LGPL - original licence link has changed is not relivant.
11321 * <script type="text/javascript">
11325 * @class Roo.data.SimpleStore
11326 * @extends Roo.data.Store
11327 * Small helper class to make creating Stores from Array data easier.
11328 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11329 * @cfg {Array} fields An array of field definition objects, or field name strings.
11330 * @cfg {Array} data The multi-dimensional array of data
11332 * @param {Object} config
11334 Roo.data.SimpleStore = function(config){
11335 Roo.data.SimpleStore.superclass.constructor.call(this, {
11337 reader: new Roo.data.ArrayReader({
11340 Roo.data.Record.create(config.fields)
11342 proxy : new Roo.data.MemoryProxy(config.data)
11346 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11348 * Ext JS Library 1.1.1
11349 * Copyright(c) 2006-2007, Ext JS, LLC.
11351 * Originally Released Under LGPL - original licence link has changed is not relivant.
11354 * <script type="text/javascript">
11359 * @extends Roo.data.Store
11360 * @class Roo.data.JsonStore
11361 * Small helper class to make creating Stores for JSON data easier. <br/>
11363 var store = new Roo.data.JsonStore({
11364 url: 'get-images.php',
11366 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11369 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11370 * JsonReader and HttpProxy (unless inline data is provided).</b>
11371 * @cfg {Array} fields An array of field definition objects, or field name strings.
11373 * @param {Object} config
11375 Roo.data.JsonStore = function(c){
11376 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11377 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11378 reader: new Roo.data.JsonReader(c, c.fields)
11381 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11383 * Ext JS Library 1.1.1
11384 * Copyright(c) 2006-2007, Ext JS, LLC.
11386 * Originally Released Under LGPL - original licence link has changed is not relivant.
11389 * <script type="text/javascript">
11393 Roo.data.Field = function(config){
11394 if(typeof config == "string"){
11395 config = {name: config};
11397 Roo.apply(this, config);
11400 this.type = "auto";
11403 var st = Roo.data.SortTypes;
11404 // named sortTypes are supported, here we look them up
11405 if(typeof this.sortType == "string"){
11406 this.sortType = st[this.sortType];
11409 // set default sortType for strings and dates
11410 if(!this.sortType){
11413 this.sortType = st.asUCString;
11416 this.sortType = st.asDate;
11419 this.sortType = st.none;
11424 var stripRe = /[\$,%]/g;
11426 // prebuilt conversion function for this field, instead of
11427 // switching every time we're reading a value
11429 var cv, dateFormat = this.dateFormat;
11434 cv = function(v){ return v; };
11437 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11441 return v !== undefined && v !== null && v !== '' ?
11442 parseInt(String(v).replace(stripRe, ""), 10) : '';
11447 return v !== undefined && v !== null && v !== '' ?
11448 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11453 cv = function(v){ return v === true || v === "true" || v == 1; };
11460 if(v instanceof Date){
11464 if(dateFormat == "timestamp"){
11465 return new Date(v*1000);
11467 return Date.parseDate(v, dateFormat);
11469 var parsed = Date.parse(v);
11470 return parsed ? new Date(parsed) : null;
11479 Roo.data.Field.prototype = {
11487 * Ext JS Library 1.1.1
11488 * Copyright(c) 2006-2007, Ext JS, LLC.
11490 * Originally Released Under LGPL - original licence link has changed is not relivant.
11493 * <script type="text/javascript">
11496 // Base class for reading structured data from a data source. This class is intended to be
11497 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11500 * @class Roo.data.DataReader
11501 * Base class for reading structured data from a data source. This class is intended to be
11502 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11505 Roo.data.DataReader = function(meta, recordType){
11509 this.recordType = recordType instanceof Array ?
11510 Roo.data.Record.create(recordType) : recordType;
11513 Roo.data.DataReader.prototype = {
11515 * Create an empty record
11516 * @param {Object} data (optional) - overlay some values
11517 * @return {Roo.data.Record} record created.
11519 newRow : function(d) {
11521 this.recordType.prototype.fields.each(function(c) {
11523 case 'int' : da[c.name] = 0; break;
11524 case 'date' : da[c.name] = new Date(); break;
11525 case 'float' : da[c.name] = 0.0; break;
11526 case 'boolean' : da[c.name] = false; break;
11527 default : da[c.name] = ""; break;
11531 return new this.recordType(Roo.apply(da, d));
11536 * Ext JS Library 1.1.1
11537 * Copyright(c) 2006-2007, Ext JS, LLC.
11539 * Originally Released Under LGPL - original licence link has changed is not relivant.
11542 * <script type="text/javascript">
11546 * @class Roo.data.DataProxy
11547 * @extends Roo.data.Observable
11548 * This class is an abstract base class for implementations which provide retrieval of
11549 * unformatted data objects.<br>
11551 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11552 * (of the appropriate type which knows how to parse the data object) to provide a block of
11553 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11555 * Custom implementations must implement the load method as described in
11556 * {@link Roo.data.HttpProxy#load}.
11558 Roo.data.DataProxy = function(){
11561 * @event beforeload
11562 * Fires before a network request is made to retrieve a data object.
11563 * @param {Object} This DataProxy object.
11564 * @param {Object} params The params parameter to the load function.
11569 * Fires before the load method's callback is called.
11570 * @param {Object} This DataProxy object.
11571 * @param {Object} o The data object.
11572 * @param {Object} arg The callback argument object passed to the load function.
11576 * @event loadexception
11577 * Fires if an Exception occurs during data retrieval.
11578 * @param {Object} This DataProxy object.
11579 * @param {Object} o The data object.
11580 * @param {Object} arg The callback argument object passed to the load function.
11581 * @param {Object} e The Exception.
11583 loadexception : true
11585 Roo.data.DataProxy.superclass.constructor.call(this);
11588 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11591 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11595 * Ext JS Library 1.1.1
11596 * Copyright(c) 2006-2007, Ext JS, LLC.
11598 * Originally Released Under LGPL - original licence link has changed is not relivant.
11601 * <script type="text/javascript">
11604 * @class Roo.data.MemoryProxy
11605 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11606 * to the Reader when its load method is called.
11608 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11610 Roo.data.MemoryProxy = function(data){
11614 Roo.data.MemoryProxy.superclass.constructor.call(this);
11618 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11621 * Load data from the requested source (in this case an in-memory
11622 * data object passed to the constructor), read the data object into
11623 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11624 * process that block using the passed callback.
11625 * @param {Object} params This parameter is not used by the MemoryProxy class.
11626 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11627 * object into a block of Roo.data.Records.
11628 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11629 * The function must be passed <ul>
11630 * <li>The Record block object</li>
11631 * <li>The "arg" argument from the load function</li>
11632 * <li>A boolean success indicator</li>
11634 * @param {Object} scope The scope in which to call the callback
11635 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11637 load : function(params, reader, callback, scope, arg){
11638 params = params || {};
11641 result = reader.readRecords(this.data);
11643 this.fireEvent("loadexception", this, arg, null, e);
11644 callback.call(scope, null, arg, false);
11647 callback.call(scope, result, arg, true);
11651 update : function(params, records){
11656 * Ext JS Library 1.1.1
11657 * Copyright(c) 2006-2007, Ext JS, LLC.
11659 * Originally Released Under LGPL - original licence link has changed is not relivant.
11662 * <script type="text/javascript">
11665 * @class Roo.data.HttpProxy
11666 * @extends Roo.data.DataProxy
11667 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11668 * configured to reference a certain URL.<br><br>
11670 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11671 * from which the running page was served.<br><br>
11673 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11675 * Be aware that to enable the browser to parse an XML document, the server must set
11676 * the Content-Type header in the HTTP response to "text/xml".
11678 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11679 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11680 * will be used to make the request.
11682 Roo.data.HttpProxy = function(conn){
11683 Roo.data.HttpProxy.superclass.constructor.call(this);
11684 // is conn a conn config or a real conn?
11686 this.useAjax = !conn || !conn.events;
11690 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11691 // thse are take from connection...
11694 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11697 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11698 * extra parameters to each request made by this object. (defaults to undefined)
11701 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11702 * to each request made by this object. (defaults to undefined)
11705 * @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)
11708 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11711 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11717 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11721 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11722 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11723 * a finer-grained basis than the DataProxy events.
11725 getConnection : function(){
11726 return this.useAjax ? Roo.Ajax : this.conn;
11730 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11731 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11732 * process that block using the passed callback.
11733 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11734 * for the request to the remote server.
11735 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11736 * object into a block of Roo.data.Records.
11737 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11738 * The function must be passed <ul>
11739 * <li>The Record block object</li>
11740 * <li>The "arg" argument from the load function</li>
11741 * <li>A boolean success indicator</li>
11743 * @param {Object} scope The scope in which to call the callback
11744 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11746 load : function(params, reader, callback, scope, arg){
11747 if(this.fireEvent("beforeload", this, params) !== false){
11749 params : params || {},
11751 callback : callback,
11756 callback : this.loadResponse,
11760 Roo.applyIf(o, this.conn);
11761 if(this.activeRequest){
11762 Roo.Ajax.abort(this.activeRequest);
11764 this.activeRequest = Roo.Ajax.request(o);
11766 this.conn.request(o);
11769 callback.call(scope||this, null, arg, false);
11774 loadResponse : function(o, success, response){
11775 delete this.activeRequest;
11777 this.fireEvent("loadexception", this, o, response);
11778 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11783 result = o.reader.read(response);
11785 this.fireEvent("loadexception", this, o, response, e);
11786 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11790 this.fireEvent("load", this, o, o.request.arg);
11791 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11795 update : function(dataSet){
11800 updateResponse : function(dataSet){
11805 * Ext JS Library 1.1.1
11806 * Copyright(c) 2006-2007, Ext JS, LLC.
11808 * Originally Released Under LGPL - original licence link has changed is not relivant.
11811 * <script type="text/javascript">
11815 * @class Roo.data.ScriptTagProxy
11816 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11817 * other than the originating domain of the running page.<br><br>
11819 * <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
11820 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11822 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11823 * source code that is used as the source inside a <script> tag.<br><br>
11825 * In order for the browser to process the returned data, the server must wrap the data object
11826 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11827 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11828 * depending on whether the callback name was passed:
11831 boolean scriptTag = false;
11832 String cb = request.getParameter("callback");
11835 response.setContentType("text/javascript");
11837 response.setContentType("application/x-json");
11839 Writer out = response.getWriter();
11841 out.write(cb + "(");
11843 out.print(dataBlock.toJsonString());
11850 * @param {Object} config A configuration object.
11852 Roo.data.ScriptTagProxy = function(config){
11853 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11854 Roo.apply(this, config);
11855 this.head = document.getElementsByTagName("head")[0];
11858 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11860 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11862 * @cfg {String} url The URL from which to request the data object.
11865 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11869 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11870 * the server the name of the callback function set up by the load call to process the returned data object.
11871 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11872 * javascript output which calls this named function passing the data object as its only parameter.
11874 callbackParam : "callback",
11876 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11877 * name to the request.
11882 * Load data from the configured URL, read the data object into
11883 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11884 * process that block using the passed callback.
11885 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11886 * for the request to the remote server.
11887 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11888 * object into a block of Roo.data.Records.
11889 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11890 * The function must be passed <ul>
11891 * <li>The Record block object</li>
11892 * <li>The "arg" argument from the load function</li>
11893 * <li>A boolean success indicator</li>
11895 * @param {Object} scope The scope in which to call the callback
11896 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11898 load : function(params, reader, callback, scope, arg){
11899 if(this.fireEvent("beforeload", this, params) !== false){
11901 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11903 var url = this.url;
11904 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11906 url += "&_dc=" + (new Date().getTime());
11908 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11911 cb : "stcCallback"+transId,
11912 scriptId : "stcScript"+transId,
11916 callback : callback,
11922 window[trans.cb] = function(o){
11923 conn.handleResponse(o, trans);
11926 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11928 if(this.autoAbort !== false){
11932 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11934 var script = document.createElement("script");
11935 script.setAttribute("src", url);
11936 script.setAttribute("type", "text/javascript");
11937 script.setAttribute("id", trans.scriptId);
11938 this.head.appendChild(script);
11940 this.trans = trans;
11942 callback.call(scope||this, null, arg, false);
11947 isLoading : function(){
11948 return this.trans ? true : false;
11952 * Abort the current server request.
11954 abort : function(){
11955 if(this.isLoading()){
11956 this.destroyTrans(this.trans);
11961 destroyTrans : function(trans, isLoaded){
11962 this.head.removeChild(document.getElementById(trans.scriptId));
11963 clearTimeout(trans.timeoutId);
11965 window[trans.cb] = undefined;
11967 delete window[trans.cb];
11970 // if hasn't been loaded, wait for load to remove it to prevent script error
11971 window[trans.cb] = function(){
11972 window[trans.cb] = undefined;
11974 delete window[trans.cb];
11981 handleResponse : function(o, trans){
11982 this.trans = false;
11983 this.destroyTrans(trans, true);
11986 result = trans.reader.readRecords(o);
11988 this.fireEvent("loadexception", this, o, trans.arg, e);
11989 trans.callback.call(trans.scope||window, null, trans.arg, false);
11992 this.fireEvent("load", this, o, trans.arg);
11993 trans.callback.call(trans.scope||window, result, trans.arg, true);
11997 handleFailure : function(trans){
11998 this.trans = false;
11999 this.destroyTrans(trans, false);
12000 this.fireEvent("loadexception", this, null, trans.arg);
12001 trans.callback.call(trans.scope||window, null, trans.arg, false);
12005 * Ext JS Library 1.1.1
12006 * Copyright(c) 2006-2007, Ext JS, LLC.
12008 * Originally Released Under LGPL - original licence link has changed is not relivant.
12011 * <script type="text/javascript">
12015 * @class Roo.data.JsonReader
12016 * @extends Roo.data.DataReader
12017 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12018 * based on mappings in a provided Roo.data.Record constructor.
12020 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12021 * in the reply previously.
12026 var RecordDef = Roo.data.Record.create([
12027 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12028 {name: 'occupation'} // This field will use "occupation" as the mapping.
12030 var myReader = new Roo.data.JsonReader({
12031 totalProperty: "results", // The property which contains the total dataset size (optional)
12032 root: "rows", // The property which contains an Array of row objects
12033 id: "id" // The property within each row object that provides an ID for the record (optional)
12037 * This would consume a JSON file like this:
12039 { 'results': 2, 'rows': [
12040 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12041 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12044 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12045 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12046 * paged from the remote server.
12047 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12048 * @cfg {String} root name of the property which contains the Array of row objects.
12049 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12050 * @cfg {Array} fields Array of field definition objects
12052 * Create a new JsonReader
12053 * @param {Object} meta Metadata configuration options
12054 * @param {Object} recordType Either an Array of field definition objects,
12055 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12057 Roo.data.JsonReader = function(meta, recordType){
12060 // set some defaults:
12061 Roo.applyIf(meta, {
12062 totalProperty: 'total',
12063 successProperty : 'success',
12068 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12070 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12073 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12074 * Used by Store query builder to append _requestMeta to params.
12077 metaFromRemote : false,
12079 * This method is only used by a DataProxy which has retrieved data from a remote server.
12080 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12081 * @return {Object} data A data block which is used by an Roo.data.Store object as
12082 * a cache of Roo.data.Records.
12084 read : function(response){
12085 var json = response.responseText;
12087 var o = /* eval:var:o */ eval("("+json+")");
12089 throw {message: "JsonReader.read: Json object not found"};
12095 this.metaFromRemote = true;
12096 this.meta = o.metaData;
12097 this.recordType = Roo.data.Record.create(o.metaData.fields);
12098 this.onMetaChange(this.meta, this.recordType, o);
12100 return this.readRecords(o);
12103 // private function a store will implement
12104 onMetaChange : function(meta, recordType, o){
12111 simpleAccess: function(obj, subsc) {
12118 getJsonAccessor: function(){
12120 return function(expr) {
12122 return(re.test(expr))
12123 ? new Function("obj", "return obj." + expr)
12128 return Roo.emptyFn;
12133 * Create a data block containing Roo.data.Records from an XML document.
12134 * @param {Object} o An object which contains an Array of row objects in the property specified
12135 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12136 * which contains the total size of the dataset.
12137 * @return {Object} data A data block which is used by an Roo.data.Store object as
12138 * a cache of Roo.data.Records.
12140 readRecords : function(o){
12142 * After any data loads, the raw JSON data is available for further custom processing.
12146 var s = this.meta, Record = this.recordType,
12147 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12149 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12151 if(s.totalProperty) {
12152 this.getTotal = this.getJsonAccessor(s.totalProperty);
12154 if(s.successProperty) {
12155 this.getSuccess = this.getJsonAccessor(s.successProperty);
12157 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12159 var g = this.getJsonAccessor(s.id);
12160 this.getId = function(rec) {
12162 return (r === undefined || r === "") ? null : r;
12165 this.getId = function(){return null;};
12168 for(var jj = 0; jj < fl; jj++){
12170 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12171 this.ef[jj] = this.getJsonAccessor(map);
12175 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12176 if(s.totalProperty){
12177 var vt = parseInt(this.getTotal(o), 10);
12182 if(s.successProperty){
12183 var vs = this.getSuccess(o);
12184 if(vs === false || vs === 'false'){
12189 for(var i = 0; i < c; i++){
12192 var id = this.getId(n);
12193 for(var j = 0; j < fl; j++){
12195 var v = this.ef[j](n);
12197 Roo.log('missing convert for ' + f.name);
12201 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12203 var record = new Record(values, id);
12205 records[i] = record;
12211 totalRecords : totalRecords
12216 * Ext JS Library 1.1.1
12217 * Copyright(c) 2006-2007, Ext JS, LLC.
12219 * Originally Released Under LGPL - original licence link has changed is not relivant.
12222 * <script type="text/javascript">
12226 * @class Roo.data.ArrayReader
12227 * @extends Roo.data.DataReader
12228 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12229 * Each element of that Array represents a row of data fields. The
12230 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12231 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12235 var RecordDef = Roo.data.Record.create([
12236 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12237 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12239 var myReader = new Roo.data.ArrayReader({
12240 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12244 * This would consume an Array like this:
12246 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12248 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12250 * Create a new JsonReader
12251 * @param {Object} meta Metadata configuration options.
12252 * @param {Object} recordType Either an Array of field definition objects
12253 * as specified to {@link Roo.data.Record#create},
12254 * or an {@link Roo.data.Record} object
12255 * created using {@link Roo.data.Record#create}.
12257 Roo.data.ArrayReader = function(meta, recordType){
12258 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12261 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12263 * Create a data block containing Roo.data.Records from an XML document.
12264 * @param {Object} o An Array of row objects which represents the dataset.
12265 * @return {Object} data A data block which is used by an Roo.data.Store object as
12266 * a cache of Roo.data.Records.
12268 readRecords : function(o){
12269 var sid = this.meta ? this.meta.id : null;
12270 var recordType = this.recordType, fields = recordType.prototype.fields;
12273 for(var i = 0; i < root.length; i++){
12276 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12277 for(var j = 0, jlen = fields.length; j < jlen; j++){
12278 var f = fields.items[j];
12279 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12280 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12282 values[f.name] = v;
12284 var record = new recordType(values, id);
12286 records[records.length] = record;
12290 totalRecords : records.length
12299 * @class Roo.bootstrap.ComboBox
12300 * @extends Roo.bootstrap.TriggerField
12301 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12302 * @cfg {Boolean} append (true|false) default false
12303 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12304 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12305 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12306 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12307 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12308 * @cfg {Boolean} animate default true
12309 * @cfg {Boolean} emptyResultText only for touch device
12310 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12311 * @cfg {String} emptyTitle default ''
12313 * Create a new ComboBox.
12314 * @param {Object} config Configuration options
12316 Roo.bootstrap.ComboBox = function(config){
12317 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12321 * Fires when the dropdown list is expanded
12322 * @param {Roo.bootstrap.ComboBox} combo This combo box
12327 * Fires when the dropdown list is collapsed
12328 * @param {Roo.bootstrap.ComboBox} combo This combo box
12332 * @event beforeselect
12333 * Fires before a list item is selected. Return false to cancel the selection.
12334 * @param {Roo.bootstrap.ComboBox} combo This combo box
12335 * @param {Roo.data.Record} record The data record returned from the underlying store
12336 * @param {Number} index The index of the selected item in the dropdown list
12338 'beforeselect' : true,
12341 * Fires when a list item is selected
12342 * @param {Roo.bootstrap.ComboBox} combo This combo box
12343 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12344 * @param {Number} index The index of the selected item in the dropdown list
12348 * @event beforequery
12349 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12350 * The event object passed has these properties:
12351 * @param {Roo.bootstrap.ComboBox} combo This combo box
12352 * @param {String} query The query
12353 * @param {Boolean} forceAll true to force "all" query
12354 * @param {Boolean} cancel true to cancel the query
12355 * @param {Object} e The query event object
12357 'beforequery': true,
12360 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12361 * @param {Roo.bootstrap.ComboBox} combo This combo box
12366 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12367 * @param {Roo.bootstrap.ComboBox} combo This combo box
12368 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12373 * Fires when the remove value from the combobox array
12374 * @param {Roo.bootstrap.ComboBox} combo This combo box
12378 * @event afterremove
12379 * Fires when the remove value from the combobox array
12380 * @param {Roo.bootstrap.ComboBox} combo This combo box
12382 'afterremove' : true,
12384 * @event specialfilter
12385 * Fires when specialfilter
12386 * @param {Roo.bootstrap.ComboBox} combo This combo box
12388 'specialfilter' : true,
12391 * Fires when tick the element
12392 * @param {Roo.bootstrap.ComboBox} combo This combo box
12396 * @event touchviewdisplay
12397 * Fires when touch view require special display (default is using displayField)
12398 * @param {Roo.bootstrap.ComboBox} combo This combo box
12399 * @param {Object} cfg set html .
12401 'touchviewdisplay' : true
12406 this.tickItems = [];
12408 this.selectedIndex = -1;
12409 if(this.mode == 'local'){
12410 if(config.queryDelay === undefined){
12411 this.queryDelay = 10;
12413 if(config.minChars === undefined){
12419 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12422 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12423 * rendering into an Roo.Editor, defaults to false)
12426 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12427 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12430 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12433 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12434 * the dropdown list (defaults to undefined, with no header element)
12438 * @cfg {String/Roo.Template} tpl The template to use to render the output
12442 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12444 listWidth: undefined,
12446 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12447 * mode = 'remote' or 'text' if mode = 'local')
12449 displayField: undefined,
12452 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12453 * mode = 'remote' or 'value' if mode = 'local').
12454 * Note: use of a valueField requires the user make a selection
12455 * in order for a value to be mapped.
12457 valueField: undefined,
12459 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12464 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12465 * field's data value (defaults to the underlying DOM element's name)
12467 hiddenName: undefined,
12469 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12473 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12475 selectedClass: 'active',
12478 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12482 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12483 * anchor positions (defaults to 'tl-bl')
12485 listAlign: 'tl-bl?',
12487 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12491 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12492 * query specified by the allQuery config option (defaults to 'query')
12494 triggerAction: 'query',
12496 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12497 * (defaults to 4, does not apply if editable = false)
12501 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12502 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12506 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12507 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12511 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12512 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12516 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12517 * when editable = true (defaults to false)
12519 selectOnFocus:false,
12521 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12523 queryParam: 'query',
12525 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12526 * when mode = 'remote' (defaults to 'Loading...')
12528 loadingText: 'Loading...',
12530 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12534 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12538 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12539 * traditional select (defaults to true)
12543 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12547 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12551 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12552 * listWidth has a higher value)
12556 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12557 * allow the user to set arbitrary text into the field (defaults to false)
12559 forceSelection:false,
12561 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12562 * if typeAhead = true (defaults to 250)
12564 typeAheadDelay : 250,
12566 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12567 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12569 valueNotFoundText : undefined,
12571 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12573 blockFocus : false,
12576 * @cfg {Boolean} disableClear Disable showing of clear button.
12578 disableClear : false,
12580 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12582 alwaysQuery : false,
12585 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12590 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12592 invalidClass : "has-warning",
12595 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12597 validClass : "has-success",
12600 * @cfg {Boolean} specialFilter (true|false) special filter default false
12602 specialFilter : false,
12605 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12607 mobileTouchView : true,
12610 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12612 useNativeIOS : false,
12614 ios_options : false,
12626 btnPosition : 'right',
12627 triggerList : true,
12628 showToggleBtn : true,
12630 emptyResultText: 'Empty',
12631 triggerText : 'Select',
12634 // element that contains real text value.. (when hidden is used..)
12636 getAutoCreate : function()
12641 * Render classic select for iso
12644 if(Roo.isIOS && this.useNativeIOS){
12645 cfg = this.getAutoCreateNativeIOS();
12653 if(Roo.isTouch && this.mobileTouchView){
12654 cfg = this.getAutoCreateTouchView();
12661 if(!this.tickable){
12662 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12663 if(this.name == 'info_year_invest_id_display_name'){
12664 Roo.log('cfg.................................................');
12671 * ComboBox with tickable selections
12674 var align = this.labelAlign || this.parentLabelAlign();
12677 cls : 'form-group roo-combobox-tickable' //input-group
12680 var btn_text_select = '';
12681 var btn_text_done = '';
12682 var btn_text_cancel = '';
12684 if (this.btn_text_show) {
12685 btn_text_select = 'Select';
12686 btn_text_done = 'Done';
12687 btn_text_cancel = 'Cancel';
12692 cls : 'tickable-buttons',
12697 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12698 //html : this.triggerText
12699 html: btn_text_select
12705 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12707 html: btn_text_done
12713 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12715 html: btn_text_cancel
12721 buttons.cn.unshift({
12723 cls: 'roo-select2-search-field-input'
12729 Roo.each(buttons.cn, function(c){
12731 c.cls += ' btn-' + _this.size;
12734 if (_this.disabled) {
12745 cls: 'form-hidden-field'
12749 cls: 'roo-select2-choices',
12753 cls: 'roo-select2-search-field',
12764 cls: 'roo-select2-container input-group roo-select2-container-multi',
12769 // cls: 'typeahead typeahead-long dropdown-menu',
12770 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12775 if(this.hasFeedback && !this.allowBlank){
12779 cls: 'glyphicon form-control-feedback'
12782 combobox.cn.push(feedback);
12786 if (align ==='left' && this.fieldLabel.length) {
12788 cfg.cls += ' roo-form-group-label-left';
12793 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12794 tooltip : 'This field is required'
12799 cls : 'control-label',
12800 html : this.fieldLabel
12812 var labelCfg = cfg.cn[1];
12813 var contentCfg = cfg.cn[2];
12816 if(this.indicatorpos == 'right'){
12822 cls : 'control-label',
12826 html : this.fieldLabel
12830 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12831 tooltip : 'This field is required'
12846 labelCfg = cfg.cn[0];
12847 contentCfg = cfg.cn[1];
12851 if(this.labelWidth > 12){
12852 labelCfg.style = "width: " + this.labelWidth + 'px';
12855 if(this.labelWidth < 13 && this.labelmd == 0){
12856 this.labelmd = this.labelWidth;
12859 if(this.labellg > 0){
12860 labelCfg.cls += ' col-lg-' + this.labellg;
12861 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12864 if(this.labelmd > 0){
12865 labelCfg.cls += ' col-md-' + this.labelmd;
12866 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12869 if(this.labelsm > 0){
12870 labelCfg.cls += ' col-sm-' + this.labelsm;
12871 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12874 if(this.labelxs > 0){
12875 labelCfg.cls += ' col-xs-' + this.labelxs;
12876 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12880 } else if ( this.fieldLabel.length) {
12881 // Roo.log(" label");
12885 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12886 tooltip : 'This field is required'
12890 //cls : 'input-group-addon',
12891 html : this.fieldLabel
12899 if(this.indicatorpos == 'right'){
12904 //cls : 'input-group-addon',
12908 html : this.fieldLabel
12912 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12913 tooltip : 'This field is required'
12928 // Roo.log(" no label && no align");
12935 ['xs','sm','md','lg'].map(function(size){
12936 if (settings[size]) {
12937 cfg.cls += ' col-' + size + '-' + settings[size];
12945 _initEventsCalled : false,
12948 initEvents: function()
12950 if (this._initEventsCalled) { // as we call render... prevent looping...
12953 this._initEventsCalled = true;
12956 throw "can not find store for combo";
12959 this.store = Roo.factory(this.store, Roo.data);
12960 this.store.parent = this;
12962 // if we are building from html. then this element is so complex, that we can not really
12963 // use the rendered HTML.
12964 // so we have to trash and replace the previous code.
12965 if (Roo.XComponent.build_from_html) {
12967 // remove this element....
12968 var e = this.el.dom, k=0;
12969 while (e ) { e = e.previousSibling; ++k;}
12974 this.rendered = false;
12976 this.render(this.parent().getChildContainer(true), k);
12982 if(Roo.isIOS && this.useNativeIOS){
12983 this.initIOSView();
12991 if(Roo.isTouch && this.mobileTouchView){
12992 this.initTouchView();
12997 this.initTickableEvents();
13001 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13003 if(this.hiddenName){
13005 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13007 this.hiddenField.dom.value =
13008 this.hiddenValue !== undefined ? this.hiddenValue :
13009 this.value !== undefined ? this.value : '';
13011 // prevent input submission
13012 this.el.dom.removeAttribute('name');
13013 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13018 // this.el.dom.setAttribute('autocomplete', 'off');
13021 var cls = 'x-combo-list';
13023 //this.list = new Roo.Layer({
13024 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13030 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13031 _this.list.setWidth(lw);
13034 this.list.on('mouseover', this.onViewOver, this);
13035 this.list.on('mousemove', this.onViewMove, this);
13037 this.list.on('scroll', this.onViewScroll, this);
13040 this.list.swallowEvent('mousewheel');
13041 this.assetHeight = 0;
13044 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13045 this.assetHeight += this.header.getHeight();
13048 this.innerList = this.list.createChild({cls:cls+'-inner'});
13049 this.innerList.on('mouseover', this.onViewOver, this);
13050 this.innerList.on('mousemove', this.onViewMove, this);
13051 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13053 if(this.allowBlank && !this.pageSize && !this.disableClear){
13054 this.footer = this.list.createChild({cls:cls+'-ft'});
13055 this.pageTb = new Roo.Toolbar(this.footer);
13059 this.footer = this.list.createChild({cls:cls+'-ft'});
13060 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13061 {pageSize: this.pageSize});
13065 if (this.pageTb && this.allowBlank && !this.disableClear) {
13067 this.pageTb.add(new Roo.Toolbar.Fill(), {
13068 cls: 'x-btn-icon x-btn-clear',
13070 handler: function()
13073 _this.clearValue();
13074 _this.onSelect(false, -1);
13079 this.assetHeight += this.footer.getHeight();
13084 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13087 this.view = new Roo.View(this.list, this.tpl, {
13088 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13090 //this.view.wrapEl.setDisplayed(false);
13091 this.view.on('click', this.onViewClick, this);
13094 this.store.on('beforeload', this.onBeforeLoad, this);
13095 this.store.on('load', this.onLoad, this);
13096 this.store.on('loadexception', this.onLoadException, this);
13098 if(this.resizable){
13099 this.resizer = new Roo.Resizable(this.list, {
13100 pinned:true, handles:'se'
13102 this.resizer.on('resize', function(r, w, h){
13103 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13104 this.listWidth = w;
13105 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13106 this.restrictHeight();
13108 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13111 if(!this.editable){
13112 this.editable = true;
13113 this.setEditable(false);
13118 if (typeof(this.events.add.listeners) != 'undefined') {
13120 this.addicon = this.wrap.createChild(
13121 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13123 this.addicon.on('click', function(e) {
13124 this.fireEvent('add', this);
13127 if (typeof(this.events.edit.listeners) != 'undefined') {
13129 this.editicon = this.wrap.createChild(
13130 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13131 if (this.addicon) {
13132 this.editicon.setStyle('margin-left', '40px');
13134 this.editicon.on('click', function(e) {
13136 // we fire even if inothing is selected..
13137 this.fireEvent('edit', this, this.lastData );
13143 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13144 "up" : function(e){
13145 this.inKeyMode = true;
13149 "down" : function(e){
13150 if(!this.isExpanded()){
13151 this.onTriggerClick();
13153 this.inKeyMode = true;
13158 "enter" : function(e){
13159 // this.onViewClick();
13163 if(this.fireEvent("specialkey", this, e)){
13164 this.onViewClick(false);
13170 "esc" : function(e){
13174 "tab" : function(e){
13177 if(this.fireEvent("specialkey", this, e)){
13178 this.onViewClick(false);
13186 doRelay : function(foo, bar, hname){
13187 if(hname == 'down' || this.scope.isExpanded()){
13188 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13197 this.queryDelay = Math.max(this.queryDelay || 10,
13198 this.mode == 'local' ? 10 : 250);
13201 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13203 if(this.typeAhead){
13204 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13206 if(this.editable !== false){
13207 this.inputEl().on("keyup", this.onKeyUp, this);
13209 if(this.forceSelection){
13210 this.inputEl().on('blur', this.doForce, this);
13214 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13215 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13219 initTickableEvents: function()
13223 if(this.hiddenName){
13225 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13227 this.hiddenField.dom.value =
13228 this.hiddenValue !== undefined ? this.hiddenValue :
13229 this.value !== undefined ? this.value : '';
13231 // prevent input submission
13232 this.el.dom.removeAttribute('name');
13233 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13238 // this.list = this.el.select('ul.dropdown-menu',true).first();
13240 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13241 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13242 if(this.triggerList){
13243 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13246 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13247 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13249 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13250 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13252 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13253 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13255 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13256 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13257 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13260 this.cancelBtn.hide();
13265 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13266 _this.list.setWidth(lw);
13269 this.list.on('mouseover', this.onViewOver, this);
13270 this.list.on('mousemove', this.onViewMove, this);
13272 this.list.on('scroll', this.onViewScroll, this);
13275 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>';
13278 this.view = new Roo.View(this.list, this.tpl, {
13279 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13282 //this.view.wrapEl.setDisplayed(false);
13283 this.view.on('click', this.onViewClick, this);
13287 this.store.on('beforeload', this.onBeforeLoad, this);
13288 this.store.on('load', this.onLoad, this);
13289 this.store.on('loadexception', this.onLoadException, this);
13292 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13293 "up" : function(e){
13294 this.inKeyMode = true;
13298 "down" : function(e){
13299 this.inKeyMode = true;
13303 "enter" : function(e){
13304 if(this.fireEvent("specialkey", this, e)){
13305 this.onViewClick(false);
13311 "esc" : function(e){
13312 this.onTickableFooterButtonClick(e, false, false);
13315 "tab" : function(e){
13316 this.fireEvent("specialkey", this, e);
13318 this.onTickableFooterButtonClick(e, false, false);
13325 doRelay : function(e, fn, key){
13326 if(this.scope.isExpanded()){
13327 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13336 this.queryDelay = Math.max(this.queryDelay || 10,
13337 this.mode == 'local' ? 10 : 250);
13340 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13342 if(this.typeAhead){
13343 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13346 if(this.editable !== false){
13347 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13350 this.indicator = this.indicatorEl();
13352 if(this.indicator){
13353 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13354 this.indicator.hide();
13359 onDestroy : function(){
13361 this.view.setStore(null);
13362 this.view.el.removeAllListeners();
13363 this.view.el.remove();
13364 this.view.purgeListeners();
13367 this.list.dom.innerHTML = '';
13371 this.store.un('beforeload', this.onBeforeLoad, this);
13372 this.store.un('load', this.onLoad, this);
13373 this.store.un('loadexception', this.onLoadException, this);
13375 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13379 fireKey : function(e){
13380 if(e.isNavKeyPress() && !this.list.isVisible()){
13381 this.fireEvent("specialkey", this, e);
13386 onResize: function(w, h){
13387 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13389 // if(typeof w != 'number'){
13390 // // we do not handle it!?!?
13393 // var tw = this.trigger.getWidth();
13394 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13395 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13397 // this.inputEl().setWidth( this.adjustWidth('input', x));
13399 // //this.trigger.setStyle('left', x+'px');
13401 // if(this.list && this.listWidth === undefined){
13402 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13403 // this.list.setWidth(lw);
13404 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13412 * Allow or prevent the user from directly editing the field text. If false is passed,
13413 * the user will only be able to select from the items defined in the dropdown list. This method
13414 * is the runtime equivalent of setting the 'editable' config option at config time.
13415 * @param {Boolean} value True to allow the user to directly edit the field text
13417 setEditable : function(value){
13418 if(value == this.editable){
13421 this.editable = value;
13423 this.inputEl().dom.setAttribute('readOnly', true);
13424 this.inputEl().on('mousedown', this.onTriggerClick, this);
13425 this.inputEl().addClass('x-combo-noedit');
13427 this.inputEl().dom.setAttribute('readOnly', false);
13428 this.inputEl().un('mousedown', this.onTriggerClick, this);
13429 this.inputEl().removeClass('x-combo-noedit');
13435 onBeforeLoad : function(combo,opts){
13436 if(!this.hasFocus){
13440 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13442 this.restrictHeight();
13443 this.selectedIndex = -1;
13447 onLoad : function(){
13449 this.hasQuery = false;
13451 if(!this.hasFocus){
13455 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13456 this.loading.hide();
13459 if(this.store.getCount() > 0){
13462 this.restrictHeight();
13463 if(this.lastQuery == this.allQuery){
13464 if(this.editable && !this.tickable){
13465 this.inputEl().dom.select();
13469 !this.selectByValue(this.value, true) &&
13472 !this.store.lastOptions ||
13473 typeof(this.store.lastOptions.add) == 'undefined' ||
13474 this.store.lastOptions.add != true
13477 this.select(0, true);
13480 if(this.autoFocus){
13483 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13484 this.taTask.delay(this.typeAheadDelay);
13488 this.onEmptyResults();
13494 onLoadException : function()
13496 this.hasQuery = false;
13498 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13499 this.loading.hide();
13502 if(this.tickable && this.editable){
13507 // only causes errors at present
13508 //Roo.log(this.store.reader.jsonData);
13509 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13511 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13517 onTypeAhead : function(){
13518 if(this.store.getCount() > 0){
13519 var r = this.store.getAt(0);
13520 var newValue = r.data[this.displayField];
13521 var len = newValue.length;
13522 var selStart = this.getRawValue().length;
13524 if(selStart != len){
13525 this.setRawValue(newValue);
13526 this.selectText(selStart, newValue.length);
13532 onSelect : function(record, index){
13534 if(this.fireEvent('beforeselect', this, record, index) !== false){
13536 this.setFromData(index > -1 ? record.data : false);
13539 this.fireEvent('select', this, record, index);
13544 * Returns the currently selected field value or empty string if no value is set.
13545 * @return {String} value The selected value
13547 getValue : function()
13549 if(Roo.isIOS && this.useNativeIOS){
13550 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13554 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13557 if(this.valueField){
13558 return typeof this.value != 'undefined' ? this.value : '';
13560 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13564 getRawValue : function()
13566 if(Roo.isIOS && this.useNativeIOS){
13567 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13570 var v = this.inputEl().getValue();
13576 * Clears any text/value currently set in the field
13578 clearValue : function(){
13580 if(this.hiddenField){
13581 this.hiddenField.dom.value = '';
13584 this.setRawValue('');
13585 this.lastSelectionText = '';
13586 this.lastData = false;
13588 var close = this.closeTriggerEl();
13599 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13600 * will be displayed in the field. If the value does not match the data value of an existing item,
13601 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13602 * Otherwise the field will be blank (although the value will still be set).
13603 * @param {String} value The value to match
13605 setValue : function(v)
13607 if(Roo.isIOS && this.useNativeIOS){
13608 this.setIOSValue(v);
13618 if(this.valueField){
13619 var r = this.findRecord(this.valueField, v);
13621 text = r.data[this.displayField];
13622 }else if(this.valueNotFoundText !== undefined){
13623 text = this.valueNotFoundText;
13626 this.lastSelectionText = text;
13627 if(this.hiddenField){
13628 this.hiddenField.dom.value = v;
13630 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13633 var close = this.closeTriggerEl();
13636 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13642 * @property {Object} the last set data for the element
13647 * Sets the value of the field based on a object which is related to the record format for the store.
13648 * @param {Object} value the value to set as. or false on reset?
13650 setFromData : function(o){
13657 var dv = ''; // display value
13658 var vv = ''; // value value..
13660 if (this.displayField) {
13661 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13663 // this is an error condition!!!
13664 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13667 if(this.valueField){
13668 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13671 var close = this.closeTriggerEl();
13674 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13677 if(this.hiddenField){
13678 this.hiddenField.dom.value = vv;
13680 this.lastSelectionText = dv;
13681 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13685 // no hidden field.. - we store the value in 'value', but still display
13686 // display field!!!!
13687 this.lastSelectionText = dv;
13688 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13695 reset : function(){
13696 // overridden so that last data is reset..
13703 this.setValue(this.originalValue);
13704 //this.clearInvalid();
13705 this.lastData = false;
13707 this.view.clearSelections();
13713 findRecord : function(prop, value){
13715 if(this.store.getCount() > 0){
13716 this.store.each(function(r){
13717 if(r.data[prop] == value){
13727 getName: function()
13729 // returns hidden if it's set..
13730 if (!this.rendered) {return ''};
13731 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13735 onViewMove : function(e, t){
13736 this.inKeyMode = false;
13740 onViewOver : function(e, t){
13741 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13744 var item = this.view.findItemFromChild(t);
13747 var index = this.view.indexOf(item);
13748 this.select(index, false);
13753 onViewClick : function(view, doFocus, el, e)
13755 var index = this.view.getSelectedIndexes()[0];
13757 var r = this.store.getAt(index);
13761 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13768 Roo.each(this.tickItems, function(v,k){
13770 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13772 _this.tickItems.splice(k, 1);
13774 if(typeof(e) == 'undefined' && view == false){
13775 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13787 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13788 this.tickItems.push(r.data);
13791 if(typeof(e) == 'undefined' && view == false){
13792 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13799 this.onSelect(r, index);
13801 if(doFocus !== false && !this.blockFocus){
13802 this.inputEl().focus();
13807 restrictHeight : function(){
13808 //this.innerList.dom.style.height = '';
13809 //var inner = this.innerList.dom;
13810 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13811 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13812 //this.list.beginUpdate();
13813 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13814 this.list.alignTo(this.inputEl(), this.listAlign);
13815 this.list.alignTo(this.inputEl(), this.listAlign);
13816 //this.list.endUpdate();
13820 onEmptyResults : function(){
13822 if(this.tickable && this.editable){
13823 this.restrictHeight();
13831 * Returns true if the dropdown list is expanded, else false.
13833 isExpanded : function(){
13834 return this.list.isVisible();
13838 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13839 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13840 * @param {String} value The data value of the item to select
13841 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13842 * selected item if it is not currently in view (defaults to true)
13843 * @return {Boolean} True if the value matched an item in the list, else false
13845 selectByValue : function(v, scrollIntoView){
13846 if(v !== undefined && v !== null){
13847 var r = this.findRecord(this.valueField || this.displayField, v);
13849 this.select(this.store.indexOf(r), scrollIntoView);
13857 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13858 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13859 * @param {Number} index The zero-based index of the list item to select
13860 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13861 * selected item if it is not currently in view (defaults to true)
13863 select : function(index, scrollIntoView){
13864 this.selectedIndex = index;
13865 this.view.select(index);
13866 if(scrollIntoView !== false){
13867 var el = this.view.getNode(index);
13869 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13872 this.list.scrollChildIntoView(el, false);
13878 selectNext : function(){
13879 var ct = this.store.getCount();
13881 if(this.selectedIndex == -1){
13883 }else if(this.selectedIndex < ct-1){
13884 this.select(this.selectedIndex+1);
13890 selectPrev : function(){
13891 var ct = this.store.getCount();
13893 if(this.selectedIndex == -1){
13895 }else if(this.selectedIndex != 0){
13896 this.select(this.selectedIndex-1);
13902 onKeyUp : function(e){
13903 if(this.editable !== false && !e.isSpecialKey()){
13904 this.lastKey = e.getKey();
13905 this.dqTask.delay(this.queryDelay);
13910 validateBlur : function(){
13911 return !this.list || !this.list.isVisible();
13915 initQuery : function(){
13917 var v = this.getRawValue();
13919 if(this.tickable && this.editable){
13920 v = this.tickableInputEl().getValue();
13927 doForce : function(){
13928 if(this.inputEl().dom.value.length > 0){
13929 this.inputEl().dom.value =
13930 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13936 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13937 * query allowing the query action to be canceled if needed.
13938 * @param {String} query The SQL query to execute
13939 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13940 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13941 * saved in the current store (defaults to false)
13943 doQuery : function(q, forceAll){
13945 if(q === undefined || q === null){
13950 forceAll: forceAll,
13954 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13959 forceAll = qe.forceAll;
13960 if(forceAll === true || (q.length >= this.minChars)){
13962 this.hasQuery = true;
13964 if(this.lastQuery != q || this.alwaysQuery){
13965 this.lastQuery = q;
13966 if(this.mode == 'local'){
13967 this.selectedIndex = -1;
13969 this.store.clearFilter();
13972 if(this.specialFilter){
13973 this.fireEvent('specialfilter', this);
13978 this.store.filter(this.displayField, q);
13981 this.store.fireEvent("datachanged", this.store);
13988 this.store.baseParams[this.queryParam] = q;
13990 var options = {params : this.getParams(q)};
13993 options.add = true;
13994 options.params.start = this.page * this.pageSize;
13997 this.store.load(options);
14000 * this code will make the page width larger, at the beginning, the list not align correctly,
14001 * we should expand the list on onLoad
14002 * so command out it
14007 this.selectedIndex = -1;
14012 this.loadNext = false;
14016 getParams : function(q){
14018 //p[this.queryParam] = q;
14022 p.limit = this.pageSize;
14028 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14030 collapse : function(){
14031 if(!this.isExpanded()){
14037 this.hasFocus = false;
14041 this.cancelBtn.hide();
14042 this.trigger.show();
14045 this.tickableInputEl().dom.value = '';
14046 this.tickableInputEl().blur();
14051 Roo.get(document).un('mousedown', this.collapseIf, this);
14052 Roo.get(document).un('mousewheel', this.collapseIf, this);
14053 if (!this.editable) {
14054 Roo.get(document).un('keydown', this.listKeyPress, this);
14056 this.fireEvent('collapse', this);
14062 collapseIf : function(e){
14063 var in_combo = e.within(this.el);
14064 var in_list = e.within(this.list);
14065 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14067 if (in_combo || in_list || is_list) {
14068 //e.stopPropagation();
14073 this.onTickableFooterButtonClick(e, false, false);
14081 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14083 expand : function(){
14085 if(this.isExpanded() || !this.hasFocus){
14089 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14090 this.list.setWidth(lw);
14096 this.restrictHeight();
14100 this.tickItems = Roo.apply([], this.item);
14103 this.cancelBtn.show();
14104 this.trigger.hide();
14107 this.tickableInputEl().focus();
14112 Roo.get(document).on('mousedown', this.collapseIf, this);
14113 Roo.get(document).on('mousewheel', this.collapseIf, this);
14114 if (!this.editable) {
14115 Roo.get(document).on('keydown', this.listKeyPress, this);
14118 this.fireEvent('expand', this);
14122 // Implements the default empty TriggerField.onTriggerClick function
14123 onTriggerClick : function(e)
14125 Roo.log('trigger click');
14127 if(this.disabled || !this.triggerList){
14132 this.loadNext = false;
14134 if(this.isExpanded()){
14136 if (!this.blockFocus) {
14137 this.inputEl().focus();
14141 this.hasFocus = true;
14142 if(this.triggerAction == 'all') {
14143 this.doQuery(this.allQuery, true);
14145 this.doQuery(this.getRawValue());
14147 if (!this.blockFocus) {
14148 this.inputEl().focus();
14153 onTickableTriggerClick : function(e)
14160 this.loadNext = false;
14161 this.hasFocus = true;
14163 if(this.triggerAction == 'all') {
14164 this.doQuery(this.allQuery, true);
14166 this.doQuery(this.getRawValue());
14170 onSearchFieldClick : function(e)
14172 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14173 this.onTickableFooterButtonClick(e, false, false);
14177 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14182 this.loadNext = false;
14183 this.hasFocus = true;
14185 if(this.triggerAction == 'all') {
14186 this.doQuery(this.allQuery, true);
14188 this.doQuery(this.getRawValue());
14192 listKeyPress : function(e)
14194 //Roo.log('listkeypress');
14195 // scroll to first matching element based on key pres..
14196 if (e.isSpecialKey()) {
14199 var k = String.fromCharCode(e.getKey()).toUpperCase();
14202 var csel = this.view.getSelectedNodes();
14203 var cselitem = false;
14205 var ix = this.view.indexOf(csel[0]);
14206 cselitem = this.store.getAt(ix);
14207 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14213 this.store.each(function(v) {
14215 // start at existing selection.
14216 if (cselitem.id == v.id) {
14222 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14223 match = this.store.indexOf(v);
14229 if (match === false) {
14230 return true; // no more action?
14233 this.view.select(match);
14234 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14235 sn.scrollIntoView(sn.dom.parentNode, false);
14238 onViewScroll : function(e, t){
14240 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){
14244 this.hasQuery = true;
14246 this.loading = this.list.select('.loading', true).first();
14248 if(this.loading === null){
14249 this.list.createChild({
14251 cls: 'loading roo-select2-more-results roo-select2-active',
14252 html: 'Loading more results...'
14255 this.loading = this.list.select('.loading', true).first();
14257 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14259 this.loading.hide();
14262 this.loading.show();
14267 this.loadNext = true;
14269 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14274 addItem : function(o)
14276 var dv = ''; // display value
14278 if (this.displayField) {
14279 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14281 // this is an error condition!!!
14282 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14289 var choice = this.choices.createChild({
14291 cls: 'roo-select2-search-choice',
14300 cls: 'roo-select2-search-choice-close',
14305 }, this.searchField);
14307 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14309 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14317 this.inputEl().dom.value = '';
14322 onRemoveItem : function(e, _self, o)
14324 e.preventDefault();
14326 this.lastItem = Roo.apply([], this.item);
14328 var index = this.item.indexOf(o.data) * 1;
14331 Roo.log('not this item?!');
14335 this.item.splice(index, 1);
14340 this.fireEvent('remove', this, e);
14346 syncValue : function()
14348 if(!this.item.length){
14355 Roo.each(this.item, function(i){
14356 if(_this.valueField){
14357 value.push(i[_this.valueField]);
14364 this.value = value.join(',');
14366 if(this.hiddenField){
14367 this.hiddenField.dom.value = this.value;
14370 this.store.fireEvent("datachanged", this.store);
14375 clearItem : function()
14377 if(!this.multiple){
14383 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14391 if(this.tickable && !Roo.isTouch){
14392 this.view.refresh();
14396 inputEl: function ()
14398 if(Roo.isIOS && this.useNativeIOS){
14399 return this.el.select('select.roo-ios-select', true).first();
14402 if(Roo.isTouch && this.mobileTouchView){
14403 return this.el.select('input.form-control',true).first();
14407 return this.searchField;
14410 return this.el.select('input.form-control',true).first();
14413 onTickableFooterButtonClick : function(e, btn, el)
14415 e.preventDefault();
14417 this.lastItem = Roo.apply([], this.item);
14419 if(btn && btn.name == 'cancel'){
14420 this.tickItems = Roo.apply([], this.item);
14429 Roo.each(this.tickItems, function(o){
14437 validate : function()
14439 var v = this.getRawValue();
14442 v = this.getValue();
14445 if(this.disabled || this.allowBlank || v.length){
14450 this.markInvalid();
14454 tickableInputEl : function()
14456 if(!this.tickable || !this.editable){
14457 return this.inputEl();
14460 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14464 getAutoCreateTouchView : function()
14469 cls: 'form-group' //input-group
14475 type : this.inputType,
14476 cls : 'form-control x-combo-noedit',
14477 autocomplete: 'new-password',
14478 placeholder : this.placeholder || '',
14483 input.name = this.name;
14487 input.cls += ' input-' + this.size;
14490 if (this.disabled) {
14491 input.disabled = true;
14502 inputblock.cls += ' input-group';
14504 inputblock.cn.unshift({
14506 cls : 'input-group-addon',
14511 if(this.removable && !this.multiple){
14512 inputblock.cls += ' roo-removable';
14514 inputblock.cn.push({
14517 cls : 'roo-combo-removable-btn close'
14521 if(this.hasFeedback && !this.allowBlank){
14523 inputblock.cls += ' has-feedback';
14525 inputblock.cn.push({
14527 cls: 'glyphicon form-control-feedback'
14534 inputblock.cls += (this.before) ? '' : ' input-group';
14536 inputblock.cn.push({
14538 cls : 'input-group-addon',
14549 cls: 'form-hidden-field'
14563 cls: 'form-hidden-field'
14567 cls: 'roo-select2-choices',
14571 cls: 'roo-select2-search-field',
14584 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14590 if(!this.multiple && this.showToggleBtn){
14597 if (this.caret != false) {
14600 cls: 'fa fa-' + this.caret
14607 cls : 'input-group-addon btn dropdown-toggle',
14612 cls: 'combobox-clear',
14626 combobox.cls += ' roo-select2-container-multi';
14629 var align = this.labelAlign || this.parentLabelAlign();
14631 if (align ==='left' && this.fieldLabel.length) {
14636 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14637 tooltip : 'This field is required'
14641 cls : 'control-label',
14642 html : this.fieldLabel
14653 var labelCfg = cfg.cn[1];
14654 var contentCfg = cfg.cn[2];
14657 if(this.indicatorpos == 'right'){
14661 cls : 'control-label',
14662 html : this.fieldLabel,
14666 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14667 tooltip : 'This field is required'
14680 labelCfg = cfg.cn[0];
14681 contentCfg = cfg.cn[2];
14683 if(this.labelWidth > 12){
14684 labelCfg.style = "width: " + this.labelWidth + 'px';
14687 if(this.labelWidth < 13 && this.labelmd == 0){
14688 this.labelmd = this.labelWidth;
14691 if(this.labellg > 0){
14692 labelCfg.cls += ' col-lg-' + this.labellg;
14693 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14696 if(this.labelmd > 0){
14697 labelCfg.cls += ' col-md-' + this.labelmd;
14698 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14701 if(this.labelsm > 0){
14702 labelCfg.cls += ' col-sm-' + this.labelsm;
14703 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14706 if(this.labelxs > 0){
14707 labelCfg.cls += ' col-xs-' + this.labelxs;
14708 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14712 } else if ( this.fieldLabel.length) {
14716 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14717 tooltip : 'This field is required'
14721 cls : 'control-label',
14722 html : this.fieldLabel
14733 if(this.indicatorpos == 'right'){
14737 cls : 'control-label',
14738 html : this.fieldLabel,
14742 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14743 tooltip : 'This field is required'
14760 var settings = this;
14762 ['xs','sm','md','lg'].map(function(size){
14763 if (settings[size]) {
14764 cfg.cls += ' col-' + size + '-' + settings[size];
14771 initTouchView : function()
14773 this.renderTouchView();
14775 this.touchViewEl.on('scroll', function(){
14776 this.el.dom.scrollTop = 0;
14779 this.originalValue = this.getValue();
14781 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14783 this.inputEl().on("click", this.showTouchView, this);
14784 if (this.triggerEl) {
14785 this.triggerEl.on("click", this.showTouchView, this);
14789 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14790 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14792 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14794 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14795 this.store.on('load', this.onTouchViewLoad, this);
14796 this.store.on('loadexception', this.onTouchViewLoadException, this);
14798 if(this.hiddenName){
14800 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14802 this.hiddenField.dom.value =
14803 this.hiddenValue !== undefined ? this.hiddenValue :
14804 this.value !== undefined ? this.value : '';
14806 this.el.dom.removeAttribute('name');
14807 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14811 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14812 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14815 if(this.removable && !this.multiple){
14816 var close = this.closeTriggerEl();
14818 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14819 close.on('click', this.removeBtnClick, this, close);
14823 * fix the bug in Safari iOS8
14825 this.inputEl().on("focus", function(e){
14826 document.activeElement.blur();
14834 renderTouchView : function()
14836 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14837 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14839 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14840 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14842 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14843 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14844 this.touchViewBodyEl.setStyle('overflow', 'auto');
14846 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14847 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14849 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14850 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14854 showTouchView : function()
14860 this.touchViewHeaderEl.hide();
14862 if(this.modalTitle.length){
14863 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14864 this.touchViewHeaderEl.show();
14867 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14868 this.touchViewEl.show();
14870 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14871 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14872 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14874 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14876 if(this.modalTitle.length){
14877 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14880 this.touchViewBodyEl.setHeight(bodyHeight);
14884 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14886 this.touchViewEl.addClass('in');
14889 this.doTouchViewQuery();
14893 hideTouchView : function()
14895 this.touchViewEl.removeClass('in');
14899 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14901 this.touchViewEl.setStyle('display', 'none');
14906 setTouchViewValue : function()
14913 Roo.each(this.tickItems, function(o){
14918 this.hideTouchView();
14921 doTouchViewQuery : function()
14930 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14934 if(!this.alwaysQuery || this.mode == 'local'){
14935 this.onTouchViewLoad();
14942 onTouchViewBeforeLoad : function(combo,opts)
14948 onTouchViewLoad : function()
14950 if(this.store.getCount() < 1){
14951 this.onTouchViewEmptyResults();
14955 this.clearTouchView();
14957 var rawValue = this.getRawValue();
14959 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14961 this.tickItems = [];
14963 this.store.data.each(function(d, rowIndex){
14964 var row = this.touchViewListGroup.createChild(template);
14966 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14967 row.addClass(d.data.cls);
14970 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14973 html : d.data[this.displayField]
14976 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14977 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14980 row.removeClass('selected');
14981 if(!this.multiple && this.valueField &&
14982 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14985 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14986 row.addClass('selected');
14989 if(this.multiple && this.valueField &&
14990 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14994 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14995 this.tickItems.push(d.data);
14998 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15002 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15004 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15006 if(this.modalTitle.length){
15007 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15010 var listHeight = this.touchViewListGroup.getHeight();
15014 if(firstChecked && listHeight > bodyHeight){
15015 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15020 onTouchViewLoadException : function()
15022 this.hideTouchView();
15025 onTouchViewEmptyResults : function()
15027 this.clearTouchView();
15029 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15031 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15035 clearTouchView : function()
15037 this.touchViewListGroup.dom.innerHTML = '';
15040 onTouchViewClick : function(e, el, o)
15042 e.preventDefault();
15045 var rowIndex = o.rowIndex;
15047 var r = this.store.getAt(rowIndex);
15049 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15051 if(!this.multiple){
15052 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15053 c.dom.removeAttribute('checked');
15056 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15058 this.setFromData(r.data);
15060 var close = this.closeTriggerEl();
15066 this.hideTouchView();
15068 this.fireEvent('select', this, r, rowIndex);
15073 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15074 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15075 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15079 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15080 this.addItem(r.data);
15081 this.tickItems.push(r.data);
15085 getAutoCreateNativeIOS : function()
15088 cls: 'form-group' //input-group,
15093 cls : 'roo-ios-select'
15097 combobox.name = this.name;
15100 if (this.disabled) {
15101 combobox.disabled = true;
15104 var settings = this;
15106 ['xs','sm','md','lg'].map(function(size){
15107 if (settings[size]) {
15108 cfg.cls += ' col-' + size + '-' + settings[size];
15118 initIOSView : function()
15120 this.store.on('load', this.onIOSViewLoad, this);
15125 onIOSViewLoad : function()
15127 if(this.store.getCount() < 1){
15131 this.clearIOSView();
15133 if(this.allowBlank) {
15135 var default_text = '-- SELECT --';
15137 var opt = this.inputEl().createChild({
15140 html : default_text
15144 o[this.valueField] = 0;
15145 o[this.displayField] = default_text;
15147 this.ios_options.push({
15154 this.store.data.each(function(d, rowIndex){
15158 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15159 html = d.data[this.displayField];
15164 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15165 value = d.data[this.valueField];
15174 if(this.value == d.data[this.valueField]){
15175 option['selected'] = true;
15178 var opt = this.inputEl().createChild(option);
15180 this.ios_options.push({
15187 this.inputEl().on('change', function(){
15188 this.fireEvent('select', this);
15193 clearIOSView: function()
15195 this.inputEl().dom.innerHTML = '';
15197 this.ios_options = [];
15200 setIOSValue: function(v)
15204 if(!this.ios_options){
15208 Roo.each(this.ios_options, function(opts){
15210 opts.el.dom.removeAttribute('selected');
15212 if(opts.data[this.valueField] != v){
15216 opts.el.dom.setAttribute('selected', true);
15222 * @cfg {Boolean} grow
15226 * @cfg {Number} growMin
15230 * @cfg {Number} growMax
15239 Roo.apply(Roo.bootstrap.ComboBox, {
15243 cls: 'modal-header',
15265 cls: 'list-group-item',
15269 cls: 'roo-combobox-list-group-item-value'
15273 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15287 listItemCheckbox : {
15289 cls: 'list-group-item',
15293 cls: 'roo-combobox-list-group-item-value'
15297 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15313 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15318 cls: 'modal-footer',
15326 cls: 'col-xs-6 text-left',
15329 cls: 'btn btn-danger roo-touch-view-cancel',
15335 cls: 'col-xs-6 text-right',
15338 cls: 'btn btn-success roo-touch-view-ok',
15349 Roo.apply(Roo.bootstrap.ComboBox, {
15351 touchViewTemplate : {
15353 cls: 'modal fade roo-combobox-touch-view',
15357 cls: 'modal-dialog',
15358 style : 'position:fixed', // we have to fix position....
15362 cls: 'modal-content',
15364 Roo.bootstrap.ComboBox.header,
15365 Roo.bootstrap.ComboBox.body,
15366 Roo.bootstrap.ComboBox.footer
15375 * Ext JS Library 1.1.1
15376 * Copyright(c) 2006-2007, Ext JS, LLC.
15378 * Originally Released Under LGPL - original licence link has changed is not relivant.
15381 * <script type="text/javascript">
15386 * @extends Roo.util.Observable
15387 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15388 * This class also supports single and multi selection modes. <br>
15389 * Create a data model bound view:
15391 var store = new Roo.data.Store(...);
15393 var view = new Roo.View({
15395 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15397 singleSelect: true,
15398 selectedClass: "ydataview-selected",
15402 // listen for node click?
15403 view.on("click", function(vw, index, node, e){
15404 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15408 dataModel.load("foobar.xml");
15410 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15412 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15413 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15415 * Note: old style constructor is still suported (container, template, config)
15418 * Create a new View
15419 * @param {Object} config The config object
15422 Roo.View = function(config, depreciated_tpl, depreciated_config){
15424 this.parent = false;
15426 if (typeof(depreciated_tpl) == 'undefined') {
15427 // new way.. - universal constructor.
15428 Roo.apply(this, config);
15429 this.el = Roo.get(this.el);
15432 this.el = Roo.get(config);
15433 this.tpl = depreciated_tpl;
15434 Roo.apply(this, depreciated_config);
15436 this.wrapEl = this.el.wrap().wrap();
15437 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15440 if(typeof(this.tpl) == "string"){
15441 this.tpl = new Roo.Template(this.tpl);
15443 // support xtype ctors..
15444 this.tpl = new Roo.factory(this.tpl, Roo);
15448 this.tpl.compile();
15453 * @event beforeclick
15454 * Fires before a click is processed. Returns false to cancel the default action.
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
15460 "beforeclick" : true,
15463 * Fires when a template node is 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
15472 * Fires when a template node is double 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
15480 * @event contextmenu
15481 * Fires when a template node is right clicked.
15482 * @param {Roo.View} this
15483 * @param {Number} index The index of the target node
15484 * @param {HTMLElement} node The target node
15485 * @param {Roo.EventObject} e The raw event object
15487 "contextmenu" : true,
15489 * @event selectionchange
15490 * Fires when the selected nodes change.
15491 * @param {Roo.View} this
15492 * @param {Array} selections Array of the selected nodes
15494 "selectionchange" : true,
15497 * @event beforeselect
15498 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15499 * @param {Roo.View} this
15500 * @param {HTMLElement} node The node to be selected
15501 * @param {Array} selections Array of currently selected nodes
15503 "beforeselect" : true,
15505 * @event preparedata
15506 * Fires on every row to render, to allow you to change the data.
15507 * @param {Roo.View} this
15508 * @param {Object} data to be rendered (change this)
15510 "preparedata" : true
15518 "click": this.onClick,
15519 "dblclick": this.onDblClick,
15520 "contextmenu": this.onContextMenu,
15524 this.selections = [];
15526 this.cmp = new Roo.CompositeElementLite([]);
15528 this.store = Roo.factory(this.store, Roo.data);
15529 this.setStore(this.store, true);
15532 if ( this.footer && this.footer.xtype) {
15534 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15536 this.footer.dataSource = this.store;
15537 this.footer.container = fctr;
15538 this.footer = Roo.factory(this.footer, Roo);
15539 fctr.insertFirst(this.el);
15541 // this is a bit insane - as the paging toolbar seems to detach the el..
15542 // dom.parentNode.parentNode.parentNode
15543 // they get detached?
15547 Roo.View.superclass.constructor.call(this);
15552 Roo.extend(Roo.View, Roo.util.Observable, {
15555 * @cfg {Roo.data.Store} store Data store to load data from.
15560 * @cfg {String|Roo.Element} el The container element.
15565 * @cfg {String|Roo.Template} tpl The template used by this View
15569 * @cfg {String} dataName the named area of the template to use as the data area
15570 * Works with domtemplates roo-name="name"
15574 * @cfg {String} selectedClass The css class to add to selected nodes
15576 selectedClass : "x-view-selected",
15578 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15583 * @cfg {String} text to display on mask (default Loading)
15587 * @cfg {Boolean} multiSelect Allow multiple selection
15589 multiSelect : false,
15591 * @cfg {Boolean} singleSelect Allow single selection
15593 singleSelect: false,
15596 * @cfg {Boolean} toggleSelect - selecting
15598 toggleSelect : false,
15601 * @cfg {Boolean} tickable - selecting
15606 * Returns the element this view is bound to.
15607 * @return {Roo.Element}
15609 getEl : function(){
15610 return this.wrapEl;
15616 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15618 refresh : function(){
15619 //Roo.log('refresh');
15622 // if we are using something like 'domtemplate', then
15623 // the what gets used is:
15624 // t.applySubtemplate(NAME, data, wrapping data..)
15625 // the outer template then get' applied with
15626 // the store 'extra data'
15627 // and the body get's added to the
15628 // roo-name="data" node?
15629 // <span class='roo-tpl-{name}'></span> ?????
15633 this.clearSelections();
15634 this.el.update("");
15636 var records = this.store.getRange();
15637 if(records.length < 1) {
15639 // is this valid?? = should it render a template??
15641 this.el.update(this.emptyText);
15645 if (this.dataName) {
15646 this.el.update(t.apply(this.store.meta)); //????
15647 el = this.el.child('.roo-tpl-' + this.dataName);
15650 for(var i = 0, len = records.length; i < len; i++){
15651 var data = this.prepareData(records[i].data, i, records[i]);
15652 this.fireEvent("preparedata", this, data, i, records[i]);
15654 var d = Roo.apply({}, data);
15657 Roo.apply(d, {'roo-id' : Roo.id()});
15661 Roo.each(this.parent.item, function(item){
15662 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15665 Roo.apply(d, {'roo-data-checked' : 'checked'});
15669 html[html.length] = Roo.util.Format.trim(
15671 t.applySubtemplate(this.dataName, d, this.store.meta) :
15678 el.update(html.join(""));
15679 this.nodes = el.dom.childNodes;
15680 this.updateIndexes(0);
15685 * Function to override to reformat the data that is sent to
15686 * the template for each node.
15687 * DEPRICATED - use the preparedata event handler.
15688 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15689 * a JSON object for an UpdateManager bound view).
15691 prepareData : function(data, index, record)
15693 this.fireEvent("preparedata", this, data, index, record);
15697 onUpdate : function(ds, record){
15698 // Roo.log('on update');
15699 this.clearSelections();
15700 var index = this.store.indexOf(record);
15701 var n = this.nodes[index];
15702 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15703 n.parentNode.removeChild(n);
15704 this.updateIndexes(index, index);
15710 onAdd : function(ds, records, index)
15712 //Roo.log(['on Add', ds, records, index] );
15713 this.clearSelections();
15714 if(this.nodes.length == 0){
15718 var n = this.nodes[index];
15719 for(var i = 0, len = records.length; i < len; i++){
15720 var d = this.prepareData(records[i].data, i, records[i]);
15722 this.tpl.insertBefore(n, d);
15725 this.tpl.append(this.el, d);
15728 this.updateIndexes(index);
15731 onRemove : function(ds, record, index){
15732 // Roo.log('onRemove');
15733 this.clearSelections();
15734 var el = this.dataName ?
15735 this.el.child('.roo-tpl-' + this.dataName) :
15738 el.dom.removeChild(this.nodes[index]);
15739 this.updateIndexes(index);
15743 * Refresh an individual node.
15744 * @param {Number} index
15746 refreshNode : function(index){
15747 this.onUpdate(this.store, this.store.getAt(index));
15750 updateIndexes : function(startIndex, endIndex){
15751 var ns = this.nodes;
15752 startIndex = startIndex || 0;
15753 endIndex = endIndex || ns.length - 1;
15754 for(var i = startIndex; i <= endIndex; i++){
15755 ns[i].nodeIndex = i;
15760 * Changes the data store this view uses and refresh the view.
15761 * @param {Store} store
15763 setStore : function(store, initial){
15764 if(!initial && this.store){
15765 this.store.un("datachanged", this.refresh);
15766 this.store.un("add", this.onAdd);
15767 this.store.un("remove", this.onRemove);
15768 this.store.un("update", this.onUpdate);
15769 this.store.un("clear", this.refresh);
15770 this.store.un("beforeload", this.onBeforeLoad);
15771 this.store.un("load", this.onLoad);
15772 this.store.un("loadexception", this.onLoad);
15776 store.on("datachanged", this.refresh, this);
15777 store.on("add", this.onAdd, this);
15778 store.on("remove", this.onRemove, this);
15779 store.on("update", this.onUpdate, this);
15780 store.on("clear", this.refresh, this);
15781 store.on("beforeload", this.onBeforeLoad, this);
15782 store.on("load", this.onLoad, this);
15783 store.on("loadexception", this.onLoad, this);
15791 * onbeforeLoad - masks the loading area.
15794 onBeforeLoad : function(store,opts)
15796 //Roo.log('onBeforeLoad');
15798 this.el.update("");
15800 this.el.mask(this.mask ? this.mask : "Loading" );
15802 onLoad : function ()
15809 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15810 * @param {HTMLElement} node
15811 * @return {HTMLElement} The template node
15813 findItemFromChild : function(node){
15814 var el = this.dataName ?
15815 this.el.child('.roo-tpl-' + this.dataName,true) :
15818 if(!node || node.parentNode == el){
15821 var p = node.parentNode;
15822 while(p && p != el){
15823 if(p.parentNode == el){
15832 onClick : function(e){
15833 var item = this.findItemFromChild(e.getTarget());
15835 var index = this.indexOf(item);
15836 if(this.onItemClick(item, index, e) !== false){
15837 this.fireEvent("click", this, index, item, e);
15840 this.clearSelections();
15845 onContextMenu : function(e){
15846 var item = this.findItemFromChild(e.getTarget());
15848 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15853 onDblClick : function(e){
15854 var item = this.findItemFromChild(e.getTarget());
15856 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15860 onItemClick : function(item, index, e)
15862 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15865 if (this.toggleSelect) {
15866 var m = this.isSelected(item) ? 'unselect' : 'select';
15869 _t[m](item, true, false);
15872 if(this.multiSelect || this.singleSelect){
15873 if(this.multiSelect && e.shiftKey && this.lastSelection){
15874 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15876 this.select(item, this.multiSelect && e.ctrlKey);
15877 this.lastSelection = item;
15880 if(!this.tickable){
15881 e.preventDefault();
15889 * Get the number of selected nodes.
15892 getSelectionCount : function(){
15893 return this.selections.length;
15897 * Get the currently selected nodes.
15898 * @return {Array} An array of HTMLElements
15900 getSelectedNodes : function(){
15901 return this.selections;
15905 * Get the indexes of the selected nodes.
15908 getSelectedIndexes : function(){
15909 var indexes = [], s = this.selections;
15910 for(var i = 0, len = s.length; i < len; i++){
15911 indexes.push(s[i].nodeIndex);
15917 * Clear all selections
15918 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15920 clearSelections : function(suppressEvent){
15921 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15922 this.cmp.elements = this.selections;
15923 this.cmp.removeClass(this.selectedClass);
15924 this.selections = [];
15925 if(!suppressEvent){
15926 this.fireEvent("selectionchange", this, this.selections);
15932 * Returns true if the passed node is selected
15933 * @param {HTMLElement/Number} node The node or node index
15934 * @return {Boolean}
15936 isSelected : function(node){
15937 var s = this.selections;
15941 node = this.getNode(node);
15942 return s.indexOf(node) !== -1;
15947 * @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
15948 * @param {Boolean} keepExisting (optional) true to keep existing selections
15949 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15951 select : function(nodeInfo, keepExisting, suppressEvent){
15952 if(nodeInfo instanceof Array){
15954 this.clearSelections(true);
15956 for(var i = 0, len = nodeInfo.length; i < len; i++){
15957 this.select(nodeInfo[i], true, true);
15961 var node = this.getNode(nodeInfo);
15962 if(!node || this.isSelected(node)){
15963 return; // already selected.
15966 this.clearSelections(true);
15969 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15970 Roo.fly(node).addClass(this.selectedClass);
15971 this.selections.push(node);
15972 if(!suppressEvent){
15973 this.fireEvent("selectionchange", this, this.selections);
15981 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
15982 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15983 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15985 unselect : function(nodeInfo, keepExisting, suppressEvent)
15987 if(nodeInfo instanceof Array){
15988 Roo.each(this.selections, function(s) {
15989 this.unselect(s, nodeInfo);
15993 var node = this.getNode(nodeInfo);
15994 if(!node || !this.isSelected(node)){
15995 //Roo.log("not selected");
15996 return; // not selected.
16000 Roo.each(this.selections, function(s) {
16002 Roo.fly(node).removeClass(this.selectedClass);
16009 this.selections= ns;
16010 this.fireEvent("selectionchange", this, this.selections);
16014 * Gets a template node.
16015 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16016 * @return {HTMLElement} The node or null if it wasn't found
16018 getNode : function(nodeInfo){
16019 if(typeof nodeInfo == "string"){
16020 return document.getElementById(nodeInfo);
16021 }else if(typeof nodeInfo == "number"){
16022 return this.nodes[nodeInfo];
16028 * Gets a range template nodes.
16029 * @param {Number} startIndex
16030 * @param {Number} endIndex
16031 * @return {Array} An array of nodes
16033 getNodes : function(start, end){
16034 var ns = this.nodes;
16035 start = start || 0;
16036 end = typeof end == "undefined" ? ns.length - 1 : end;
16039 for(var i = start; i <= end; i++){
16043 for(var i = start; i >= end; i--){
16051 * Finds the index of the passed node
16052 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16053 * @return {Number} The index of the node or -1
16055 indexOf : function(node){
16056 node = this.getNode(node);
16057 if(typeof node.nodeIndex == "number"){
16058 return node.nodeIndex;
16060 var ns = this.nodes;
16061 for(var i = 0, len = ns.length; i < len; i++){
16072 * based on jquery fullcalendar
16076 Roo.bootstrap = Roo.bootstrap || {};
16078 * @class Roo.bootstrap.Calendar
16079 * @extends Roo.bootstrap.Component
16080 * Bootstrap Calendar class
16081 * @cfg {Boolean} loadMask (true|false) default false
16082 * @cfg {Object} header generate the user specific header of the calendar, default false
16085 * Create a new Container
16086 * @param {Object} config The config object
16091 Roo.bootstrap.Calendar = function(config){
16092 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16096 * Fires when a date is selected
16097 * @param {DatePicker} this
16098 * @param {Date} date The selected date
16102 * @event monthchange
16103 * Fires when the displayed month changes
16104 * @param {DatePicker} this
16105 * @param {Date} date The selected month
16107 'monthchange': true,
16109 * @event evententer
16110 * Fires when mouse over an event
16111 * @param {Calendar} this
16112 * @param {event} Event
16114 'evententer': true,
16116 * @event eventleave
16117 * Fires when the mouse leaves an
16118 * @param {Calendar} this
16121 'eventleave': true,
16123 * @event eventclick
16124 * Fires when the mouse click an
16125 * @param {Calendar} this
16134 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16137 * @cfg {Number} startDay
16138 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16146 getAutoCreate : function(){
16149 var fc_button = function(name, corner, style, content ) {
16150 return Roo.apply({},{
16152 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16154 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16157 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16168 style : 'width:100%',
16175 cls : 'fc-header-left',
16177 fc_button('prev', 'left', 'arrow', '‹' ),
16178 fc_button('next', 'right', 'arrow', '›' ),
16179 { tag: 'span', cls: 'fc-header-space' },
16180 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16188 cls : 'fc-header-center',
16192 cls: 'fc-header-title',
16195 html : 'month / year'
16203 cls : 'fc-header-right',
16205 /* fc_button('month', 'left', '', 'month' ),
16206 fc_button('week', '', '', 'week' ),
16207 fc_button('day', 'right', '', 'day' )
16219 header = this.header;
16222 var cal_heads = function() {
16224 // fixme - handle this.
16226 for (var i =0; i < Date.dayNames.length; i++) {
16227 var d = Date.dayNames[i];
16230 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16231 html : d.substring(0,3)
16235 ret[0].cls += ' fc-first';
16236 ret[6].cls += ' fc-last';
16239 var cal_cell = function(n) {
16242 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16247 cls: 'fc-day-number',
16251 cls: 'fc-day-content',
16255 style: 'position: relative;' // height: 17px;
16267 var cal_rows = function() {
16270 for (var r = 0; r < 6; r++) {
16277 for (var i =0; i < Date.dayNames.length; i++) {
16278 var d = Date.dayNames[i];
16279 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16282 row.cn[0].cls+=' fc-first';
16283 row.cn[0].cn[0].style = 'min-height:90px';
16284 row.cn[6].cls+=' fc-last';
16288 ret[0].cls += ' fc-first';
16289 ret[4].cls += ' fc-prev-last';
16290 ret[5].cls += ' fc-last';
16297 cls: 'fc-border-separate',
16298 style : 'width:100%',
16306 cls : 'fc-first fc-last',
16324 cls : 'fc-content',
16325 style : "position: relative;",
16328 cls : 'fc-view fc-view-month fc-grid',
16329 style : 'position: relative',
16330 unselectable : 'on',
16333 cls : 'fc-event-container',
16334 style : 'position:absolute;z-index:8;top:0;left:0;'
16352 initEvents : function()
16355 throw "can not find store for calendar";
16361 style: "text-align:center",
16365 style: "background-color:white;width:50%;margin:250 auto",
16369 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16380 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16382 var size = this.el.select('.fc-content', true).first().getSize();
16383 this.maskEl.setSize(size.width, size.height);
16384 this.maskEl.enableDisplayMode("block");
16385 if(!this.loadMask){
16386 this.maskEl.hide();
16389 this.store = Roo.factory(this.store, Roo.data);
16390 this.store.on('load', this.onLoad, this);
16391 this.store.on('beforeload', this.onBeforeLoad, this);
16395 this.cells = this.el.select('.fc-day',true);
16396 //Roo.log(this.cells);
16397 this.textNodes = this.el.query('.fc-day-number');
16398 this.cells.addClassOnOver('fc-state-hover');
16400 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16401 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16402 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16403 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16405 this.on('monthchange', this.onMonthChange, this);
16407 this.update(new Date().clearTime());
16410 resize : function() {
16411 var sz = this.el.getSize();
16413 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16414 this.el.select('.fc-day-content div',true).setHeight(34);
16419 showPrevMonth : function(e){
16420 this.update(this.activeDate.add("mo", -1));
16422 showToday : function(e){
16423 this.update(new Date().clearTime());
16426 showNextMonth : function(e){
16427 this.update(this.activeDate.add("mo", 1));
16431 showPrevYear : function(){
16432 this.update(this.activeDate.add("y", -1));
16436 showNextYear : function(){
16437 this.update(this.activeDate.add("y", 1));
16442 update : function(date)
16444 var vd = this.activeDate;
16445 this.activeDate = date;
16446 // if(vd && this.el){
16447 // var t = date.getTime();
16448 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16449 // Roo.log('using add remove');
16451 // this.fireEvent('monthchange', this, date);
16453 // this.cells.removeClass("fc-state-highlight");
16454 // this.cells.each(function(c){
16455 // if(c.dateValue == t){
16456 // c.addClass("fc-state-highlight");
16457 // setTimeout(function(){
16458 // try{c.dom.firstChild.focus();}catch(e){}
16468 var days = date.getDaysInMonth();
16470 var firstOfMonth = date.getFirstDateOfMonth();
16471 var startingPos = firstOfMonth.getDay()-this.startDay;
16473 if(startingPos < this.startDay){
16477 var pm = date.add(Date.MONTH, -1);
16478 var prevStart = pm.getDaysInMonth()-startingPos;
16480 this.cells = this.el.select('.fc-day',true);
16481 this.textNodes = this.el.query('.fc-day-number');
16482 this.cells.addClassOnOver('fc-state-hover');
16484 var cells = this.cells.elements;
16485 var textEls = this.textNodes;
16487 Roo.each(cells, function(cell){
16488 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16491 days += startingPos;
16493 // convert everything to numbers so it's fast
16494 var day = 86400000;
16495 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16498 //Roo.log(prevStart);
16500 var today = new Date().clearTime().getTime();
16501 var sel = date.clearTime().getTime();
16502 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16503 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16504 var ddMatch = this.disabledDatesRE;
16505 var ddText = this.disabledDatesText;
16506 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16507 var ddaysText = this.disabledDaysText;
16508 var format = this.format;
16510 var setCellClass = function(cal, cell){
16514 //Roo.log('set Cell Class');
16516 var t = d.getTime();
16520 cell.dateValue = t;
16522 cell.className += " fc-today";
16523 cell.className += " fc-state-highlight";
16524 cell.title = cal.todayText;
16527 // disable highlight in other month..
16528 //cell.className += " fc-state-highlight";
16533 cell.className = " fc-state-disabled";
16534 cell.title = cal.minText;
16538 cell.className = " fc-state-disabled";
16539 cell.title = cal.maxText;
16543 if(ddays.indexOf(d.getDay()) != -1){
16544 cell.title = ddaysText;
16545 cell.className = " fc-state-disabled";
16548 if(ddMatch && format){
16549 var fvalue = d.dateFormat(format);
16550 if(ddMatch.test(fvalue)){
16551 cell.title = ddText.replace("%0", fvalue);
16552 cell.className = " fc-state-disabled";
16556 if (!cell.initialClassName) {
16557 cell.initialClassName = cell.dom.className;
16560 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16565 for(; i < startingPos; i++) {
16566 textEls[i].innerHTML = (++prevStart);
16567 d.setDate(d.getDate()+1);
16569 cells[i].className = "fc-past fc-other-month";
16570 setCellClass(this, cells[i]);
16575 for(; i < days; i++){
16576 intDay = i - startingPos + 1;
16577 textEls[i].innerHTML = (intDay);
16578 d.setDate(d.getDate()+1);
16580 cells[i].className = ''; // "x-date-active";
16581 setCellClass(this, cells[i]);
16585 for(; i < 42; i++) {
16586 textEls[i].innerHTML = (++extraDays);
16587 d.setDate(d.getDate()+1);
16589 cells[i].className = "fc-future fc-other-month";
16590 setCellClass(this, cells[i]);
16593 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16595 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16597 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16598 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16600 if(totalRows != 6){
16601 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16602 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16605 this.fireEvent('monthchange', this, date);
16609 if(!this.internalRender){
16610 var main = this.el.dom.firstChild;
16611 var w = main.offsetWidth;
16612 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16613 Roo.fly(main).setWidth(w);
16614 this.internalRender = true;
16615 // opera does not respect the auto grow header center column
16616 // then, after it gets a width opera refuses to recalculate
16617 // without a second pass
16618 if(Roo.isOpera && !this.secondPass){
16619 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16620 this.secondPass = true;
16621 this.update.defer(10, this, [date]);
16628 findCell : function(dt) {
16629 dt = dt.clearTime().getTime();
16631 this.cells.each(function(c){
16632 //Roo.log("check " +c.dateValue + '?=' + dt);
16633 if(c.dateValue == dt){
16643 findCells : function(ev) {
16644 var s = ev.start.clone().clearTime().getTime();
16646 var e= ev.end.clone().clearTime().getTime();
16649 this.cells.each(function(c){
16650 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16652 if(c.dateValue > e){
16655 if(c.dateValue < s){
16664 // findBestRow: function(cells)
16668 // for (var i =0 ; i < cells.length;i++) {
16669 // ret = Math.max(cells[i].rows || 0,ret);
16676 addItem : function(ev)
16678 // look for vertical location slot in
16679 var cells = this.findCells(ev);
16681 // ev.row = this.findBestRow(cells);
16683 // work out the location.
16687 for(var i =0; i < cells.length; i++) {
16689 cells[i].row = cells[0].row;
16692 cells[i].row = cells[i].row + 1;
16702 if (crow.start.getY() == cells[i].getY()) {
16704 crow.end = cells[i];
16721 cells[0].events.push(ev);
16723 this.calevents.push(ev);
16726 clearEvents: function() {
16728 if(!this.calevents){
16732 Roo.each(this.cells.elements, function(c){
16738 Roo.each(this.calevents, function(e) {
16739 Roo.each(e.els, function(el) {
16740 el.un('mouseenter' ,this.onEventEnter, this);
16741 el.un('mouseleave' ,this.onEventLeave, this);
16746 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16752 renderEvents: function()
16756 this.cells.each(function(c) {
16765 if(c.row != c.events.length){
16766 r = 4 - (4 - (c.row - c.events.length));
16769 c.events = ev.slice(0, r);
16770 c.more = ev.slice(r);
16772 if(c.more.length && c.more.length == 1){
16773 c.events.push(c.more.pop());
16776 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16780 this.cells.each(function(c) {
16782 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16785 for (var e = 0; e < c.events.length; e++){
16786 var ev = c.events[e];
16787 var rows = ev.rows;
16789 for(var i = 0; i < rows.length; i++) {
16791 // how many rows should it span..
16794 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16795 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16797 unselectable : "on",
16800 cls: 'fc-event-inner',
16804 // cls: 'fc-event-time',
16805 // html : cells.length > 1 ? '' : ev.time
16809 cls: 'fc-event-title',
16810 html : String.format('{0}', ev.title)
16817 cls: 'ui-resizable-handle ui-resizable-e',
16818 html : '  '
16825 cfg.cls += ' fc-event-start';
16827 if ((i+1) == rows.length) {
16828 cfg.cls += ' fc-event-end';
16831 var ctr = _this.el.select('.fc-event-container',true).first();
16832 var cg = ctr.createChild(cfg);
16834 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16835 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16837 var r = (c.more.length) ? 1 : 0;
16838 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16839 cg.setWidth(ebox.right - sbox.x -2);
16841 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16842 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16843 cg.on('click', _this.onEventClick, _this, ev);
16854 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16855 style : 'position: absolute',
16856 unselectable : "on",
16859 cls: 'fc-event-inner',
16863 cls: 'fc-event-title',
16871 cls: 'ui-resizable-handle ui-resizable-e',
16872 html : '  '
16878 var ctr = _this.el.select('.fc-event-container',true).first();
16879 var cg = ctr.createChild(cfg);
16881 var sbox = c.select('.fc-day-content',true).first().getBox();
16882 var ebox = c.select('.fc-day-content',true).first().getBox();
16884 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16885 cg.setWidth(ebox.right - sbox.x -2);
16887 cg.on('click', _this.onMoreEventClick, _this, c.more);
16897 onEventEnter: function (e, el,event,d) {
16898 this.fireEvent('evententer', this, el, event);
16901 onEventLeave: function (e, el,event,d) {
16902 this.fireEvent('eventleave', this, el, event);
16905 onEventClick: function (e, el,event,d) {
16906 this.fireEvent('eventclick', this, el, event);
16909 onMonthChange: function () {
16913 onMoreEventClick: function(e, el, more)
16917 this.calpopover.placement = 'right';
16918 this.calpopover.setTitle('More');
16920 this.calpopover.setContent('');
16922 var ctr = this.calpopover.el.select('.popover-content', true).first();
16924 Roo.each(more, function(m){
16926 cls : 'fc-event-hori fc-event-draggable',
16929 var cg = ctr.createChild(cfg);
16931 cg.on('click', _this.onEventClick, _this, m);
16934 this.calpopover.show(el);
16939 onLoad: function ()
16941 this.calevents = [];
16944 if(this.store.getCount() > 0){
16945 this.store.data.each(function(d){
16948 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16949 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16950 time : d.data.start_time,
16951 title : d.data.title,
16952 description : d.data.description,
16953 venue : d.data.venue
16958 this.renderEvents();
16960 if(this.calevents.length && this.loadMask){
16961 this.maskEl.hide();
16965 onBeforeLoad: function()
16967 this.clearEvents();
16969 this.maskEl.show();
16983 * @class Roo.bootstrap.Popover
16984 * @extends Roo.bootstrap.Component
16985 * Bootstrap Popover class
16986 * @cfg {String} html contents of the popover (or false to use children..)
16987 * @cfg {String} title of popover (or false to hide)
16988 * @cfg {String} placement how it is placed
16989 * @cfg {String} trigger click || hover (or false to trigger manually)
16990 * @cfg {String} over what (parent or false to trigger manually.)
16991 * @cfg {Number} delay - delay before showing
16994 * Create a new Popover
16995 * @param {Object} config The config object
16998 Roo.bootstrap.Popover = function(config){
16999 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17005 * After the popover show
17007 * @param {Roo.bootstrap.Popover} this
17012 * After the popover hide
17014 * @param {Roo.bootstrap.Popover} this
17020 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17022 title: 'Fill in a title',
17025 placement : 'right',
17026 trigger : 'hover', // hover
17032 can_build_overlaid : false,
17034 getChildContainer : function()
17036 return this.el.select('.popover-content',true).first();
17039 getAutoCreate : function(){
17042 cls : 'popover roo-dynamic',
17043 style: 'display:block',
17049 cls : 'popover-inner',
17053 cls: 'popover-title',
17057 cls : 'popover-content',
17068 setTitle: function(str)
17071 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17073 setContent: function(str)
17076 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17078 // as it get's added to the bottom of the page.
17079 onRender : function(ct, position)
17081 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17083 var cfg = Roo.apply({}, this.getAutoCreate());
17087 cfg.cls += ' ' + this.cls;
17090 cfg.style = this.style;
17092 //Roo.log("adding to ");
17093 this.el = Roo.get(document.body).createChild(cfg, position);
17094 // Roo.log(this.el);
17099 initEvents : function()
17101 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17102 this.el.enableDisplayMode('block');
17104 if (this.over === false) {
17107 if (this.triggers === false) {
17110 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17111 var triggers = this.trigger ? this.trigger.split(' ') : [];
17112 Roo.each(triggers, function(trigger) {
17114 if (trigger == 'click') {
17115 on_el.on('click', this.toggle, this);
17116 } else if (trigger != 'manual') {
17117 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17118 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17120 on_el.on(eventIn ,this.enter, this);
17121 on_el.on(eventOut, this.leave, this);
17132 toggle : function () {
17133 this.hoverState == 'in' ? this.leave() : this.enter();
17136 enter : function () {
17138 clearTimeout(this.timeout);
17140 this.hoverState = 'in';
17142 if (!this.delay || !this.delay.show) {
17147 this.timeout = setTimeout(function () {
17148 if (_t.hoverState == 'in') {
17151 }, this.delay.show)
17154 leave : function() {
17155 clearTimeout(this.timeout);
17157 this.hoverState = 'out';
17159 if (!this.delay || !this.delay.hide) {
17164 this.timeout = setTimeout(function () {
17165 if (_t.hoverState == 'out') {
17168 }, this.delay.hide)
17171 show : function (on_el)
17174 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17178 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17179 if (this.html !== false) {
17180 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17182 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17183 if (!this.title.length) {
17184 this.el.select('.popover-title',true).hide();
17187 var placement = typeof this.placement == 'function' ?
17188 this.placement.call(this, this.el, on_el) :
17191 var autoToken = /\s?auto?\s?/i;
17192 var autoPlace = autoToken.test(placement);
17194 placement = placement.replace(autoToken, '') || 'top';
17198 //this.el.setXY([0,0]);
17200 this.el.dom.style.display='block';
17201 this.el.addClass(placement);
17203 //this.el.appendTo(on_el);
17205 var p = this.getPosition();
17206 var box = this.el.getBox();
17211 var align = Roo.bootstrap.Popover.alignment[placement];
17212 this.el.alignTo(on_el, align[0],align[1]);
17213 //var arrow = this.el.select('.arrow',true).first();
17214 //arrow.set(align[2],
17216 this.el.addClass('in');
17219 if (this.el.hasClass('fade')) {
17223 this.hoverState = 'in';
17225 this.fireEvent('show', this);
17230 this.el.setXY([0,0]);
17231 this.el.removeClass('in');
17233 this.hoverState = null;
17235 this.fireEvent('hide', this);
17240 Roo.bootstrap.Popover.alignment = {
17241 'left' : ['r-l', [-10,0], 'right'],
17242 'right' : ['l-r', [10,0], 'left'],
17243 'bottom' : ['t-b', [0,10], 'top'],
17244 'top' : [ 'b-t', [0,-10], 'bottom']
17255 * @class Roo.bootstrap.Progress
17256 * @extends Roo.bootstrap.Component
17257 * Bootstrap Progress class
17258 * @cfg {Boolean} striped striped of the progress bar
17259 * @cfg {Boolean} active animated of the progress bar
17263 * Create a new Progress
17264 * @param {Object} config The config object
17267 Roo.bootstrap.Progress = function(config){
17268 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17271 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17276 getAutoCreate : function(){
17284 cfg.cls += ' progress-striped';
17288 cfg.cls += ' active';
17307 * @class Roo.bootstrap.ProgressBar
17308 * @extends Roo.bootstrap.Component
17309 * Bootstrap ProgressBar class
17310 * @cfg {Number} aria_valuenow aria-value now
17311 * @cfg {Number} aria_valuemin aria-value min
17312 * @cfg {Number} aria_valuemax aria-value max
17313 * @cfg {String} label label for the progress bar
17314 * @cfg {String} panel (success | info | warning | danger )
17315 * @cfg {String} role role of the progress bar
17316 * @cfg {String} sr_only text
17320 * Create a new ProgressBar
17321 * @param {Object} config The config object
17324 Roo.bootstrap.ProgressBar = function(config){
17325 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17328 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17332 aria_valuemax : 100,
17338 getAutoCreate : function()
17343 cls: 'progress-bar',
17344 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17356 cfg.role = this.role;
17359 if(this.aria_valuenow){
17360 cfg['aria-valuenow'] = this.aria_valuenow;
17363 if(this.aria_valuemin){
17364 cfg['aria-valuemin'] = this.aria_valuemin;
17367 if(this.aria_valuemax){
17368 cfg['aria-valuemax'] = this.aria_valuemax;
17371 if(this.label && !this.sr_only){
17372 cfg.html = this.label;
17376 cfg.cls += ' progress-bar-' + this.panel;
17382 update : function(aria_valuenow)
17384 this.aria_valuenow = aria_valuenow;
17386 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17401 * @class Roo.bootstrap.TabGroup
17402 * @extends Roo.bootstrap.Column
17403 * Bootstrap Column class
17404 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17405 * @cfg {Boolean} carousel true to make the group behave like a carousel
17406 * @cfg {Boolean} bullets show bullets for the panels
17407 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17408 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17409 * @cfg {Boolean} showarrow (true|false) show arrow default true
17412 * Create a new TabGroup
17413 * @param {Object} config The config object
17416 Roo.bootstrap.TabGroup = function(config){
17417 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17419 this.navId = Roo.id();
17422 Roo.bootstrap.TabGroup.register(this);
17426 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17429 transition : false,
17434 slideOnTouch : false,
17437 getAutoCreate : function()
17439 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17441 cfg.cls += ' tab-content';
17443 if (this.carousel) {
17444 cfg.cls += ' carousel slide';
17447 cls : 'carousel-inner',
17451 if(this.bullets && !Roo.isTouch){
17454 cls : 'carousel-bullets',
17458 if(this.bullets_cls){
17459 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17466 cfg.cn[0].cn.push(bullets);
17469 if(this.showarrow){
17470 cfg.cn[0].cn.push({
17472 class : 'carousel-arrow',
17476 class : 'carousel-prev',
17480 class : 'fa fa-chevron-left'
17486 class : 'carousel-next',
17490 class : 'fa fa-chevron-right'
17503 initEvents: function()
17505 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17506 // this.el.on("touchstart", this.onTouchStart, this);
17509 if(this.autoslide){
17512 this.slideFn = window.setInterval(function() {
17513 _this.showPanelNext();
17517 if(this.showarrow){
17518 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17519 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17525 // onTouchStart : function(e, el, o)
17527 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17531 // this.showPanelNext();
17535 getChildContainer : function()
17537 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17541 * register a Navigation item
17542 * @param {Roo.bootstrap.NavItem} the navitem to add
17544 register : function(item)
17546 this.tabs.push( item);
17547 item.navId = this.navId; // not really needed..
17552 getActivePanel : function()
17555 Roo.each(this.tabs, function(t) {
17565 getPanelByName : function(n)
17568 Roo.each(this.tabs, function(t) {
17569 if (t.tabId == n) {
17577 indexOfPanel : function(p)
17580 Roo.each(this.tabs, function(t,i) {
17581 if (t.tabId == p.tabId) {
17590 * show a specific panel
17591 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17592 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17594 showPanel : function (pan)
17596 if(this.transition || typeof(pan) == 'undefined'){
17597 Roo.log("waiting for the transitionend");
17601 if (typeof(pan) == 'number') {
17602 pan = this.tabs[pan];
17605 if (typeof(pan) == 'string') {
17606 pan = this.getPanelByName(pan);
17609 var cur = this.getActivePanel();
17612 Roo.log('pan or acitve pan is undefined');
17616 if (pan.tabId == this.getActivePanel().tabId) {
17620 if (false === cur.fireEvent('beforedeactivate')) {
17624 if(this.bullets > 0 && !Roo.isTouch){
17625 this.setActiveBullet(this.indexOfPanel(pan));
17628 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17630 this.transition = true;
17631 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17632 var lr = dir == 'next' ? 'left' : 'right';
17633 pan.el.addClass(dir); // or prev
17634 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17635 cur.el.addClass(lr); // or right
17636 pan.el.addClass(lr);
17639 cur.el.on('transitionend', function() {
17640 Roo.log("trans end?");
17642 pan.el.removeClass([lr,dir]);
17643 pan.setActive(true);
17645 cur.el.removeClass([lr]);
17646 cur.setActive(false);
17648 _this.transition = false;
17650 }, this, { single: true } );
17655 cur.setActive(false);
17656 pan.setActive(true);
17661 showPanelNext : function()
17663 var i = this.indexOfPanel(this.getActivePanel());
17665 if (i >= this.tabs.length - 1 && !this.autoslide) {
17669 if (i >= this.tabs.length - 1 && this.autoslide) {
17673 this.showPanel(this.tabs[i+1]);
17676 showPanelPrev : function()
17678 var i = this.indexOfPanel(this.getActivePanel());
17680 if (i < 1 && !this.autoslide) {
17684 if (i < 1 && this.autoslide) {
17685 i = this.tabs.length;
17688 this.showPanel(this.tabs[i-1]);
17692 addBullet: function()
17694 if(!this.bullets || Roo.isTouch){
17697 var ctr = this.el.select('.carousel-bullets',true).first();
17698 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17699 var bullet = ctr.createChild({
17700 cls : 'bullet bullet-' + i
17701 },ctr.dom.lastChild);
17706 bullet.on('click', (function(e, el, o, ii, t){
17708 e.preventDefault();
17710 this.showPanel(ii);
17712 if(this.autoslide && this.slideFn){
17713 clearInterval(this.slideFn);
17714 this.slideFn = window.setInterval(function() {
17715 _this.showPanelNext();
17719 }).createDelegate(this, [i, bullet], true));
17724 setActiveBullet : function(i)
17730 Roo.each(this.el.select('.bullet', true).elements, function(el){
17731 el.removeClass('selected');
17734 var bullet = this.el.select('.bullet-' + i, true).first();
17740 bullet.addClass('selected');
17751 Roo.apply(Roo.bootstrap.TabGroup, {
17755 * register a Navigation Group
17756 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17758 register : function(navgrp)
17760 this.groups[navgrp.navId] = navgrp;
17764 * fetch a Navigation Group based on the navigation ID
17765 * if one does not exist , it will get created.
17766 * @param {string} the navgroup to add
17767 * @returns {Roo.bootstrap.NavGroup} the navgroup
17769 get: function(navId) {
17770 if (typeof(this.groups[navId]) == 'undefined') {
17771 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17773 return this.groups[navId] ;
17788 * @class Roo.bootstrap.TabPanel
17789 * @extends Roo.bootstrap.Component
17790 * Bootstrap TabPanel class
17791 * @cfg {Boolean} active panel active
17792 * @cfg {String} html panel content
17793 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17794 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17795 * @cfg {String} href click to link..
17799 * Create a new TabPanel
17800 * @param {Object} config The config object
17803 Roo.bootstrap.TabPanel = function(config){
17804 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17808 * Fires when the active status changes
17809 * @param {Roo.bootstrap.TabPanel} this
17810 * @param {Boolean} state the new state
17815 * @event beforedeactivate
17816 * Fires before a tab is de-activated - can be used to do validation on a form.
17817 * @param {Roo.bootstrap.TabPanel} this
17818 * @return {Boolean} false if there is an error
17821 'beforedeactivate': true
17824 this.tabId = this.tabId || Roo.id();
17828 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17836 getAutoCreate : function(){
17839 // item is needed for carousel - not sure if it has any effect otherwise
17840 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17841 html: this.html || ''
17845 cfg.cls += ' active';
17849 cfg.tabId = this.tabId;
17856 initEvents: function()
17858 var p = this.parent();
17860 this.navId = this.navId || p.navId;
17862 if (typeof(this.navId) != 'undefined') {
17863 // not really needed.. but just in case.. parent should be a NavGroup.
17864 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17868 var i = tg.tabs.length - 1;
17870 if(this.active && tg.bullets > 0 && i < tg.bullets){
17871 tg.setActiveBullet(i);
17875 this.el.on('click', this.onClick, this);
17878 this.el.on("touchstart", this.onTouchStart, this);
17879 this.el.on("touchmove", this.onTouchMove, this);
17880 this.el.on("touchend", this.onTouchEnd, this);
17885 onRender : function(ct, position)
17887 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17890 setActive : function(state)
17892 Roo.log("panel - set active " + this.tabId + "=" + state);
17894 this.active = state;
17896 this.el.removeClass('active');
17898 } else if (!this.el.hasClass('active')) {
17899 this.el.addClass('active');
17902 this.fireEvent('changed', this, state);
17905 onClick : function(e)
17907 e.preventDefault();
17909 if(!this.href.length){
17913 window.location.href = this.href;
17922 onTouchStart : function(e)
17924 this.swiping = false;
17926 this.startX = e.browserEvent.touches[0].clientX;
17927 this.startY = e.browserEvent.touches[0].clientY;
17930 onTouchMove : function(e)
17932 this.swiping = true;
17934 this.endX = e.browserEvent.touches[0].clientX;
17935 this.endY = e.browserEvent.touches[0].clientY;
17938 onTouchEnd : function(e)
17945 var tabGroup = this.parent();
17947 if(this.endX > this.startX){ // swiping right
17948 tabGroup.showPanelPrev();
17952 if(this.startX > this.endX){ // swiping left
17953 tabGroup.showPanelNext();
17972 * @class Roo.bootstrap.DateField
17973 * @extends Roo.bootstrap.Input
17974 * Bootstrap DateField class
17975 * @cfg {Number} weekStart default 0
17976 * @cfg {String} viewMode default empty, (months|years)
17977 * @cfg {String} minViewMode default empty, (months|years)
17978 * @cfg {Number} startDate default -Infinity
17979 * @cfg {Number} endDate default Infinity
17980 * @cfg {Boolean} todayHighlight default false
17981 * @cfg {Boolean} todayBtn default false
17982 * @cfg {Boolean} calendarWeeks default false
17983 * @cfg {Object} daysOfWeekDisabled default empty
17984 * @cfg {Boolean} singleMode default false (true | false)
17986 * @cfg {Boolean} keyboardNavigation default true
17987 * @cfg {String} language default en
17990 * Create a new DateField
17991 * @param {Object} config The config object
17994 Roo.bootstrap.DateField = function(config){
17995 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17999 * Fires when this field show.
18000 * @param {Roo.bootstrap.DateField} this
18001 * @param {Mixed} date The date value
18006 * Fires when this field hide.
18007 * @param {Roo.bootstrap.DateField} this
18008 * @param {Mixed} date The date value
18013 * Fires when select a date.
18014 * @param {Roo.bootstrap.DateField} this
18015 * @param {Mixed} date The date value
18019 * @event beforeselect
18020 * Fires when before select a date.
18021 * @param {Roo.bootstrap.DateField} this
18022 * @param {Mixed} date The date value
18024 beforeselect : true
18028 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18031 * @cfg {String} format
18032 * The default date format string which can be overriden for localization support. The format must be
18033 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18037 * @cfg {String} altFormats
18038 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18039 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18041 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18049 todayHighlight : false,
18055 keyboardNavigation: true,
18057 calendarWeeks: false,
18059 startDate: -Infinity,
18063 daysOfWeekDisabled: [],
18067 singleMode : false,
18069 UTCDate: function()
18071 return new Date(Date.UTC.apply(Date, arguments));
18074 UTCToday: function()
18076 var today = new Date();
18077 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18080 getDate: function() {
18081 var d = this.getUTCDate();
18082 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18085 getUTCDate: function() {
18089 setDate: function(d) {
18090 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18093 setUTCDate: function(d) {
18095 this.setValue(this.formatDate(this.date));
18098 onRender: function(ct, position)
18101 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18103 this.language = this.language || 'en';
18104 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18105 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18107 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18108 this.format = this.format || 'm/d/y';
18109 this.isInline = false;
18110 this.isInput = true;
18111 this.component = this.el.select('.add-on', true).first() || false;
18112 this.component = (this.component && this.component.length === 0) ? false : this.component;
18113 this.hasInput = this.component && this.inputEl().length;
18115 if (typeof(this.minViewMode === 'string')) {
18116 switch (this.minViewMode) {
18118 this.minViewMode = 1;
18121 this.minViewMode = 2;
18124 this.minViewMode = 0;
18129 if (typeof(this.viewMode === 'string')) {
18130 switch (this.viewMode) {
18143 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18145 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18147 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18149 this.picker().on('mousedown', this.onMousedown, this);
18150 this.picker().on('click', this.onClick, this);
18152 this.picker().addClass('datepicker-dropdown');
18154 this.startViewMode = this.viewMode;
18156 if(this.singleMode){
18157 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18158 v.setVisibilityMode(Roo.Element.DISPLAY);
18162 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18163 v.setStyle('width', '189px');
18167 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18168 if(!this.calendarWeeks){
18173 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18174 v.attr('colspan', function(i, val){
18175 return parseInt(val) + 1;
18180 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18182 this.setStartDate(this.startDate);
18183 this.setEndDate(this.endDate);
18185 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18192 if(this.isInline) {
18197 picker : function()
18199 return this.pickerEl;
18200 // return this.el.select('.datepicker', true).first();
18203 fillDow: function()
18205 var dowCnt = this.weekStart;
18214 if(this.calendarWeeks){
18222 while (dowCnt < this.weekStart + 7) {
18226 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18230 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18233 fillMonths: function()
18236 var months = this.picker().select('>.datepicker-months td', true).first();
18238 months.dom.innerHTML = '';
18244 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18247 months.createChild(month);
18254 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;
18256 if (this.date < this.startDate) {
18257 this.viewDate = new Date(this.startDate);
18258 } else if (this.date > this.endDate) {
18259 this.viewDate = new Date(this.endDate);
18261 this.viewDate = new Date(this.date);
18269 var d = new Date(this.viewDate),
18270 year = d.getUTCFullYear(),
18271 month = d.getUTCMonth(),
18272 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18273 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18274 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18275 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18276 currentDate = this.date && this.date.valueOf(),
18277 today = this.UTCToday();
18279 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18281 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18283 // this.picker.select('>tfoot th.today').
18284 // .text(dates[this.language].today)
18285 // .toggle(this.todayBtn !== false);
18287 this.updateNavArrows();
18290 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18292 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18294 prevMonth.setUTCDate(day);
18296 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18298 var nextMonth = new Date(prevMonth);
18300 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18302 nextMonth = nextMonth.valueOf();
18304 var fillMonths = false;
18306 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18308 while(prevMonth.valueOf() < nextMonth) {
18311 if (prevMonth.getUTCDay() === this.weekStart) {
18313 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18321 if(this.calendarWeeks){
18322 // ISO 8601: First week contains first thursday.
18323 // ISO also states week starts on Monday, but we can be more abstract here.
18325 // Start of current week: based on weekstart/current date
18326 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18327 // Thursday of this week
18328 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18329 // First Thursday of year, year from thursday
18330 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18331 // Calendar week: ms between thursdays, div ms per day, div 7 days
18332 calWeek = (th - yth) / 864e5 / 7 + 1;
18334 fillMonths.cn.push({
18342 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18344 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18347 if (this.todayHighlight &&
18348 prevMonth.getUTCFullYear() == today.getFullYear() &&
18349 prevMonth.getUTCMonth() == today.getMonth() &&
18350 prevMonth.getUTCDate() == today.getDate()) {
18351 clsName += ' today';
18354 if (currentDate && prevMonth.valueOf() === currentDate) {
18355 clsName += ' active';
18358 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18359 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18360 clsName += ' disabled';
18363 fillMonths.cn.push({
18365 cls: 'day ' + clsName,
18366 html: prevMonth.getDate()
18369 prevMonth.setDate(prevMonth.getDate()+1);
18372 var currentYear = this.date && this.date.getUTCFullYear();
18373 var currentMonth = this.date && this.date.getUTCMonth();
18375 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18377 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18378 v.removeClass('active');
18380 if(currentYear === year && k === currentMonth){
18381 v.addClass('active');
18384 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18385 v.addClass('disabled');
18391 year = parseInt(year/10, 10) * 10;
18393 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18395 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18398 for (var i = -1; i < 11; i++) {
18399 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18401 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18409 showMode: function(dir)
18412 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18415 Roo.each(this.picker().select('>div',true).elements, function(v){
18416 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18419 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18424 if(this.isInline) {
18428 this.picker().removeClass(['bottom', 'top']);
18430 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18432 * place to the top of element!
18436 this.picker().addClass('top');
18437 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18442 this.picker().addClass('bottom');
18444 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18447 parseDate : function(value)
18449 if(!value || value instanceof Date){
18452 var v = Date.parseDate(value, this.format);
18453 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18454 v = Date.parseDate(value, 'Y-m-d');
18456 if(!v && this.altFormats){
18457 if(!this.altFormatsArray){
18458 this.altFormatsArray = this.altFormats.split("|");
18460 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18461 v = Date.parseDate(value, this.altFormatsArray[i]);
18467 formatDate : function(date, fmt)
18469 return (!date || !(date instanceof Date)) ?
18470 date : date.dateFormat(fmt || this.format);
18473 onFocus : function()
18475 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18479 onBlur : function()
18481 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18483 var d = this.inputEl().getValue();
18492 this.picker().show();
18496 this.fireEvent('show', this, this.date);
18501 if(this.isInline) {
18504 this.picker().hide();
18505 this.viewMode = this.startViewMode;
18508 this.fireEvent('hide', this, this.date);
18512 onMousedown: function(e)
18514 e.stopPropagation();
18515 e.preventDefault();
18520 Roo.bootstrap.DateField.superclass.keyup.call(this);
18524 setValue: function(v)
18526 if(this.fireEvent('beforeselect', this, v) !== false){
18527 var d = new Date(this.parseDate(v) ).clearTime();
18529 if(isNaN(d.getTime())){
18530 this.date = this.viewDate = '';
18531 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18535 v = this.formatDate(d);
18537 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18539 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18543 this.fireEvent('select', this, this.date);
18547 getValue: function()
18549 return this.formatDate(this.date);
18552 fireKey: function(e)
18554 if (!this.picker().isVisible()){
18555 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18561 var dateChanged = false,
18563 newDate, newViewDate;
18568 e.preventDefault();
18572 if (!this.keyboardNavigation) {
18575 dir = e.keyCode == 37 ? -1 : 1;
18578 newDate = this.moveYear(this.date, dir);
18579 newViewDate = this.moveYear(this.viewDate, dir);
18580 } else if (e.shiftKey){
18581 newDate = this.moveMonth(this.date, dir);
18582 newViewDate = this.moveMonth(this.viewDate, dir);
18584 newDate = new Date(this.date);
18585 newDate.setUTCDate(this.date.getUTCDate() + dir);
18586 newViewDate = new Date(this.viewDate);
18587 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18589 if (this.dateWithinRange(newDate)){
18590 this.date = newDate;
18591 this.viewDate = newViewDate;
18592 this.setValue(this.formatDate(this.date));
18594 e.preventDefault();
18595 dateChanged = true;
18600 if (!this.keyboardNavigation) {
18603 dir = e.keyCode == 38 ? -1 : 1;
18605 newDate = this.moveYear(this.date, dir);
18606 newViewDate = this.moveYear(this.viewDate, dir);
18607 } else if (e.shiftKey){
18608 newDate = this.moveMonth(this.date, dir);
18609 newViewDate = this.moveMonth(this.viewDate, dir);
18611 newDate = new Date(this.date);
18612 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18613 newViewDate = new Date(this.viewDate);
18614 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18616 if (this.dateWithinRange(newDate)){
18617 this.date = newDate;
18618 this.viewDate = newViewDate;
18619 this.setValue(this.formatDate(this.date));
18621 e.preventDefault();
18622 dateChanged = true;
18626 this.setValue(this.formatDate(this.date));
18628 e.preventDefault();
18631 this.setValue(this.formatDate(this.date));
18645 onClick: function(e)
18647 e.stopPropagation();
18648 e.preventDefault();
18650 var target = e.getTarget();
18652 if(target.nodeName.toLowerCase() === 'i'){
18653 target = Roo.get(target).dom.parentNode;
18656 var nodeName = target.nodeName;
18657 var className = target.className;
18658 var html = target.innerHTML;
18659 //Roo.log(nodeName);
18661 switch(nodeName.toLowerCase()) {
18663 switch(className) {
18669 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18670 switch(this.viewMode){
18672 this.viewDate = this.moveMonth(this.viewDate, dir);
18676 this.viewDate = this.moveYear(this.viewDate, dir);
18682 var date = new Date();
18683 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18685 this.setValue(this.formatDate(this.date));
18692 if (className.indexOf('disabled') < 0) {
18693 this.viewDate.setUTCDate(1);
18694 if (className.indexOf('month') > -1) {
18695 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18697 var year = parseInt(html, 10) || 0;
18698 this.viewDate.setUTCFullYear(year);
18702 if(this.singleMode){
18703 this.setValue(this.formatDate(this.viewDate));
18714 //Roo.log(className);
18715 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18716 var day = parseInt(html, 10) || 1;
18717 var year = this.viewDate.getUTCFullYear(),
18718 month = this.viewDate.getUTCMonth();
18720 if (className.indexOf('old') > -1) {
18727 } else if (className.indexOf('new') > -1) {
18735 //Roo.log([year,month,day]);
18736 this.date = this.UTCDate(year, month, day,0,0,0,0);
18737 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18739 //Roo.log(this.formatDate(this.date));
18740 this.setValue(this.formatDate(this.date));
18747 setStartDate: function(startDate)
18749 this.startDate = startDate || -Infinity;
18750 if (this.startDate !== -Infinity) {
18751 this.startDate = this.parseDate(this.startDate);
18754 this.updateNavArrows();
18757 setEndDate: function(endDate)
18759 this.endDate = endDate || Infinity;
18760 if (this.endDate !== Infinity) {
18761 this.endDate = this.parseDate(this.endDate);
18764 this.updateNavArrows();
18767 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18769 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18770 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18771 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18773 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18774 return parseInt(d, 10);
18777 this.updateNavArrows();
18780 updateNavArrows: function()
18782 if(this.singleMode){
18786 var d = new Date(this.viewDate),
18787 year = d.getUTCFullYear(),
18788 month = d.getUTCMonth();
18790 Roo.each(this.picker().select('.prev', true).elements, function(v){
18792 switch (this.viewMode) {
18795 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18801 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18808 Roo.each(this.picker().select('.next', true).elements, function(v){
18810 switch (this.viewMode) {
18813 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18819 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18827 moveMonth: function(date, dir)
18832 var new_date = new Date(date.valueOf()),
18833 day = new_date.getUTCDate(),
18834 month = new_date.getUTCMonth(),
18835 mag = Math.abs(dir),
18837 dir = dir > 0 ? 1 : -1;
18840 // If going back one month, make sure month is not current month
18841 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18843 return new_date.getUTCMonth() == month;
18845 // If going forward one month, make sure month is as expected
18846 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18848 return new_date.getUTCMonth() != new_month;
18850 new_month = month + dir;
18851 new_date.setUTCMonth(new_month);
18852 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18853 if (new_month < 0 || new_month > 11) {
18854 new_month = (new_month + 12) % 12;
18857 // For magnitudes >1, move one month at a time...
18858 for (var i=0; i<mag; i++) {
18859 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18860 new_date = this.moveMonth(new_date, dir);
18862 // ...then reset the day, keeping it in the new month
18863 new_month = new_date.getUTCMonth();
18864 new_date.setUTCDate(day);
18866 return new_month != new_date.getUTCMonth();
18869 // Common date-resetting loop -- if date is beyond end of month, make it
18872 new_date.setUTCDate(--day);
18873 new_date.setUTCMonth(new_month);
18878 moveYear: function(date, dir)
18880 return this.moveMonth(date, dir*12);
18883 dateWithinRange: function(date)
18885 return date >= this.startDate && date <= this.endDate;
18891 this.picker().remove();
18894 validateValue : function(value)
18896 if(value.length < 1) {
18897 if(this.allowBlank){
18903 if(value.length < this.minLength){
18906 if(value.length > this.maxLength){
18910 var vt = Roo.form.VTypes;
18911 if(!vt[this.vtype](value, this)){
18915 if(typeof this.validator == "function"){
18916 var msg = this.validator(value);
18922 if(this.regex && !this.regex.test(value)){
18926 if(typeof(this.parseDate(value)) == 'undefined'){
18930 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18934 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18944 Roo.apply(Roo.bootstrap.DateField, {
18955 html: '<i class="fa fa-arrow-left"/>'
18965 html: '<i class="fa fa-arrow-right"/>'
19007 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19008 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19009 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19010 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19011 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19024 navFnc: 'FullYear',
19029 navFnc: 'FullYear',
19034 Roo.apply(Roo.bootstrap.DateField, {
19038 cls: 'datepicker dropdown-menu roo-dynamic',
19042 cls: 'datepicker-days',
19046 cls: 'table-condensed',
19048 Roo.bootstrap.DateField.head,
19052 Roo.bootstrap.DateField.footer
19059 cls: 'datepicker-months',
19063 cls: 'table-condensed',
19065 Roo.bootstrap.DateField.head,
19066 Roo.bootstrap.DateField.content,
19067 Roo.bootstrap.DateField.footer
19074 cls: 'datepicker-years',
19078 cls: 'table-condensed',
19080 Roo.bootstrap.DateField.head,
19081 Roo.bootstrap.DateField.content,
19082 Roo.bootstrap.DateField.footer
19101 * @class Roo.bootstrap.TimeField
19102 * @extends Roo.bootstrap.Input
19103 * Bootstrap DateField class
19107 * Create a new TimeField
19108 * @param {Object} config The config object
19111 Roo.bootstrap.TimeField = function(config){
19112 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19116 * Fires when this field show.
19117 * @param {Roo.bootstrap.DateField} thisthis
19118 * @param {Mixed} date The date value
19123 * Fires when this field hide.
19124 * @param {Roo.bootstrap.DateField} this
19125 * @param {Mixed} date The date value
19130 * Fires when select a date.
19131 * @param {Roo.bootstrap.DateField} this
19132 * @param {Mixed} date The date value
19138 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19141 * @cfg {String} format
19142 * The default time format string which can be overriden for localization support. The format must be
19143 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19147 onRender: function(ct, position)
19150 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19152 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19154 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19156 this.pop = this.picker().select('>.datepicker-time',true).first();
19157 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19159 this.picker().on('mousedown', this.onMousedown, this);
19160 this.picker().on('click', this.onClick, this);
19162 this.picker().addClass('datepicker-dropdown');
19167 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19168 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19169 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19170 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19171 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19172 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19176 fireKey: function(e){
19177 if (!this.picker().isVisible()){
19178 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19184 e.preventDefault();
19192 this.onTogglePeriod();
19195 this.onIncrementMinutes();
19198 this.onDecrementMinutes();
19207 onClick: function(e) {
19208 e.stopPropagation();
19209 e.preventDefault();
19212 picker : function()
19214 return this.el.select('.datepicker', true).first();
19217 fillTime: function()
19219 var time = this.pop.select('tbody', true).first();
19221 time.dom.innerHTML = '';
19236 cls: 'hours-up glyphicon glyphicon-chevron-up'
19256 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19277 cls: 'timepicker-hour',
19292 cls: 'timepicker-minute',
19307 cls: 'btn btn-primary period',
19329 cls: 'hours-down glyphicon glyphicon-chevron-down'
19349 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19367 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19374 var hours = this.time.getHours();
19375 var minutes = this.time.getMinutes();
19388 hours = hours - 12;
19392 hours = '0' + hours;
19396 minutes = '0' + minutes;
19399 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19400 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19401 this.pop.select('button', true).first().dom.innerHTML = period;
19407 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19409 var cls = ['bottom'];
19411 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19418 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19423 this.picker().addClass(cls.join('-'));
19427 Roo.each(cls, function(c){
19429 _this.picker().setTop(_this.inputEl().getHeight());
19433 _this.picker().setTop(0 - _this.picker().getHeight());
19438 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19442 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19449 onFocus : function()
19451 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19455 onBlur : function()
19457 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19463 this.picker().show();
19468 this.fireEvent('show', this, this.date);
19473 this.picker().hide();
19476 this.fireEvent('hide', this, this.date);
19479 setTime : function()
19482 this.setValue(this.time.format(this.format));
19484 this.fireEvent('select', this, this.date);
19489 onMousedown: function(e){
19490 e.stopPropagation();
19491 e.preventDefault();
19494 onIncrementHours: function()
19496 Roo.log('onIncrementHours');
19497 this.time = this.time.add(Date.HOUR, 1);
19502 onDecrementHours: function()
19504 Roo.log('onDecrementHours');
19505 this.time = this.time.add(Date.HOUR, -1);
19509 onIncrementMinutes: function()
19511 Roo.log('onIncrementMinutes');
19512 this.time = this.time.add(Date.MINUTE, 1);
19516 onDecrementMinutes: function()
19518 Roo.log('onDecrementMinutes');
19519 this.time = this.time.add(Date.MINUTE, -1);
19523 onTogglePeriod: function()
19525 Roo.log('onTogglePeriod');
19526 this.time = this.time.add(Date.HOUR, 12);
19533 Roo.apply(Roo.bootstrap.TimeField, {
19563 cls: 'btn btn-info ok',
19575 Roo.apply(Roo.bootstrap.TimeField, {
19579 cls: 'datepicker dropdown-menu',
19583 cls: 'datepicker-time',
19587 cls: 'table-condensed',
19589 Roo.bootstrap.TimeField.content,
19590 Roo.bootstrap.TimeField.footer
19609 * @class Roo.bootstrap.MonthField
19610 * @extends Roo.bootstrap.Input
19611 * Bootstrap MonthField class
19613 * @cfg {String} language default en
19616 * Create a new MonthField
19617 * @param {Object} config The config object
19620 Roo.bootstrap.MonthField = function(config){
19621 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19626 * Fires when this field show.
19627 * @param {Roo.bootstrap.MonthField} this
19628 * @param {Mixed} date The date value
19633 * Fires when this field hide.
19634 * @param {Roo.bootstrap.MonthField} this
19635 * @param {Mixed} date The date value
19640 * Fires when select a date.
19641 * @param {Roo.bootstrap.MonthField} this
19642 * @param {String} oldvalue The old value
19643 * @param {String} newvalue The new value
19649 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19651 onRender: function(ct, position)
19654 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19656 this.language = this.language || 'en';
19657 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19658 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19660 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19661 this.isInline = false;
19662 this.isInput = true;
19663 this.component = this.el.select('.add-on', true).first() || false;
19664 this.component = (this.component && this.component.length === 0) ? false : this.component;
19665 this.hasInput = this.component && this.inputEL().length;
19667 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19669 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19671 this.picker().on('mousedown', this.onMousedown, this);
19672 this.picker().on('click', this.onClick, this);
19674 this.picker().addClass('datepicker-dropdown');
19676 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19677 v.setStyle('width', '189px');
19684 if(this.isInline) {
19690 setValue: function(v, suppressEvent)
19692 var o = this.getValue();
19694 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19698 if(suppressEvent !== true){
19699 this.fireEvent('select', this, o, v);
19704 getValue: function()
19709 onClick: function(e)
19711 e.stopPropagation();
19712 e.preventDefault();
19714 var target = e.getTarget();
19716 if(target.nodeName.toLowerCase() === 'i'){
19717 target = Roo.get(target).dom.parentNode;
19720 var nodeName = target.nodeName;
19721 var className = target.className;
19722 var html = target.innerHTML;
19724 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19728 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19730 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19736 picker : function()
19738 return this.pickerEl;
19741 fillMonths: function()
19744 var months = this.picker().select('>.datepicker-months td', true).first();
19746 months.dom.innerHTML = '';
19752 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19755 months.createChild(month);
19764 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19765 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19768 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19769 e.removeClass('active');
19771 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19772 e.addClass('active');
19779 if(this.isInline) {
19783 this.picker().removeClass(['bottom', 'top']);
19785 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19787 * place to the top of element!
19791 this.picker().addClass('top');
19792 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19797 this.picker().addClass('bottom');
19799 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19802 onFocus : function()
19804 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19808 onBlur : function()
19810 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19812 var d = this.inputEl().getValue();
19821 this.picker().show();
19822 this.picker().select('>.datepicker-months', true).first().show();
19826 this.fireEvent('show', this, this.date);
19831 if(this.isInline) {
19834 this.picker().hide();
19835 this.fireEvent('hide', this, this.date);
19839 onMousedown: function(e)
19841 e.stopPropagation();
19842 e.preventDefault();
19847 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19851 fireKey: function(e)
19853 if (!this.picker().isVisible()){
19854 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19865 e.preventDefault();
19869 dir = e.keyCode == 37 ? -1 : 1;
19871 this.vIndex = this.vIndex + dir;
19873 if(this.vIndex < 0){
19877 if(this.vIndex > 11){
19881 if(isNaN(this.vIndex)){
19885 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19891 dir = e.keyCode == 38 ? -1 : 1;
19893 this.vIndex = this.vIndex + dir * 4;
19895 if(this.vIndex < 0){
19899 if(this.vIndex > 11){
19903 if(isNaN(this.vIndex)){
19907 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19912 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19913 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19917 e.preventDefault();
19920 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19921 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19937 this.picker().remove();
19942 Roo.apply(Roo.bootstrap.MonthField, {
19961 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19962 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19967 Roo.apply(Roo.bootstrap.MonthField, {
19971 cls: 'datepicker dropdown-menu roo-dynamic',
19975 cls: 'datepicker-months',
19979 cls: 'table-condensed',
19981 Roo.bootstrap.DateField.content
20001 * @class Roo.bootstrap.CheckBox
20002 * @extends Roo.bootstrap.Input
20003 * Bootstrap CheckBox class
20005 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20006 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20007 * @cfg {String} boxLabel The text that appears beside the checkbox
20008 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20009 * @cfg {Boolean} checked initnal the element
20010 * @cfg {Boolean} inline inline the element (default false)
20011 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20014 * Create a new CheckBox
20015 * @param {Object} config The config object
20018 Roo.bootstrap.CheckBox = function(config){
20019 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20024 * Fires when the element is checked or unchecked.
20025 * @param {Roo.bootstrap.CheckBox} this This input
20026 * @param {Boolean} checked The new checked value
20033 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20035 inputType: 'checkbox',
20043 getAutoCreate : function()
20045 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20051 cfg.cls = 'form-group ' + this.inputType; //input-group
20054 cfg.cls += ' ' + this.inputType + '-inline';
20060 type : this.inputType,
20061 value : this.inputValue,
20062 cls : 'roo-' + this.inputType, //'form-box',
20063 placeholder : this.placeholder || ''
20067 if(this.inputType != 'radio'){
20071 cls : 'roo-hidden-value',
20072 value : this.checked ? this.valueOff : this.inputValue
20077 if (this.weight) { // Validity check?
20078 cfg.cls += " " + this.inputType + "-" + this.weight;
20081 if (this.disabled) {
20082 input.disabled=true;
20086 input.checked = this.checked;
20093 input.name = this.name;
20095 if(this.inputType != 'radio'){
20096 hidden.name = this.name;
20097 input.name = '_hidden_' + this.name;
20102 input.cls += ' input-' + this.size;
20107 ['xs','sm','md','lg'].map(function(size){
20108 if (settings[size]) {
20109 cfg.cls += ' col-' + size + '-' + settings[size];
20113 var inputblock = input;
20115 if (this.before || this.after) {
20118 cls : 'input-group',
20123 inputblock.cn.push({
20125 cls : 'input-group-addon',
20130 inputblock.cn.push(input);
20132 if(this.inputType != 'radio'){
20133 inputblock.cn.push(hidden);
20137 inputblock.cn.push({
20139 cls : 'input-group-addon',
20146 if (align ==='left' && this.fieldLabel.length) {
20147 // Roo.log("left and has label");
20152 cls : 'control-label',
20153 html : this.fieldLabel
20164 if(this.labelWidth > 12){
20165 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20168 if(this.labelWidth < 13 && this.labelmd == 0){
20169 this.labelmd = this.labelWidth;
20172 if(this.labellg > 0){
20173 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20174 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20177 if(this.labelmd > 0){
20178 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20179 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20182 if(this.labelsm > 0){
20183 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20184 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20187 if(this.labelxs > 0){
20188 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20189 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20192 } else if ( this.fieldLabel.length) {
20193 // Roo.log(" label");
20197 tag: this.boxLabel ? 'span' : 'label',
20199 cls: 'control-label box-input-label',
20200 //cls : 'input-group-addon',
20201 html : this.fieldLabel
20211 // Roo.log(" no label && no align");
20212 cfg.cn = [ inputblock ] ;
20218 var boxLabelCfg = {
20220 //'for': id, // box label is handled by onclick - so no for...
20222 html: this.boxLabel
20226 boxLabelCfg.tooltip = this.tooltip;
20229 cfg.cn.push(boxLabelCfg);
20232 if(this.inputType != 'radio'){
20233 cfg.cn.push(hidden);
20241 * return the real input element.
20243 inputEl: function ()
20245 return this.el.select('input.roo-' + this.inputType,true).first();
20247 hiddenEl: function ()
20249 return this.el.select('input.roo-hidden-value',true).first();
20252 labelEl: function()
20254 return this.el.select('label.control-label',true).first();
20256 /* depricated... */
20260 return this.labelEl();
20263 boxLabelEl: function()
20265 return this.el.select('label.box-label',true).first();
20268 initEvents : function()
20270 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20272 this.inputEl().on('click', this.onClick, this);
20274 if (this.boxLabel) {
20275 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20278 this.startValue = this.getValue();
20281 Roo.bootstrap.CheckBox.register(this);
20285 onClick : function()
20287 this.setChecked(!this.checked);
20290 setChecked : function(state,suppressEvent)
20292 this.startValue = this.getValue();
20294 if(this.inputType == 'radio'){
20296 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20297 e.dom.checked = false;
20300 this.inputEl().dom.checked = true;
20302 this.inputEl().dom.value = this.inputValue;
20304 if(suppressEvent !== true){
20305 this.fireEvent('check', this, true);
20313 this.checked = state;
20315 this.inputEl().dom.checked = state;
20318 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20320 if(suppressEvent !== true){
20321 this.fireEvent('check', this, state);
20327 getValue : function()
20329 if(this.inputType == 'radio'){
20330 return this.getGroupValue();
20333 return this.hiddenEl().dom.value;
20337 getGroupValue : function()
20339 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20343 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20346 setValue : function(v,suppressEvent)
20348 if(this.inputType == 'radio'){
20349 this.setGroupValue(v, suppressEvent);
20353 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20358 setGroupValue : function(v, suppressEvent)
20360 this.startValue = this.getValue();
20362 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20363 e.dom.checked = false;
20365 if(e.dom.value == v){
20366 e.dom.checked = true;
20370 if(suppressEvent !== true){
20371 this.fireEvent('check', this, true);
20379 validate : function()
20383 (this.inputType == 'radio' && this.validateRadio()) ||
20384 (this.inputType == 'checkbox' && this.validateCheckbox())
20390 this.markInvalid();
20394 validateRadio : function()
20396 if(this.allowBlank){
20402 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20403 if(!e.dom.checked){
20415 validateCheckbox : function()
20418 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20419 //return (this.getValue() == this.inputValue) ? true : false;
20422 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20430 for(var i in group){
20435 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20442 * Mark this field as valid
20444 markValid : function()
20448 this.fireEvent('valid', this);
20450 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20453 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20460 if(this.inputType == 'radio'){
20461 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20462 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20463 e.findParent('.form-group', false, true).addClass(_this.validClass);
20470 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20471 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20475 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20481 for(var i in group){
20482 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20483 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20488 * Mark this field as invalid
20489 * @param {String} msg The validation message
20491 markInvalid : function(msg)
20493 if(this.allowBlank){
20499 this.fireEvent('invalid', this, msg);
20501 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20504 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20508 label.markInvalid();
20511 if(this.inputType == 'radio'){
20512 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20513 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20514 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20521 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20522 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20526 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20532 for(var i in group){
20533 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20534 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20539 clearInvalid : function()
20541 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20543 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20545 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20548 label.iconEl.removeClass(label.validClass);
20549 label.iconEl.removeClass(label.invalidClass);
20553 disable : function()
20555 if(this.inputType != 'radio'){
20556 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20563 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20564 _this.getActionEl().addClass(this.disabledClass);
20565 e.dom.disabled = true;
20569 this.disabled = true;
20570 this.fireEvent("disable", this);
20574 enable : function()
20576 if(this.inputType != 'radio'){
20577 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20584 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20585 _this.getActionEl().removeClass(this.disabledClass);
20586 e.dom.disabled = false;
20590 this.disabled = false;
20591 this.fireEvent("enable", this);
20597 Roo.apply(Roo.bootstrap.CheckBox, {
20602 * register a CheckBox Group
20603 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20605 register : function(checkbox)
20607 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20608 this.groups[checkbox.groupId] = {};
20611 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20615 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20619 * fetch a CheckBox Group based on the group ID
20620 * @param {string} the group ID
20621 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20623 get: function(groupId) {
20624 if (typeof(this.groups[groupId]) == 'undefined') {
20628 return this.groups[groupId] ;
20641 * @class Roo.bootstrap.Radio
20642 * @extends Roo.bootstrap.Component
20643 * Bootstrap Radio class
20644 * @cfg {String} boxLabel - the label associated
20645 * @cfg {String} value - the value of radio
20648 * Create a new Radio
20649 * @param {Object} config The config object
20651 Roo.bootstrap.Radio = function(config){
20652 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20656 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20662 getAutoCreate : function()
20666 cls : 'form-group radio',
20671 html : this.boxLabel
20679 initEvents : function()
20681 this.parent().register(this);
20683 this.el.on('click', this.onClick, this);
20687 onClick : function()
20689 this.setChecked(true);
20692 setChecked : function(state, suppressEvent)
20694 this.parent().setValue(this.value, suppressEvent);
20709 * @class Roo.bootstrap.SecurePass
20710 * @extends Roo.bootstrap.Input
20711 * Bootstrap SecurePass class
20715 * Create a new SecurePass
20716 * @param {Object} config The config object
20719 Roo.bootstrap.SecurePass = function (config) {
20720 // these go here, so the translation tool can replace them..
20722 PwdEmpty: "Please type a password, and then retype it to confirm.",
20723 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20724 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20725 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20726 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20727 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20728 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20729 TooWeak: "Your password is Too Weak."
20731 this.meterLabel = "Password strength:";
20732 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20733 this.meterClass = [
20734 "roo-password-meter-tooweak",
20735 "roo-password-meter-weak",
20736 "roo-password-meter-medium",
20737 "roo-password-meter-strong",
20738 "roo-password-meter-grey"
20743 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20746 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20748 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20750 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20751 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20752 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20753 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20754 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20755 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20756 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20766 * @cfg {String/Object} Label for the strength meter (defaults to
20767 * 'Password strength:')
20772 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20773 * ['Weak', 'Medium', 'Strong'])
20776 pwdStrengths: false,
20789 initEvents: function ()
20791 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20793 if (this.el.is('input[type=password]') && Roo.isSafari) {
20794 this.el.on('keydown', this.SafariOnKeyDown, this);
20797 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20800 onRender: function (ct, position)
20802 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20803 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20804 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20806 this.trigger.createChild({
20811 cls: 'roo-password-meter-grey col-xs-12',
20814 //width: this.meterWidth + 'px'
20818 cls: 'roo-password-meter-text'
20824 if (this.hideTrigger) {
20825 this.trigger.setDisplayed(false);
20827 this.setSize(this.width || '', this.height || '');
20830 onDestroy: function ()
20832 if (this.trigger) {
20833 this.trigger.removeAllListeners();
20834 this.trigger.remove();
20837 this.wrap.remove();
20839 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20842 checkStrength: function ()
20844 var pwd = this.inputEl().getValue();
20845 if (pwd == this._lastPwd) {
20850 if (this.ClientSideStrongPassword(pwd)) {
20852 } else if (this.ClientSideMediumPassword(pwd)) {
20854 } else if (this.ClientSideWeakPassword(pwd)) {
20860 Roo.log('strength1: ' + strength);
20862 //var pm = this.trigger.child('div/div/div').dom;
20863 var pm = this.trigger.child('div/div');
20864 pm.removeClass(this.meterClass);
20865 pm.addClass(this.meterClass[strength]);
20868 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20870 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20872 this._lastPwd = pwd;
20876 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20878 this._lastPwd = '';
20880 var pm = this.trigger.child('div/div');
20881 pm.removeClass(this.meterClass);
20882 pm.addClass('roo-password-meter-grey');
20885 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20888 this.inputEl().dom.type='password';
20891 validateValue: function (value)
20894 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20897 if (value.length == 0) {
20898 if (this.allowBlank) {
20899 this.clearInvalid();
20903 this.markInvalid(this.errors.PwdEmpty);
20904 this.errorMsg = this.errors.PwdEmpty;
20912 if ('[\x21-\x7e]*'.match(value)) {
20913 this.markInvalid(this.errors.PwdBadChar);
20914 this.errorMsg = this.errors.PwdBadChar;
20917 if (value.length < 6) {
20918 this.markInvalid(this.errors.PwdShort);
20919 this.errorMsg = this.errors.PwdShort;
20922 if (value.length > 16) {
20923 this.markInvalid(this.errors.PwdLong);
20924 this.errorMsg = this.errors.PwdLong;
20928 if (this.ClientSideStrongPassword(value)) {
20930 } else if (this.ClientSideMediumPassword(value)) {
20932 } else if (this.ClientSideWeakPassword(value)) {
20939 if (strength < 2) {
20940 //this.markInvalid(this.errors.TooWeak);
20941 this.errorMsg = this.errors.TooWeak;
20946 console.log('strength2: ' + strength);
20948 //var pm = this.trigger.child('div/div/div').dom;
20950 var pm = this.trigger.child('div/div');
20951 pm.removeClass(this.meterClass);
20952 pm.addClass(this.meterClass[strength]);
20954 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20956 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20958 this.errorMsg = '';
20962 CharacterSetChecks: function (type)
20965 this.fResult = false;
20968 isctype: function (character, type)
20971 case this.kCapitalLetter:
20972 if (character >= 'A' && character <= 'Z') {
20977 case this.kSmallLetter:
20978 if (character >= 'a' && character <= 'z') {
20984 if (character >= '0' && character <= '9') {
20989 case this.kPunctuation:
20990 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21001 IsLongEnough: function (pwd, size)
21003 return !(pwd == null || isNaN(size) || pwd.length < size);
21006 SpansEnoughCharacterSets: function (word, nb)
21008 if (!this.IsLongEnough(word, nb))
21013 var characterSetChecks = new Array(
21014 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21015 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21018 for (var index = 0; index < word.length; ++index) {
21019 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21020 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21021 characterSetChecks[nCharSet].fResult = true;
21028 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21029 if (characterSetChecks[nCharSet].fResult) {
21034 if (nCharSets < nb) {
21040 ClientSideStrongPassword: function (pwd)
21042 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21045 ClientSideMediumPassword: function (pwd)
21047 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21050 ClientSideWeakPassword: function (pwd)
21052 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21055 })//<script type="text/javascript">
21058 * Based Ext JS Library 1.1.1
21059 * Copyright(c) 2006-2007, Ext JS, LLC.
21065 * @class Roo.HtmlEditorCore
21066 * @extends Roo.Component
21067 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21069 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21072 Roo.HtmlEditorCore = function(config){
21075 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21080 * @event initialize
21081 * Fires when the editor is fully initialized (including the iframe)
21082 * @param {Roo.HtmlEditorCore} this
21087 * Fires when the editor is first receives the focus. Any insertion must wait
21088 * until after this event.
21089 * @param {Roo.HtmlEditorCore} this
21093 * @event beforesync
21094 * Fires before the textarea is updated with content from the editor iframe. Return false
21095 * to cancel the sync.
21096 * @param {Roo.HtmlEditorCore} this
21097 * @param {String} html
21101 * @event beforepush
21102 * Fires before the iframe editor is updated with content from the textarea. Return false
21103 * to cancel the push.
21104 * @param {Roo.HtmlEditorCore} this
21105 * @param {String} html
21110 * Fires when the textarea is updated with content from the editor iframe.
21111 * @param {Roo.HtmlEditorCore} this
21112 * @param {String} html
21117 * Fires when the iframe editor is updated with content from the textarea.
21118 * @param {Roo.HtmlEditorCore} this
21119 * @param {String} html
21124 * @event editorevent
21125 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21126 * @param {Roo.HtmlEditorCore} this
21132 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21134 // defaults : white / black...
21135 this.applyBlacklists();
21142 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21146 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21152 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21157 * @cfg {Number} height (in pixels)
21161 * @cfg {Number} width (in pixels)
21166 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21169 stylesheets: false,
21174 // private properties
21175 validationEvent : false,
21177 initialized : false,
21179 sourceEditMode : false,
21180 onFocus : Roo.emptyFn,
21182 hideMode:'offsets',
21186 // blacklist + whitelisted elements..
21193 * Protected method that will not generally be called directly. It
21194 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21195 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21197 getDocMarkup : function(){
21201 // inherit styels from page...??
21202 if (this.stylesheets === false) {
21204 Roo.get(document.head).select('style').each(function(node) {
21205 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21208 Roo.get(document.head).select('link').each(function(node) {
21209 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21212 } else if (!this.stylesheets.length) {
21214 st = '<style type="text/css">' +
21215 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21221 st += '<style type="text/css">' +
21222 'IMG { cursor: pointer } ' +
21226 return '<html><head>' + st +
21227 //<style type="text/css">' +
21228 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21230 ' </head><body class="roo-htmleditor-body"></body></html>';
21234 onRender : function(ct, position)
21237 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21238 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21241 this.el.dom.style.border = '0 none';
21242 this.el.dom.setAttribute('tabIndex', -1);
21243 this.el.addClass('x-hidden hide');
21247 if(Roo.isIE){ // fix IE 1px bogus margin
21248 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21252 this.frameId = Roo.id();
21256 var iframe = this.owner.wrap.createChild({
21258 cls: 'form-control', // bootstrap..
21260 name: this.frameId,
21261 frameBorder : 'no',
21262 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21267 this.iframe = iframe.dom;
21269 this.assignDocWin();
21271 this.doc.designMode = 'on';
21274 this.doc.write(this.getDocMarkup());
21278 var task = { // must defer to wait for browser to be ready
21280 //console.log("run task?" + this.doc.readyState);
21281 this.assignDocWin();
21282 if(this.doc.body || this.doc.readyState == 'complete'){
21284 this.doc.designMode="on";
21288 Roo.TaskMgr.stop(task);
21289 this.initEditor.defer(10, this);
21296 Roo.TaskMgr.start(task);
21301 onResize : function(w, h)
21303 Roo.log('resize: ' +w + ',' + h );
21304 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21308 if(typeof w == 'number'){
21310 this.iframe.style.width = w + 'px';
21312 if(typeof h == 'number'){
21314 this.iframe.style.height = h + 'px';
21316 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21323 * Toggles the editor between standard and source edit mode.
21324 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21326 toggleSourceEdit : function(sourceEditMode){
21328 this.sourceEditMode = sourceEditMode === true;
21330 if(this.sourceEditMode){
21332 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21335 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21336 //this.iframe.className = '';
21339 //this.setSize(this.owner.wrap.getSize());
21340 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21347 * Protected method that will not generally be called directly. If you need/want
21348 * custom HTML cleanup, this is the method you should override.
21349 * @param {String} html The HTML to be cleaned
21350 * return {String} The cleaned HTML
21352 cleanHtml : function(html){
21353 html = String(html);
21354 if(html.length > 5){
21355 if(Roo.isSafari){ // strip safari nonsense
21356 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21359 if(html == ' '){
21366 * HTML Editor -> Textarea
21367 * Protected method that will not generally be called directly. Syncs the contents
21368 * of the editor iframe with the textarea.
21370 syncValue : function(){
21371 if(this.initialized){
21372 var bd = (this.doc.body || this.doc.documentElement);
21373 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21374 var html = bd.innerHTML;
21376 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21377 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21379 html = '<div style="'+m[0]+'">' + html + '</div>';
21382 html = this.cleanHtml(html);
21383 // fix up the special chars.. normaly like back quotes in word...
21384 // however we do not want to do this with chinese..
21385 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21386 var cc = b.charCodeAt();
21388 (cc >= 0x4E00 && cc < 0xA000 ) ||
21389 (cc >= 0x3400 && cc < 0x4E00 ) ||
21390 (cc >= 0xf900 && cc < 0xfb00 )
21396 if(this.owner.fireEvent('beforesync', this, html) !== false){
21397 this.el.dom.value = html;
21398 this.owner.fireEvent('sync', this, html);
21404 * Protected method that will not generally be called directly. Pushes the value of the textarea
21405 * into the iframe editor.
21407 pushValue : function(){
21408 if(this.initialized){
21409 var v = this.el.dom.value.trim();
21411 // if(v.length < 1){
21415 if(this.owner.fireEvent('beforepush', this, v) !== false){
21416 var d = (this.doc.body || this.doc.documentElement);
21418 this.cleanUpPaste();
21419 this.el.dom.value = d.innerHTML;
21420 this.owner.fireEvent('push', this, v);
21426 deferFocus : function(){
21427 this.focus.defer(10, this);
21431 focus : function(){
21432 if(this.win && !this.sourceEditMode){
21439 assignDocWin: function()
21441 var iframe = this.iframe;
21444 this.doc = iframe.contentWindow.document;
21445 this.win = iframe.contentWindow;
21447 // if (!Roo.get(this.frameId)) {
21450 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21451 // this.win = Roo.get(this.frameId).dom.contentWindow;
21453 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21457 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21458 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21463 initEditor : function(){
21464 //console.log("INIT EDITOR");
21465 this.assignDocWin();
21469 this.doc.designMode="on";
21471 this.doc.write(this.getDocMarkup());
21474 var dbody = (this.doc.body || this.doc.documentElement);
21475 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21476 // this copies styles from the containing element into thsi one..
21477 // not sure why we need all of this..
21478 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21480 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21481 //ss['background-attachment'] = 'fixed'; // w3c
21482 dbody.bgProperties = 'fixed'; // ie
21483 //Roo.DomHelper.applyStyles(dbody, ss);
21484 Roo.EventManager.on(this.doc, {
21485 //'mousedown': this.onEditorEvent,
21486 'mouseup': this.onEditorEvent,
21487 'dblclick': this.onEditorEvent,
21488 'click': this.onEditorEvent,
21489 'keyup': this.onEditorEvent,
21494 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21496 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21497 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21499 this.initialized = true;
21501 this.owner.fireEvent('initialize', this);
21506 onDestroy : function(){
21512 //for (var i =0; i < this.toolbars.length;i++) {
21513 // // fixme - ask toolbars for heights?
21514 // this.toolbars[i].onDestroy();
21517 //this.wrap.dom.innerHTML = '';
21518 //this.wrap.remove();
21523 onFirstFocus : function(){
21525 this.assignDocWin();
21528 this.activated = true;
21531 if(Roo.isGecko){ // prevent silly gecko errors
21533 var s = this.win.getSelection();
21534 if(!s.focusNode || s.focusNode.nodeType != 3){
21535 var r = s.getRangeAt(0);
21536 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21541 this.execCmd('useCSS', true);
21542 this.execCmd('styleWithCSS', false);
21545 this.owner.fireEvent('activate', this);
21549 adjustFont: function(btn){
21550 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21551 //if(Roo.isSafari){ // safari
21554 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21555 if(Roo.isSafari){ // safari
21556 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21557 v = (v < 10) ? 10 : v;
21558 v = (v > 48) ? 48 : v;
21559 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21564 v = Math.max(1, v+adjust);
21566 this.execCmd('FontSize', v );
21569 onEditorEvent : function(e)
21571 this.owner.fireEvent('editorevent', this, e);
21572 // this.updateToolbar();
21573 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21576 insertTag : function(tg)
21578 // could be a bit smarter... -> wrap the current selected tRoo..
21579 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21581 range = this.createRange(this.getSelection());
21582 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21583 wrappingNode.appendChild(range.extractContents());
21584 range.insertNode(wrappingNode);
21591 this.execCmd("formatblock", tg);
21595 insertText : function(txt)
21599 var range = this.createRange();
21600 range.deleteContents();
21601 //alert(Sender.getAttribute('label'));
21603 range.insertNode(this.doc.createTextNode(txt));
21609 * Executes a Midas editor command on the editor document and performs necessary focus and
21610 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21611 * @param {String} cmd The Midas command
21612 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21614 relayCmd : function(cmd, value){
21616 this.execCmd(cmd, value);
21617 this.owner.fireEvent('editorevent', this);
21618 //this.updateToolbar();
21619 this.owner.deferFocus();
21623 * Executes a Midas editor command directly on the editor document.
21624 * For visual commands, you should use {@link #relayCmd} instead.
21625 * <b>This should only be called after the editor is initialized.</b>
21626 * @param {String} cmd The Midas command
21627 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21629 execCmd : function(cmd, value){
21630 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21637 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21639 * @param {String} text | dom node..
21641 insertAtCursor : function(text)
21644 if(!this.activated){
21650 var r = this.doc.selection.createRange();
21661 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21665 // from jquery ui (MIT licenced)
21667 var win = this.win;
21669 if (win.getSelection && win.getSelection().getRangeAt) {
21670 range = win.getSelection().getRangeAt(0);
21671 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21672 range.insertNode(node);
21673 } else if (win.document.selection && win.document.selection.createRange) {
21674 // no firefox support
21675 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21676 win.document.selection.createRange().pasteHTML(txt);
21678 // no firefox support
21679 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21680 this.execCmd('InsertHTML', txt);
21689 mozKeyPress : function(e){
21691 var c = e.getCharCode(), cmd;
21694 c = String.fromCharCode(c).toLowerCase();
21708 this.cleanUpPaste.defer(100, this);
21716 e.preventDefault();
21724 fixKeys : function(){ // load time branching for fastest keydown performance
21726 return function(e){
21727 var k = e.getKey(), r;
21730 r = this.doc.selection.createRange();
21733 r.pasteHTML('    ');
21740 r = this.doc.selection.createRange();
21742 var target = r.parentElement();
21743 if(!target || target.tagName.toLowerCase() != 'li'){
21745 r.pasteHTML('<br />');
21751 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21752 this.cleanUpPaste.defer(100, this);
21758 }else if(Roo.isOpera){
21759 return function(e){
21760 var k = e.getKey();
21764 this.execCmd('InsertHTML','    ');
21767 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21768 this.cleanUpPaste.defer(100, this);
21773 }else if(Roo.isSafari){
21774 return function(e){
21775 var k = e.getKey();
21779 this.execCmd('InsertText','\t');
21783 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21784 this.cleanUpPaste.defer(100, this);
21792 getAllAncestors: function()
21794 var p = this.getSelectedNode();
21797 a.push(p); // push blank onto stack..
21798 p = this.getParentElement();
21802 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21806 a.push(this.doc.body);
21810 lastSelNode : false,
21813 getSelection : function()
21815 this.assignDocWin();
21816 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21819 getSelectedNode: function()
21821 // this may only work on Gecko!!!
21823 // should we cache this!!!!
21828 var range = this.createRange(this.getSelection()).cloneRange();
21831 var parent = range.parentElement();
21833 var testRange = range.duplicate();
21834 testRange.moveToElementText(parent);
21835 if (testRange.inRange(range)) {
21838 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21841 parent = parent.parentElement;
21846 // is ancestor a text element.
21847 var ac = range.commonAncestorContainer;
21848 if (ac.nodeType == 3) {
21849 ac = ac.parentNode;
21852 var ar = ac.childNodes;
21855 var other_nodes = [];
21856 var has_other_nodes = false;
21857 for (var i=0;i<ar.length;i++) {
21858 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21861 // fullly contained node.
21863 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21868 // probably selected..
21869 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21870 other_nodes.push(ar[i]);
21874 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21879 has_other_nodes = true;
21881 if (!nodes.length && other_nodes.length) {
21882 nodes= other_nodes;
21884 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21890 createRange: function(sel)
21892 // this has strange effects when using with
21893 // top toolbar - not sure if it's a great idea.
21894 //this.editor.contentWindow.focus();
21895 if (typeof sel != "undefined") {
21897 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21899 return this.doc.createRange();
21902 return this.doc.createRange();
21905 getParentElement: function()
21908 this.assignDocWin();
21909 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21911 var range = this.createRange(sel);
21914 var p = range.commonAncestorContainer;
21915 while (p.nodeType == 3) { // text node
21926 * Range intersection.. the hard stuff...
21930 * [ -- selected range --- ]
21934 * if end is before start or hits it. fail.
21935 * if start is after end or hits it fail.
21937 * if either hits (but other is outside. - then it's not
21943 // @see http://www.thismuchiknow.co.uk/?p=64.
21944 rangeIntersectsNode : function(range, node)
21946 var nodeRange = node.ownerDocument.createRange();
21948 nodeRange.selectNode(node);
21950 nodeRange.selectNodeContents(node);
21953 var rangeStartRange = range.cloneRange();
21954 rangeStartRange.collapse(true);
21956 var rangeEndRange = range.cloneRange();
21957 rangeEndRange.collapse(false);
21959 var nodeStartRange = nodeRange.cloneRange();
21960 nodeStartRange.collapse(true);
21962 var nodeEndRange = nodeRange.cloneRange();
21963 nodeEndRange.collapse(false);
21965 return rangeStartRange.compareBoundaryPoints(
21966 Range.START_TO_START, nodeEndRange) == -1 &&
21967 rangeEndRange.compareBoundaryPoints(
21968 Range.START_TO_START, nodeStartRange) == 1;
21972 rangeCompareNode : function(range, node)
21974 var nodeRange = node.ownerDocument.createRange();
21976 nodeRange.selectNode(node);
21978 nodeRange.selectNodeContents(node);
21982 range.collapse(true);
21984 nodeRange.collapse(true);
21986 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21987 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21989 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21991 var nodeIsBefore = ss == 1;
21992 var nodeIsAfter = ee == -1;
21994 if (nodeIsBefore && nodeIsAfter) {
21997 if (!nodeIsBefore && nodeIsAfter) {
21998 return 1; //right trailed.
22001 if (nodeIsBefore && !nodeIsAfter) {
22002 return 2; // left trailed.
22008 // private? - in a new class?
22009 cleanUpPaste : function()
22011 // cleans up the whole document..
22012 Roo.log('cleanuppaste');
22014 this.cleanUpChildren(this.doc.body);
22015 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22016 if (clean != this.doc.body.innerHTML) {
22017 this.doc.body.innerHTML = clean;
22022 cleanWordChars : function(input) {// change the chars to hex code
22023 var he = Roo.HtmlEditorCore;
22025 var output = input;
22026 Roo.each(he.swapCodes, function(sw) {
22027 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22029 output = output.replace(swapper, sw[1]);
22036 cleanUpChildren : function (n)
22038 if (!n.childNodes.length) {
22041 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22042 this.cleanUpChild(n.childNodes[i]);
22049 cleanUpChild : function (node)
22052 //console.log(node);
22053 if (node.nodeName == "#text") {
22054 // clean up silly Windows -- stuff?
22057 if (node.nodeName == "#comment") {
22058 node.parentNode.removeChild(node);
22059 // clean up silly Windows -- stuff?
22062 var lcname = node.tagName.toLowerCase();
22063 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22064 // whitelist of tags..
22066 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22068 node.parentNode.removeChild(node);
22073 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22075 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22076 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22078 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22079 // remove_keep_children = true;
22082 if (remove_keep_children) {
22083 this.cleanUpChildren(node);
22084 // inserts everything just before this node...
22085 while (node.childNodes.length) {
22086 var cn = node.childNodes[0];
22087 node.removeChild(cn);
22088 node.parentNode.insertBefore(cn, node);
22090 node.parentNode.removeChild(node);
22094 if (!node.attributes || !node.attributes.length) {
22095 this.cleanUpChildren(node);
22099 function cleanAttr(n,v)
22102 if (v.match(/^\./) || v.match(/^\//)) {
22105 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22108 if (v.match(/^#/)) {
22111 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22112 node.removeAttribute(n);
22116 var cwhite = this.cwhite;
22117 var cblack = this.cblack;
22119 function cleanStyle(n,v)
22121 if (v.match(/expression/)) { //XSS?? should we even bother..
22122 node.removeAttribute(n);
22126 var parts = v.split(/;/);
22129 Roo.each(parts, function(p) {
22130 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22134 var l = p.split(':').shift().replace(/\s+/g,'');
22135 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22137 if ( cwhite.length && cblack.indexOf(l) > -1) {
22138 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22139 //node.removeAttribute(n);
22143 // only allow 'c whitelisted system attributes'
22144 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22145 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22146 //node.removeAttribute(n);
22156 if (clean.length) {
22157 node.setAttribute(n, clean.join(';'));
22159 node.removeAttribute(n);
22165 for (var i = node.attributes.length-1; i > -1 ; i--) {
22166 var a = node.attributes[i];
22169 if (a.name.toLowerCase().substr(0,2)=='on') {
22170 node.removeAttribute(a.name);
22173 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22174 node.removeAttribute(a.name);
22177 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22178 cleanAttr(a.name,a.value); // fixme..
22181 if (a.name == 'style') {
22182 cleanStyle(a.name,a.value);
22185 /// clean up MS crap..
22186 // tecnically this should be a list of valid class'es..
22189 if (a.name == 'class') {
22190 if (a.value.match(/^Mso/)) {
22191 node.className = '';
22194 if (a.value.match(/^body$/)) {
22195 node.className = '';
22206 this.cleanUpChildren(node);
22212 * Clean up MS wordisms...
22214 cleanWord : function(node)
22219 this.cleanWord(this.doc.body);
22222 if (node.nodeName == "#text") {
22223 // clean up silly Windows -- stuff?
22226 if (node.nodeName == "#comment") {
22227 node.parentNode.removeChild(node);
22228 // clean up silly Windows -- stuff?
22232 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22233 node.parentNode.removeChild(node);
22237 // remove - but keep children..
22238 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22239 while (node.childNodes.length) {
22240 var cn = node.childNodes[0];
22241 node.removeChild(cn);
22242 node.parentNode.insertBefore(cn, node);
22244 node.parentNode.removeChild(node);
22245 this.iterateChildren(node, this.cleanWord);
22249 if (node.className.length) {
22251 var cn = node.className.split(/\W+/);
22253 Roo.each(cn, function(cls) {
22254 if (cls.match(/Mso[a-zA-Z]+/)) {
22259 node.className = cna.length ? cna.join(' ') : '';
22261 node.removeAttribute("class");
22265 if (node.hasAttribute("lang")) {
22266 node.removeAttribute("lang");
22269 if (node.hasAttribute("style")) {
22271 var styles = node.getAttribute("style").split(";");
22273 Roo.each(styles, function(s) {
22274 if (!s.match(/:/)) {
22277 var kv = s.split(":");
22278 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22281 // what ever is left... we allow.
22284 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22285 if (!nstyle.length) {
22286 node.removeAttribute('style');
22289 this.iterateChildren(node, this.cleanWord);
22295 * iterateChildren of a Node, calling fn each time, using this as the scole..
22296 * @param {DomNode} node node to iterate children of.
22297 * @param {Function} fn method of this class to call on each item.
22299 iterateChildren : function(node, fn)
22301 if (!node.childNodes.length) {
22304 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22305 fn.call(this, node.childNodes[i])
22311 * cleanTableWidths.
22313 * Quite often pasting from word etc.. results in tables with column and widths.
22314 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22317 cleanTableWidths : function(node)
22322 this.cleanTableWidths(this.doc.body);
22327 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22330 Roo.log(node.tagName);
22331 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22332 this.iterateChildren(node, this.cleanTableWidths);
22335 if (node.hasAttribute('width')) {
22336 node.removeAttribute('width');
22340 if (node.hasAttribute("style")) {
22343 var styles = node.getAttribute("style").split(";");
22345 Roo.each(styles, function(s) {
22346 if (!s.match(/:/)) {
22349 var kv = s.split(":");
22350 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22353 // what ever is left... we allow.
22356 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22357 if (!nstyle.length) {
22358 node.removeAttribute('style');
22362 this.iterateChildren(node, this.cleanTableWidths);
22370 domToHTML : function(currentElement, depth, nopadtext) {
22372 depth = depth || 0;
22373 nopadtext = nopadtext || false;
22375 if (!currentElement) {
22376 return this.domToHTML(this.doc.body);
22379 //Roo.log(currentElement);
22381 var allText = false;
22382 var nodeName = currentElement.nodeName;
22383 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22385 if (nodeName == '#text') {
22387 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22392 if (nodeName != 'BODY') {
22395 // Prints the node tagName, such as <A>, <IMG>, etc
22398 for(i = 0; i < currentElement.attributes.length;i++) {
22400 var aname = currentElement.attributes.item(i).name;
22401 if (!currentElement.attributes.item(i).value.length) {
22404 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22407 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22416 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22419 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22424 // Traverse the tree
22426 var currentElementChild = currentElement.childNodes.item(i);
22427 var allText = true;
22428 var innerHTML = '';
22430 while (currentElementChild) {
22431 // Formatting code (indent the tree so it looks nice on the screen)
22432 var nopad = nopadtext;
22433 if (lastnode == 'SPAN') {
22437 if (currentElementChild.nodeName == '#text') {
22438 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22439 toadd = nopadtext ? toadd : toadd.trim();
22440 if (!nopad && toadd.length > 80) {
22441 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22443 innerHTML += toadd;
22446 currentElementChild = currentElement.childNodes.item(i);
22452 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22454 // Recursively traverse the tree structure of the child node
22455 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22456 lastnode = currentElementChild.nodeName;
22458 currentElementChild=currentElement.childNodes.item(i);
22464 // The remaining code is mostly for formatting the tree
22465 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22470 ret+= "</"+tagName+">";
22476 applyBlacklists : function()
22478 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22479 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22483 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22484 if (b.indexOf(tag) > -1) {
22487 this.white.push(tag);
22491 Roo.each(w, function(tag) {
22492 if (b.indexOf(tag) > -1) {
22495 if (this.white.indexOf(tag) > -1) {
22498 this.white.push(tag);
22503 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22504 if (w.indexOf(tag) > -1) {
22507 this.black.push(tag);
22511 Roo.each(b, function(tag) {
22512 if (w.indexOf(tag) > -1) {
22515 if (this.black.indexOf(tag) > -1) {
22518 this.black.push(tag);
22523 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22524 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22528 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22529 if (b.indexOf(tag) > -1) {
22532 this.cwhite.push(tag);
22536 Roo.each(w, function(tag) {
22537 if (b.indexOf(tag) > -1) {
22540 if (this.cwhite.indexOf(tag) > -1) {
22543 this.cwhite.push(tag);
22548 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22549 if (w.indexOf(tag) > -1) {
22552 this.cblack.push(tag);
22556 Roo.each(b, function(tag) {
22557 if (w.indexOf(tag) > -1) {
22560 if (this.cblack.indexOf(tag) > -1) {
22563 this.cblack.push(tag);
22568 setStylesheets : function(stylesheets)
22570 if(typeof(stylesheets) == 'string'){
22571 Roo.get(this.iframe.contentDocument.head).createChild({
22573 rel : 'stylesheet',
22582 Roo.each(stylesheets, function(s) {
22587 Roo.get(_this.iframe.contentDocument.head).createChild({
22589 rel : 'stylesheet',
22598 removeStylesheets : function()
22602 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22607 // hide stuff that is not compatible
22621 * @event specialkey
22625 * @cfg {String} fieldClass @hide
22628 * @cfg {String} focusClass @hide
22631 * @cfg {String} autoCreate @hide
22634 * @cfg {String} inputType @hide
22637 * @cfg {String} invalidClass @hide
22640 * @cfg {String} invalidText @hide
22643 * @cfg {String} msgFx @hide
22646 * @cfg {String} validateOnBlur @hide
22650 Roo.HtmlEditorCore.white = [
22651 'area', 'br', 'img', 'input', 'hr', 'wbr',
22653 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22654 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22655 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22656 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22657 'table', 'ul', 'xmp',
22659 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22662 'dir', 'menu', 'ol', 'ul', 'dl',
22668 Roo.HtmlEditorCore.black = [
22669 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22671 'base', 'basefont', 'bgsound', 'blink', 'body',
22672 'frame', 'frameset', 'head', 'html', 'ilayer',
22673 'iframe', 'layer', 'link', 'meta', 'object',
22674 'script', 'style' ,'title', 'xml' // clean later..
22676 Roo.HtmlEditorCore.clean = [
22677 'script', 'style', 'title', 'xml'
22679 Roo.HtmlEditorCore.remove = [
22684 Roo.HtmlEditorCore.ablack = [
22688 Roo.HtmlEditorCore.aclean = [
22689 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22693 Roo.HtmlEditorCore.pwhite= [
22694 'http', 'https', 'mailto'
22697 // white listed style attributes.
22698 Roo.HtmlEditorCore.cwhite= [
22699 // 'text-align', /// default is to allow most things..
22705 // black listed style attributes.
22706 Roo.HtmlEditorCore.cblack= [
22707 // 'font-size' -- this can be set by the project
22711 Roo.HtmlEditorCore.swapCodes =[
22730 * @class Roo.bootstrap.HtmlEditor
22731 * @extends Roo.bootstrap.TextArea
22732 * Bootstrap HtmlEditor class
22735 * Create a new HtmlEditor
22736 * @param {Object} config The config object
22739 Roo.bootstrap.HtmlEditor = function(config){
22740 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22741 if (!this.toolbars) {
22742 this.toolbars = [];
22745 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22748 * @event initialize
22749 * Fires when the editor is fully initialized (including the iframe)
22750 * @param {HtmlEditor} this
22755 * Fires when the editor is first receives the focus. Any insertion must wait
22756 * until after this event.
22757 * @param {HtmlEditor} this
22761 * @event beforesync
22762 * Fires before the textarea is updated with content from the editor iframe. Return false
22763 * to cancel the sync.
22764 * @param {HtmlEditor} this
22765 * @param {String} html
22769 * @event beforepush
22770 * Fires before the iframe editor is updated with content from the textarea. Return false
22771 * to cancel the push.
22772 * @param {HtmlEditor} this
22773 * @param {String} html
22778 * Fires when the textarea is updated with content from the editor iframe.
22779 * @param {HtmlEditor} this
22780 * @param {String} html
22785 * Fires when the iframe editor is updated with content from the textarea.
22786 * @param {HtmlEditor} this
22787 * @param {String} html
22791 * @event editmodechange
22792 * Fires when the editor switches edit modes
22793 * @param {HtmlEditor} this
22794 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22796 editmodechange: true,
22798 * @event editorevent
22799 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22800 * @param {HtmlEditor} this
22804 * @event firstfocus
22805 * Fires when on first focus - needed by toolbars..
22806 * @param {HtmlEditor} this
22811 * Auto save the htmlEditor value as a file into Events
22812 * @param {HtmlEditor} this
22816 * @event savedpreview
22817 * preview the saved version of htmlEditor
22818 * @param {HtmlEditor} this
22825 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22829 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22834 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22839 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22844 * @cfg {Number} height (in pixels)
22848 * @cfg {Number} width (in pixels)
22853 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22856 stylesheets: false,
22861 // private properties
22862 validationEvent : false,
22864 initialized : false,
22867 onFocus : Roo.emptyFn,
22869 hideMode:'offsets',
22871 tbContainer : false,
22873 toolbarContainer :function() {
22874 return this.wrap.select('.x-html-editor-tb',true).first();
22878 * Protected method that will not generally be called directly. It
22879 * is called when the editor creates its toolbar. Override this method if you need to
22880 * add custom toolbar buttons.
22881 * @param {HtmlEditor} editor
22883 createToolbar : function(){
22884 Roo.log('renewing');
22885 Roo.log("create toolbars");
22887 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22888 this.toolbars[0].render(this.toolbarContainer());
22892 // if (!editor.toolbars || !editor.toolbars.length) {
22893 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22896 // for (var i =0 ; i < editor.toolbars.length;i++) {
22897 // editor.toolbars[i] = Roo.factory(
22898 // typeof(editor.toolbars[i]) == 'string' ?
22899 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22900 // Roo.bootstrap.HtmlEditor);
22901 // editor.toolbars[i].init(editor);
22907 onRender : function(ct, position)
22909 // Roo.log("Call onRender: " + this.xtype);
22911 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22913 this.wrap = this.inputEl().wrap({
22914 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22917 this.editorcore.onRender(ct, position);
22919 if (this.resizable) {
22920 this.resizeEl = new Roo.Resizable(this.wrap, {
22924 minHeight : this.height,
22925 height: this.height,
22926 handles : this.resizable,
22929 resize : function(r, w, h) {
22930 _t.onResize(w,h); // -something
22936 this.createToolbar(this);
22939 if(!this.width && this.resizable){
22940 this.setSize(this.wrap.getSize());
22942 if (this.resizeEl) {
22943 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22944 // should trigger onReize..
22950 onResize : function(w, h)
22952 Roo.log('resize: ' +w + ',' + h );
22953 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22957 if(this.inputEl() ){
22958 if(typeof w == 'number'){
22959 var aw = w - this.wrap.getFrameWidth('lr');
22960 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22963 if(typeof h == 'number'){
22964 var tbh = -11; // fixme it needs to tool bar size!
22965 for (var i =0; i < this.toolbars.length;i++) {
22966 // fixme - ask toolbars for heights?
22967 tbh += this.toolbars[i].el.getHeight();
22968 //if (this.toolbars[i].footer) {
22969 // tbh += this.toolbars[i].footer.el.getHeight();
22977 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22978 ah -= 5; // knock a few pixes off for look..
22979 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22983 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22984 this.editorcore.onResize(ew,eh);
22989 * Toggles the editor between standard and source edit mode.
22990 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22992 toggleSourceEdit : function(sourceEditMode)
22994 this.editorcore.toggleSourceEdit(sourceEditMode);
22996 if(this.editorcore.sourceEditMode){
22997 Roo.log('editor - showing textarea');
23000 // Roo.log(this.syncValue());
23002 this.inputEl().removeClass(['hide', 'x-hidden']);
23003 this.inputEl().dom.removeAttribute('tabIndex');
23004 this.inputEl().focus();
23006 Roo.log('editor - hiding textarea');
23008 // Roo.log(this.pushValue());
23011 this.inputEl().addClass(['hide', 'x-hidden']);
23012 this.inputEl().dom.setAttribute('tabIndex', -1);
23013 //this.deferFocus();
23016 if(this.resizable){
23017 this.setSize(this.wrap.getSize());
23020 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23023 // private (for BoxComponent)
23024 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23026 // private (for BoxComponent)
23027 getResizeEl : function(){
23031 // private (for BoxComponent)
23032 getPositionEl : function(){
23037 initEvents : function(){
23038 this.originalValue = this.getValue();
23042 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23045 // markInvalid : Roo.emptyFn,
23047 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23050 // clearInvalid : Roo.emptyFn,
23052 setValue : function(v){
23053 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23054 this.editorcore.pushValue();
23059 deferFocus : function(){
23060 this.focus.defer(10, this);
23064 focus : function(){
23065 this.editorcore.focus();
23071 onDestroy : function(){
23077 for (var i =0; i < this.toolbars.length;i++) {
23078 // fixme - ask toolbars for heights?
23079 this.toolbars[i].onDestroy();
23082 this.wrap.dom.innerHTML = '';
23083 this.wrap.remove();
23088 onFirstFocus : function(){
23089 //Roo.log("onFirstFocus");
23090 this.editorcore.onFirstFocus();
23091 for (var i =0; i < this.toolbars.length;i++) {
23092 this.toolbars[i].onFirstFocus();
23098 syncValue : function()
23100 this.editorcore.syncValue();
23103 pushValue : function()
23105 this.editorcore.pushValue();
23109 // hide stuff that is not compatible
23123 * @event specialkey
23127 * @cfg {String} fieldClass @hide
23130 * @cfg {String} focusClass @hide
23133 * @cfg {String} autoCreate @hide
23136 * @cfg {String} inputType @hide
23139 * @cfg {String} invalidClass @hide
23142 * @cfg {String} invalidText @hide
23145 * @cfg {String} msgFx @hide
23148 * @cfg {String} validateOnBlur @hide
23157 Roo.namespace('Roo.bootstrap.htmleditor');
23159 * @class Roo.bootstrap.HtmlEditorToolbar1
23164 new Roo.bootstrap.HtmlEditor({
23167 new Roo.bootstrap.HtmlEditorToolbar1({
23168 disable : { fonts: 1 , format: 1, ..., ... , ...],
23174 * @cfg {Object} disable List of elements to disable..
23175 * @cfg {Array} btns List of additional buttons.
23179 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23182 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23185 Roo.apply(this, config);
23187 // default disabled, based on 'good practice'..
23188 this.disable = this.disable || {};
23189 Roo.applyIf(this.disable, {
23192 specialElements : true
23194 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23196 this.editor = config.editor;
23197 this.editorcore = config.editor.editorcore;
23199 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23201 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23202 // dont call parent... till later.
23204 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23209 editorcore : false,
23214 "h1","h2","h3","h4","h5","h6",
23216 "abbr", "acronym", "address", "cite", "samp", "var",
23220 onRender : function(ct, position)
23222 // Roo.log("Call onRender: " + this.xtype);
23224 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23226 this.el.dom.style.marginBottom = '0';
23228 var editorcore = this.editorcore;
23229 var editor= this.editor;
23232 var btn = function(id,cmd , toggle, handler){
23234 var event = toggle ? 'toggle' : 'click';
23239 xns: Roo.bootstrap,
23242 enableToggle:toggle !== false,
23244 pressed : toggle ? false : null,
23247 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23248 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23254 // var cb_box = function...
23259 xns: Roo.bootstrap,
23260 glyphicon : 'font',
23264 xns: Roo.bootstrap,
23268 Roo.each(this.formats, function(f) {
23269 style.menu.items.push({
23271 xns: Roo.bootstrap,
23272 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23277 editorcore.insertTag(this.tagname);
23284 children.push(style);
23286 btn('bold',false,true);
23287 btn('italic',false,true);
23288 btn('align-left', 'justifyleft',true);
23289 btn('align-center', 'justifycenter',true);
23290 btn('align-right' , 'justifyright',true);
23291 btn('link', false, false, function(btn) {
23292 //Roo.log("create link?");
23293 var url = prompt(this.createLinkText, this.defaultLinkValue);
23294 if(url && url != 'http:/'+'/'){
23295 this.editorcore.relayCmd('createlink', url);
23298 btn('list','insertunorderedlist',true);
23299 btn('pencil', false,true, function(btn){
23301 this.toggleSourceEdit(btn.pressed);
23304 if (this.editor.btns.length > 0) {
23305 for (var i = 0; i<this.editor.btns.length; i++) {
23306 btn(this.editor.btns[i].glyphicon,false,true,this.editor.btns[i].listeners.click);
23314 xns: Roo.bootstrap,
23319 xns: Roo.bootstrap,
23324 cog.menu.items.push({
23326 xns: Roo.bootstrap,
23327 html : Clean styles,
23332 editorcore.insertTag(this.tagname);
23341 this.xtype = 'NavSimplebar';
23343 for(var i=0;i< children.length;i++) {
23345 this.buttons.add(this.addxtypeChild(children[i]));
23349 editor.on('editorevent', this.updateToolbar, this);
23351 onBtnClick : function(id)
23353 this.editorcore.relayCmd(id);
23354 this.editorcore.focus();
23358 * Protected method that will not generally be called directly. It triggers
23359 * a toolbar update by reading the markup state of the current selection in the editor.
23361 updateToolbar: function(){
23363 if(!this.editorcore.activated){
23364 this.editor.onFirstFocus(); // is this neeed?
23368 var btns = this.buttons;
23369 var doc = this.editorcore.doc;
23370 btns.get('bold').setActive(doc.queryCommandState('bold'));
23371 btns.get('italic').setActive(doc.queryCommandState('italic'));
23372 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23374 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23375 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23376 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23378 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23379 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23382 var ans = this.editorcore.getAllAncestors();
23383 if (this.formatCombo) {
23386 var store = this.formatCombo.store;
23387 this.formatCombo.setValue("");
23388 for (var i =0; i < ans.length;i++) {
23389 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23391 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23399 // hides menus... - so this cant be on a menu...
23400 Roo.bootstrap.MenuMgr.hideAll();
23402 Roo.bootstrap.MenuMgr.hideAll();
23403 //this.editorsyncValue();
23405 onFirstFocus: function() {
23406 this.buttons.each(function(item){
23410 toggleSourceEdit : function(sourceEditMode){
23413 if(sourceEditMode){
23414 Roo.log("disabling buttons");
23415 this.buttons.each( function(item){
23416 if(item.cmd != 'pencil'){
23422 Roo.log("enabling buttons");
23423 if(this.editorcore.initialized){
23424 this.buttons.each( function(item){
23430 Roo.log("calling toggole on editor");
23431 // tell the editor that it's been pressed..
23432 this.editor.toggleSourceEdit(sourceEditMode);
23442 * @class Roo.bootstrap.Table.AbstractSelectionModel
23443 * @extends Roo.util.Observable
23444 * Abstract base class for grid SelectionModels. It provides the interface that should be
23445 * implemented by descendant classes. This class should not be directly instantiated.
23448 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23449 this.locked = false;
23450 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23454 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23455 /** @ignore Called by the grid automatically. Do not call directly. */
23456 init : function(grid){
23462 * Locks the selections.
23465 this.locked = true;
23469 * Unlocks the selections.
23471 unlock : function(){
23472 this.locked = false;
23476 * Returns true if the selections are locked.
23477 * @return {Boolean}
23479 isLocked : function(){
23480 return this.locked;
23484 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23485 * @class Roo.bootstrap.Table.RowSelectionModel
23486 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23487 * It supports multiple selections and keyboard selection/navigation.
23489 * @param {Object} config
23492 Roo.bootstrap.Table.RowSelectionModel = function(config){
23493 Roo.apply(this, config);
23494 this.selections = new Roo.util.MixedCollection(false, function(o){
23499 this.lastActive = false;
23503 * @event selectionchange
23504 * Fires when the selection changes
23505 * @param {SelectionModel} this
23507 "selectionchange" : true,
23509 * @event afterselectionchange
23510 * Fires after the selection changes (eg. by key press or clicking)
23511 * @param {SelectionModel} this
23513 "afterselectionchange" : true,
23515 * @event beforerowselect
23516 * Fires when a row is selected being selected, return false to cancel.
23517 * @param {SelectionModel} this
23518 * @param {Number} rowIndex The selected index
23519 * @param {Boolean} keepExisting False if other selections will be cleared
23521 "beforerowselect" : true,
23524 * Fires when a row is selected.
23525 * @param {SelectionModel} this
23526 * @param {Number} rowIndex The selected index
23527 * @param {Roo.data.Record} r The record
23529 "rowselect" : true,
23531 * @event rowdeselect
23532 * Fires when a row is deselected.
23533 * @param {SelectionModel} this
23534 * @param {Number} rowIndex The selected index
23536 "rowdeselect" : true
23538 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23539 this.locked = false;
23542 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23544 * @cfg {Boolean} singleSelect
23545 * True to allow selection of only one row at a time (defaults to false)
23547 singleSelect : false,
23550 initEvents : function()
23553 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23554 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23555 //}else{ // allow click to work like normal
23556 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23558 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23559 this.grid.on("rowclick", this.handleMouseDown, this);
23561 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23562 "up" : function(e){
23564 this.selectPrevious(e.shiftKey);
23565 }else if(this.last !== false && this.lastActive !== false){
23566 var last = this.last;
23567 this.selectRange(this.last, this.lastActive-1);
23568 this.grid.getView().focusRow(this.lastActive);
23569 if(last !== false){
23573 this.selectFirstRow();
23575 this.fireEvent("afterselectionchange", this);
23577 "down" : function(e){
23579 this.selectNext(e.shiftKey);
23580 }else if(this.last !== false && this.lastActive !== false){
23581 var last = this.last;
23582 this.selectRange(this.last, this.lastActive+1);
23583 this.grid.getView().focusRow(this.lastActive);
23584 if(last !== false){
23588 this.selectFirstRow();
23590 this.fireEvent("afterselectionchange", this);
23594 this.grid.store.on('load', function(){
23595 this.selections.clear();
23598 var view = this.grid.view;
23599 view.on("refresh", this.onRefresh, this);
23600 view.on("rowupdated", this.onRowUpdated, this);
23601 view.on("rowremoved", this.onRemove, this);
23606 onRefresh : function()
23608 var ds = this.grid.store, i, v = this.grid.view;
23609 var s = this.selections;
23610 s.each(function(r){
23611 if((i = ds.indexOfId(r.id)) != -1){
23620 onRemove : function(v, index, r){
23621 this.selections.remove(r);
23625 onRowUpdated : function(v, index, r){
23626 if(this.isSelected(r)){
23627 v.onRowSelect(index);
23633 * @param {Array} records The records to select
23634 * @param {Boolean} keepExisting (optional) True to keep existing selections
23636 selectRecords : function(records, keepExisting)
23639 this.clearSelections();
23641 var ds = this.grid.store;
23642 for(var i = 0, len = records.length; i < len; i++){
23643 this.selectRow(ds.indexOf(records[i]), true);
23648 * Gets the number of selected rows.
23651 getCount : function(){
23652 return this.selections.length;
23656 * Selects the first row in the grid.
23658 selectFirstRow : function(){
23663 * Select the last row.
23664 * @param {Boolean} keepExisting (optional) True to keep existing selections
23666 selectLastRow : function(keepExisting){
23667 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23668 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23672 * Selects the row immediately following the last selected row.
23673 * @param {Boolean} keepExisting (optional) True to keep existing selections
23675 selectNext : function(keepExisting)
23677 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23678 this.selectRow(this.last+1, keepExisting);
23679 this.grid.getView().focusRow(this.last);
23684 * Selects the row that precedes the last selected row.
23685 * @param {Boolean} keepExisting (optional) True to keep existing selections
23687 selectPrevious : function(keepExisting){
23689 this.selectRow(this.last-1, keepExisting);
23690 this.grid.getView().focusRow(this.last);
23695 * Returns the selected records
23696 * @return {Array} Array of selected records
23698 getSelections : function(){
23699 return [].concat(this.selections.items);
23703 * Returns the first selected record.
23706 getSelected : function(){
23707 return this.selections.itemAt(0);
23712 * Clears all selections.
23714 clearSelections : function(fast)
23720 var ds = this.grid.store;
23721 var s = this.selections;
23722 s.each(function(r){
23723 this.deselectRow(ds.indexOfId(r.id));
23727 this.selections.clear();
23734 * Selects all rows.
23736 selectAll : function(){
23740 this.selections.clear();
23741 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23742 this.selectRow(i, true);
23747 * Returns True if there is a selection.
23748 * @return {Boolean}
23750 hasSelection : function(){
23751 return this.selections.length > 0;
23755 * Returns True if the specified row is selected.
23756 * @param {Number/Record} record The record or index of the record to check
23757 * @return {Boolean}
23759 isSelected : function(index){
23760 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23761 return (r && this.selections.key(r.id) ? true : false);
23765 * Returns True if the specified record id is selected.
23766 * @param {String} id The id of record to check
23767 * @return {Boolean}
23769 isIdSelected : function(id){
23770 return (this.selections.key(id) ? true : false);
23775 handleMouseDBClick : function(e, t){
23779 handleMouseDown : function(e, t)
23781 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23782 if(this.isLocked() || rowIndex < 0 ){
23785 if(e.shiftKey && this.last !== false){
23786 var last = this.last;
23787 this.selectRange(last, rowIndex, e.ctrlKey);
23788 this.last = last; // reset the last
23792 var isSelected = this.isSelected(rowIndex);
23793 //Roo.log("select row:" + rowIndex);
23795 this.deselectRow(rowIndex);
23797 this.selectRow(rowIndex, true);
23801 if(e.button !== 0 && isSelected){
23802 alert('rowIndex 2: ' + rowIndex);
23803 view.focusRow(rowIndex);
23804 }else if(e.ctrlKey && isSelected){
23805 this.deselectRow(rowIndex);
23806 }else if(!isSelected){
23807 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23808 view.focusRow(rowIndex);
23812 this.fireEvent("afterselectionchange", this);
23815 handleDragableRowClick : function(grid, rowIndex, e)
23817 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23818 this.selectRow(rowIndex, false);
23819 grid.view.focusRow(rowIndex);
23820 this.fireEvent("afterselectionchange", this);
23825 * Selects multiple rows.
23826 * @param {Array} rows Array of the indexes of the row to select
23827 * @param {Boolean} keepExisting (optional) True to keep existing selections
23829 selectRows : function(rows, keepExisting){
23831 this.clearSelections();
23833 for(var i = 0, len = rows.length; i < len; i++){
23834 this.selectRow(rows[i], true);
23839 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23840 * @param {Number} startRow The index of the first row in the range
23841 * @param {Number} endRow The index of the last row in the range
23842 * @param {Boolean} keepExisting (optional) True to retain existing selections
23844 selectRange : function(startRow, endRow, keepExisting){
23849 this.clearSelections();
23851 if(startRow <= endRow){
23852 for(var i = startRow; i <= endRow; i++){
23853 this.selectRow(i, true);
23856 for(var i = startRow; i >= endRow; i--){
23857 this.selectRow(i, true);
23863 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23864 * @param {Number} startRow The index of the first row in the range
23865 * @param {Number} endRow The index of the last row in the range
23867 deselectRange : function(startRow, endRow, preventViewNotify){
23871 for(var i = startRow; i <= endRow; i++){
23872 this.deselectRow(i, preventViewNotify);
23878 * @param {Number} row The index of the row to select
23879 * @param {Boolean} keepExisting (optional) True to keep existing selections
23881 selectRow : function(index, keepExisting, preventViewNotify)
23883 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23886 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23887 if(!keepExisting || this.singleSelect){
23888 this.clearSelections();
23891 var r = this.grid.store.getAt(index);
23892 //console.log('selectRow - record id :' + r.id);
23894 this.selections.add(r);
23895 this.last = this.lastActive = index;
23896 if(!preventViewNotify){
23897 var proxy = new Roo.Element(
23898 this.grid.getRowDom(index)
23900 proxy.addClass('bg-info info');
23902 this.fireEvent("rowselect", this, index, r);
23903 this.fireEvent("selectionchange", this);
23909 * @param {Number} row The index of the row to deselect
23911 deselectRow : function(index, preventViewNotify)
23916 if(this.last == index){
23919 if(this.lastActive == index){
23920 this.lastActive = false;
23923 var r = this.grid.store.getAt(index);
23928 this.selections.remove(r);
23929 //.console.log('deselectRow - record id :' + r.id);
23930 if(!preventViewNotify){
23932 var proxy = new Roo.Element(
23933 this.grid.getRowDom(index)
23935 proxy.removeClass('bg-info info');
23937 this.fireEvent("rowdeselect", this, index);
23938 this.fireEvent("selectionchange", this);
23942 restoreLast : function(){
23944 this.last = this._last;
23949 acceptsNav : function(row, col, cm){
23950 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23954 onEditorKey : function(field, e){
23955 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23960 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23962 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23964 }else if(k == e.ENTER && !e.ctrlKey){
23968 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23970 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23972 }else if(k == e.ESC){
23976 g.startEditing(newCell[0], newCell[1]);
23982 * Ext JS Library 1.1.1
23983 * Copyright(c) 2006-2007, Ext JS, LLC.
23985 * Originally Released Under LGPL - original licence link has changed is not relivant.
23988 * <script type="text/javascript">
23992 * @class Roo.bootstrap.PagingToolbar
23993 * @extends Roo.bootstrap.NavSimplebar
23994 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23996 * Create a new PagingToolbar
23997 * @param {Object} config The config object
23998 * @param {Roo.data.Store} store
24000 Roo.bootstrap.PagingToolbar = function(config)
24002 // old args format still supported... - xtype is prefered..
24003 // created from xtype...
24005 this.ds = config.dataSource;
24007 if (config.store && !this.ds) {
24008 this.store= Roo.factory(config.store, Roo.data);
24009 this.ds = this.store;
24010 this.ds.xmodule = this.xmodule || false;
24013 this.toolbarItems = [];
24014 if (config.items) {
24015 this.toolbarItems = config.items;
24018 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24023 this.bind(this.ds);
24026 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24030 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24032 * @cfg {Roo.data.Store} dataSource
24033 * The underlying data store providing the paged data
24036 * @cfg {String/HTMLElement/Element} container
24037 * container The id or element that will contain the toolbar
24040 * @cfg {Boolean} displayInfo
24041 * True to display the displayMsg (defaults to false)
24044 * @cfg {Number} pageSize
24045 * The number of records to display per page (defaults to 20)
24049 * @cfg {String} displayMsg
24050 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24052 displayMsg : 'Displaying {0} - {1} of {2}',
24054 * @cfg {String} emptyMsg
24055 * The message to display when no records are found (defaults to "No data to display")
24057 emptyMsg : 'No data to display',
24059 * Customizable piece of the default paging text (defaults to "Page")
24062 beforePageText : "Page",
24064 * Customizable piece of the default paging text (defaults to "of %0")
24067 afterPageText : "of {0}",
24069 * Customizable piece of the default paging text (defaults to "First Page")
24072 firstText : "First Page",
24074 * Customizable piece of the default paging text (defaults to "Previous Page")
24077 prevText : "Previous Page",
24079 * Customizable piece of the default paging text (defaults to "Next Page")
24082 nextText : "Next Page",
24084 * Customizable piece of the default paging text (defaults to "Last Page")
24087 lastText : "Last Page",
24089 * Customizable piece of the default paging text (defaults to "Refresh")
24092 refreshText : "Refresh",
24096 onRender : function(ct, position)
24098 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24099 this.navgroup.parentId = this.id;
24100 this.navgroup.onRender(this.el, null);
24101 // add the buttons to the navgroup
24103 if(this.displayInfo){
24104 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24105 this.displayEl = this.el.select('.x-paging-info', true).first();
24106 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24107 // this.displayEl = navel.el.select('span',true).first();
24113 Roo.each(_this.buttons, function(e){ // this might need to use render????
24114 Roo.factory(e).onRender(_this.el, null);
24118 Roo.each(_this.toolbarItems, function(e) {
24119 _this.navgroup.addItem(e);
24123 this.first = this.navgroup.addItem({
24124 tooltip: this.firstText,
24126 icon : 'fa fa-backward',
24128 preventDefault: true,
24129 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24132 this.prev = this.navgroup.addItem({
24133 tooltip: this.prevText,
24135 icon : 'fa fa-step-backward',
24137 preventDefault: true,
24138 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24140 //this.addSeparator();
24143 var field = this.navgroup.addItem( {
24145 cls : 'x-paging-position',
24147 html : this.beforePageText +
24148 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24149 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24152 this.field = field.el.select('input', true).first();
24153 this.field.on("keydown", this.onPagingKeydown, this);
24154 this.field.on("focus", function(){this.dom.select();});
24157 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24158 //this.field.setHeight(18);
24159 //this.addSeparator();
24160 this.next = this.navgroup.addItem({
24161 tooltip: this.nextText,
24163 html : ' <i class="fa fa-step-forward">',
24165 preventDefault: true,
24166 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24168 this.last = this.navgroup.addItem({
24169 tooltip: this.lastText,
24170 icon : 'fa fa-forward',
24173 preventDefault: true,
24174 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24176 //this.addSeparator();
24177 this.loading = this.navgroup.addItem({
24178 tooltip: this.refreshText,
24179 icon: 'fa fa-refresh',
24180 preventDefault: true,
24181 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24187 updateInfo : function(){
24188 if(this.displayEl){
24189 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24190 var msg = count == 0 ?
24194 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24196 this.displayEl.update(msg);
24201 onLoad : function(ds, r, o){
24202 this.cursor = o.params ? o.params.start : 0;
24203 var d = this.getPageData(),
24207 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24208 this.field.dom.value = ap;
24209 this.first.setDisabled(ap == 1);
24210 this.prev.setDisabled(ap == 1);
24211 this.next.setDisabled(ap == ps);
24212 this.last.setDisabled(ap == ps);
24213 this.loading.enable();
24218 getPageData : function(){
24219 var total = this.ds.getTotalCount();
24222 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24223 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24228 onLoadError : function(){
24229 this.loading.enable();
24233 onPagingKeydown : function(e){
24234 var k = e.getKey();
24235 var d = this.getPageData();
24237 var v = this.field.dom.value, pageNum;
24238 if(!v || isNaN(pageNum = parseInt(v, 10))){
24239 this.field.dom.value = d.activePage;
24242 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24243 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24246 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))
24248 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24249 this.field.dom.value = pageNum;
24250 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24253 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24255 var v = this.field.dom.value, pageNum;
24256 var increment = (e.shiftKey) ? 10 : 1;
24257 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24260 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24261 this.field.dom.value = d.activePage;
24264 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24266 this.field.dom.value = parseInt(v, 10) + increment;
24267 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24268 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24275 beforeLoad : function(){
24277 this.loading.disable();
24282 onClick : function(which){
24291 ds.load({params:{start: 0, limit: this.pageSize}});
24294 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24297 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24300 var total = ds.getTotalCount();
24301 var extra = total % this.pageSize;
24302 var lastStart = extra ? (total - extra) : total-this.pageSize;
24303 ds.load({params:{start: lastStart, limit: this.pageSize}});
24306 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24312 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24313 * @param {Roo.data.Store} store The data store to unbind
24315 unbind : function(ds){
24316 ds.un("beforeload", this.beforeLoad, this);
24317 ds.un("load", this.onLoad, this);
24318 ds.un("loadexception", this.onLoadError, this);
24319 ds.un("remove", this.updateInfo, this);
24320 ds.un("add", this.updateInfo, this);
24321 this.ds = undefined;
24325 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24326 * @param {Roo.data.Store} store The data store to bind
24328 bind : function(ds){
24329 ds.on("beforeload", this.beforeLoad, this);
24330 ds.on("load", this.onLoad, this);
24331 ds.on("loadexception", this.onLoadError, this);
24332 ds.on("remove", this.updateInfo, this);
24333 ds.on("add", this.updateInfo, this);
24344 * @class Roo.bootstrap.MessageBar
24345 * @extends Roo.bootstrap.Component
24346 * Bootstrap MessageBar class
24347 * @cfg {String} html contents of the MessageBar
24348 * @cfg {String} weight (info | success | warning | danger) default info
24349 * @cfg {String} beforeClass insert the bar before the given class
24350 * @cfg {Boolean} closable (true | false) default false
24351 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24354 * Create a new Element
24355 * @param {Object} config The config object
24358 Roo.bootstrap.MessageBar = function(config){
24359 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24362 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24368 beforeClass: 'bootstrap-sticky-wrap',
24370 getAutoCreate : function(){
24374 cls: 'alert alert-dismissable alert-' + this.weight,
24379 html: this.html || ''
24385 cfg.cls += ' alert-messages-fixed';
24399 onRender : function(ct, position)
24401 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24404 var cfg = Roo.apply({}, this.getAutoCreate());
24408 cfg.cls += ' ' + this.cls;
24411 cfg.style = this.style;
24413 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24415 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24418 this.el.select('>button.close').on('click', this.hide, this);
24424 if (!this.rendered) {
24430 this.fireEvent('show', this);
24436 if (!this.rendered) {
24442 this.fireEvent('hide', this);
24445 update : function()
24447 // var e = this.el.dom.firstChild;
24449 // if(this.closable){
24450 // e = e.nextSibling;
24453 // e.data = this.html || '';
24455 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24471 * @class Roo.bootstrap.Graph
24472 * @extends Roo.bootstrap.Component
24473 * Bootstrap Graph class
24477 @cfg {String} graphtype bar | vbar | pie
24478 @cfg {number} g_x coodinator | centre x (pie)
24479 @cfg {number} g_y coodinator | centre y (pie)
24480 @cfg {number} g_r radius (pie)
24481 @cfg {number} g_height height of the chart (respected by all elements in the set)
24482 @cfg {number} g_width width of the chart (respected by all elements in the set)
24483 @cfg {Object} title The title of the chart
24486 -opts (object) options for the chart
24488 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24489 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24491 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.
24492 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24494 o stretch (boolean)
24496 -opts (object) options for the pie
24499 o startAngle (number)
24500 o endAngle (number)
24504 * Create a new Input
24505 * @param {Object} config The config object
24508 Roo.bootstrap.Graph = function(config){
24509 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24515 * The img click event for the img.
24516 * @param {Roo.EventObject} e
24522 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24533 //g_colors: this.colors,
24540 getAutoCreate : function(){
24551 onRender : function(ct,position){
24554 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24556 if (typeof(Raphael) == 'undefined') {
24557 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24561 this.raphael = Raphael(this.el.dom);
24563 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24564 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24565 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24566 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24568 r.text(160, 10, "Single Series Chart").attr(txtattr);
24569 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24570 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24571 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24573 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24574 r.barchart(330, 10, 300, 220, data1);
24575 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24576 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24579 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24580 // r.barchart(30, 30, 560, 250, xdata, {
24581 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24582 // axis : "0 0 1 1",
24583 // axisxlabels : xdata
24584 // //yvalues : cols,
24587 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24589 // this.load(null,xdata,{
24590 // axis : "0 0 1 1",
24591 // axisxlabels : xdata
24596 load : function(graphtype,xdata,opts)
24598 this.raphael.clear();
24600 graphtype = this.graphtype;
24605 var r = this.raphael,
24606 fin = function () {
24607 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24609 fout = function () {
24610 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24612 pfin = function() {
24613 this.sector.stop();
24614 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24617 this.label[0].stop();
24618 this.label[0].attr({ r: 7.5 });
24619 this.label[1].attr({ "font-weight": 800 });
24622 pfout = function() {
24623 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24626 this.label[0].animate({ r: 5 }, 500, "bounce");
24627 this.label[1].attr({ "font-weight": 400 });
24633 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24636 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24639 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24640 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24642 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24649 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24654 setTitle: function(o)
24659 initEvents: function() {
24662 this.el.on('click', this.onClick, this);
24666 onClick : function(e)
24668 Roo.log('img onclick');
24669 this.fireEvent('click', this, e);
24681 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24684 * @class Roo.bootstrap.dash.NumberBox
24685 * @extends Roo.bootstrap.Component
24686 * Bootstrap NumberBox class
24687 * @cfg {String} headline Box headline
24688 * @cfg {String} content Box content
24689 * @cfg {String} icon Box icon
24690 * @cfg {String} footer Footer text
24691 * @cfg {String} fhref Footer href
24694 * Create a new NumberBox
24695 * @param {Object} config The config object
24699 Roo.bootstrap.dash.NumberBox = function(config){
24700 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24704 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24713 getAutoCreate : function(){
24717 cls : 'small-box ',
24725 cls : 'roo-headline',
24726 html : this.headline
24730 cls : 'roo-content',
24731 html : this.content
24745 cls : 'ion ' + this.icon
24754 cls : 'small-box-footer',
24755 href : this.fhref || '#',
24759 cfg.cn.push(footer);
24766 onRender : function(ct,position){
24767 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24774 setHeadline: function (value)
24776 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24779 setFooter: function (value, href)
24781 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24784 this.el.select('a.small-box-footer',true).first().attr('href', href);
24789 setContent: function (value)
24791 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24794 initEvents: function()
24808 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24811 * @class Roo.bootstrap.dash.TabBox
24812 * @extends Roo.bootstrap.Component
24813 * Bootstrap TabBox class
24814 * @cfg {String} title Title of the TabBox
24815 * @cfg {String} icon Icon of the TabBox
24816 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24817 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24820 * Create a new TabBox
24821 * @param {Object} config The config object
24825 Roo.bootstrap.dash.TabBox = function(config){
24826 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24831 * When a pane is added
24832 * @param {Roo.bootstrap.dash.TabPane} pane
24836 * @event activatepane
24837 * When a pane is activated
24838 * @param {Roo.bootstrap.dash.TabPane} pane
24840 "activatepane" : true
24848 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24853 tabScrollable : false,
24855 getChildContainer : function()
24857 return this.el.select('.tab-content', true).first();
24860 getAutoCreate : function(){
24864 cls: 'pull-left header',
24872 cls: 'fa ' + this.icon
24878 cls: 'nav nav-tabs pull-right',
24884 if(this.tabScrollable){
24891 cls: 'nav nav-tabs pull-right',
24902 cls: 'nav-tabs-custom',
24907 cls: 'tab-content no-padding',
24915 initEvents : function()
24917 //Roo.log('add add pane handler');
24918 this.on('addpane', this.onAddPane, this);
24921 * Updates the box title
24922 * @param {String} html to set the title to.
24924 setTitle : function(value)
24926 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24928 onAddPane : function(pane)
24930 this.panes.push(pane);
24931 //Roo.log('addpane');
24933 // tabs are rendere left to right..
24934 if(!this.showtabs){
24938 var ctr = this.el.select('.nav-tabs', true).first();
24941 var existing = ctr.select('.nav-tab',true);
24942 var qty = existing.getCount();;
24945 var tab = ctr.createChild({
24947 cls : 'nav-tab' + (qty ? '' : ' active'),
24955 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24958 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24960 pane.el.addClass('active');
24965 onTabClick : function(ev,un,ob,pane)
24967 //Roo.log('tab - prev default');
24968 ev.preventDefault();
24971 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24972 pane.tab.addClass('active');
24973 //Roo.log(pane.title);
24974 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24975 // technically we should have a deactivate event.. but maybe add later.
24976 // and it should not de-activate the selected tab...
24977 this.fireEvent('activatepane', pane);
24978 pane.el.addClass('active');
24979 pane.fireEvent('activate');
24984 getActivePane : function()
24987 Roo.each(this.panes, function(p) {
24988 if(p.el.hasClass('active')){
25009 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25011 * @class Roo.bootstrap.TabPane
25012 * @extends Roo.bootstrap.Component
25013 * Bootstrap TabPane class
25014 * @cfg {Boolean} active (false | true) Default false
25015 * @cfg {String} title title of panel
25019 * Create a new TabPane
25020 * @param {Object} config The config object
25023 Roo.bootstrap.dash.TabPane = function(config){
25024 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25030 * When a pane is activated
25031 * @param {Roo.bootstrap.dash.TabPane} pane
25038 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25043 // the tabBox that this is attached to.
25046 getAutoCreate : function()
25054 cfg.cls += ' active';
25059 initEvents : function()
25061 //Roo.log('trigger add pane handler');
25062 this.parent().fireEvent('addpane', this)
25066 * Updates the tab title
25067 * @param {String} html to set the title to.
25069 setTitle: function(str)
25075 this.tab.select('a', true).first().dom.innerHTML = str;
25092 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25095 * @class Roo.bootstrap.menu.Menu
25096 * @extends Roo.bootstrap.Component
25097 * Bootstrap Menu class - container for Menu
25098 * @cfg {String} html Text of the menu
25099 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25100 * @cfg {String} icon Font awesome icon
25101 * @cfg {String} pos Menu align to (top | bottom) default bottom
25105 * Create a new Menu
25106 * @param {Object} config The config object
25110 Roo.bootstrap.menu.Menu = function(config){
25111 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25115 * @event beforeshow
25116 * Fires before this menu is displayed
25117 * @param {Roo.bootstrap.menu.Menu} this
25121 * @event beforehide
25122 * Fires before this menu is hidden
25123 * @param {Roo.bootstrap.menu.Menu} this
25128 * Fires after this menu is displayed
25129 * @param {Roo.bootstrap.menu.Menu} this
25134 * Fires after this menu is hidden
25135 * @param {Roo.bootstrap.menu.Menu} this
25140 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25141 * @param {Roo.bootstrap.menu.Menu} this
25142 * @param {Roo.EventObject} e
25149 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25153 weight : 'default',
25158 getChildContainer : function() {
25159 if(this.isSubMenu){
25163 return this.el.select('ul.dropdown-menu', true).first();
25166 getAutoCreate : function()
25171 cls : 'roo-menu-text',
25179 cls : 'fa ' + this.icon
25190 cls : 'dropdown-button btn btn-' + this.weight,
25195 cls : 'dropdown-toggle btn btn-' + this.weight,
25205 cls : 'dropdown-menu'
25211 if(this.pos == 'top'){
25212 cfg.cls += ' dropup';
25215 if(this.isSubMenu){
25218 cls : 'dropdown-menu'
25225 onRender : function(ct, position)
25227 this.isSubMenu = ct.hasClass('dropdown-submenu');
25229 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25232 initEvents : function()
25234 if(this.isSubMenu){
25238 this.hidden = true;
25240 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25241 this.triggerEl.on('click', this.onTriggerPress, this);
25243 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25244 this.buttonEl.on('click', this.onClick, this);
25250 if(this.isSubMenu){
25254 return this.el.select('ul.dropdown-menu', true).first();
25257 onClick : function(e)
25259 this.fireEvent("click", this, e);
25262 onTriggerPress : function(e)
25264 if (this.isVisible()) {
25271 isVisible : function(){
25272 return !this.hidden;
25277 this.fireEvent("beforeshow", this);
25279 this.hidden = false;
25280 this.el.addClass('open');
25282 Roo.get(document).on("mouseup", this.onMouseUp, this);
25284 this.fireEvent("show", this);
25291 this.fireEvent("beforehide", this);
25293 this.hidden = true;
25294 this.el.removeClass('open');
25296 Roo.get(document).un("mouseup", this.onMouseUp);
25298 this.fireEvent("hide", this);
25301 onMouseUp : function()
25315 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25318 * @class Roo.bootstrap.menu.Item
25319 * @extends Roo.bootstrap.Component
25320 * Bootstrap MenuItem class
25321 * @cfg {Boolean} submenu (true | false) default false
25322 * @cfg {String} html text of the item
25323 * @cfg {String} href the link
25324 * @cfg {Boolean} disable (true | false) default false
25325 * @cfg {Boolean} preventDefault (true | false) default true
25326 * @cfg {String} icon Font awesome icon
25327 * @cfg {String} pos Submenu align to (left | right) default right
25331 * Create a new Item
25332 * @param {Object} config The config object
25336 Roo.bootstrap.menu.Item = function(config){
25337 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25341 * Fires when the mouse is hovering over this menu
25342 * @param {Roo.bootstrap.menu.Item} this
25343 * @param {Roo.EventObject} e
25348 * Fires when the mouse exits this menu
25349 * @param {Roo.bootstrap.menu.Item} this
25350 * @param {Roo.EventObject} e
25356 * The raw click event for the entire grid.
25357 * @param {Roo.EventObject} e
25363 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25368 preventDefault: true,
25373 getAutoCreate : function()
25378 cls : 'roo-menu-item-text',
25386 cls : 'fa ' + this.icon
25395 href : this.href || '#',
25402 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25406 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25408 if(this.pos == 'left'){
25409 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25416 initEvents : function()
25418 this.el.on('mouseover', this.onMouseOver, this);
25419 this.el.on('mouseout', this.onMouseOut, this);
25421 this.el.select('a', true).first().on('click', this.onClick, this);
25425 onClick : function(e)
25427 if(this.preventDefault){
25428 e.preventDefault();
25431 this.fireEvent("click", this, e);
25434 onMouseOver : function(e)
25436 if(this.submenu && this.pos == 'left'){
25437 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25440 this.fireEvent("mouseover", this, e);
25443 onMouseOut : function(e)
25445 this.fireEvent("mouseout", this, e);
25457 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25460 * @class Roo.bootstrap.menu.Separator
25461 * @extends Roo.bootstrap.Component
25462 * Bootstrap Separator class
25465 * Create a new Separator
25466 * @param {Object} config The config object
25470 Roo.bootstrap.menu.Separator = function(config){
25471 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25474 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25476 getAutoCreate : function(){
25497 * @class Roo.bootstrap.Tooltip
25498 * Bootstrap Tooltip class
25499 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25500 * to determine which dom element triggers the tooltip.
25502 * It needs to add support for additional attributes like tooltip-position
25505 * Create a new Toolti
25506 * @param {Object} config The config object
25509 Roo.bootstrap.Tooltip = function(config){
25510 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25512 this.alignment = Roo.bootstrap.Tooltip.alignment;
25514 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25515 this.alignment = config.alignment;
25520 Roo.apply(Roo.bootstrap.Tooltip, {
25522 * @function init initialize tooltip monitoring.
25526 currentTip : false,
25527 currentRegion : false,
25533 Roo.get(document).on('mouseover', this.enter ,this);
25534 Roo.get(document).on('mouseout', this.leave, this);
25537 this.currentTip = new Roo.bootstrap.Tooltip();
25540 enter : function(ev)
25542 var dom = ev.getTarget();
25544 //Roo.log(['enter',dom]);
25545 var el = Roo.fly(dom);
25546 if (this.currentEl) {
25548 //Roo.log(this.currentEl);
25549 //Roo.log(this.currentEl.contains(dom));
25550 if (this.currentEl == el) {
25553 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25559 if (this.currentTip.el) {
25560 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25564 if(!el || el.dom == document){
25570 // you can not look for children, as if el is the body.. then everythign is the child..
25571 if (!el.attr('tooltip')) { //
25572 if (!el.select("[tooltip]").elements.length) {
25575 // is the mouse over this child...?
25576 bindEl = el.select("[tooltip]").first();
25577 var xy = ev.getXY();
25578 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25579 //Roo.log("not in region.");
25582 //Roo.log("child element over..");
25585 this.currentEl = bindEl;
25586 this.currentTip.bind(bindEl);
25587 this.currentRegion = Roo.lib.Region.getRegion(dom);
25588 this.currentTip.enter();
25591 leave : function(ev)
25593 var dom = ev.getTarget();
25594 //Roo.log(['leave',dom]);
25595 if (!this.currentEl) {
25600 if (dom != this.currentEl.dom) {
25603 var xy = ev.getXY();
25604 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25607 // only activate leave if mouse cursor is outside... bounding box..
25612 if (this.currentTip) {
25613 this.currentTip.leave();
25615 //Roo.log('clear currentEl');
25616 this.currentEl = false;
25621 'left' : ['r-l', [-2,0], 'right'],
25622 'right' : ['l-r', [2,0], 'left'],
25623 'bottom' : ['t-b', [0,2], 'top'],
25624 'top' : [ 'b-t', [0,-2], 'bottom']
25630 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25635 delay : null, // can be { show : 300 , hide: 500}
25639 hoverState : null, //???
25641 placement : 'bottom',
25645 getAutoCreate : function(){
25652 cls : 'tooltip-arrow'
25655 cls : 'tooltip-inner'
25662 bind : function(el)
25668 enter : function () {
25670 if (this.timeout != null) {
25671 clearTimeout(this.timeout);
25674 this.hoverState = 'in';
25675 //Roo.log("enter - show");
25676 if (!this.delay || !this.delay.show) {
25681 this.timeout = setTimeout(function () {
25682 if (_t.hoverState == 'in') {
25685 }, this.delay.show);
25689 clearTimeout(this.timeout);
25691 this.hoverState = 'out';
25692 if (!this.delay || !this.delay.hide) {
25698 this.timeout = setTimeout(function () {
25699 //Roo.log("leave - timeout");
25701 if (_t.hoverState == 'out') {
25703 Roo.bootstrap.Tooltip.currentEl = false;
25708 show : function (msg)
25711 this.render(document.body);
25714 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25716 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25718 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25720 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25722 var placement = typeof this.placement == 'function' ?
25723 this.placement.call(this, this.el, on_el) :
25726 var autoToken = /\s?auto?\s?/i;
25727 var autoPlace = autoToken.test(placement);
25729 placement = placement.replace(autoToken, '') || 'top';
25733 //this.el.setXY([0,0]);
25735 //this.el.dom.style.display='block';
25737 //this.el.appendTo(on_el);
25739 var p = this.getPosition();
25740 var box = this.el.getBox();
25746 var align = this.alignment[placement];
25748 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25750 if(placement == 'top' || placement == 'bottom'){
25752 placement = 'right';
25755 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25756 placement = 'left';
25759 var scroll = Roo.select('body', true).first().getScroll();
25761 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25767 this.el.alignTo(this.bindEl, align[0],align[1]);
25768 //var arrow = this.el.select('.arrow',true).first();
25769 //arrow.set(align[2],
25771 this.el.addClass(placement);
25773 this.el.addClass('in fade');
25775 this.hoverState = null;
25777 if (this.el.hasClass('fade')) {
25788 //this.el.setXY([0,0]);
25789 this.el.removeClass('in');
25805 * @class Roo.bootstrap.LocationPicker
25806 * @extends Roo.bootstrap.Component
25807 * Bootstrap LocationPicker class
25808 * @cfg {Number} latitude Position when init default 0
25809 * @cfg {Number} longitude Position when init default 0
25810 * @cfg {Number} zoom default 15
25811 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25812 * @cfg {Boolean} mapTypeControl default false
25813 * @cfg {Boolean} disableDoubleClickZoom default false
25814 * @cfg {Boolean} scrollwheel default true
25815 * @cfg {Boolean} streetViewControl default false
25816 * @cfg {Number} radius default 0
25817 * @cfg {String} locationName
25818 * @cfg {Boolean} draggable default true
25819 * @cfg {Boolean} enableAutocomplete default false
25820 * @cfg {Boolean} enableReverseGeocode default true
25821 * @cfg {String} markerTitle
25824 * Create a new LocationPicker
25825 * @param {Object} config The config object
25829 Roo.bootstrap.LocationPicker = function(config){
25831 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25836 * Fires when the picker initialized.
25837 * @param {Roo.bootstrap.LocationPicker} this
25838 * @param {Google Location} location
25842 * @event positionchanged
25843 * Fires when the picker position changed.
25844 * @param {Roo.bootstrap.LocationPicker} this
25845 * @param {Google Location} location
25847 positionchanged : true,
25850 * Fires when the map resize.
25851 * @param {Roo.bootstrap.LocationPicker} this
25856 * Fires when the map show.
25857 * @param {Roo.bootstrap.LocationPicker} this
25862 * Fires when the map hide.
25863 * @param {Roo.bootstrap.LocationPicker} this
25868 * Fires when click the map.
25869 * @param {Roo.bootstrap.LocationPicker} this
25870 * @param {Map event} e
25874 * @event mapRightClick
25875 * Fires when right click the map.
25876 * @param {Roo.bootstrap.LocationPicker} this
25877 * @param {Map event} e
25879 mapRightClick : true,
25881 * @event markerClick
25882 * Fires when click the marker.
25883 * @param {Roo.bootstrap.LocationPicker} this
25884 * @param {Map event} e
25886 markerClick : true,
25888 * @event markerRightClick
25889 * Fires when right click the marker.
25890 * @param {Roo.bootstrap.LocationPicker} this
25891 * @param {Map event} e
25893 markerRightClick : true,
25895 * @event OverlayViewDraw
25896 * Fires when OverlayView Draw
25897 * @param {Roo.bootstrap.LocationPicker} this
25899 OverlayViewDraw : true,
25901 * @event OverlayViewOnAdd
25902 * Fires when OverlayView Draw
25903 * @param {Roo.bootstrap.LocationPicker} this
25905 OverlayViewOnAdd : true,
25907 * @event OverlayViewOnRemove
25908 * Fires when OverlayView Draw
25909 * @param {Roo.bootstrap.LocationPicker} this
25911 OverlayViewOnRemove : true,
25913 * @event OverlayViewShow
25914 * Fires when OverlayView Draw
25915 * @param {Roo.bootstrap.LocationPicker} this
25916 * @param {Pixel} cpx
25918 OverlayViewShow : true,
25920 * @event OverlayViewHide
25921 * Fires when OverlayView Draw
25922 * @param {Roo.bootstrap.LocationPicker} this
25924 OverlayViewHide : true,
25926 * @event loadexception
25927 * Fires when load google lib failed.
25928 * @param {Roo.bootstrap.LocationPicker} this
25930 loadexception : true
25935 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25937 gMapContext: false,
25943 mapTypeControl: false,
25944 disableDoubleClickZoom: false,
25946 streetViewControl: false,
25950 enableAutocomplete: false,
25951 enableReverseGeocode: true,
25954 getAutoCreate: function()
25959 cls: 'roo-location-picker'
25965 initEvents: function(ct, position)
25967 if(!this.el.getWidth() || this.isApplied()){
25971 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25976 initial: function()
25978 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25979 this.fireEvent('loadexception', this);
25983 if(!this.mapTypeId){
25984 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25987 this.gMapContext = this.GMapContext();
25989 this.initOverlayView();
25991 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25995 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25996 _this.setPosition(_this.gMapContext.marker.position);
25999 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26000 _this.fireEvent('mapClick', this, event);
26004 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26005 _this.fireEvent('mapRightClick', this, event);
26009 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26010 _this.fireEvent('markerClick', this, event);
26014 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26015 _this.fireEvent('markerRightClick', this, event);
26019 this.setPosition(this.gMapContext.location);
26021 this.fireEvent('initial', this, this.gMapContext.location);
26024 initOverlayView: function()
26028 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26032 _this.fireEvent('OverlayViewDraw', _this);
26037 _this.fireEvent('OverlayViewOnAdd', _this);
26040 onRemove: function()
26042 _this.fireEvent('OverlayViewOnRemove', _this);
26045 show: function(cpx)
26047 _this.fireEvent('OverlayViewShow', _this, cpx);
26052 _this.fireEvent('OverlayViewHide', _this);
26058 fromLatLngToContainerPixel: function(event)
26060 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26063 isApplied: function()
26065 return this.getGmapContext() == false ? false : true;
26068 getGmapContext: function()
26070 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26073 GMapContext: function()
26075 var position = new google.maps.LatLng(this.latitude, this.longitude);
26077 var _map = new google.maps.Map(this.el.dom, {
26080 mapTypeId: this.mapTypeId,
26081 mapTypeControl: this.mapTypeControl,
26082 disableDoubleClickZoom: this.disableDoubleClickZoom,
26083 scrollwheel: this.scrollwheel,
26084 streetViewControl: this.streetViewControl,
26085 locationName: this.locationName,
26086 draggable: this.draggable,
26087 enableAutocomplete: this.enableAutocomplete,
26088 enableReverseGeocode: this.enableReverseGeocode
26091 var _marker = new google.maps.Marker({
26092 position: position,
26094 title: this.markerTitle,
26095 draggable: this.draggable
26102 location: position,
26103 radius: this.radius,
26104 locationName: this.locationName,
26105 addressComponents: {
26106 formatted_address: null,
26107 addressLine1: null,
26108 addressLine2: null,
26110 streetNumber: null,
26114 stateOrProvince: null
26117 domContainer: this.el.dom,
26118 geodecoder: new google.maps.Geocoder()
26122 drawCircle: function(center, radius, options)
26124 if (this.gMapContext.circle != null) {
26125 this.gMapContext.circle.setMap(null);
26129 options = Roo.apply({}, options, {
26130 strokeColor: "#0000FF",
26131 strokeOpacity: .35,
26133 fillColor: "#0000FF",
26137 options.map = this.gMapContext.map;
26138 options.radius = radius;
26139 options.center = center;
26140 this.gMapContext.circle = new google.maps.Circle(options);
26141 return this.gMapContext.circle;
26147 setPosition: function(location)
26149 this.gMapContext.location = location;
26150 this.gMapContext.marker.setPosition(location);
26151 this.gMapContext.map.panTo(location);
26152 this.drawCircle(location, this.gMapContext.radius, {});
26156 if (this.gMapContext.settings.enableReverseGeocode) {
26157 this.gMapContext.geodecoder.geocode({
26158 latLng: this.gMapContext.location
26159 }, function(results, status) {
26161 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26162 _this.gMapContext.locationName = results[0].formatted_address;
26163 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26165 _this.fireEvent('positionchanged', this, location);
26172 this.fireEvent('positionchanged', this, location);
26177 google.maps.event.trigger(this.gMapContext.map, "resize");
26179 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26181 this.fireEvent('resize', this);
26184 setPositionByLatLng: function(latitude, longitude)
26186 this.setPosition(new google.maps.LatLng(latitude, longitude));
26189 getCurrentPosition: function()
26192 latitude: this.gMapContext.location.lat(),
26193 longitude: this.gMapContext.location.lng()
26197 getAddressName: function()
26199 return this.gMapContext.locationName;
26202 getAddressComponents: function()
26204 return this.gMapContext.addressComponents;
26207 address_component_from_google_geocode: function(address_components)
26211 for (var i = 0; i < address_components.length; i++) {
26212 var component = address_components[i];
26213 if (component.types.indexOf("postal_code") >= 0) {
26214 result.postalCode = component.short_name;
26215 } else if (component.types.indexOf("street_number") >= 0) {
26216 result.streetNumber = component.short_name;
26217 } else if (component.types.indexOf("route") >= 0) {
26218 result.streetName = component.short_name;
26219 } else if (component.types.indexOf("neighborhood") >= 0) {
26220 result.city = component.short_name;
26221 } else if (component.types.indexOf("locality") >= 0) {
26222 result.city = component.short_name;
26223 } else if (component.types.indexOf("sublocality") >= 0) {
26224 result.district = component.short_name;
26225 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26226 result.stateOrProvince = component.short_name;
26227 } else if (component.types.indexOf("country") >= 0) {
26228 result.country = component.short_name;
26232 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26233 result.addressLine2 = "";
26237 setZoomLevel: function(zoom)
26239 this.gMapContext.map.setZoom(zoom);
26252 this.fireEvent('show', this);
26263 this.fireEvent('hide', this);
26268 Roo.apply(Roo.bootstrap.LocationPicker, {
26270 OverlayView : function(map, options)
26272 options = options || {};
26286 * @class Roo.bootstrap.Alert
26287 * @extends Roo.bootstrap.Component
26288 * Bootstrap Alert class
26289 * @cfg {String} title The title of alert
26290 * @cfg {String} html The content of alert
26291 * @cfg {String} weight ( success | info | warning | danger )
26292 * @cfg {String} faicon font-awesomeicon
26295 * Create a new alert
26296 * @param {Object} config The config object
26300 Roo.bootstrap.Alert = function(config){
26301 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26305 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26312 getAutoCreate : function()
26321 cls : 'roo-alert-icon'
26326 cls : 'roo-alert-title',
26331 cls : 'roo-alert-text',
26338 cfg.cn[0].cls += ' fa ' + this.faicon;
26342 cfg.cls += ' alert-' + this.weight;
26348 initEvents: function()
26350 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26353 setTitle : function(str)
26355 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26358 setText : function(str)
26360 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26363 setWeight : function(weight)
26366 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26369 this.weight = weight;
26371 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26374 setIcon : function(icon)
26377 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26380 this.faicon = icon;
26382 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26403 * @class Roo.bootstrap.UploadCropbox
26404 * @extends Roo.bootstrap.Component
26405 * Bootstrap UploadCropbox class
26406 * @cfg {String} emptyText show when image has been loaded
26407 * @cfg {String} rotateNotify show when image too small to rotate
26408 * @cfg {Number} errorTimeout default 3000
26409 * @cfg {Number} minWidth default 300
26410 * @cfg {Number} minHeight default 300
26411 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26412 * @cfg {Boolean} isDocument (true|false) default false
26413 * @cfg {String} url action url
26414 * @cfg {String} paramName default 'imageUpload'
26415 * @cfg {String} method default POST
26416 * @cfg {Boolean} loadMask (true|false) default true
26417 * @cfg {Boolean} loadingText default 'Loading...'
26420 * Create a new UploadCropbox
26421 * @param {Object} config The config object
26424 Roo.bootstrap.UploadCropbox = function(config){
26425 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26429 * @event beforeselectfile
26430 * Fire before select file
26431 * @param {Roo.bootstrap.UploadCropbox} this
26433 "beforeselectfile" : true,
26436 * Fire after initEvent
26437 * @param {Roo.bootstrap.UploadCropbox} this
26442 * Fire after initEvent
26443 * @param {Roo.bootstrap.UploadCropbox} this
26444 * @param {String} data
26449 * Fire when preparing the file data
26450 * @param {Roo.bootstrap.UploadCropbox} this
26451 * @param {Object} file
26456 * Fire when get exception
26457 * @param {Roo.bootstrap.UploadCropbox} this
26458 * @param {XMLHttpRequest} xhr
26460 "exception" : true,
26462 * @event beforeloadcanvas
26463 * Fire before load the canvas
26464 * @param {Roo.bootstrap.UploadCropbox} this
26465 * @param {String} src
26467 "beforeloadcanvas" : true,
26470 * Fire when trash image
26471 * @param {Roo.bootstrap.UploadCropbox} this
26476 * Fire when download the image
26477 * @param {Roo.bootstrap.UploadCropbox} this
26481 * @event footerbuttonclick
26482 * Fire when footerbuttonclick
26483 * @param {Roo.bootstrap.UploadCropbox} this
26484 * @param {String} type
26486 "footerbuttonclick" : true,
26490 * @param {Roo.bootstrap.UploadCropbox} this
26495 * Fire when rotate the image
26496 * @param {Roo.bootstrap.UploadCropbox} this
26497 * @param {String} pos
26502 * Fire when inspect the file
26503 * @param {Roo.bootstrap.UploadCropbox} this
26504 * @param {Object} file
26509 * Fire when xhr upload the file
26510 * @param {Roo.bootstrap.UploadCropbox} this
26511 * @param {Object} data
26516 * Fire when arrange the file data
26517 * @param {Roo.bootstrap.UploadCropbox} this
26518 * @param {Object} formData
26523 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26526 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26528 emptyText : 'Click to upload image',
26529 rotateNotify : 'Image is too small to rotate',
26530 errorTimeout : 3000,
26544 cropType : 'image/jpeg',
26546 canvasLoaded : false,
26547 isDocument : false,
26549 paramName : 'imageUpload',
26551 loadingText : 'Loading...',
26554 getAutoCreate : function()
26558 cls : 'roo-upload-cropbox',
26562 cls : 'roo-upload-cropbox-selector',
26567 cls : 'roo-upload-cropbox-body',
26568 style : 'cursor:pointer',
26572 cls : 'roo-upload-cropbox-preview'
26576 cls : 'roo-upload-cropbox-thumb'
26580 cls : 'roo-upload-cropbox-empty-notify',
26581 html : this.emptyText
26585 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26586 html : this.rotateNotify
26592 cls : 'roo-upload-cropbox-footer',
26595 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26605 onRender : function(ct, position)
26607 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26609 if (this.buttons.length) {
26611 Roo.each(this.buttons, function(bb) {
26613 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26615 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26621 this.maskEl = this.el;
26625 initEvents : function()
26627 this.urlAPI = (window.createObjectURL && window) ||
26628 (window.URL && URL.revokeObjectURL && URL) ||
26629 (window.webkitURL && webkitURL);
26631 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26632 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26634 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26635 this.selectorEl.hide();
26637 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26638 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26640 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26641 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26642 this.thumbEl.hide();
26644 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26645 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26647 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26648 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26649 this.errorEl.hide();
26651 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26652 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26653 this.footerEl.hide();
26655 this.setThumbBoxSize();
26661 this.fireEvent('initial', this);
26668 window.addEventListener("resize", function() { _this.resize(); } );
26670 this.bodyEl.on('click', this.beforeSelectFile, this);
26673 this.bodyEl.on('touchstart', this.onTouchStart, this);
26674 this.bodyEl.on('touchmove', this.onTouchMove, this);
26675 this.bodyEl.on('touchend', this.onTouchEnd, this);
26679 this.bodyEl.on('mousedown', this.onMouseDown, this);
26680 this.bodyEl.on('mousemove', this.onMouseMove, this);
26681 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26682 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26683 Roo.get(document).on('mouseup', this.onMouseUp, this);
26686 this.selectorEl.on('change', this.onFileSelected, this);
26692 this.baseScale = 1;
26694 this.baseRotate = 1;
26695 this.dragable = false;
26696 this.pinching = false;
26699 this.cropData = false;
26700 this.notifyEl.dom.innerHTML = this.emptyText;
26702 this.selectorEl.dom.value = '';
26706 resize : function()
26708 if(this.fireEvent('resize', this) != false){
26709 this.setThumbBoxPosition();
26710 this.setCanvasPosition();
26714 onFooterButtonClick : function(e, el, o, type)
26717 case 'rotate-left' :
26718 this.onRotateLeft(e);
26720 case 'rotate-right' :
26721 this.onRotateRight(e);
26724 this.beforeSelectFile(e);
26739 this.fireEvent('footerbuttonclick', this, type);
26742 beforeSelectFile : function(e)
26744 e.preventDefault();
26746 if(this.fireEvent('beforeselectfile', this) != false){
26747 this.selectorEl.dom.click();
26751 onFileSelected : function(e)
26753 e.preventDefault();
26755 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26759 var file = this.selectorEl.dom.files[0];
26761 if(this.fireEvent('inspect', this, file) != false){
26762 this.prepare(file);
26767 trash : function(e)
26769 this.fireEvent('trash', this);
26772 download : function(e)
26774 this.fireEvent('download', this);
26777 loadCanvas : function(src)
26779 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26783 this.imageEl = document.createElement('img');
26787 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26789 this.imageEl.src = src;
26793 onLoadCanvas : function()
26795 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26796 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26798 this.bodyEl.un('click', this.beforeSelectFile, this);
26800 this.notifyEl.hide();
26801 this.thumbEl.show();
26802 this.footerEl.show();
26804 this.baseRotateLevel();
26806 if(this.isDocument){
26807 this.setThumbBoxSize();
26810 this.setThumbBoxPosition();
26812 this.baseScaleLevel();
26818 this.canvasLoaded = true;
26821 this.maskEl.unmask();
26826 setCanvasPosition : function()
26828 if(!this.canvasEl){
26832 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26833 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26835 this.previewEl.setLeft(pw);
26836 this.previewEl.setTop(ph);
26840 onMouseDown : function(e)
26844 this.dragable = true;
26845 this.pinching = false;
26847 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26848 this.dragable = false;
26852 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26853 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26857 onMouseMove : function(e)
26861 if(!this.canvasLoaded){
26865 if (!this.dragable){
26869 var minX = Math.ceil(this.thumbEl.getLeft(true));
26870 var minY = Math.ceil(this.thumbEl.getTop(true));
26872 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26873 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26875 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26876 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26878 x = x - this.mouseX;
26879 y = y - this.mouseY;
26881 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26882 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26884 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26885 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26887 this.previewEl.setLeft(bgX);
26888 this.previewEl.setTop(bgY);
26890 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26891 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26894 onMouseUp : function(e)
26898 this.dragable = false;
26901 onMouseWheel : function(e)
26905 this.startScale = this.scale;
26907 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26909 if(!this.zoomable()){
26910 this.scale = this.startScale;
26919 zoomable : function()
26921 var minScale = this.thumbEl.getWidth() / this.minWidth;
26923 if(this.minWidth < this.minHeight){
26924 minScale = this.thumbEl.getHeight() / this.minHeight;
26927 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26928 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26932 (this.rotate == 0 || this.rotate == 180) &&
26934 width > this.imageEl.OriginWidth ||
26935 height > this.imageEl.OriginHeight ||
26936 (width < this.minWidth && height < this.minHeight)
26944 (this.rotate == 90 || this.rotate == 270) &&
26946 width > this.imageEl.OriginWidth ||
26947 height > this.imageEl.OriginHeight ||
26948 (width < this.minHeight && height < this.minWidth)
26955 !this.isDocument &&
26956 (this.rotate == 0 || this.rotate == 180) &&
26958 width < this.minWidth ||
26959 width > this.imageEl.OriginWidth ||
26960 height < this.minHeight ||
26961 height > this.imageEl.OriginHeight
26968 !this.isDocument &&
26969 (this.rotate == 90 || this.rotate == 270) &&
26971 width < this.minHeight ||
26972 width > this.imageEl.OriginWidth ||
26973 height < this.minWidth ||
26974 height > this.imageEl.OriginHeight
26984 onRotateLeft : function(e)
26986 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26988 var minScale = this.thumbEl.getWidth() / this.minWidth;
26990 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26991 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26993 this.startScale = this.scale;
26995 while (this.getScaleLevel() < minScale){
26997 this.scale = this.scale + 1;
26999 if(!this.zoomable()){
27004 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27005 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27010 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27017 this.scale = this.startScale;
27019 this.onRotateFail();
27024 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27026 if(this.isDocument){
27027 this.setThumbBoxSize();
27028 this.setThumbBoxPosition();
27029 this.setCanvasPosition();
27034 this.fireEvent('rotate', this, 'left');
27038 onRotateRight : function(e)
27040 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27042 var minScale = this.thumbEl.getWidth() / this.minWidth;
27044 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27045 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27047 this.startScale = this.scale;
27049 while (this.getScaleLevel() < minScale){
27051 this.scale = this.scale + 1;
27053 if(!this.zoomable()){
27058 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27059 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27064 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27071 this.scale = this.startScale;
27073 this.onRotateFail();
27078 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27080 if(this.isDocument){
27081 this.setThumbBoxSize();
27082 this.setThumbBoxPosition();
27083 this.setCanvasPosition();
27088 this.fireEvent('rotate', this, 'right');
27091 onRotateFail : function()
27093 this.errorEl.show(true);
27097 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27102 this.previewEl.dom.innerHTML = '';
27104 var canvasEl = document.createElement("canvas");
27106 var contextEl = canvasEl.getContext("2d");
27108 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27109 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27110 var center = this.imageEl.OriginWidth / 2;
27112 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27113 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27114 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27115 center = this.imageEl.OriginHeight / 2;
27118 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27120 contextEl.translate(center, center);
27121 contextEl.rotate(this.rotate * Math.PI / 180);
27123 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27125 this.canvasEl = document.createElement("canvas");
27127 this.contextEl = this.canvasEl.getContext("2d");
27129 switch (this.rotate) {
27132 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27133 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27135 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27140 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27141 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27143 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27144 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27148 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27153 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27154 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27156 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27157 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);
27161 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);
27166 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27167 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27169 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27170 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27174 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);
27181 this.previewEl.appendChild(this.canvasEl);
27183 this.setCanvasPosition();
27188 if(!this.canvasLoaded){
27192 var imageCanvas = document.createElement("canvas");
27194 var imageContext = imageCanvas.getContext("2d");
27196 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27197 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27199 var center = imageCanvas.width / 2;
27201 imageContext.translate(center, center);
27203 imageContext.rotate(this.rotate * Math.PI / 180);
27205 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27207 var canvas = document.createElement("canvas");
27209 var context = canvas.getContext("2d");
27211 canvas.width = this.minWidth;
27212 canvas.height = this.minHeight;
27214 switch (this.rotate) {
27217 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27218 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27220 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27221 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27223 var targetWidth = this.minWidth - 2 * x;
27224 var targetHeight = this.minHeight - 2 * y;
27228 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27229 scale = targetWidth / width;
27232 if(x > 0 && y == 0){
27233 scale = targetHeight / height;
27236 if(x > 0 && y > 0){
27237 scale = targetWidth / width;
27239 if(width < height){
27240 scale = targetHeight / height;
27244 context.scale(scale, scale);
27246 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27247 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27249 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27250 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27252 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27257 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27258 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27260 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27261 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27263 var targetWidth = this.minWidth - 2 * x;
27264 var targetHeight = this.minHeight - 2 * y;
27268 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27269 scale = targetWidth / width;
27272 if(x > 0 && y == 0){
27273 scale = targetHeight / height;
27276 if(x > 0 && y > 0){
27277 scale = targetWidth / width;
27279 if(width < height){
27280 scale = targetHeight / height;
27284 context.scale(scale, scale);
27286 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27287 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27289 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27290 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27292 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27294 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27299 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27300 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27302 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27303 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27305 var targetWidth = this.minWidth - 2 * x;
27306 var targetHeight = this.minHeight - 2 * y;
27310 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27311 scale = targetWidth / width;
27314 if(x > 0 && y == 0){
27315 scale = targetHeight / height;
27318 if(x > 0 && y > 0){
27319 scale = targetWidth / width;
27321 if(width < height){
27322 scale = targetHeight / height;
27326 context.scale(scale, scale);
27328 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27329 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27331 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27332 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27334 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27335 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27337 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27342 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27343 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27345 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27346 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27348 var targetWidth = this.minWidth - 2 * x;
27349 var targetHeight = this.minHeight - 2 * y;
27353 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27354 scale = targetWidth / width;
27357 if(x > 0 && y == 0){
27358 scale = targetHeight / height;
27361 if(x > 0 && y > 0){
27362 scale = targetWidth / width;
27364 if(width < height){
27365 scale = targetHeight / height;
27369 context.scale(scale, scale);
27371 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27372 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27374 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27375 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27377 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27379 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27386 this.cropData = canvas.toDataURL(this.cropType);
27388 if(this.fireEvent('crop', this, this.cropData) !== false){
27389 this.process(this.file, this.cropData);
27396 setThumbBoxSize : function()
27400 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27401 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27402 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27404 this.minWidth = width;
27405 this.minHeight = height;
27407 if(this.rotate == 90 || this.rotate == 270){
27408 this.minWidth = height;
27409 this.minHeight = width;
27414 width = Math.ceil(this.minWidth * height / this.minHeight);
27416 if(this.minWidth > this.minHeight){
27418 height = Math.ceil(this.minHeight * width / this.minWidth);
27421 this.thumbEl.setStyle({
27422 width : width + 'px',
27423 height : height + 'px'
27430 setThumbBoxPosition : function()
27432 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27433 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27435 this.thumbEl.setLeft(x);
27436 this.thumbEl.setTop(y);
27440 baseRotateLevel : function()
27442 this.baseRotate = 1;
27445 typeof(this.exif) != 'undefined' &&
27446 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27447 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27449 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27452 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27456 baseScaleLevel : function()
27460 if(this.isDocument){
27462 if(this.baseRotate == 6 || this.baseRotate == 8){
27464 height = this.thumbEl.getHeight();
27465 this.baseScale = height / this.imageEl.OriginWidth;
27467 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27468 width = this.thumbEl.getWidth();
27469 this.baseScale = width / this.imageEl.OriginHeight;
27475 height = this.thumbEl.getHeight();
27476 this.baseScale = height / this.imageEl.OriginHeight;
27478 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27479 width = this.thumbEl.getWidth();
27480 this.baseScale = width / this.imageEl.OriginWidth;
27486 if(this.baseRotate == 6 || this.baseRotate == 8){
27488 width = this.thumbEl.getHeight();
27489 this.baseScale = width / this.imageEl.OriginHeight;
27491 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27492 height = this.thumbEl.getWidth();
27493 this.baseScale = height / this.imageEl.OriginHeight;
27496 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27497 height = this.thumbEl.getWidth();
27498 this.baseScale = height / this.imageEl.OriginHeight;
27500 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27501 width = this.thumbEl.getHeight();
27502 this.baseScale = width / this.imageEl.OriginWidth;
27509 width = this.thumbEl.getWidth();
27510 this.baseScale = width / this.imageEl.OriginWidth;
27512 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27513 height = this.thumbEl.getHeight();
27514 this.baseScale = height / this.imageEl.OriginHeight;
27517 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27519 height = this.thumbEl.getHeight();
27520 this.baseScale = height / this.imageEl.OriginHeight;
27522 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27523 width = this.thumbEl.getWidth();
27524 this.baseScale = width / this.imageEl.OriginWidth;
27532 getScaleLevel : function()
27534 return this.baseScale * Math.pow(1.1, this.scale);
27537 onTouchStart : function(e)
27539 if(!this.canvasLoaded){
27540 this.beforeSelectFile(e);
27544 var touches = e.browserEvent.touches;
27550 if(touches.length == 1){
27551 this.onMouseDown(e);
27555 if(touches.length != 2){
27561 for(var i = 0, finger; finger = touches[i]; i++){
27562 coords.push(finger.pageX, finger.pageY);
27565 var x = Math.pow(coords[0] - coords[2], 2);
27566 var y = Math.pow(coords[1] - coords[3], 2);
27568 this.startDistance = Math.sqrt(x + y);
27570 this.startScale = this.scale;
27572 this.pinching = true;
27573 this.dragable = false;
27577 onTouchMove : function(e)
27579 if(!this.pinching && !this.dragable){
27583 var touches = e.browserEvent.touches;
27590 this.onMouseMove(e);
27596 for(var i = 0, finger; finger = touches[i]; i++){
27597 coords.push(finger.pageX, finger.pageY);
27600 var x = Math.pow(coords[0] - coords[2], 2);
27601 var y = Math.pow(coords[1] - coords[3], 2);
27603 this.endDistance = Math.sqrt(x + y);
27605 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27607 if(!this.zoomable()){
27608 this.scale = this.startScale;
27616 onTouchEnd : function(e)
27618 this.pinching = false;
27619 this.dragable = false;
27623 process : function(file, crop)
27626 this.maskEl.mask(this.loadingText);
27629 this.xhr = new XMLHttpRequest();
27631 file.xhr = this.xhr;
27633 this.xhr.open(this.method, this.url, true);
27636 "Accept": "application/json",
27637 "Cache-Control": "no-cache",
27638 "X-Requested-With": "XMLHttpRequest"
27641 for (var headerName in headers) {
27642 var headerValue = headers[headerName];
27644 this.xhr.setRequestHeader(headerName, headerValue);
27650 this.xhr.onload = function()
27652 _this.xhrOnLoad(_this.xhr);
27655 this.xhr.onerror = function()
27657 _this.xhrOnError(_this.xhr);
27660 var formData = new FormData();
27662 formData.append('returnHTML', 'NO');
27665 formData.append('crop', crop);
27668 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27669 formData.append(this.paramName, file, file.name);
27672 if(typeof(file.filename) != 'undefined'){
27673 formData.append('filename', file.filename);
27676 if(typeof(file.mimetype) != 'undefined'){
27677 formData.append('mimetype', file.mimetype);
27680 if(this.fireEvent('arrange', this, formData) != false){
27681 this.xhr.send(formData);
27685 xhrOnLoad : function(xhr)
27688 this.maskEl.unmask();
27691 if (xhr.readyState !== 4) {
27692 this.fireEvent('exception', this, xhr);
27696 var response = Roo.decode(xhr.responseText);
27698 if(!response.success){
27699 this.fireEvent('exception', this, xhr);
27703 var response = Roo.decode(xhr.responseText);
27705 this.fireEvent('upload', this, response);
27709 xhrOnError : function()
27712 this.maskEl.unmask();
27715 Roo.log('xhr on error');
27717 var response = Roo.decode(xhr.responseText);
27723 prepare : function(file)
27726 this.maskEl.mask(this.loadingText);
27732 if(typeof(file) === 'string'){
27733 this.loadCanvas(file);
27737 if(!file || !this.urlAPI){
27742 this.cropType = file.type;
27746 if(this.fireEvent('prepare', this, this.file) != false){
27748 var reader = new FileReader();
27750 reader.onload = function (e) {
27751 if (e.target.error) {
27752 Roo.log(e.target.error);
27756 var buffer = e.target.result,
27757 dataView = new DataView(buffer),
27759 maxOffset = dataView.byteLength - 4,
27763 if (dataView.getUint16(0) === 0xffd8) {
27764 while (offset < maxOffset) {
27765 markerBytes = dataView.getUint16(offset);
27767 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27768 markerLength = dataView.getUint16(offset + 2) + 2;
27769 if (offset + markerLength > dataView.byteLength) {
27770 Roo.log('Invalid meta data: Invalid segment size.');
27774 if(markerBytes == 0xffe1){
27775 _this.parseExifData(
27782 offset += markerLength;
27792 var url = _this.urlAPI.createObjectURL(_this.file);
27794 _this.loadCanvas(url);
27799 reader.readAsArrayBuffer(this.file);
27805 parseExifData : function(dataView, offset, length)
27807 var tiffOffset = offset + 10,
27811 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27812 // No Exif data, might be XMP data instead
27816 // Check for the ASCII code for "Exif" (0x45786966):
27817 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27818 // No Exif data, might be XMP data instead
27821 if (tiffOffset + 8 > dataView.byteLength) {
27822 Roo.log('Invalid Exif data: Invalid segment size.');
27825 // Check for the two null bytes:
27826 if (dataView.getUint16(offset + 8) !== 0x0000) {
27827 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27830 // Check the byte alignment:
27831 switch (dataView.getUint16(tiffOffset)) {
27833 littleEndian = true;
27836 littleEndian = false;
27839 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27842 // Check for the TIFF tag marker (0x002A):
27843 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27844 Roo.log('Invalid Exif data: Missing TIFF marker.');
27847 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27848 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27850 this.parseExifTags(
27853 tiffOffset + dirOffset,
27858 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27863 if (dirOffset + 6 > dataView.byteLength) {
27864 Roo.log('Invalid Exif data: Invalid directory offset.');
27867 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27868 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27869 if (dirEndOffset + 4 > dataView.byteLength) {
27870 Roo.log('Invalid Exif data: Invalid directory size.');
27873 for (i = 0; i < tagsNumber; i += 1) {
27877 dirOffset + 2 + 12 * i, // tag offset
27881 // Return the offset to the next directory:
27882 return dataView.getUint32(dirEndOffset, littleEndian);
27885 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27887 var tag = dataView.getUint16(offset, littleEndian);
27889 this.exif[tag] = this.getExifValue(
27893 dataView.getUint16(offset + 2, littleEndian), // tag type
27894 dataView.getUint32(offset + 4, littleEndian), // tag length
27899 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27901 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27910 Roo.log('Invalid Exif data: Invalid tag type.');
27914 tagSize = tagType.size * length;
27915 // Determine if the value is contained in the dataOffset bytes,
27916 // or if the value at the dataOffset is a pointer to the actual data:
27917 dataOffset = tagSize > 4 ?
27918 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27919 if (dataOffset + tagSize > dataView.byteLength) {
27920 Roo.log('Invalid Exif data: Invalid data offset.');
27923 if (length === 1) {
27924 return tagType.getValue(dataView, dataOffset, littleEndian);
27927 for (i = 0; i < length; i += 1) {
27928 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27931 if (tagType.ascii) {
27933 // Concatenate the chars:
27934 for (i = 0; i < values.length; i += 1) {
27936 // Ignore the terminating NULL byte(s):
27937 if (c === '\u0000') {
27949 Roo.apply(Roo.bootstrap.UploadCropbox, {
27951 'Orientation': 0x0112
27955 1: 0, //'top-left',
27957 3: 180, //'bottom-right',
27958 // 4: 'bottom-left',
27960 6: 90, //'right-top',
27961 // 7: 'right-bottom',
27962 8: 270 //'left-bottom'
27966 // byte, 8-bit unsigned int:
27968 getValue: function (dataView, dataOffset) {
27969 return dataView.getUint8(dataOffset);
27973 // ascii, 8-bit byte:
27975 getValue: function (dataView, dataOffset) {
27976 return String.fromCharCode(dataView.getUint8(dataOffset));
27981 // short, 16 bit int:
27983 getValue: function (dataView, dataOffset, littleEndian) {
27984 return dataView.getUint16(dataOffset, littleEndian);
27988 // long, 32 bit int:
27990 getValue: function (dataView, dataOffset, littleEndian) {
27991 return dataView.getUint32(dataOffset, littleEndian);
27995 // rational = two long values, first is numerator, second is denominator:
27997 getValue: function (dataView, dataOffset, littleEndian) {
27998 return dataView.getUint32(dataOffset, littleEndian) /
27999 dataView.getUint32(dataOffset + 4, littleEndian);
28003 // slong, 32 bit signed int:
28005 getValue: function (dataView, dataOffset, littleEndian) {
28006 return dataView.getInt32(dataOffset, littleEndian);
28010 // srational, two slongs, first is numerator, second is denominator:
28012 getValue: function (dataView, dataOffset, littleEndian) {
28013 return dataView.getInt32(dataOffset, littleEndian) /
28014 dataView.getInt32(dataOffset + 4, littleEndian);
28024 cls : 'btn-group roo-upload-cropbox-rotate-left',
28025 action : 'rotate-left',
28029 cls : 'btn btn-default',
28030 html : '<i class="fa fa-undo"></i>'
28036 cls : 'btn-group roo-upload-cropbox-picture',
28037 action : 'picture',
28041 cls : 'btn btn-default',
28042 html : '<i class="fa fa-picture-o"></i>'
28048 cls : 'btn-group roo-upload-cropbox-rotate-right',
28049 action : 'rotate-right',
28053 cls : 'btn btn-default',
28054 html : '<i class="fa fa-repeat"></i>'
28062 cls : 'btn-group roo-upload-cropbox-rotate-left',
28063 action : 'rotate-left',
28067 cls : 'btn btn-default',
28068 html : '<i class="fa fa-undo"></i>'
28074 cls : 'btn-group roo-upload-cropbox-download',
28075 action : 'download',
28079 cls : 'btn btn-default',
28080 html : '<i class="fa fa-download"></i>'
28086 cls : 'btn-group roo-upload-cropbox-crop',
28091 cls : 'btn btn-default',
28092 html : '<i class="fa fa-crop"></i>'
28098 cls : 'btn-group roo-upload-cropbox-trash',
28103 cls : 'btn btn-default',
28104 html : '<i class="fa fa-trash"></i>'
28110 cls : 'btn-group roo-upload-cropbox-rotate-right',
28111 action : 'rotate-right',
28115 cls : 'btn btn-default',
28116 html : '<i class="fa fa-repeat"></i>'
28124 cls : 'btn-group roo-upload-cropbox-rotate-left',
28125 action : 'rotate-left',
28129 cls : 'btn btn-default',
28130 html : '<i class="fa fa-undo"></i>'
28136 cls : 'btn-group roo-upload-cropbox-rotate-right',
28137 action : 'rotate-right',
28141 cls : 'btn btn-default',
28142 html : '<i class="fa fa-repeat"></i>'
28155 * @class Roo.bootstrap.DocumentManager
28156 * @extends Roo.bootstrap.Component
28157 * Bootstrap DocumentManager class
28158 * @cfg {String} paramName default 'imageUpload'
28159 * @cfg {String} toolTipName default 'filename'
28160 * @cfg {String} method default POST
28161 * @cfg {String} url action url
28162 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28163 * @cfg {Boolean} multiple multiple upload default true
28164 * @cfg {Number} thumbSize default 300
28165 * @cfg {String} fieldLabel
28166 * @cfg {Number} labelWidth default 4
28167 * @cfg {String} labelAlign (left|top) default left
28168 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28169 * @cfg {Number} labellg set the width of label (1-12)
28170 * @cfg {Number} labelmd set the width of label (1-12)
28171 * @cfg {Number} labelsm set the width of label (1-12)
28172 * @cfg {Number} labelxs set the width of label (1-12)
28175 * Create a new DocumentManager
28176 * @param {Object} config The config object
28179 Roo.bootstrap.DocumentManager = function(config){
28180 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28183 this.delegates = [];
28188 * Fire when initial the DocumentManager
28189 * @param {Roo.bootstrap.DocumentManager} this
28194 * inspect selected file
28195 * @param {Roo.bootstrap.DocumentManager} this
28196 * @param {File} file
28201 * Fire when xhr load exception
28202 * @param {Roo.bootstrap.DocumentManager} this
28203 * @param {XMLHttpRequest} xhr
28205 "exception" : true,
28207 * @event afterupload
28208 * Fire when xhr load exception
28209 * @param {Roo.bootstrap.DocumentManager} this
28210 * @param {XMLHttpRequest} xhr
28212 "afterupload" : true,
28215 * prepare the form data
28216 * @param {Roo.bootstrap.DocumentManager} this
28217 * @param {Object} formData
28222 * Fire when remove the file
28223 * @param {Roo.bootstrap.DocumentManager} this
28224 * @param {Object} file
28229 * Fire after refresh the file
28230 * @param {Roo.bootstrap.DocumentManager} this
28235 * Fire after click the image
28236 * @param {Roo.bootstrap.DocumentManager} this
28237 * @param {Object} file
28242 * Fire when upload a image and editable set to true
28243 * @param {Roo.bootstrap.DocumentManager} this
28244 * @param {Object} file
28248 * @event beforeselectfile
28249 * Fire before select file
28250 * @param {Roo.bootstrap.DocumentManager} this
28252 "beforeselectfile" : true,
28255 * Fire before process file
28256 * @param {Roo.bootstrap.DocumentManager} this
28257 * @param {Object} file
28264 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28273 paramName : 'imageUpload',
28274 toolTipName : 'filename',
28277 labelAlign : 'left',
28287 getAutoCreate : function()
28289 var managerWidget = {
28291 cls : 'roo-document-manager',
28295 cls : 'roo-document-manager-selector',
28300 cls : 'roo-document-manager-uploader',
28304 cls : 'roo-document-manager-upload-btn',
28305 html : '<i class="fa fa-plus"></i>'
28316 cls : 'column col-md-12',
28321 if(this.fieldLabel.length){
28326 cls : 'column col-md-12',
28327 html : this.fieldLabel
28331 cls : 'column col-md-12',
28336 if(this.labelAlign == 'left'){
28341 html : this.fieldLabel
28350 if(this.labelWidth > 12){
28351 content[0].style = "width: " + this.labelWidth + 'px';
28354 if(this.labelWidth < 13 && this.labelmd == 0){
28355 this.labelmd = this.labelWidth;
28358 if(this.labellg > 0){
28359 content[0].cls += ' col-lg-' + this.labellg;
28360 content[1].cls += ' col-lg-' + (12 - this.labellg);
28363 if(this.labelmd > 0){
28364 content[0].cls += ' col-md-' + this.labelmd;
28365 content[1].cls += ' col-md-' + (12 - this.labelmd);
28368 if(this.labelsm > 0){
28369 content[0].cls += ' col-sm-' + this.labelsm;
28370 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28373 if(this.labelxs > 0){
28374 content[0].cls += ' col-xs-' + this.labelxs;
28375 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28383 cls : 'row clearfix',
28391 initEvents : function()
28393 this.managerEl = this.el.select('.roo-document-manager', true).first();
28394 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28396 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28397 this.selectorEl.hide();
28400 this.selectorEl.attr('multiple', 'multiple');
28403 this.selectorEl.on('change', this.onFileSelected, this);
28405 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28406 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28408 this.uploader.on('click', this.onUploaderClick, this);
28410 this.renderProgressDialog();
28414 window.addEventListener("resize", function() { _this.refresh(); } );
28416 this.fireEvent('initial', this);
28419 renderProgressDialog : function()
28423 this.progressDialog = new Roo.bootstrap.Modal({
28424 cls : 'roo-document-manager-progress-dialog',
28425 allow_close : false,
28435 btnclick : function() {
28436 _this.uploadCancel();
28442 this.progressDialog.render(Roo.get(document.body));
28444 this.progress = new Roo.bootstrap.Progress({
28445 cls : 'roo-document-manager-progress',
28450 this.progress.render(this.progressDialog.getChildContainer());
28452 this.progressBar = new Roo.bootstrap.ProgressBar({
28453 cls : 'roo-document-manager-progress-bar',
28456 aria_valuemax : 12,
28460 this.progressBar.render(this.progress.getChildContainer());
28463 onUploaderClick : function(e)
28465 e.preventDefault();
28467 if(this.fireEvent('beforeselectfile', this) != false){
28468 this.selectorEl.dom.click();
28473 onFileSelected : function(e)
28475 e.preventDefault();
28477 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28481 Roo.each(this.selectorEl.dom.files, function(file){
28482 if(this.fireEvent('inspect', this, file) != false){
28483 this.files.push(file);
28493 this.selectorEl.dom.value = '';
28495 if(!this.files.length){
28499 if(this.boxes > 0 && this.files.length > this.boxes){
28500 this.files = this.files.slice(0, this.boxes);
28503 this.uploader.show();
28505 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28506 this.uploader.hide();
28515 Roo.each(this.files, function(file){
28517 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28518 var f = this.renderPreview(file);
28523 if(file.type.indexOf('image') != -1){
28524 this.delegates.push(
28526 _this.process(file);
28527 }).createDelegate(this)
28535 _this.process(file);
28536 }).createDelegate(this)
28541 this.files = files;
28543 this.delegates = this.delegates.concat(docs);
28545 if(!this.delegates.length){
28550 this.progressBar.aria_valuemax = this.delegates.length;
28557 arrange : function()
28559 if(!this.delegates.length){
28560 this.progressDialog.hide();
28565 var delegate = this.delegates.shift();
28567 this.progressDialog.show();
28569 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28571 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28576 refresh : function()
28578 this.uploader.show();
28580 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28581 this.uploader.hide();
28584 Roo.isTouch ? this.closable(false) : this.closable(true);
28586 this.fireEvent('refresh', this);
28589 onRemove : function(e, el, o)
28591 e.preventDefault();
28593 this.fireEvent('remove', this, o);
28597 remove : function(o)
28601 Roo.each(this.files, function(file){
28602 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28611 this.files = files;
28618 Roo.each(this.files, function(file){
28623 file.target.remove();
28632 onClick : function(e, el, o)
28634 e.preventDefault();
28636 this.fireEvent('click', this, o);
28640 closable : function(closable)
28642 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28644 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28656 xhrOnLoad : function(xhr)
28658 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28662 if (xhr.readyState !== 4) {
28664 this.fireEvent('exception', this, xhr);
28668 var response = Roo.decode(xhr.responseText);
28670 if(!response.success){
28672 this.fireEvent('exception', this, xhr);
28676 var file = this.renderPreview(response.data);
28678 this.files.push(file);
28682 this.fireEvent('afterupload', this, xhr);
28686 xhrOnError : function(xhr)
28688 Roo.log('xhr on error');
28690 var response = Roo.decode(xhr.responseText);
28697 process : function(file)
28699 if(this.fireEvent('process', this, file) !== false){
28700 if(this.editable && file.type.indexOf('image') != -1){
28701 this.fireEvent('edit', this, file);
28705 this.uploadStart(file, false);
28712 uploadStart : function(file, crop)
28714 this.xhr = new XMLHttpRequest();
28716 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28721 file.xhr = this.xhr;
28723 this.managerEl.createChild({
28725 cls : 'roo-document-manager-loading',
28729 tooltip : file.name,
28730 cls : 'roo-document-manager-thumb',
28731 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28737 this.xhr.open(this.method, this.url, true);
28740 "Accept": "application/json",
28741 "Cache-Control": "no-cache",
28742 "X-Requested-With": "XMLHttpRequest"
28745 for (var headerName in headers) {
28746 var headerValue = headers[headerName];
28748 this.xhr.setRequestHeader(headerName, headerValue);
28754 this.xhr.onload = function()
28756 _this.xhrOnLoad(_this.xhr);
28759 this.xhr.onerror = function()
28761 _this.xhrOnError(_this.xhr);
28764 var formData = new FormData();
28766 formData.append('returnHTML', 'NO');
28769 formData.append('crop', crop);
28772 formData.append(this.paramName, file, file.name);
28779 if(this.fireEvent('prepare', this, formData, options) != false){
28781 if(options.manually){
28785 this.xhr.send(formData);
28789 this.uploadCancel();
28792 uploadCancel : function()
28798 this.delegates = [];
28800 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28807 renderPreview : function(file)
28809 if(typeof(file.target) != 'undefined' && file.target){
28813 var previewEl = this.managerEl.createChild({
28815 cls : 'roo-document-manager-preview',
28819 tooltip : file[this.toolTipName],
28820 cls : 'roo-document-manager-thumb',
28821 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28826 html : '<i class="fa fa-times-circle"></i>'
28831 var close = previewEl.select('button.close', true).first();
28833 close.on('click', this.onRemove, this, file);
28835 file.target = previewEl;
28837 var image = previewEl.select('img', true).first();
28841 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28843 image.on('click', this.onClick, this, file);
28849 onPreviewLoad : function(file, image)
28851 if(typeof(file.target) == 'undefined' || !file.target){
28855 var width = image.dom.naturalWidth || image.dom.width;
28856 var height = image.dom.naturalHeight || image.dom.height;
28858 if(width > height){
28859 file.target.addClass('wide');
28863 file.target.addClass('tall');
28868 uploadFromSource : function(file, crop)
28870 this.xhr = new XMLHttpRequest();
28872 this.managerEl.createChild({
28874 cls : 'roo-document-manager-loading',
28878 tooltip : file.name,
28879 cls : 'roo-document-manager-thumb',
28880 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28886 this.xhr.open(this.method, this.url, true);
28889 "Accept": "application/json",
28890 "Cache-Control": "no-cache",
28891 "X-Requested-With": "XMLHttpRequest"
28894 for (var headerName in headers) {
28895 var headerValue = headers[headerName];
28897 this.xhr.setRequestHeader(headerName, headerValue);
28903 this.xhr.onload = function()
28905 _this.xhrOnLoad(_this.xhr);
28908 this.xhr.onerror = function()
28910 _this.xhrOnError(_this.xhr);
28913 var formData = new FormData();
28915 formData.append('returnHTML', 'NO');
28917 formData.append('crop', crop);
28919 if(typeof(file.filename) != 'undefined'){
28920 formData.append('filename', file.filename);
28923 if(typeof(file.mimetype) != 'undefined'){
28924 formData.append('mimetype', file.mimetype);
28929 if(this.fireEvent('prepare', this, formData) != false){
28930 this.xhr.send(formData);
28940 * @class Roo.bootstrap.DocumentViewer
28941 * @extends Roo.bootstrap.Component
28942 * Bootstrap DocumentViewer class
28943 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28944 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28947 * Create a new DocumentViewer
28948 * @param {Object} config The config object
28951 Roo.bootstrap.DocumentViewer = function(config){
28952 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28957 * Fire after initEvent
28958 * @param {Roo.bootstrap.DocumentViewer} this
28964 * @param {Roo.bootstrap.DocumentViewer} this
28969 * Fire after download button
28970 * @param {Roo.bootstrap.DocumentViewer} this
28975 * Fire after trash button
28976 * @param {Roo.bootstrap.DocumentViewer} this
28983 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28985 showDownload : true,
28989 getAutoCreate : function()
28993 cls : 'roo-document-viewer',
28997 cls : 'roo-document-viewer-body',
29001 cls : 'roo-document-viewer-thumb',
29005 cls : 'roo-document-viewer-image'
29013 cls : 'roo-document-viewer-footer',
29016 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29020 cls : 'btn-group roo-document-viewer-download',
29024 cls : 'btn btn-default',
29025 html : '<i class="fa fa-download"></i>'
29031 cls : 'btn-group roo-document-viewer-trash',
29035 cls : 'btn btn-default',
29036 html : '<i class="fa fa-trash"></i>'
29049 initEvents : function()
29051 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29052 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29054 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29055 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29057 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29058 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29060 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29061 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29063 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29064 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29066 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29067 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29069 this.bodyEl.on('click', this.onClick, this);
29070 this.downloadBtn.on('click', this.onDownload, this);
29071 this.trashBtn.on('click', this.onTrash, this);
29073 this.downloadBtn.hide();
29074 this.trashBtn.hide();
29076 if(this.showDownload){
29077 this.downloadBtn.show();
29080 if(this.showTrash){
29081 this.trashBtn.show();
29084 if(!this.showDownload && !this.showTrash) {
29085 this.footerEl.hide();
29090 initial : function()
29092 this.fireEvent('initial', this);
29096 onClick : function(e)
29098 e.preventDefault();
29100 this.fireEvent('click', this);
29103 onDownload : function(e)
29105 e.preventDefault();
29107 this.fireEvent('download', this);
29110 onTrash : function(e)
29112 e.preventDefault();
29114 this.fireEvent('trash', this);
29126 * @class Roo.bootstrap.NavProgressBar
29127 * @extends Roo.bootstrap.Component
29128 * Bootstrap NavProgressBar class
29131 * Create a new nav progress bar
29132 * @param {Object} config The config object
29135 Roo.bootstrap.NavProgressBar = function(config){
29136 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29138 this.bullets = this.bullets || [];
29140 // Roo.bootstrap.NavProgressBar.register(this);
29144 * Fires when the active item changes
29145 * @param {Roo.bootstrap.NavProgressBar} this
29146 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29147 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29154 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29159 getAutoCreate : function()
29161 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29165 cls : 'roo-navigation-bar-group',
29169 cls : 'roo-navigation-top-bar'
29173 cls : 'roo-navigation-bullets-bar',
29177 cls : 'roo-navigation-bar'
29184 cls : 'roo-navigation-bottom-bar'
29194 initEvents: function()
29199 onRender : function(ct, position)
29201 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29203 if(this.bullets.length){
29204 Roo.each(this.bullets, function(b){
29213 addItem : function(cfg)
29215 var item = new Roo.bootstrap.NavProgressItem(cfg);
29217 item.parentId = this.id;
29218 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29221 var top = new Roo.bootstrap.Element({
29223 cls : 'roo-navigation-bar-text'
29226 var bottom = new Roo.bootstrap.Element({
29228 cls : 'roo-navigation-bar-text'
29231 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29232 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29234 var topText = new Roo.bootstrap.Element({
29236 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29239 var bottomText = new Roo.bootstrap.Element({
29241 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29244 topText.onRender(top.el, null);
29245 bottomText.onRender(bottom.el, null);
29248 item.bottomEl = bottom;
29251 this.barItems.push(item);
29256 getActive : function()
29258 var active = false;
29260 Roo.each(this.barItems, function(v){
29262 if (!v.isActive()) {
29274 setActiveItem : function(item)
29278 Roo.each(this.barItems, function(v){
29279 if (v.rid == item.rid) {
29283 if (v.isActive()) {
29284 v.setActive(false);
29289 item.setActive(true);
29291 this.fireEvent('changed', this, item, prev);
29294 getBarItem: function(rid)
29298 Roo.each(this.barItems, function(e) {
29299 if (e.rid != rid) {
29310 indexOfItem : function(item)
29314 Roo.each(this.barItems, function(v, i){
29316 if (v.rid != item.rid) {
29327 setActiveNext : function()
29329 var i = this.indexOfItem(this.getActive());
29331 if (i > this.barItems.length) {
29335 this.setActiveItem(this.barItems[i+1]);
29338 setActivePrev : function()
29340 var i = this.indexOfItem(this.getActive());
29346 this.setActiveItem(this.barItems[i-1]);
29349 format : function()
29351 if(!this.barItems.length){
29355 var width = 100 / this.barItems.length;
29357 Roo.each(this.barItems, function(i){
29358 i.el.setStyle('width', width + '%');
29359 i.topEl.el.setStyle('width', width + '%');
29360 i.bottomEl.el.setStyle('width', width + '%');
29369 * Nav Progress Item
29374 * @class Roo.bootstrap.NavProgressItem
29375 * @extends Roo.bootstrap.Component
29376 * Bootstrap NavProgressItem class
29377 * @cfg {String} rid the reference id
29378 * @cfg {Boolean} active (true|false) Is item active default false
29379 * @cfg {Boolean} disabled (true|false) Is item active default false
29380 * @cfg {String} html
29381 * @cfg {String} position (top|bottom) text position default bottom
29382 * @cfg {String} icon show icon instead of number
29385 * Create a new NavProgressItem
29386 * @param {Object} config The config object
29388 Roo.bootstrap.NavProgressItem = function(config){
29389 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29394 * The raw click event for the entire grid.
29395 * @param {Roo.bootstrap.NavProgressItem} this
29396 * @param {Roo.EventObject} e
29403 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29409 position : 'bottom',
29412 getAutoCreate : function()
29414 var iconCls = 'roo-navigation-bar-item-icon';
29416 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29420 cls: 'roo-navigation-bar-item',
29430 cfg.cls += ' active';
29433 cfg.cls += ' disabled';
29439 disable : function()
29441 this.setDisabled(true);
29444 enable : function()
29446 this.setDisabled(false);
29449 initEvents: function()
29451 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29453 this.iconEl.on('click', this.onClick, this);
29456 onClick : function(e)
29458 e.preventDefault();
29464 if(this.fireEvent('click', this, e) === false){
29468 this.parent().setActiveItem(this);
29471 isActive: function ()
29473 return this.active;
29476 setActive : function(state)
29478 if(this.active == state){
29482 this.active = state;
29485 this.el.addClass('active');
29489 this.el.removeClass('active');
29494 setDisabled : function(state)
29496 if(this.disabled == state){
29500 this.disabled = state;
29503 this.el.addClass('disabled');
29507 this.el.removeClass('disabled');
29510 tooltipEl : function()
29512 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29525 * @class Roo.bootstrap.FieldLabel
29526 * @extends Roo.bootstrap.Component
29527 * Bootstrap FieldLabel class
29528 * @cfg {String} html contents of the element
29529 * @cfg {String} tag tag of the element default label
29530 * @cfg {String} cls class of the element
29531 * @cfg {String} target label target
29532 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29533 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29534 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29535 * @cfg {String} iconTooltip default "This field is required"
29538 * Create a new FieldLabel
29539 * @param {Object} config The config object
29542 Roo.bootstrap.FieldLabel = function(config){
29543 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29548 * Fires after the field has been marked as invalid.
29549 * @param {Roo.form.FieldLabel} this
29550 * @param {String} msg The validation message
29555 * Fires after the field has been validated with no errors.
29556 * @param {Roo.form.FieldLabel} this
29562 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29569 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29570 validClass : 'text-success fa fa-lg fa-check',
29571 iconTooltip : 'This field is required',
29573 getAutoCreate : function(){
29577 cls : 'roo-bootstrap-field-label ' + this.cls,
29583 tooltip : this.iconTooltip
29595 initEvents: function()
29597 Roo.bootstrap.Element.superclass.initEvents.call(this);
29599 this.iconEl = this.el.select('i', true).first();
29601 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29603 Roo.bootstrap.FieldLabel.register(this);
29607 * Mark this field as valid
29609 markValid : function()
29611 this.iconEl.show();
29613 this.iconEl.removeClass(this.invalidClass);
29615 this.iconEl.addClass(this.validClass);
29617 this.fireEvent('valid', this);
29621 * Mark this field as invalid
29622 * @param {String} msg The validation message
29624 markInvalid : function(msg)
29626 this.iconEl.show();
29628 this.iconEl.removeClass(this.validClass);
29630 this.iconEl.addClass(this.invalidClass);
29632 this.fireEvent('invalid', this, msg);
29638 Roo.apply(Roo.bootstrap.FieldLabel, {
29643 * register a FieldLabel Group
29644 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29646 register : function(label)
29648 if(this.groups.hasOwnProperty(label.target)){
29652 this.groups[label.target] = label;
29656 * fetch a FieldLabel Group based on the target
29657 * @param {string} target
29658 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29660 get: function(target) {
29661 if (typeof(this.groups[target]) == 'undefined') {
29665 return this.groups[target] ;
29674 * page DateSplitField.
29680 * @class Roo.bootstrap.DateSplitField
29681 * @extends Roo.bootstrap.Component
29682 * Bootstrap DateSplitField class
29683 * @cfg {string} fieldLabel - the label associated
29684 * @cfg {Number} labelWidth set the width of label (0-12)
29685 * @cfg {String} labelAlign (top|left)
29686 * @cfg {Boolean} dayAllowBlank (true|false) default false
29687 * @cfg {Boolean} monthAllowBlank (true|false) default false
29688 * @cfg {Boolean} yearAllowBlank (true|false) default false
29689 * @cfg {string} dayPlaceholder
29690 * @cfg {string} monthPlaceholder
29691 * @cfg {string} yearPlaceholder
29692 * @cfg {string} dayFormat default 'd'
29693 * @cfg {string} monthFormat default 'm'
29694 * @cfg {string} yearFormat default 'Y'
29695 * @cfg {Number} labellg set the width of label (1-12)
29696 * @cfg {Number} labelmd set the width of label (1-12)
29697 * @cfg {Number} labelsm set the width of label (1-12)
29698 * @cfg {Number} labelxs set the width of label (1-12)
29702 * Create a new DateSplitField
29703 * @param {Object} config The config object
29706 Roo.bootstrap.DateSplitField = function(config){
29707 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29713 * getting the data of years
29714 * @param {Roo.bootstrap.DateSplitField} this
29715 * @param {Object} years
29720 * getting the data of days
29721 * @param {Roo.bootstrap.DateSplitField} this
29722 * @param {Object} days
29727 * Fires after the field has been marked as invalid.
29728 * @param {Roo.form.Field} this
29729 * @param {String} msg The validation message
29734 * Fires after the field has been validated with no errors.
29735 * @param {Roo.form.Field} this
29741 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29744 labelAlign : 'top',
29746 dayAllowBlank : false,
29747 monthAllowBlank : false,
29748 yearAllowBlank : false,
29749 dayPlaceholder : '',
29750 monthPlaceholder : '',
29751 yearPlaceholder : '',
29755 isFormField : true,
29761 getAutoCreate : function()
29765 cls : 'row roo-date-split-field-group',
29770 cls : 'form-hidden-field roo-date-split-field-group-value',
29776 var labelCls = 'col-md-12';
29777 var contentCls = 'col-md-4';
29779 if(this.fieldLabel){
29783 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29787 html : this.fieldLabel
29792 if(this.labelAlign == 'left'){
29794 if(this.labelWidth > 12){
29795 label.style = "width: " + this.labelWidth + 'px';
29798 if(this.labelWidth < 13 && this.labelmd == 0){
29799 this.labelmd = this.labelWidth;
29802 if(this.labellg > 0){
29803 labelCls = ' col-lg-' + this.labellg;
29804 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29807 if(this.labelmd > 0){
29808 labelCls = ' col-md-' + this.labelmd;
29809 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29812 if(this.labelsm > 0){
29813 labelCls = ' col-sm-' + this.labelsm;
29814 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29817 if(this.labelxs > 0){
29818 labelCls = ' col-xs-' + this.labelxs;
29819 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29823 label.cls += ' ' + labelCls;
29825 cfg.cn.push(label);
29828 Roo.each(['day', 'month', 'year'], function(t){
29831 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29838 inputEl: function ()
29840 return this.el.select('.roo-date-split-field-group-value', true).first();
29843 onRender : function(ct, position)
29847 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29849 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29851 this.dayField = new Roo.bootstrap.ComboBox({
29852 allowBlank : this.dayAllowBlank,
29853 alwaysQuery : true,
29854 displayField : 'value',
29857 forceSelection : true,
29859 placeholder : this.dayPlaceholder,
29860 selectOnFocus : true,
29861 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29862 triggerAction : 'all',
29864 valueField : 'value',
29865 store : new Roo.data.SimpleStore({
29866 data : (function() {
29868 _this.fireEvent('days', _this, days);
29871 fields : [ 'value' ]
29874 select : function (_self, record, index)
29876 _this.setValue(_this.getValue());
29881 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29883 this.monthField = new Roo.bootstrap.MonthField({
29884 after : '<i class=\"fa fa-calendar\"></i>',
29885 allowBlank : this.monthAllowBlank,
29886 placeholder : this.monthPlaceholder,
29889 render : function (_self)
29891 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29892 e.preventDefault();
29896 select : function (_self, oldvalue, newvalue)
29898 _this.setValue(_this.getValue());
29903 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29905 this.yearField = new Roo.bootstrap.ComboBox({
29906 allowBlank : this.yearAllowBlank,
29907 alwaysQuery : true,
29908 displayField : 'value',
29911 forceSelection : true,
29913 placeholder : this.yearPlaceholder,
29914 selectOnFocus : true,
29915 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29916 triggerAction : 'all',
29918 valueField : 'value',
29919 store : new Roo.data.SimpleStore({
29920 data : (function() {
29922 _this.fireEvent('years', _this, years);
29925 fields : [ 'value' ]
29928 select : function (_self, record, index)
29930 _this.setValue(_this.getValue());
29935 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29938 setValue : function(v, format)
29940 this.inputEl.dom.value = v;
29942 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29944 var d = Date.parseDate(v, f);
29951 this.setDay(d.format(this.dayFormat));
29952 this.setMonth(d.format(this.monthFormat));
29953 this.setYear(d.format(this.yearFormat));
29960 setDay : function(v)
29962 this.dayField.setValue(v);
29963 this.inputEl.dom.value = this.getValue();
29968 setMonth : function(v)
29970 this.monthField.setValue(v, true);
29971 this.inputEl.dom.value = this.getValue();
29976 setYear : function(v)
29978 this.yearField.setValue(v);
29979 this.inputEl.dom.value = this.getValue();
29984 getDay : function()
29986 return this.dayField.getValue();
29989 getMonth : function()
29991 return this.monthField.getValue();
29994 getYear : function()
29996 return this.yearField.getValue();
29999 getValue : function()
30001 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30003 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30013 this.inputEl.dom.value = '';
30018 validate : function()
30020 var d = this.dayField.validate();
30021 var m = this.monthField.validate();
30022 var y = this.yearField.validate();
30027 (!this.dayAllowBlank && !d) ||
30028 (!this.monthAllowBlank && !m) ||
30029 (!this.yearAllowBlank && !y)
30034 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30043 this.markInvalid();
30048 markValid : function()
30051 var label = this.el.select('label', true).first();
30052 var icon = this.el.select('i.fa-star', true).first();
30058 this.fireEvent('valid', this);
30062 * Mark this field as invalid
30063 * @param {String} msg The validation message
30065 markInvalid : function(msg)
30068 var label = this.el.select('label', true).first();
30069 var icon = this.el.select('i.fa-star', true).first();
30071 if(label && !icon){
30072 this.el.select('.roo-date-split-field-label', true).createChild({
30074 cls : 'text-danger fa fa-lg fa-star',
30075 tooltip : 'This field is required',
30076 style : 'margin-right:5px;'
30080 this.fireEvent('invalid', this, msg);
30083 clearInvalid : function()
30085 var label = this.el.select('label', true).first();
30086 var icon = this.el.select('i.fa-star', true).first();
30092 this.fireEvent('valid', this);
30095 getName: function()
30105 * http://masonry.desandro.com
30107 * The idea is to render all the bricks based on vertical width...
30109 * The original code extends 'outlayer' - we might need to use that....
30115 * @class Roo.bootstrap.LayoutMasonry
30116 * @extends Roo.bootstrap.Component
30117 * Bootstrap Layout Masonry class
30120 * Create a new Element
30121 * @param {Object} config The config object
30124 Roo.bootstrap.LayoutMasonry = function(config){
30126 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30130 Roo.bootstrap.LayoutMasonry.register(this);
30136 * Fire after layout the items
30137 * @param {Roo.bootstrap.LayoutMasonry} this
30138 * @param {Roo.EventObject} e
30145 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30148 * @cfg {Boolean} isLayoutInstant = no animation?
30150 isLayoutInstant : false, // needed?
30153 * @cfg {Number} boxWidth width of the columns
30158 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30163 * @cfg {Number} padWidth padding below box..
30168 * @cfg {Number} gutter gutter width..
30173 * @cfg {Number} maxCols maximum number of columns
30179 * @cfg {Boolean} isAutoInitial defalut true
30181 isAutoInitial : true,
30186 * @cfg {Boolean} isHorizontal defalut false
30188 isHorizontal : false,
30190 currentSize : null,
30196 bricks: null, //CompositeElement
30200 _isLayoutInited : false,
30202 // isAlternative : false, // only use for vertical layout...
30205 * @cfg {Number} alternativePadWidth padding below box..
30207 alternativePadWidth : 50,
30209 selectedBrick : [],
30211 getAutoCreate : function(){
30213 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30217 cls: 'blog-masonary-wrapper ' + this.cls,
30219 cls : 'mas-boxes masonary'
30226 getChildContainer: function( )
30228 if (this.boxesEl) {
30229 return this.boxesEl;
30232 this.boxesEl = this.el.select('.mas-boxes').first();
30234 return this.boxesEl;
30238 initEvents : function()
30242 if(this.isAutoInitial){
30243 Roo.log('hook children rendered');
30244 this.on('childrenrendered', function() {
30245 Roo.log('children rendered');
30251 initial : function()
30253 this.selectedBrick = [];
30255 this.currentSize = this.el.getBox(true);
30257 Roo.EventManager.onWindowResize(this.resize, this);
30259 if(!this.isAutoInitial){
30267 //this.layout.defer(500,this);
30271 resize : function()
30273 var cs = this.el.getBox(true);
30276 this.currentSize.width == cs.width &&
30277 this.currentSize.x == cs.x &&
30278 this.currentSize.height == cs.height &&
30279 this.currentSize.y == cs.y
30281 Roo.log("no change in with or X or Y");
30285 this.currentSize = cs;
30291 layout : function()
30293 this._resetLayout();
30295 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30297 this.layoutItems( isInstant );
30299 this._isLayoutInited = true;
30301 this.fireEvent('layout', this);
30305 _resetLayout : function()
30307 if(this.isHorizontal){
30308 this.horizontalMeasureColumns();
30312 this.verticalMeasureColumns();
30316 verticalMeasureColumns : function()
30318 this.getContainerWidth();
30320 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30321 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30325 var boxWidth = this.boxWidth + this.padWidth;
30327 if(this.containerWidth < this.boxWidth){
30328 boxWidth = this.containerWidth
30331 var containerWidth = this.containerWidth;
30333 var cols = Math.floor(containerWidth / boxWidth);
30335 this.cols = Math.max( cols, 1 );
30337 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30339 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30341 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30343 this.colWidth = boxWidth + avail - this.padWidth;
30345 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30346 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30349 horizontalMeasureColumns : function()
30351 this.getContainerWidth();
30353 var boxWidth = this.boxWidth;
30355 if(this.containerWidth < boxWidth){
30356 boxWidth = this.containerWidth;
30359 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30361 this.el.setHeight(boxWidth);
30365 getContainerWidth : function()
30367 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30370 layoutItems : function( isInstant )
30372 Roo.log(this.bricks);
30374 var items = Roo.apply([], this.bricks);
30376 if(this.isHorizontal){
30377 this._horizontalLayoutItems( items , isInstant );
30381 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30382 // this._verticalAlternativeLayoutItems( items , isInstant );
30386 this._verticalLayoutItems( items , isInstant );
30390 _verticalLayoutItems : function ( items , isInstant)
30392 if ( !items || !items.length ) {
30397 ['xs', 'xs', 'xs', 'tall'],
30398 ['xs', 'xs', 'tall'],
30399 ['xs', 'xs', 'sm'],
30400 ['xs', 'xs', 'xs'],
30406 ['sm', 'xs', 'xs'],
30410 ['tall', 'xs', 'xs', 'xs'],
30411 ['tall', 'xs', 'xs'],
30423 Roo.each(items, function(item, k){
30425 switch (item.size) {
30426 // these layouts take up a full box,
30437 boxes.push([item]);
30460 var filterPattern = function(box, length)
30468 var pattern = box.slice(0, length);
30472 Roo.each(pattern, function(i){
30473 format.push(i.size);
30476 Roo.each(standard, function(s){
30478 if(String(s) != String(format)){
30487 if(!match && length == 1){
30492 filterPattern(box, length - 1);
30496 queue.push(pattern);
30498 box = box.slice(length, box.length);
30500 filterPattern(box, 4);
30506 Roo.each(boxes, function(box, k){
30512 if(box.length == 1){
30517 filterPattern(box, 4);
30521 this._processVerticalLayoutQueue( queue, isInstant );
30525 // _verticalAlternativeLayoutItems : function( items , isInstant )
30527 // if ( !items || !items.length ) {
30531 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30535 _horizontalLayoutItems : function ( items , isInstant)
30537 if ( !items || !items.length || items.length < 3) {
30543 var eItems = items.slice(0, 3);
30545 items = items.slice(3, items.length);
30548 ['xs', 'xs', 'xs', 'wide'],
30549 ['xs', 'xs', 'wide'],
30550 ['xs', 'xs', 'sm'],
30551 ['xs', 'xs', 'xs'],
30557 ['sm', 'xs', 'xs'],
30561 ['wide', 'xs', 'xs', 'xs'],
30562 ['wide', 'xs', 'xs'],
30575 Roo.each(items, function(item, k){
30577 switch (item.size) {
30588 boxes.push([item]);
30612 var filterPattern = function(box, length)
30620 var pattern = box.slice(0, length);
30624 Roo.each(pattern, function(i){
30625 format.push(i.size);
30628 Roo.each(standard, function(s){
30630 if(String(s) != String(format)){
30639 if(!match && length == 1){
30644 filterPattern(box, length - 1);
30648 queue.push(pattern);
30650 box = box.slice(length, box.length);
30652 filterPattern(box, 4);
30658 Roo.each(boxes, function(box, k){
30664 if(box.length == 1){
30669 filterPattern(box, 4);
30676 var pos = this.el.getBox(true);
30680 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30682 var hit_end = false;
30684 Roo.each(queue, function(box){
30688 Roo.each(box, function(b){
30690 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30700 Roo.each(box, function(b){
30702 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30705 mx = Math.max(mx, b.x);
30709 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30713 Roo.each(box, function(b){
30715 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30729 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30732 /** Sets position of item in DOM
30733 * @param {Element} item
30734 * @param {Number} x - horizontal position
30735 * @param {Number} y - vertical position
30736 * @param {Boolean} isInstant - disables transitions
30738 _processVerticalLayoutQueue : function( queue, isInstant )
30740 var pos = this.el.getBox(true);
30745 for (var i = 0; i < this.cols; i++){
30749 Roo.each(queue, function(box, k){
30751 var col = k % this.cols;
30753 Roo.each(box, function(b,kk){
30755 b.el.position('absolute');
30757 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30758 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30760 if(b.size == 'md-left' || b.size == 'md-right'){
30761 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30762 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30765 b.el.setWidth(width);
30766 b.el.setHeight(height);
30768 b.el.select('iframe',true).setSize(width,height);
30772 for (var i = 0; i < this.cols; i++){
30774 if(maxY[i] < maxY[col]){
30779 col = Math.min(col, i);
30783 x = pos.x + col * (this.colWidth + this.padWidth);
30787 var positions = [];
30789 switch (box.length){
30791 positions = this.getVerticalOneBoxColPositions(x, y, box);
30794 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30797 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30800 positions = this.getVerticalFourBoxColPositions(x, y, box);
30806 Roo.each(box, function(b,kk){
30808 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30810 var sz = b.el.getSize();
30812 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30820 for (var i = 0; i < this.cols; i++){
30821 mY = Math.max(mY, maxY[i]);
30824 this.el.setHeight(mY - pos.y);
30828 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30830 // var pos = this.el.getBox(true);
30833 // var maxX = pos.right;
30835 // var maxHeight = 0;
30837 // Roo.each(items, function(item, k){
30841 // item.el.position('absolute');
30843 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30845 // item.el.setWidth(width);
30847 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30849 // item.el.setHeight(height);
30852 // item.el.setXY([x, y], isInstant ? false : true);
30854 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30857 // y = y + height + this.alternativePadWidth;
30859 // maxHeight = maxHeight + height + this.alternativePadWidth;
30863 // this.el.setHeight(maxHeight);
30867 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30869 var pos = this.el.getBox(true);
30874 var maxX = pos.right;
30876 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30878 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30880 Roo.each(queue, function(box, k){
30882 Roo.each(box, function(b, kk){
30884 b.el.position('absolute');
30886 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30887 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30889 if(b.size == 'md-left' || b.size == 'md-right'){
30890 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30891 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30894 b.el.setWidth(width);
30895 b.el.setHeight(height);
30903 var positions = [];
30905 switch (box.length){
30907 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30910 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30913 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30916 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30922 Roo.each(box, function(b,kk){
30924 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30926 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30934 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30936 Roo.each(eItems, function(b,k){
30938 b.size = (k == 0) ? 'sm' : 'xs';
30939 b.x = (k == 0) ? 2 : 1;
30940 b.y = (k == 0) ? 2 : 1;
30942 b.el.position('absolute');
30944 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30946 b.el.setWidth(width);
30948 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30950 b.el.setHeight(height);
30954 var positions = [];
30957 x : maxX - this.unitWidth * 2 - this.gutter,
30962 x : maxX - this.unitWidth,
30963 y : minY + (this.unitWidth + this.gutter) * 2
30967 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30971 Roo.each(eItems, function(b,k){
30973 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30979 getVerticalOneBoxColPositions : function(x, y, box)
30983 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30985 if(box[0].size == 'md-left'){
30989 if(box[0].size == 'md-right'){
30994 x : x + (this.unitWidth + this.gutter) * rand,
31001 getVerticalTwoBoxColPositions : function(x, y, box)
31005 if(box[0].size == 'xs'){
31009 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31013 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31027 x : x + (this.unitWidth + this.gutter) * 2,
31028 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31035 getVerticalThreeBoxColPositions : function(x, y, box)
31039 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31047 x : x + (this.unitWidth + this.gutter) * 1,
31052 x : x + (this.unitWidth + this.gutter) * 2,
31060 if(box[0].size == 'xs' && box[1].size == 'xs'){
31069 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31073 x : x + (this.unitWidth + this.gutter) * 1,
31087 x : x + (this.unitWidth + this.gutter) * 2,
31092 x : x + (this.unitWidth + this.gutter) * 2,
31093 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31100 getVerticalFourBoxColPositions : function(x, y, box)
31104 if(box[0].size == 'xs'){
31113 y : y + (this.unitHeight + this.gutter) * 1
31118 y : y + (this.unitHeight + this.gutter) * 2
31122 x : x + (this.unitWidth + this.gutter) * 1,
31136 x : x + (this.unitWidth + this.gutter) * 2,
31141 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31142 y : y + (this.unitHeight + this.gutter) * 1
31146 x : x + (this.unitWidth + this.gutter) * 2,
31147 y : y + (this.unitWidth + this.gutter) * 2
31154 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31158 if(box[0].size == 'md-left'){
31160 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31167 if(box[0].size == 'md-right'){
31169 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31170 y : minY + (this.unitWidth + this.gutter) * 1
31176 var rand = Math.floor(Math.random() * (4 - box[0].y));
31179 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31180 y : minY + (this.unitWidth + this.gutter) * rand
31187 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31191 if(box[0].size == 'xs'){
31194 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31199 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31200 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31208 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31213 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31214 y : minY + (this.unitWidth + this.gutter) * 2
31221 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31225 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31228 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31233 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31234 y : minY + (this.unitWidth + this.gutter) * 1
31238 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31239 y : minY + (this.unitWidth + this.gutter) * 2
31246 if(box[0].size == 'xs' && box[1].size == 'xs'){
31249 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31254 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31259 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31260 y : minY + (this.unitWidth + this.gutter) * 1
31268 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31273 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31274 y : minY + (this.unitWidth + this.gutter) * 2
31278 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31279 y : minY + (this.unitWidth + this.gutter) * 2
31286 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31290 if(box[0].size == 'xs'){
31293 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31298 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31303 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),
31308 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31309 y : minY + (this.unitWidth + this.gutter) * 1
31317 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31322 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31323 y : minY + (this.unitWidth + this.gutter) * 2
31327 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31328 y : minY + (this.unitWidth + this.gutter) * 2
31332 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),
31333 y : minY + (this.unitWidth + this.gutter) * 2
31341 * remove a Masonry Brick
31342 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31344 removeBrick : function(brick_id)
31350 for (var i = 0; i<this.bricks.length; i++) {
31351 if (this.bricks[i].id == brick_id) {
31352 this.bricks.splice(i,1);
31353 this.selectedBrick = [];
31354 this.el.dom.removeChild(Roo.get(brick_id).dom);
31361 * adds a Masonry Brick
31362 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31364 addBrick : function(cfg)
31366 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31367 //this.register(cn);
31368 cn.parentId = this.id;
31369 cn.onRender(this.el, null);
31374 * register a Masonry Brick
31375 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31378 register : function(brick)
31380 this.bricks.push(brick);
31381 brick.masonryId = this.id;
31385 * clear all the Masonry Brick
31387 clearAll : function()
31390 //this.getChildContainer().dom.innerHTML = "";
31391 this.el.dom.innerHTML = '';
31394 getSelected : function()
31396 if (!this.selectedBrick) {
31400 return this.selectedBrick;
31404 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31408 * register a Masonry Layout
31409 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31412 register : function(layout)
31414 this.groups[layout.id] = layout;
31417 * fetch a Masonry Layout based on the masonry layout ID
31418 * @param {string} the masonry layout to add
31419 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31422 get: function(layout_id) {
31423 if (typeof(this.groups[layout_id]) == 'undefined') {
31426 return this.groups[layout_id] ;
31438 * http://masonry.desandro.com
31440 * The idea is to render all the bricks based on vertical width...
31442 * The original code extends 'outlayer' - we might need to use that....
31448 * @class Roo.bootstrap.LayoutMasonryAuto
31449 * @extends Roo.bootstrap.Component
31450 * Bootstrap Layout Masonry class
31453 * Create a new Element
31454 * @param {Object} config The config object
31457 Roo.bootstrap.LayoutMasonryAuto = function(config){
31458 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31461 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31464 * @cfg {Boolean} isFitWidth - resize the width..
31466 isFitWidth : false, // options..
31468 * @cfg {Boolean} isOriginLeft = left align?
31470 isOriginLeft : true,
31472 * @cfg {Boolean} isOriginTop = top align?
31474 isOriginTop : false,
31476 * @cfg {Boolean} isLayoutInstant = no animation?
31478 isLayoutInstant : false, // needed?
31480 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31482 isResizingContainer : true,
31484 * @cfg {Number} columnWidth width of the columns
31490 * @cfg {Number} maxCols maximum number of columns
31495 * @cfg {Number} padHeight padding below box..
31501 * @cfg {Boolean} isAutoInitial defalut true
31504 isAutoInitial : true,
31510 initialColumnWidth : 0,
31511 currentSize : null,
31513 colYs : null, // array.
31520 bricks: null, //CompositeElement
31521 cols : 0, // array?
31522 // element : null, // wrapped now this.el
31523 _isLayoutInited : null,
31526 getAutoCreate : function(){
31530 cls: 'blog-masonary-wrapper ' + this.cls,
31532 cls : 'mas-boxes masonary'
31539 getChildContainer: function( )
31541 if (this.boxesEl) {
31542 return this.boxesEl;
31545 this.boxesEl = this.el.select('.mas-boxes').first();
31547 return this.boxesEl;
31551 initEvents : function()
31555 if(this.isAutoInitial){
31556 Roo.log('hook children rendered');
31557 this.on('childrenrendered', function() {
31558 Roo.log('children rendered');
31565 initial : function()
31567 this.reloadItems();
31569 this.currentSize = this.el.getBox(true);
31571 /// was window resize... - let's see if this works..
31572 Roo.EventManager.onWindowResize(this.resize, this);
31574 if(!this.isAutoInitial){
31579 this.layout.defer(500,this);
31582 reloadItems: function()
31584 this.bricks = this.el.select('.masonry-brick', true);
31586 this.bricks.each(function(b) {
31587 //Roo.log(b.getSize());
31588 if (!b.attr('originalwidth')) {
31589 b.attr('originalwidth', b.getSize().width);
31594 Roo.log(this.bricks.elements.length);
31597 resize : function()
31600 var cs = this.el.getBox(true);
31602 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31603 Roo.log("no change in with or X");
31606 this.currentSize = cs;
31610 layout : function()
31613 this._resetLayout();
31614 //this._manageStamps();
31616 // don't animate first layout
31617 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31618 this.layoutItems( isInstant );
31620 // flag for initalized
31621 this._isLayoutInited = true;
31624 layoutItems : function( isInstant )
31626 //var items = this._getItemsForLayout( this.items );
31627 // original code supports filtering layout items.. we just ignore it..
31629 this._layoutItems( this.bricks , isInstant );
31631 this._postLayout();
31633 _layoutItems : function ( items , isInstant)
31635 //this.fireEvent( 'layout', this, items );
31638 if ( !items || !items.elements.length ) {
31639 // no items, emit event with empty array
31644 items.each(function(item) {
31645 Roo.log("layout item");
31647 // get x/y object from method
31648 var position = this._getItemLayoutPosition( item );
31650 position.item = item;
31651 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31652 queue.push( position );
31655 this._processLayoutQueue( queue );
31657 /** Sets position of item in DOM
31658 * @param {Element} item
31659 * @param {Number} x - horizontal position
31660 * @param {Number} y - vertical position
31661 * @param {Boolean} isInstant - disables transitions
31663 _processLayoutQueue : function( queue )
31665 for ( var i=0, len = queue.length; i < len; i++ ) {
31666 var obj = queue[i];
31667 obj.item.position('absolute');
31668 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31674 * Any logic you want to do after each layout,
31675 * i.e. size the container
31677 _postLayout : function()
31679 this.resizeContainer();
31682 resizeContainer : function()
31684 if ( !this.isResizingContainer ) {
31687 var size = this._getContainerSize();
31689 this.el.setSize(size.width,size.height);
31690 this.boxesEl.setSize(size.width,size.height);
31696 _resetLayout : function()
31698 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31699 this.colWidth = this.el.getWidth();
31700 //this.gutter = this.el.getWidth();
31702 this.measureColumns();
31708 this.colYs.push( 0 );
31714 measureColumns : function()
31716 this.getContainerWidth();
31717 // if columnWidth is 0, default to outerWidth of first item
31718 if ( !this.columnWidth ) {
31719 var firstItem = this.bricks.first();
31720 Roo.log(firstItem);
31721 this.columnWidth = this.containerWidth;
31722 if (firstItem && firstItem.attr('originalwidth') ) {
31723 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31725 // columnWidth fall back to item of first element
31726 Roo.log("set column width?");
31727 this.initialColumnWidth = this.columnWidth ;
31729 // if first elem has no width, default to size of container
31734 if (this.initialColumnWidth) {
31735 this.columnWidth = this.initialColumnWidth;
31740 // column width is fixed at the top - however if container width get's smaller we should
31743 // this bit calcs how man columns..
31745 var columnWidth = this.columnWidth += this.gutter;
31747 // calculate columns
31748 var containerWidth = this.containerWidth + this.gutter;
31750 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31751 // fix rounding errors, typically with gutters
31752 var excess = columnWidth - containerWidth % columnWidth;
31755 // if overshoot is less than a pixel, round up, otherwise floor it
31756 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31757 cols = Math[ mathMethod ]( cols );
31758 this.cols = Math.max( cols, 1 );
31759 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31761 // padding positioning..
31762 var totalColWidth = this.cols * this.columnWidth;
31763 var padavail = this.containerWidth - totalColWidth;
31764 // so for 2 columns - we need 3 'pads'
31766 var padNeeded = (1+this.cols) * this.padWidth;
31768 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31770 this.columnWidth += padExtra
31771 //this.padWidth = Math.floor(padavail / ( this.cols));
31773 // adjust colum width so that padding is fixed??
31775 // we have 3 columns ... total = width * 3
31776 // we have X left over... that should be used by
31778 //if (this.expandC) {
31786 getContainerWidth : function()
31788 /* // container is parent if fit width
31789 var container = this.isFitWidth ? this.element.parentNode : this.element;
31790 // check that this.size and size are there
31791 // IE8 triggers resize on body size change, so they might not be
31793 var size = getSize( container ); //FIXME
31794 this.containerWidth = size && size.innerWidth; //FIXME
31797 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31801 _getItemLayoutPosition : function( item ) // what is item?
31803 // we resize the item to our columnWidth..
31805 item.setWidth(this.columnWidth);
31806 item.autoBoxAdjust = false;
31808 var sz = item.getSize();
31810 // how many columns does this brick span
31811 var remainder = this.containerWidth % this.columnWidth;
31813 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31814 // round if off by 1 pixel, otherwise use ceil
31815 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31816 colSpan = Math.min( colSpan, this.cols );
31818 // normally this should be '1' as we dont' currently allow multi width columns..
31820 var colGroup = this._getColGroup( colSpan );
31821 // get the minimum Y value from the columns
31822 var minimumY = Math.min.apply( Math, colGroup );
31823 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31825 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31827 // position the brick
31829 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31830 y: this.currentSize.y + minimumY + this.padHeight
31834 // apply setHeight to necessary columns
31835 var setHeight = minimumY + sz.height + this.padHeight;
31836 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31838 var setSpan = this.cols + 1 - colGroup.length;
31839 for ( var i = 0; i < setSpan; i++ ) {
31840 this.colYs[ shortColIndex + i ] = setHeight ;
31847 * @param {Number} colSpan - number of columns the element spans
31848 * @returns {Array} colGroup
31850 _getColGroup : function( colSpan )
31852 if ( colSpan < 2 ) {
31853 // if brick spans only one column, use all the column Ys
31858 // how many different places could this brick fit horizontally
31859 var groupCount = this.cols + 1 - colSpan;
31860 // for each group potential horizontal position
31861 for ( var i = 0; i < groupCount; i++ ) {
31862 // make an array of colY values for that one group
31863 var groupColYs = this.colYs.slice( i, i + colSpan );
31864 // and get the max value of the array
31865 colGroup[i] = Math.max.apply( Math, groupColYs );
31870 _manageStamp : function( stamp )
31872 var stampSize = stamp.getSize();
31873 var offset = stamp.getBox();
31874 // get the columns that this stamp affects
31875 var firstX = this.isOriginLeft ? offset.x : offset.right;
31876 var lastX = firstX + stampSize.width;
31877 var firstCol = Math.floor( firstX / this.columnWidth );
31878 firstCol = Math.max( 0, firstCol );
31880 var lastCol = Math.floor( lastX / this.columnWidth );
31881 // lastCol should not go over if multiple of columnWidth #425
31882 lastCol -= lastX % this.columnWidth ? 0 : 1;
31883 lastCol = Math.min( this.cols - 1, lastCol );
31885 // set colYs to bottom of the stamp
31886 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31889 for ( var i = firstCol; i <= lastCol; i++ ) {
31890 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31895 _getContainerSize : function()
31897 this.maxY = Math.max.apply( Math, this.colYs );
31902 if ( this.isFitWidth ) {
31903 size.width = this._getContainerFitWidth();
31909 _getContainerFitWidth : function()
31911 var unusedCols = 0;
31912 // count unused columns
31915 if ( this.colYs[i] !== 0 ) {
31920 // fit container to columns that have been used
31921 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31924 needsResizeLayout : function()
31926 var previousWidth = this.containerWidth;
31927 this.getContainerWidth();
31928 return previousWidth !== this.containerWidth;
31943 * @class Roo.bootstrap.MasonryBrick
31944 * @extends Roo.bootstrap.Component
31945 * Bootstrap MasonryBrick class
31948 * Create a new MasonryBrick
31949 * @param {Object} config The config object
31952 Roo.bootstrap.MasonryBrick = function(config){
31954 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31956 Roo.bootstrap.MasonryBrick.register(this);
31962 * When a MasonryBrick is clcik
31963 * @param {Roo.bootstrap.MasonryBrick} this
31964 * @param {Roo.EventObject} e
31970 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31973 * @cfg {String} title
31977 * @cfg {String} html
31981 * @cfg {String} bgimage
31985 * @cfg {String} videourl
31989 * @cfg {String} cls
31993 * @cfg {String} href
31997 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32002 * @cfg {String} placetitle (center|bottom)
32007 * @cfg {Boolean} isFitContainer defalut true
32009 isFitContainer : true,
32012 * @cfg {Boolean} preventDefault defalut false
32014 preventDefault : false,
32017 * @cfg {Boolean} inverse defalut false
32019 maskInverse : false,
32021 getAutoCreate : function()
32023 if(!this.isFitContainer){
32024 return this.getSplitAutoCreate();
32027 var cls = 'masonry-brick masonry-brick-full';
32029 if(this.href.length){
32030 cls += ' masonry-brick-link';
32033 if(this.bgimage.length){
32034 cls += ' masonry-brick-image';
32037 if(this.maskInverse){
32038 cls += ' mask-inverse';
32041 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32042 cls += ' enable-mask';
32046 cls += ' masonry-' + this.size + '-brick';
32049 if(this.placetitle.length){
32051 switch (this.placetitle) {
32053 cls += ' masonry-center-title';
32056 cls += ' masonry-bottom-title';
32063 if(!this.html.length && !this.bgimage.length){
32064 cls += ' masonry-center-title';
32067 if(!this.html.length && this.bgimage.length){
32068 cls += ' masonry-bottom-title';
32073 cls += ' ' + this.cls;
32077 tag: (this.href.length) ? 'a' : 'div',
32082 cls: 'masonry-brick-mask'
32086 cls: 'masonry-brick-paragraph',
32092 if(this.href.length){
32093 cfg.href = this.href;
32096 var cn = cfg.cn[1].cn;
32098 if(this.title.length){
32101 cls: 'masonry-brick-title',
32106 if(this.html.length){
32109 cls: 'masonry-brick-text',
32114 if (!this.title.length && !this.html.length) {
32115 cfg.cn[1].cls += ' hide';
32118 if(this.bgimage.length){
32121 cls: 'masonry-brick-image-view',
32126 if(this.videourl.length){
32127 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32128 // youtube support only?
32131 cls: 'masonry-brick-image-view',
32134 allowfullscreen : true
32142 getSplitAutoCreate : function()
32144 var cls = 'masonry-brick masonry-brick-split';
32146 if(this.href.length){
32147 cls += ' masonry-brick-link';
32150 if(this.bgimage.length){
32151 cls += ' masonry-brick-image';
32155 cls += ' masonry-' + this.size + '-brick';
32158 switch (this.placetitle) {
32160 cls += ' masonry-center-title';
32163 cls += ' masonry-bottom-title';
32166 if(!this.bgimage.length){
32167 cls += ' masonry-center-title';
32170 if(this.bgimage.length){
32171 cls += ' masonry-bottom-title';
32177 cls += ' ' + this.cls;
32181 tag: (this.href.length) ? 'a' : 'div',
32186 cls: 'masonry-brick-split-head',
32190 cls: 'masonry-brick-paragraph',
32197 cls: 'masonry-brick-split-body',
32203 if(this.href.length){
32204 cfg.href = this.href;
32207 if(this.title.length){
32208 cfg.cn[0].cn[0].cn.push({
32210 cls: 'masonry-brick-title',
32215 if(this.html.length){
32216 cfg.cn[1].cn.push({
32218 cls: 'masonry-brick-text',
32223 if(this.bgimage.length){
32224 cfg.cn[0].cn.push({
32226 cls: 'masonry-brick-image-view',
32231 if(this.videourl.length){
32232 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32233 // youtube support only?
32234 cfg.cn[0].cn.cn.push({
32236 cls: 'masonry-brick-image-view',
32239 allowfullscreen : true
32246 initEvents: function()
32248 switch (this.size) {
32281 this.el.on('touchstart', this.onTouchStart, this);
32282 this.el.on('touchmove', this.onTouchMove, this);
32283 this.el.on('touchend', this.onTouchEnd, this);
32284 this.el.on('contextmenu', this.onContextMenu, this);
32286 this.el.on('mouseenter' ,this.enter, this);
32287 this.el.on('mouseleave', this.leave, this);
32288 this.el.on('click', this.onClick, this);
32291 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32292 this.parent().bricks.push(this);
32297 onClick: function(e, el)
32299 var time = this.endTimer - this.startTimer;
32300 // Roo.log(e.preventDefault());
32303 e.preventDefault();
32308 if(!this.preventDefault){
32312 e.preventDefault();
32314 if (this.activcClass != '') {
32315 this.selectBrick();
32318 this.fireEvent('click', this);
32321 enter: function(e, el)
32323 e.preventDefault();
32325 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32329 if(this.bgimage.length && this.html.length){
32330 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32334 leave: function(e, el)
32336 e.preventDefault();
32338 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32342 if(this.bgimage.length && this.html.length){
32343 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32347 onTouchStart: function(e, el)
32349 // e.preventDefault();
32351 this.touchmoved = false;
32353 if(!this.isFitContainer){
32357 if(!this.bgimage.length || !this.html.length){
32361 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32363 this.timer = new Date().getTime();
32367 onTouchMove: function(e, el)
32369 this.touchmoved = true;
32372 onContextMenu : function(e,el)
32374 e.preventDefault();
32375 e.stopPropagation();
32379 onTouchEnd: function(e, el)
32381 // e.preventDefault();
32383 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32390 if(!this.bgimage.length || !this.html.length){
32392 if(this.href.length){
32393 window.location.href = this.href;
32399 if(!this.isFitContainer){
32403 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32405 window.location.href = this.href;
32408 //selection on single brick only
32409 selectBrick : function() {
32411 if (!this.parentId) {
32415 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32416 var index = m.selectedBrick.indexOf(this.id);
32419 m.selectedBrick.splice(index,1);
32420 this.el.removeClass(this.activeClass);
32424 for(var i = 0; i < m.selectedBrick.length; i++) {
32425 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32426 b.el.removeClass(b.activeClass);
32429 m.selectedBrick = [];
32431 m.selectedBrick.push(this.id);
32432 this.el.addClass(this.activeClass);
32438 Roo.apply(Roo.bootstrap.MasonryBrick, {
32441 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32443 * register a Masonry Brick
32444 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32447 register : function(brick)
32449 //this.groups[brick.id] = brick;
32450 this.groups.add(brick.id, brick);
32453 * fetch a masonry brick based on the masonry brick ID
32454 * @param {string} the masonry brick to add
32455 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32458 get: function(brick_id)
32460 // if (typeof(this.groups[brick_id]) == 'undefined') {
32463 // return this.groups[brick_id] ;
32465 if(this.groups.key(brick_id)) {
32466 return this.groups.key(brick_id);
32484 * @class Roo.bootstrap.Brick
32485 * @extends Roo.bootstrap.Component
32486 * Bootstrap Brick class
32489 * Create a new Brick
32490 * @param {Object} config The config object
32493 Roo.bootstrap.Brick = function(config){
32494 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32500 * When a Brick is click
32501 * @param {Roo.bootstrap.Brick} this
32502 * @param {Roo.EventObject} e
32508 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32511 * @cfg {String} title
32515 * @cfg {String} html
32519 * @cfg {String} bgimage
32523 * @cfg {String} cls
32527 * @cfg {String} href
32531 * @cfg {String} video
32535 * @cfg {Boolean} square
32539 getAutoCreate : function()
32541 var cls = 'roo-brick';
32543 if(this.href.length){
32544 cls += ' roo-brick-link';
32547 if(this.bgimage.length){
32548 cls += ' roo-brick-image';
32551 if(!this.html.length && !this.bgimage.length){
32552 cls += ' roo-brick-center-title';
32555 if(!this.html.length && this.bgimage.length){
32556 cls += ' roo-brick-bottom-title';
32560 cls += ' ' + this.cls;
32564 tag: (this.href.length) ? 'a' : 'div',
32569 cls: 'roo-brick-paragraph',
32575 if(this.href.length){
32576 cfg.href = this.href;
32579 var cn = cfg.cn[0].cn;
32581 if(this.title.length){
32584 cls: 'roo-brick-title',
32589 if(this.html.length){
32592 cls: 'roo-brick-text',
32599 if(this.bgimage.length){
32602 cls: 'roo-brick-image-view',
32610 initEvents: function()
32612 if(this.title.length || this.html.length){
32613 this.el.on('mouseenter' ,this.enter, this);
32614 this.el.on('mouseleave', this.leave, this);
32618 Roo.EventManager.onWindowResize(this.resize, this);
32623 resize : function()
32625 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32627 paragraph.setWidth(paragraph.getWidth() + paragraph.getPadding('lr'));
32628 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32630 if(this.bgimage.length){
32631 var image = this.el.select('.roo-brick-image-view', true).first();
32632 image.setWidth(paragraph.getWidth());
32633 // image.setHeight(paragraph.getWidth());
32635 this.el.setHeight(image.getHeight());
32636 paragraph.setHeight(image.getHeight());
32642 enter: function(e, el)
32644 e.preventDefault();
32646 if(this.bgimage.length){
32647 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32648 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32652 leave: function(e, el)
32654 e.preventDefault();
32656 if(this.bgimage.length){
32657 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32658 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32674 * @class Roo.bootstrap.NumberField
32675 * @extends Roo.bootstrap.Input
32676 * Bootstrap NumberField class
32682 * Create a new NumberField
32683 * @param {Object} config The config object
32686 Roo.bootstrap.NumberField = function(config){
32687 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32690 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32693 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32695 allowDecimals : true,
32697 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32699 decimalSeparator : ".",
32701 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32703 decimalPrecision : 2,
32705 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32707 allowNegative : true,
32709 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32711 minValue : Number.NEGATIVE_INFINITY,
32713 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32715 maxValue : Number.MAX_VALUE,
32717 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32719 minText : "The minimum value for this field is {0}",
32721 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32723 maxText : "The maximum value for this field is {0}",
32725 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32726 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32728 nanText : "{0} is not a valid number",
32730 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32735 initEvents : function()
32737 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32739 var allowed = "0123456789";
32741 if(this.allowDecimals){
32742 allowed += this.decimalSeparator;
32745 if(this.allowNegative){
32749 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32751 var keyPress = function(e){
32753 var k = e.getKey();
32755 var c = e.getCharCode();
32758 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32759 allowed.indexOf(String.fromCharCode(c)) === -1
32765 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32769 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32774 this.el.on("keypress", keyPress, this);
32777 validateValue : function(value)
32780 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32784 var num = this.parseValue(value);
32787 this.markInvalid(String.format(this.nanText, value));
32791 if(num < this.minValue){
32792 this.markInvalid(String.format(this.minText, this.minValue));
32796 if(num > this.maxValue){
32797 this.markInvalid(String.format(this.maxText, this.maxValue));
32804 getValue : function()
32806 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32809 parseValue : function(value)
32811 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32812 return isNaN(value) ? '' : value;
32815 fixPrecision : function(value)
32817 var nan = isNaN(value);
32819 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32820 return nan ? '' : value;
32822 return parseFloat(value).toFixed(this.decimalPrecision);
32825 setValue : function(v)
32827 v = this.fixPrecision(v);
32828 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32831 decimalPrecisionFcn : function(v)
32833 return Math.floor(v);
32836 beforeBlur : function()
32842 var v = this.parseValue(this.getRawValue());
32857 * @class Roo.bootstrap.DocumentSlider
32858 * @extends Roo.bootstrap.Component
32859 * Bootstrap DocumentSlider class
32862 * Create a new DocumentViewer
32863 * @param {Object} config The config object
32866 Roo.bootstrap.DocumentSlider = function(config){
32867 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32874 * Fire after initEvent
32875 * @param {Roo.bootstrap.DocumentSlider} this
32880 * Fire after update
32881 * @param {Roo.bootstrap.DocumentSlider} this
32887 * @param {Roo.bootstrap.DocumentSlider} this
32893 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32899 getAutoCreate : function()
32903 cls : 'roo-document-slider',
32907 cls : 'roo-document-slider-header',
32911 cls : 'roo-document-slider-header-title'
32917 cls : 'roo-document-slider-body',
32921 cls : 'roo-document-slider-prev',
32925 cls : 'fa fa-chevron-left'
32931 cls : 'roo-document-slider-thumb',
32935 cls : 'roo-document-slider-image'
32941 cls : 'roo-document-slider-next',
32945 cls : 'fa fa-chevron-right'
32957 initEvents : function()
32959 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32960 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32962 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32963 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32965 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32966 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32968 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32969 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32971 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32972 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32974 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32975 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32977 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32978 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32980 this.thumbEl.on('click', this.onClick, this);
32982 this.prevIndicator.on('click', this.prev, this);
32984 this.nextIndicator.on('click', this.next, this);
32988 initial : function()
32990 if(this.files.length){
32991 this.indicator = 1;
32995 this.fireEvent('initial', this);
32998 update : function()
33000 this.imageEl.attr('src', this.files[this.indicator - 1]);
33002 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33004 this.prevIndicator.show();
33006 if(this.indicator == 1){
33007 this.prevIndicator.hide();
33010 this.nextIndicator.show();
33012 if(this.indicator == this.files.length){
33013 this.nextIndicator.hide();
33016 this.thumbEl.scrollTo('top');
33018 this.fireEvent('update', this);
33021 onClick : function(e)
33023 e.preventDefault();
33025 this.fireEvent('click', this);
33030 e.preventDefault();
33032 this.indicator = Math.max(1, this.indicator - 1);
33039 e.preventDefault();
33041 this.indicator = Math.min(this.files.length, this.indicator + 1);
33055 * @class Roo.bootstrap.RadioSet
33056 * @extends Roo.bootstrap.Input
33057 * Bootstrap RadioSet class
33058 * @cfg {String} indicatorpos (left|right) default left
33059 * @cfg {Boolean} inline (true|false) inline the element (default true)
33060 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33062 * Create a new RadioSet
33063 * @param {Object} config The config object
33066 Roo.bootstrap.RadioSet = function(config){
33068 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33072 Roo.bootstrap.RadioSet.register(this);
33077 * Fires when the element is checked or unchecked.
33078 * @param {Roo.bootstrap.RadioSet} this This radio
33079 * @param {Roo.bootstrap.Radio} item The checked item
33086 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33094 indicatorpos : 'left',
33096 getAutoCreate : function()
33100 cls : 'roo-radio-set-label',
33104 html : this.fieldLabel
33109 if(this.indicatorpos == 'left'){
33112 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33113 tooltip : 'This field is required'
33118 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33119 tooltip : 'This field is required'
33125 cls : 'roo-radio-set-items'
33128 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33130 if (align === 'left' && this.fieldLabel.length) {
33133 cls : "roo-radio-set-right",
33139 if(this.labelWidth > 12){
33140 label.style = "width: " + this.labelWidth + 'px';
33143 if(this.labelWidth < 13 && this.labelmd == 0){
33144 this.labelmd = this.labelWidth;
33147 if(this.labellg > 0){
33148 label.cls += ' col-lg-' + this.labellg;
33149 items.cls += ' col-lg-' + (12 - this.labellg);
33152 if(this.labelmd > 0){
33153 label.cls += ' col-md-' + this.labelmd;
33154 items.cls += ' col-md-' + (12 - this.labelmd);
33157 if(this.labelsm > 0){
33158 label.cls += ' col-sm-' + this.labelsm;
33159 items.cls += ' col-sm-' + (12 - this.labelsm);
33162 if(this.labelxs > 0){
33163 label.cls += ' col-xs-' + this.labelxs;
33164 items.cls += ' col-xs-' + (12 - this.labelxs);
33170 cls : 'roo-radio-set',
33174 cls : 'roo-radio-set-input',
33177 value : this.value ? this.value : ''
33184 if(this.weight.length){
33185 cfg.cls += ' roo-radio-' + this.weight;
33189 cfg.cls += ' roo-radio-set-inline';
33196 initEvents : function()
33198 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33199 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33201 if(!this.fieldLabel.length){
33202 this.labelEl.hide();
33205 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33206 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33208 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33209 this.indicatorEl().hide();
33211 this.originalValue = this.getValue();
33215 inputEl: function ()
33217 return this.el.select('.roo-radio-set-input', true).first();
33220 getChildContainer : function()
33222 return this.itemsEl;
33225 register : function(item)
33227 this.radioes.push(item);
33231 validate : function()
33235 Roo.each(this.radioes, function(i){
33244 if(this.allowBlank) {
33248 if(this.disabled || valid){
33253 this.markInvalid();
33258 markValid : function()
33260 if(this.labelEl.isVisible(true)){
33261 this.indicatorEl().hide();
33264 this.el.removeClass([this.invalidClass, this.validClass]);
33265 this.el.addClass(this.validClass);
33267 this.fireEvent('valid', this);
33270 markInvalid : function(msg)
33272 if(this.allowBlank || this.disabled){
33276 if(this.labelEl.isVisible(true)){
33277 this.indicatorEl().show();
33280 this.el.removeClass([this.invalidClass, this.validClass]);
33281 this.el.addClass(this.invalidClass);
33283 this.fireEvent('invalid', this, msg);
33287 setValue : function(v, suppressEvent)
33289 Roo.each(this.radioes, function(i){
33292 i.el.removeClass('checked');
33294 if(i.value === v || i.value.toString() === v.toString()){
33296 i.el.addClass('checked');
33298 if(suppressEvent !== true){
33299 this.fireEvent('check', this, i);
33305 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
33309 clearInvalid : function(){
33311 if(!this.el || this.preventMark){
33316 this.el.removeClass([this.invalidClass]);
33318 this.fireEvent('valid', this);
33323 Roo.apply(Roo.bootstrap.RadioSet, {
33327 register : function(set)
33329 this.groups[set.name] = set;
33332 get: function(name)
33334 if (typeof(this.groups[name]) == 'undefined') {
33338 return this.groups[name] ;
33344 * Ext JS Library 1.1.1
33345 * Copyright(c) 2006-2007, Ext JS, LLC.
33347 * Originally Released Under LGPL - original licence link has changed is not relivant.
33350 * <script type="text/javascript">
33355 * @class Roo.bootstrap.SplitBar
33356 * @extends Roo.util.Observable
33357 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33361 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33362 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33363 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33364 split.minSize = 100;
33365 split.maxSize = 600;
33366 split.animate = true;
33367 split.on('moved', splitterMoved);
33370 * Create a new SplitBar
33371 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33372 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33373 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33374 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33375 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33376 position of the SplitBar).
33378 Roo.bootstrap.SplitBar = function(cfg){
33383 // dragElement : elm
33384 // resizingElement: el,
33386 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33387 // placement : Roo.bootstrap.SplitBar.LEFT ,
33388 // existingProxy ???
33391 this.el = Roo.get(cfg.dragElement, true);
33392 this.el.dom.unselectable = "on";
33394 this.resizingEl = Roo.get(cfg.resizingElement, true);
33398 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33399 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33402 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33405 * The minimum size of the resizing element. (Defaults to 0)
33411 * The maximum size of the resizing element. (Defaults to 2000)
33414 this.maxSize = 2000;
33417 * Whether to animate the transition to the new size
33420 this.animate = false;
33423 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33426 this.useShim = false;
33431 if(!cfg.existingProxy){
33433 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33435 this.proxy = Roo.get(cfg.existingProxy).dom;
33438 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33441 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33444 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33447 this.dragSpecs = {};
33450 * @private The adapter to use to positon and resize elements
33452 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33453 this.adapter.init(this);
33455 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33457 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33458 this.el.addClass("roo-splitbar-h");
33461 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33462 this.el.addClass("roo-splitbar-v");
33468 * Fires when the splitter is moved (alias for {@link #event-moved})
33469 * @param {Roo.bootstrap.SplitBar} this
33470 * @param {Number} newSize the new width or height
33475 * Fires when the splitter is moved
33476 * @param {Roo.bootstrap.SplitBar} this
33477 * @param {Number} newSize the new width or height
33481 * @event beforeresize
33482 * Fires before the splitter is dragged
33483 * @param {Roo.bootstrap.SplitBar} this
33485 "beforeresize" : true,
33487 "beforeapply" : true
33490 Roo.util.Observable.call(this);
33493 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33494 onStartProxyDrag : function(x, y){
33495 this.fireEvent("beforeresize", this);
33497 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33499 o.enableDisplayMode("block");
33500 // all splitbars share the same overlay
33501 Roo.bootstrap.SplitBar.prototype.overlay = o;
33503 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33504 this.overlay.show();
33505 Roo.get(this.proxy).setDisplayed("block");
33506 var size = this.adapter.getElementSize(this);
33507 this.activeMinSize = this.getMinimumSize();;
33508 this.activeMaxSize = this.getMaximumSize();;
33509 var c1 = size - this.activeMinSize;
33510 var c2 = Math.max(this.activeMaxSize - size, 0);
33511 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33512 this.dd.resetConstraints();
33513 this.dd.setXConstraint(
33514 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33515 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33517 this.dd.setYConstraint(0, 0);
33519 this.dd.resetConstraints();
33520 this.dd.setXConstraint(0, 0);
33521 this.dd.setYConstraint(
33522 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33523 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33526 this.dragSpecs.startSize = size;
33527 this.dragSpecs.startPoint = [x, y];
33528 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33532 * @private Called after the drag operation by the DDProxy
33534 onEndProxyDrag : function(e){
33535 Roo.get(this.proxy).setDisplayed(false);
33536 var endPoint = Roo.lib.Event.getXY(e);
33538 this.overlay.hide();
33541 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33542 newSize = this.dragSpecs.startSize +
33543 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33544 endPoint[0] - this.dragSpecs.startPoint[0] :
33545 this.dragSpecs.startPoint[0] - endPoint[0]
33548 newSize = this.dragSpecs.startSize +
33549 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33550 endPoint[1] - this.dragSpecs.startPoint[1] :
33551 this.dragSpecs.startPoint[1] - endPoint[1]
33554 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33555 if(newSize != this.dragSpecs.startSize){
33556 if(this.fireEvent('beforeapply', this, newSize) !== false){
33557 this.adapter.setElementSize(this, newSize);
33558 this.fireEvent("moved", this, newSize);
33559 this.fireEvent("resize", this, newSize);
33565 * Get the adapter this SplitBar uses
33566 * @return The adapter object
33568 getAdapter : function(){
33569 return this.adapter;
33573 * Set the adapter this SplitBar uses
33574 * @param {Object} adapter A SplitBar adapter object
33576 setAdapter : function(adapter){
33577 this.adapter = adapter;
33578 this.adapter.init(this);
33582 * Gets the minimum size for the resizing element
33583 * @return {Number} The minimum size
33585 getMinimumSize : function(){
33586 return this.minSize;
33590 * Sets the minimum size for the resizing element
33591 * @param {Number} minSize The minimum size
33593 setMinimumSize : function(minSize){
33594 this.minSize = minSize;
33598 * Gets the maximum size for the resizing element
33599 * @return {Number} The maximum size
33601 getMaximumSize : function(){
33602 return this.maxSize;
33606 * Sets the maximum size for the resizing element
33607 * @param {Number} maxSize The maximum size
33609 setMaximumSize : function(maxSize){
33610 this.maxSize = maxSize;
33614 * Sets the initialize size for the resizing element
33615 * @param {Number} size The initial size
33617 setCurrentSize : function(size){
33618 var oldAnimate = this.animate;
33619 this.animate = false;
33620 this.adapter.setElementSize(this, size);
33621 this.animate = oldAnimate;
33625 * Destroy this splitbar.
33626 * @param {Boolean} removeEl True to remove the element
33628 destroy : function(removeEl){
33630 this.shim.remove();
33633 this.proxy.parentNode.removeChild(this.proxy);
33641 * @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.
33643 Roo.bootstrap.SplitBar.createProxy = function(dir){
33644 var proxy = new Roo.Element(document.createElement("div"));
33645 proxy.unselectable();
33646 var cls = 'roo-splitbar-proxy';
33647 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33648 document.body.appendChild(proxy.dom);
33653 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33654 * Default Adapter. It assumes the splitter and resizing element are not positioned
33655 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33657 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33660 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33661 // do nothing for now
33662 init : function(s){
33666 * Called before drag operations to get the current size of the resizing element.
33667 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33669 getElementSize : function(s){
33670 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33671 return s.resizingEl.getWidth();
33673 return s.resizingEl.getHeight();
33678 * Called after drag operations to set the size of the resizing element.
33679 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33680 * @param {Number} newSize The new size to set
33681 * @param {Function} onComplete A function to be invoked when resizing is complete
33683 setElementSize : function(s, newSize, onComplete){
33684 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33686 s.resizingEl.setWidth(newSize);
33688 onComplete(s, newSize);
33691 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33696 s.resizingEl.setHeight(newSize);
33698 onComplete(s, newSize);
33701 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33708 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33709 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33710 * Adapter that moves the splitter element to align with the resized sizing element.
33711 * Used with an absolute positioned SplitBar.
33712 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33713 * document.body, make sure you assign an id to the body element.
33715 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33716 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33717 this.container = Roo.get(container);
33720 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33721 init : function(s){
33722 this.basic.init(s);
33725 getElementSize : function(s){
33726 return this.basic.getElementSize(s);
33729 setElementSize : function(s, newSize, onComplete){
33730 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33733 moveSplitter : function(s){
33734 var yes = Roo.bootstrap.SplitBar;
33735 switch(s.placement){
33737 s.el.setX(s.resizingEl.getRight());
33740 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33743 s.el.setY(s.resizingEl.getBottom());
33746 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33753 * Orientation constant - Create a vertical SplitBar
33757 Roo.bootstrap.SplitBar.VERTICAL = 1;
33760 * Orientation constant - Create a horizontal SplitBar
33764 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33767 * Placement constant - The resizing element is to the left of the splitter element
33771 Roo.bootstrap.SplitBar.LEFT = 1;
33774 * Placement constant - The resizing element is to the right of the splitter element
33778 Roo.bootstrap.SplitBar.RIGHT = 2;
33781 * Placement constant - The resizing element is positioned above the splitter element
33785 Roo.bootstrap.SplitBar.TOP = 3;
33788 * Placement constant - The resizing element is positioned under splitter element
33792 Roo.bootstrap.SplitBar.BOTTOM = 4;
33793 Roo.namespace("Roo.bootstrap.layout");/*
33795 * Ext JS Library 1.1.1
33796 * Copyright(c) 2006-2007, Ext JS, LLC.
33798 * Originally Released Under LGPL - original licence link has changed is not relivant.
33801 * <script type="text/javascript">
33805 * @class Roo.bootstrap.layout.Manager
33806 * @extends Roo.bootstrap.Component
33807 * Base class for layout managers.
33809 Roo.bootstrap.layout.Manager = function(config)
33811 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33817 /** false to disable window resize monitoring @type Boolean */
33818 this.monitorWindowResize = true;
33823 * Fires when a layout is performed.
33824 * @param {Roo.LayoutManager} this
33828 * @event regionresized
33829 * Fires when the user resizes a region.
33830 * @param {Roo.LayoutRegion} region The resized region
33831 * @param {Number} newSize The new size (width for east/west, height for north/south)
33833 "regionresized" : true,
33835 * @event regioncollapsed
33836 * Fires when a region is collapsed.
33837 * @param {Roo.LayoutRegion} region The collapsed region
33839 "regioncollapsed" : true,
33841 * @event regionexpanded
33842 * Fires when a region is expanded.
33843 * @param {Roo.LayoutRegion} region The expanded region
33845 "regionexpanded" : true
33847 this.updating = false;
33850 this.el = Roo.get(config.el);
33856 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33861 monitorWindowResize : true,
33867 onRender : function(ct, position)
33870 this.el = Roo.get(ct);
33873 //this.fireEvent('render',this);
33877 initEvents: function()
33881 // ie scrollbar fix
33882 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33883 document.body.scroll = "no";
33884 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33885 this.el.position('relative');
33887 this.id = this.el.id;
33888 this.el.addClass("roo-layout-container");
33889 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33890 if(this.el.dom != document.body ) {
33891 this.el.on('resize', this.layout,this);
33892 this.el.on('show', this.layout,this);
33898 * Returns true if this layout is currently being updated
33899 * @return {Boolean}
33901 isUpdating : function(){
33902 return this.updating;
33906 * Suspend the LayoutManager from doing auto-layouts while
33907 * making multiple add or remove calls
33909 beginUpdate : function(){
33910 this.updating = true;
33914 * Restore auto-layouts and optionally disable the manager from performing a layout
33915 * @param {Boolean} noLayout true to disable a layout update
33917 endUpdate : function(noLayout){
33918 this.updating = false;
33924 layout: function(){
33928 onRegionResized : function(region, newSize){
33929 this.fireEvent("regionresized", region, newSize);
33933 onRegionCollapsed : function(region){
33934 this.fireEvent("regioncollapsed", region);
33937 onRegionExpanded : function(region){
33938 this.fireEvent("regionexpanded", region);
33942 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33943 * performs box-model adjustments.
33944 * @return {Object} The size as an object {width: (the width), height: (the height)}
33946 getViewSize : function()
33949 if(this.el.dom != document.body){
33950 size = this.el.getSize();
33952 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33954 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33955 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33960 * Returns the Element this layout is bound to.
33961 * @return {Roo.Element}
33963 getEl : function(){
33968 * Returns the specified region.
33969 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33970 * @return {Roo.LayoutRegion}
33972 getRegion : function(target){
33973 return this.regions[target.toLowerCase()];
33976 onWindowResize : function(){
33977 if(this.monitorWindowResize){
33984 * Ext JS Library 1.1.1
33985 * Copyright(c) 2006-2007, Ext JS, LLC.
33987 * Originally Released Under LGPL - original licence link has changed is not relivant.
33990 * <script type="text/javascript">
33993 * @class Roo.bootstrap.layout.Border
33994 * @extends Roo.bootstrap.layout.Manager
33995 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33996 * please see: examples/bootstrap/nested.html<br><br>
33998 <b>The container the layout is rendered into can be either the body element or any other element.
33999 If it is not the body element, the container needs to either be an absolute positioned element,
34000 or you will need to add "position:relative" to the css of the container. You will also need to specify
34001 the container size if it is not the body element.</b>
34004 * Create a new Border
34005 * @param {Object} config Configuration options
34007 Roo.bootstrap.layout.Border = function(config){
34008 config = config || {};
34009 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34013 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34014 if(config[region]){
34015 config[region].region = region;
34016 this.addRegion(config[region]);
34022 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34024 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34026 * Creates and adds a new region if it doesn't already exist.
34027 * @param {String} target The target region key (north, south, east, west or center).
34028 * @param {Object} config The regions config object
34029 * @return {BorderLayoutRegion} The new region
34031 addRegion : function(config)
34033 if(!this.regions[config.region]){
34034 var r = this.factory(config);
34035 this.bindRegion(r);
34037 return this.regions[config.region];
34041 bindRegion : function(r){
34042 this.regions[r.config.region] = r;
34044 r.on("visibilitychange", this.layout, this);
34045 r.on("paneladded", this.layout, this);
34046 r.on("panelremoved", this.layout, this);
34047 r.on("invalidated", this.layout, this);
34048 r.on("resized", this.onRegionResized, this);
34049 r.on("collapsed", this.onRegionCollapsed, this);
34050 r.on("expanded", this.onRegionExpanded, this);
34054 * Performs a layout update.
34056 layout : function()
34058 if(this.updating) {
34062 // render all the rebions if they have not been done alreayd?
34063 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34064 if(this.regions[region] && !this.regions[region].bodyEl){
34065 this.regions[region].onRender(this.el)
34069 var size = this.getViewSize();
34070 var w = size.width;
34071 var h = size.height;
34076 //var x = 0, y = 0;
34078 var rs = this.regions;
34079 var north = rs["north"];
34080 var south = rs["south"];
34081 var west = rs["west"];
34082 var east = rs["east"];
34083 var center = rs["center"];
34084 //if(this.hideOnLayout){ // not supported anymore
34085 //c.el.setStyle("display", "none");
34087 if(north && north.isVisible()){
34088 var b = north.getBox();
34089 var m = north.getMargins();
34090 b.width = w - (m.left+m.right);
34093 centerY = b.height + b.y + m.bottom;
34094 centerH -= centerY;
34095 north.updateBox(this.safeBox(b));
34097 if(south && south.isVisible()){
34098 var b = south.getBox();
34099 var m = south.getMargins();
34100 b.width = w - (m.left+m.right);
34102 var totalHeight = (b.height + m.top + m.bottom);
34103 b.y = h - totalHeight + m.top;
34104 centerH -= totalHeight;
34105 south.updateBox(this.safeBox(b));
34107 if(west && west.isVisible()){
34108 var b = west.getBox();
34109 var m = west.getMargins();
34110 b.height = centerH - (m.top+m.bottom);
34112 b.y = centerY + m.top;
34113 var totalWidth = (b.width + m.left + m.right);
34114 centerX += totalWidth;
34115 centerW -= totalWidth;
34116 west.updateBox(this.safeBox(b));
34118 if(east && east.isVisible()){
34119 var b = east.getBox();
34120 var m = east.getMargins();
34121 b.height = centerH - (m.top+m.bottom);
34122 var totalWidth = (b.width + m.left + m.right);
34123 b.x = w - totalWidth + m.left;
34124 b.y = centerY + m.top;
34125 centerW -= totalWidth;
34126 east.updateBox(this.safeBox(b));
34129 var m = center.getMargins();
34131 x: centerX + m.left,
34132 y: centerY + m.top,
34133 width: centerW - (m.left+m.right),
34134 height: centerH - (m.top+m.bottom)
34136 //if(this.hideOnLayout){
34137 //center.el.setStyle("display", "block");
34139 center.updateBox(this.safeBox(centerBox));
34142 this.fireEvent("layout", this);
34146 safeBox : function(box){
34147 box.width = Math.max(0, box.width);
34148 box.height = Math.max(0, box.height);
34153 * Adds a ContentPanel (or subclass) to this layout.
34154 * @param {String} target The target region key (north, south, east, west or center).
34155 * @param {Roo.ContentPanel} panel The panel to add
34156 * @return {Roo.ContentPanel} The added panel
34158 add : function(target, panel){
34160 target = target.toLowerCase();
34161 return this.regions[target].add(panel);
34165 * Remove a ContentPanel (or subclass) to this layout.
34166 * @param {String} target The target region key (north, south, east, west or center).
34167 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34168 * @return {Roo.ContentPanel} The removed panel
34170 remove : function(target, panel){
34171 target = target.toLowerCase();
34172 return this.regions[target].remove(panel);
34176 * Searches all regions for a panel with the specified id
34177 * @param {String} panelId
34178 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34180 findPanel : function(panelId){
34181 var rs = this.regions;
34182 for(var target in rs){
34183 if(typeof rs[target] != "function"){
34184 var p = rs[target].getPanel(panelId);
34194 * Searches all regions for a panel with the specified id and activates (shows) it.
34195 * @param {String/ContentPanel} panelId The panels id or the panel itself
34196 * @return {Roo.ContentPanel} The shown panel or null
34198 showPanel : function(panelId) {
34199 var rs = this.regions;
34200 for(var target in rs){
34201 var r = rs[target];
34202 if(typeof r != "function"){
34203 if(r.hasPanel(panelId)){
34204 return r.showPanel(panelId);
34212 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34213 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34216 restoreState : function(provider){
34218 provider = Roo.state.Manager;
34220 var sm = new Roo.LayoutStateManager();
34221 sm.init(this, provider);
34227 * Adds a xtype elements to the layout.
34231 xtype : 'ContentPanel',
34238 xtype : 'NestedLayoutPanel',
34244 items : [ ... list of content panels or nested layout panels.. ]
34248 * @param {Object} cfg Xtype definition of item to add.
34250 addxtype : function(cfg)
34252 // basically accepts a pannel...
34253 // can accept a layout region..!?!?
34254 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34257 // theory? children can only be panels??
34259 //if (!cfg.xtype.match(/Panel$/)) {
34264 if (typeof(cfg.region) == 'undefined') {
34265 Roo.log("Failed to add Panel, region was not set");
34269 var region = cfg.region;
34275 xitems = cfg.items;
34282 case 'Content': // ContentPanel (el, cfg)
34283 case 'Scroll': // ContentPanel (el, cfg)
34285 cfg.autoCreate = true;
34286 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34288 // var el = this.el.createChild();
34289 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34292 this.add(region, ret);
34296 case 'TreePanel': // our new panel!
34297 cfg.el = this.el.createChild();
34298 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34299 this.add(region, ret);
34304 // create a new Layout (which is a Border Layout...
34306 var clayout = cfg.layout;
34307 clayout.el = this.el.createChild();
34308 clayout.items = clayout.items || [];
34312 // replace this exitems with the clayout ones..
34313 xitems = clayout.items;
34315 // force background off if it's in center...
34316 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34317 cfg.background = false;
34319 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34322 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34323 //console.log('adding nested layout panel ' + cfg.toSource());
34324 this.add(region, ret);
34325 nb = {}; /// find first...
34330 // needs grid and region
34332 //var el = this.getRegion(region).el.createChild();
34334 *var el = this.el.createChild();
34335 // create the grid first...
34336 cfg.grid.container = el;
34337 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34340 if (region == 'center' && this.active ) {
34341 cfg.background = false;
34344 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34346 this.add(region, ret);
34348 if (cfg.background) {
34349 // render grid on panel activation (if panel background)
34350 ret.on('activate', function(gp) {
34351 if (!gp.grid.rendered) {
34352 // gp.grid.render(el);
34356 // cfg.grid.render(el);
34362 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34363 // it was the old xcomponent building that caused this before.
34364 // espeically if border is the top element in the tree.
34374 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34376 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34377 this.add(region, ret);
34381 throw "Can not add '" + cfg.xtype + "' to Border";
34387 this.beginUpdate();
34391 Roo.each(xitems, function(i) {
34392 region = nb && i.region ? i.region : false;
34394 var add = ret.addxtype(i);
34397 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34398 if (!i.background) {
34399 abn[region] = nb[region] ;
34406 // make the last non-background panel active..
34407 //if (nb) { Roo.log(abn); }
34410 for(var r in abn) {
34411 region = this.getRegion(r);
34413 // tried using nb[r], but it does not work..
34415 region.showPanel(abn[r]);
34426 factory : function(cfg)
34429 var validRegions = Roo.bootstrap.layout.Border.regions;
34431 var target = cfg.region;
34434 var r = Roo.bootstrap.layout;
34438 return new r.North(cfg);
34440 return new r.South(cfg);
34442 return new r.East(cfg);
34444 return new r.West(cfg);
34446 return new r.Center(cfg);
34448 throw 'Layout region "'+target+'" not supported.';
34455 * Ext JS Library 1.1.1
34456 * Copyright(c) 2006-2007, Ext JS, LLC.
34458 * Originally Released Under LGPL - original licence link has changed is not relivant.
34461 * <script type="text/javascript">
34465 * @class Roo.bootstrap.layout.Basic
34466 * @extends Roo.util.Observable
34467 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34468 * and does not have a titlebar, tabs or any other features. All it does is size and position
34469 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34470 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34471 * @cfg {string} region the region that it inhabits..
34472 * @cfg {bool} skipConfig skip config?
34476 Roo.bootstrap.layout.Basic = function(config){
34478 this.mgr = config.mgr;
34480 this.position = config.region;
34482 var skipConfig = config.skipConfig;
34486 * @scope Roo.BasicLayoutRegion
34490 * @event beforeremove
34491 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34492 * @param {Roo.LayoutRegion} this
34493 * @param {Roo.ContentPanel} panel The panel
34494 * @param {Object} e The cancel event object
34496 "beforeremove" : true,
34498 * @event invalidated
34499 * Fires when the layout for this region is changed.
34500 * @param {Roo.LayoutRegion} this
34502 "invalidated" : true,
34504 * @event visibilitychange
34505 * Fires when this region is shown or hidden
34506 * @param {Roo.LayoutRegion} this
34507 * @param {Boolean} visibility true or false
34509 "visibilitychange" : true,
34511 * @event paneladded
34512 * Fires when a panel is added.
34513 * @param {Roo.LayoutRegion} this
34514 * @param {Roo.ContentPanel} panel The panel
34516 "paneladded" : true,
34518 * @event panelremoved
34519 * Fires when a panel is removed.
34520 * @param {Roo.LayoutRegion} this
34521 * @param {Roo.ContentPanel} panel The panel
34523 "panelremoved" : true,
34525 * @event beforecollapse
34526 * Fires when this region before collapse.
34527 * @param {Roo.LayoutRegion} this
34529 "beforecollapse" : true,
34532 * Fires when this region is collapsed.
34533 * @param {Roo.LayoutRegion} this
34535 "collapsed" : true,
34538 * Fires when this region is expanded.
34539 * @param {Roo.LayoutRegion} this
34544 * Fires when this region is slid into view.
34545 * @param {Roo.LayoutRegion} this
34547 "slideshow" : true,
34550 * Fires when this region slides out of view.
34551 * @param {Roo.LayoutRegion} this
34553 "slidehide" : true,
34555 * @event panelactivated
34556 * Fires when a panel is activated.
34557 * @param {Roo.LayoutRegion} this
34558 * @param {Roo.ContentPanel} panel The activated panel
34560 "panelactivated" : true,
34563 * Fires when the user resizes this region.
34564 * @param {Roo.LayoutRegion} this
34565 * @param {Number} newSize The new size (width for east/west, height for north/south)
34569 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34570 this.panels = new Roo.util.MixedCollection();
34571 this.panels.getKey = this.getPanelId.createDelegate(this);
34573 this.activePanel = null;
34574 // ensure listeners are added...
34576 if (config.listeners || config.events) {
34577 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34578 listeners : config.listeners || {},
34579 events : config.events || {}
34583 if(skipConfig !== true){
34584 this.applyConfig(config);
34588 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34590 getPanelId : function(p){
34594 applyConfig : function(config){
34595 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34596 this.config = config;
34601 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34602 * the width, for horizontal (north, south) the height.
34603 * @param {Number} newSize The new width or height
34605 resizeTo : function(newSize){
34606 var el = this.el ? this.el :
34607 (this.activePanel ? this.activePanel.getEl() : null);
34609 switch(this.position){
34612 el.setWidth(newSize);
34613 this.fireEvent("resized", this, newSize);
34617 el.setHeight(newSize);
34618 this.fireEvent("resized", this, newSize);
34624 getBox : function(){
34625 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34628 getMargins : function(){
34629 return this.margins;
34632 updateBox : function(box){
34634 var el = this.activePanel.getEl();
34635 el.dom.style.left = box.x + "px";
34636 el.dom.style.top = box.y + "px";
34637 this.activePanel.setSize(box.width, box.height);
34641 * Returns the container element for this region.
34642 * @return {Roo.Element}
34644 getEl : function(){
34645 return this.activePanel;
34649 * Returns true if this region is currently visible.
34650 * @return {Boolean}
34652 isVisible : function(){
34653 return this.activePanel ? true : false;
34656 setActivePanel : function(panel){
34657 panel = this.getPanel(panel);
34658 if(this.activePanel && this.activePanel != panel){
34659 this.activePanel.setActiveState(false);
34660 this.activePanel.getEl().setLeftTop(-10000,-10000);
34662 this.activePanel = panel;
34663 panel.setActiveState(true);
34665 panel.setSize(this.box.width, this.box.height);
34667 this.fireEvent("panelactivated", this, panel);
34668 this.fireEvent("invalidated");
34672 * Show the specified panel.
34673 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34674 * @return {Roo.ContentPanel} The shown panel or null
34676 showPanel : function(panel){
34677 panel = this.getPanel(panel);
34679 this.setActivePanel(panel);
34685 * Get the active panel for this region.
34686 * @return {Roo.ContentPanel} The active panel or null
34688 getActivePanel : function(){
34689 return this.activePanel;
34693 * Add the passed ContentPanel(s)
34694 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34695 * @return {Roo.ContentPanel} The panel added (if only one was added)
34697 add : function(panel){
34698 if(arguments.length > 1){
34699 for(var i = 0, len = arguments.length; i < len; i++) {
34700 this.add(arguments[i]);
34704 if(this.hasPanel(panel)){
34705 this.showPanel(panel);
34708 var el = panel.getEl();
34709 if(el.dom.parentNode != this.mgr.el.dom){
34710 this.mgr.el.dom.appendChild(el.dom);
34712 if(panel.setRegion){
34713 panel.setRegion(this);
34715 this.panels.add(panel);
34716 el.setStyle("position", "absolute");
34717 if(!panel.background){
34718 this.setActivePanel(panel);
34719 if(this.config.initialSize && this.panels.getCount()==1){
34720 this.resizeTo(this.config.initialSize);
34723 this.fireEvent("paneladded", this, panel);
34728 * Returns true if the panel is in this region.
34729 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34730 * @return {Boolean}
34732 hasPanel : function(panel){
34733 if(typeof panel == "object"){ // must be panel obj
34734 panel = panel.getId();
34736 return this.getPanel(panel) ? true : false;
34740 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34741 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34742 * @param {Boolean} preservePanel Overrides the config preservePanel option
34743 * @return {Roo.ContentPanel} The panel that was removed
34745 remove : function(panel, preservePanel){
34746 panel = this.getPanel(panel);
34751 this.fireEvent("beforeremove", this, panel, e);
34752 if(e.cancel === true){
34755 var panelId = panel.getId();
34756 this.panels.removeKey(panelId);
34761 * Returns the panel specified or null if it's not in this region.
34762 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34763 * @return {Roo.ContentPanel}
34765 getPanel : function(id){
34766 if(typeof id == "object"){ // must be panel obj
34769 return this.panels.get(id);
34773 * Returns this regions position (north/south/east/west/center).
34776 getPosition: function(){
34777 return this.position;
34781 * Ext JS Library 1.1.1
34782 * Copyright(c) 2006-2007, Ext JS, LLC.
34784 * Originally Released Under LGPL - original licence link has changed is not relivant.
34787 * <script type="text/javascript">
34791 * @class Roo.bootstrap.layout.Region
34792 * @extends Roo.bootstrap.layout.Basic
34793 * This class represents a region in a layout manager.
34795 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34796 * @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})
34797 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34798 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34799 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34800 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34801 * @cfg {String} title The title for the region (overrides panel titles)
34802 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34803 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34804 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34805 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34806 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34807 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34808 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34809 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34810 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34811 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34813 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34814 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34815 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34816 * @cfg {Number} width For East/West panels
34817 * @cfg {Number} height For North/South panels
34818 * @cfg {Boolean} split To show the splitter
34819 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34821 * @cfg {string} cls Extra CSS classes to add to region
34823 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34824 * @cfg {string} region the region that it inhabits..
34827 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34828 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34830 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34831 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34832 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34834 Roo.bootstrap.layout.Region = function(config)
34836 this.applyConfig(config);
34838 var mgr = config.mgr;
34839 var pos = config.region;
34840 config.skipConfig = true;
34841 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34844 this.onRender(mgr.el);
34847 this.visible = true;
34848 this.collapsed = false;
34849 this.unrendered_panels = [];
34852 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34854 position: '', // set by wrapper (eg. north/south etc..)
34855 unrendered_panels : null, // unrendered panels.
34856 createBody : function(){
34857 /** This region's body element
34858 * @type Roo.Element */
34859 this.bodyEl = this.el.createChild({
34861 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34865 onRender: function(ctr, pos)
34867 var dh = Roo.DomHelper;
34868 /** This region's container element
34869 * @type Roo.Element */
34870 this.el = dh.append(ctr.dom, {
34872 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34874 /** This region's title element
34875 * @type Roo.Element */
34877 this.titleEl = dh.append(this.el.dom,
34880 unselectable: "on",
34881 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34883 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34884 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34887 this.titleEl.enableDisplayMode();
34888 /** This region's title text element
34889 * @type HTMLElement */
34890 this.titleTextEl = this.titleEl.dom.firstChild;
34891 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34893 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34894 this.closeBtn.enableDisplayMode();
34895 this.closeBtn.on("click", this.closeClicked, this);
34896 this.closeBtn.hide();
34898 this.createBody(this.config);
34899 if(this.config.hideWhenEmpty){
34901 this.on("paneladded", this.validateVisibility, this);
34902 this.on("panelremoved", this.validateVisibility, this);
34904 if(this.autoScroll){
34905 this.bodyEl.setStyle("overflow", "auto");
34907 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34909 //if(c.titlebar !== false){
34910 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34911 this.titleEl.hide();
34913 this.titleEl.show();
34914 if(this.config.title){
34915 this.titleTextEl.innerHTML = this.config.title;
34919 if(this.config.collapsed){
34920 this.collapse(true);
34922 if(this.config.hidden){
34926 if (this.unrendered_panels && this.unrendered_panels.length) {
34927 for (var i =0;i< this.unrendered_panels.length; i++) {
34928 this.add(this.unrendered_panels[i]);
34930 this.unrendered_panels = null;
34936 applyConfig : function(c)
34939 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34940 var dh = Roo.DomHelper;
34941 if(c.titlebar !== false){
34942 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34943 this.collapseBtn.on("click", this.collapse, this);
34944 this.collapseBtn.enableDisplayMode();
34946 if(c.showPin === true || this.showPin){
34947 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34948 this.stickBtn.enableDisplayMode();
34949 this.stickBtn.on("click", this.expand, this);
34950 this.stickBtn.hide();
34955 /** This region's collapsed element
34956 * @type Roo.Element */
34959 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34960 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34963 if(c.floatable !== false){
34964 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34965 this.collapsedEl.on("click", this.collapseClick, this);
34968 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34969 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34970 id: "message", unselectable: "on", style:{"float":"left"}});
34971 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34973 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34974 this.expandBtn.on("click", this.expand, this);
34978 if(this.collapseBtn){
34979 this.collapseBtn.setVisible(c.collapsible == true);
34982 this.cmargins = c.cmargins || this.cmargins ||
34983 (this.position == "west" || this.position == "east" ?
34984 {top: 0, left: 2, right:2, bottom: 0} :
34985 {top: 2, left: 0, right:0, bottom: 2});
34987 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34990 this.bottomTabs = c.tabPosition != "top";
34992 this.autoScroll = c.autoScroll || false;
34997 this.duration = c.duration || .30;
34998 this.slideDuration = c.slideDuration || .45;
35003 * Returns true if this region is currently visible.
35004 * @return {Boolean}
35006 isVisible : function(){
35007 return this.visible;
35011 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35012 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35014 //setCollapsedTitle : function(title){
35015 // title = title || " ";
35016 // if(this.collapsedTitleTextEl){
35017 // this.collapsedTitleTextEl.innerHTML = title;
35021 getBox : function(){
35023 // if(!this.collapsed){
35024 b = this.el.getBox(false, true);
35026 // b = this.collapsedEl.getBox(false, true);
35031 getMargins : function(){
35032 return this.margins;
35033 //return this.collapsed ? this.cmargins : this.margins;
35036 highlight : function(){
35037 this.el.addClass("x-layout-panel-dragover");
35040 unhighlight : function(){
35041 this.el.removeClass("x-layout-panel-dragover");
35044 updateBox : function(box)
35046 if (!this.bodyEl) {
35047 return; // not rendered yet..
35051 if(!this.collapsed){
35052 this.el.dom.style.left = box.x + "px";
35053 this.el.dom.style.top = box.y + "px";
35054 this.updateBody(box.width, box.height);
35056 this.collapsedEl.dom.style.left = box.x + "px";
35057 this.collapsedEl.dom.style.top = box.y + "px";
35058 this.collapsedEl.setSize(box.width, box.height);
35061 this.tabs.autoSizeTabs();
35065 updateBody : function(w, h)
35068 this.el.setWidth(w);
35069 w -= this.el.getBorderWidth("rl");
35070 if(this.config.adjustments){
35071 w += this.config.adjustments[0];
35074 if(h !== null && h > 0){
35075 this.el.setHeight(h);
35076 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35077 h -= this.el.getBorderWidth("tb");
35078 if(this.config.adjustments){
35079 h += this.config.adjustments[1];
35081 this.bodyEl.setHeight(h);
35083 h = this.tabs.syncHeight(h);
35086 if(this.panelSize){
35087 w = w !== null ? w : this.panelSize.width;
35088 h = h !== null ? h : this.panelSize.height;
35090 if(this.activePanel){
35091 var el = this.activePanel.getEl();
35092 w = w !== null ? w : el.getWidth();
35093 h = h !== null ? h : el.getHeight();
35094 this.panelSize = {width: w, height: h};
35095 this.activePanel.setSize(w, h);
35097 if(Roo.isIE && this.tabs){
35098 this.tabs.el.repaint();
35103 * Returns the container element for this region.
35104 * @return {Roo.Element}
35106 getEl : function(){
35111 * Hides this region.
35114 //if(!this.collapsed){
35115 this.el.dom.style.left = "-2000px";
35118 // this.collapsedEl.dom.style.left = "-2000px";
35119 // this.collapsedEl.hide();
35121 this.visible = false;
35122 this.fireEvent("visibilitychange", this, false);
35126 * Shows this region if it was previously hidden.
35129 //if(!this.collapsed){
35132 // this.collapsedEl.show();
35134 this.visible = true;
35135 this.fireEvent("visibilitychange", this, true);
35138 closeClicked : function(){
35139 if(this.activePanel){
35140 this.remove(this.activePanel);
35144 collapseClick : function(e){
35146 e.stopPropagation();
35149 e.stopPropagation();
35155 * Collapses this region.
35156 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35159 collapse : function(skipAnim, skipCheck = false){
35160 if(this.collapsed) {
35164 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35166 this.collapsed = true;
35168 this.split.el.hide();
35170 if(this.config.animate && skipAnim !== true){
35171 this.fireEvent("invalidated", this);
35172 this.animateCollapse();
35174 this.el.setLocation(-20000,-20000);
35176 this.collapsedEl.show();
35177 this.fireEvent("collapsed", this);
35178 this.fireEvent("invalidated", this);
35184 animateCollapse : function(){
35189 * Expands this region if it was previously collapsed.
35190 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35191 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35194 expand : function(e, skipAnim){
35196 e.stopPropagation();
35198 if(!this.collapsed || this.el.hasActiveFx()) {
35202 this.afterSlideIn();
35205 this.collapsed = false;
35206 if(this.config.animate && skipAnim !== true){
35207 this.animateExpand();
35211 this.split.el.show();
35213 this.collapsedEl.setLocation(-2000,-2000);
35214 this.collapsedEl.hide();
35215 this.fireEvent("invalidated", this);
35216 this.fireEvent("expanded", this);
35220 animateExpand : function(){
35224 initTabs : function()
35226 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35228 var ts = new Roo.bootstrap.panel.Tabs({
35229 el: this.bodyEl.dom,
35230 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35231 disableTooltips: this.config.disableTabTips,
35232 toolbar : this.config.toolbar
35235 if(this.config.hideTabs){
35236 ts.stripWrap.setDisplayed(false);
35239 ts.resizeTabs = this.config.resizeTabs === true;
35240 ts.minTabWidth = this.config.minTabWidth || 40;
35241 ts.maxTabWidth = this.config.maxTabWidth || 250;
35242 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35243 ts.monitorResize = false;
35244 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35245 ts.bodyEl.addClass('roo-layout-tabs-body');
35246 this.panels.each(this.initPanelAsTab, this);
35249 initPanelAsTab : function(panel){
35250 var ti = this.tabs.addTab(
35254 this.config.closeOnTab && panel.isClosable(),
35257 if(panel.tabTip !== undefined){
35258 ti.setTooltip(panel.tabTip);
35260 ti.on("activate", function(){
35261 this.setActivePanel(panel);
35264 if(this.config.closeOnTab){
35265 ti.on("beforeclose", function(t, e){
35267 this.remove(panel);
35271 panel.tabItem = ti;
35276 updatePanelTitle : function(panel, title)
35278 if(this.activePanel == panel){
35279 this.updateTitle(title);
35282 var ti = this.tabs.getTab(panel.getEl().id);
35284 if(panel.tabTip !== undefined){
35285 ti.setTooltip(panel.tabTip);
35290 updateTitle : function(title){
35291 if(this.titleTextEl && !this.config.title){
35292 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35296 setActivePanel : function(panel)
35298 panel = this.getPanel(panel);
35299 if(this.activePanel && this.activePanel != panel){
35300 this.activePanel.setActiveState(false);
35302 this.activePanel = panel;
35303 panel.setActiveState(true);
35304 if(this.panelSize){
35305 panel.setSize(this.panelSize.width, this.panelSize.height);
35308 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35310 this.updateTitle(panel.getTitle());
35312 this.fireEvent("invalidated", this);
35314 this.fireEvent("panelactivated", this, panel);
35318 * Shows the specified panel.
35319 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35320 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35322 showPanel : function(panel)
35324 panel = this.getPanel(panel);
35327 var tab = this.tabs.getTab(panel.getEl().id);
35328 if(tab.isHidden()){
35329 this.tabs.unhideTab(tab.id);
35333 this.setActivePanel(panel);
35340 * Get the active panel for this region.
35341 * @return {Roo.ContentPanel} The active panel or null
35343 getActivePanel : function(){
35344 return this.activePanel;
35347 validateVisibility : function(){
35348 if(this.panels.getCount() < 1){
35349 this.updateTitle(" ");
35350 this.closeBtn.hide();
35353 if(!this.isVisible()){
35360 * Adds the passed ContentPanel(s) to this region.
35361 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35362 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35364 add : function(panel)
35366 if(arguments.length > 1){
35367 for(var i = 0, len = arguments.length; i < len; i++) {
35368 this.add(arguments[i]);
35373 // if we have not been rendered yet, then we can not really do much of this..
35374 if (!this.bodyEl) {
35375 this.unrendered_panels.push(panel);
35382 if(this.hasPanel(panel)){
35383 this.showPanel(panel);
35386 panel.setRegion(this);
35387 this.panels.add(panel);
35388 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35389 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35390 // and hide them... ???
35391 this.bodyEl.dom.appendChild(panel.getEl().dom);
35392 if(panel.background !== true){
35393 this.setActivePanel(panel);
35395 this.fireEvent("paneladded", this, panel);
35402 this.initPanelAsTab(panel);
35406 if(panel.background !== true){
35407 this.tabs.activate(panel.getEl().id);
35409 this.fireEvent("paneladded", this, panel);
35414 * Hides the tab for the specified panel.
35415 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35417 hidePanel : function(panel){
35418 if(this.tabs && (panel = this.getPanel(panel))){
35419 this.tabs.hideTab(panel.getEl().id);
35424 * Unhides the tab for a previously hidden panel.
35425 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35427 unhidePanel : function(panel){
35428 if(this.tabs && (panel = this.getPanel(panel))){
35429 this.tabs.unhideTab(panel.getEl().id);
35433 clearPanels : function(){
35434 while(this.panels.getCount() > 0){
35435 this.remove(this.panels.first());
35440 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35441 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35442 * @param {Boolean} preservePanel Overrides the config preservePanel option
35443 * @return {Roo.ContentPanel} The panel that was removed
35445 remove : function(panel, preservePanel)
35447 panel = this.getPanel(panel);
35452 this.fireEvent("beforeremove", this, panel, e);
35453 if(e.cancel === true){
35456 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35457 var panelId = panel.getId();
35458 this.panels.removeKey(panelId);
35460 document.body.appendChild(panel.getEl().dom);
35463 this.tabs.removeTab(panel.getEl().id);
35464 }else if (!preservePanel){
35465 this.bodyEl.dom.removeChild(panel.getEl().dom);
35467 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35468 var p = this.panels.first();
35469 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35470 tempEl.appendChild(p.getEl().dom);
35471 this.bodyEl.update("");
35472 this.bodyEl.dom.appendChild(p.getEl().dom);
35474 this.updateTitle(p.getTitle());
35476 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35477 this.setActivePanel(p);
35479 panel.setRegion(null);
35480 if(this.activePanel == panel){
35481 this.activePanel = null;
35483 if(this.config.autoDestroy !== false && preservePanel !== true){
35484 try{panel.destroy();}catch(e){}
35486 this.fireEvent("panelremoved", this, panel);
35491 * Returns the TabPanel component used by this region
35492 * @return {Roo.TabPanel}
35494 getTabs : function(){
35498 createTool : function(parentEl, className){
35499 var btn = Roo.DomHelper.append(parentEl, {
35501 cls: "x-layout-tools-button",
35504 cls: "roo-layout-tools-button-inner " + className,
35508 btn.addClassOnOver("roo-layout-tools-button-over");
35513 * Ext JS Library 1.1.1
35514 * Copyright(c) 2006-2007, Ext JS, LLC.
35516 * Originally Released Under LGPL - original licence link has changed is not relivant.
35519 * <script type="text/javascript">
35525 * @class Roo.SplitLayoutRegion
35526 * @extends Roo.LayoutRegion
35527 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35529 Roo.bootstrap.layout.Split = function(config){
35530 this.cursor = config.cursor;
35531 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35534 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35536 splitTip : "Drag to resize.",
35537 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35538 useSplitTips : false,
35540 applyConfig : function(config){
35541 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35544 onRender : function(ctr,pos) {
35546 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35547 if(!this.config.split){
35552 var splitEl = Roo.DomHelper.append(ctr.dom, {
35554 id: this.el.id + "-split",
35555 cls: "roo-layout-split roo-layout-split-"+this.position,
35558 /** The SplitBar for this region
35559 * @type Roo.SplitBar */
35560 // does not exist yet...
35561 Roo.log([this.position, this.orientation]);
35563 this.split = new Roo.bootstrap.SplitBar({
35564 dragElement : splitEl,
35565 resizingElement: this.el,
35566 orientation : this.orientation
35569 this.split.on("moved", this.onSplitMove, this);
35570 this.split.useShim = this.config.useShim === true;
35571 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35572 if(this.useSplitTips){
35573 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35575 //if(config.collapsible){
35576 // this.split.el.on("dblclick", this.collapse, this);
35579 if(typeof this.config.minSize != "undefined"){
35580 this.split.minSize = this.config.minSize;
35582 if(typeof this.config.maxSize != "undefined"){
35583 this.split.maxSize = this.config.maxSize;
35585 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35586 this.hideSplitter();
35591 getHMaxSize : function(){
35592 var cmax = this.config.maxSize || 10000;
35593 var center = this.mgr.getRegion("center");
35594 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35597 getVMaxSize : function(){
35598 var cmax = this.config.maxSize || 10000;
35599 var center = this.mgr.getRegion("center");
35600 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35603 onSplitMove : function(split, newSize){
35604 this.fireEvent("resized", this, newSize);
35608 * Returns the {@link Roo.SplitBar} for this region.
35609 * @return {Roo.SplitBar}
35611 getSplitBar : function(){
35616 this.hideSplitter();
35617 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35620 hideSplitter : function(){
35622 this.split.el.setLocation(-2000,-2000);
35623 this.split.el.hide();
35629 this.split.el.show();
35631 Roo.bootstrap.layout.Split.superclass.show.call(this);
35634 beforeSlide: function(){
35635 if(Roo.isGecko){// firefox overflow auto bug workaround
35636 this.bodyEl.clip();
35638 this.tabs.bodyEl.clip();
35640 if(this.activePanel){
35641 this.activePanel.getEl().clip();
35643 if(this.activePanel.beforeSlide){
35644 this.activePanel.beforeSlide();
35650 afterSlide : function(){
35651 if(Roo.isGecko){// firefox overflow auto bug workaround
35652 this.bodyEl.unclip();
35654 this.tabs.bodyEl.unclip();
35656 if(this.activePanel){
35657 this.activePanel.getEl().unclip();
35658 if(this.activePanel.afterSlide){
35659 this.activePanel.afterSlide();
35665 initAutoHide : function(){
35666 if(this.autoHide !== false){
35667 if(!this.autoHideHd){
35668 var st = new Roo.util.DelayedTask(this.slideIn, this);
35669 this.autoHideHd = {
35670 "mouseout": function(e){
35671 if(!e.within(this.el, true)){
35675 "mouseover" : function(e){
35681 this.el.on(this.autoHideHd);
35685 clearAutoHide : function(){
35686 if(this.autoHide !== false){
35687 this.el.un("mouseout", this.autoHideHd.mouseout);
35688 this.el.un("mouseover", this.autoHideHd.mouseover);
35692 clearMonitor : function(){
35693 Roo.get(document).un("click", this.slideInIf, this);
35696 // these names are backwards but not changed for compat
35697 slideOut : function(){
35698 if(this.isSlid || this.el.hasActiveFx()){
35701 this.isSlid = true;
35702 if(this.collapseBtn){
35703 this.collapseBtn.hide();
35705 this.closeBtnState = this.closeBtn.getStyle('display');
35706 this.closeBtn.hide();
35708 this.stickBtn.show();
35711 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35712 this.beforeSlide();
35713 this.el.setStyle("z-index", 10001);
35714 this.el.slideIn(this.getSlideAnchor(), {
35715 callback: function(){
35717 this.initAutoHide();
35718 Roo.get(document).on("click", this.slideInIf, this);
35719 this.fireEvent("slideshow", this);
35726 afterSlideIn : function(){
35727 this.clearAutoHide();
35728 this.isSlid = false;
35729 this.clearMonitor();
35730 this.el.setStyle("z-index", "");
35731 if(this.collapseBtn){
35732 this.collapseBtn.show();
35734 this.closeBtn.setStyle('display', this.closeBtnState);
35736 this.stickBtn.hide();
35738 this.fireEvent("slidehide", this);
35741 slideIn : function(cb){
35742 if(!this.isSlid || this.el.hasActiveFx()){
35746 this.isSlid = false;
35747 this.beforeSlide();
35748 this.el.slideOut(this.getSlideAnchor(), {
35749 callback: function(){
35750 this.el.setLeftTop(-10000, -10000);
35752 this.afterSlideIn();
35760 slideInIf : function(e){
35761 if(!e.within(this.el)){
35766 animateCollapse : function(){
35767 this.beforeSlide();
35768 this.el.setStyle("z-index", 20000);
35769 var anchor = this.getSlideAnchor();
35770 this.el.slideOut(anchor, {
35771 callback : function(){
35772 this.el.setStyle("z-index", "");
35773 this.collapsedEl.slideIn(anchor, {duration:.3});
35775 this.el.setLocation(-10000,-10000);
35777 this.fireEvent("collapsed", this);
35784 animateExpand : function(){
35785 this.beforeSlide();
35786 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35787 this.el.setStyle("z-index", 20000);
35788 this.collapsedEl.hide({
35791 this.el.slideIn(this.getSlideAnchor(), {
35792 callback : function(){
35793 this.el.setStyle("z-index", "");
35796 this.split.el.show();
35798 this.fireEvent("invalidated", this);
35799 this.fireEvent("expanded", this);
35827 getAnchor : function(){
35828 return this.anchors[this.position];
35831 getCollapseAnchor : function(){
35832 return this.canchors[this.position];
35835 getSlideAnchor : function(){
35836 return this.sanchors[this.position];
35839 getAlignAdj : function(){
35840 var cm = this.cmargins;
35841 switch(this.position){
35857 getExpandAdj : function(){
35858 var c = this.collapsedEl, cm = this.cmargins;
35859 switch(this.position){
35861 return [-(cm.right+c.getWidth()+cm.left), 0];
35864 return [cm.right+c.getWidth()+cm.left, 0];
35867 return [0, -(cm.top+cm.bottom+c.getHeight())];
35870 return [0, cm.top+cm.bottom+c.getHeight()];
35876 * Ext JS Library 1.1.1
35877 * Copyright(c) 2006-2007, Ext JS, LLC.
35879 * Originally Released Under LGPL - original licence link has changed is not relivant.
35882 * <script type="text/javascript">
35885 * These classes are private internal classes
35887 Roo.bootstrap.layout.Center = function(config){
35888 config.region = "center";
35889 Roo.bootstrap.layout.Region.call(this, config);
35890 this.visible = true;
35891 this.minWidth = config.minWidth || 20;
35892 this.minHeight = config.minHeight || 20;
35895 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35897 // center panel can't be hidden
35901 // center panel can't be hidden
35904 getMinWidth: function(){
35905 return this.minWidth;
35908 getMinHeight: function(){
35909 return this.minHeight;
35922 Roo.bootstrap.layout.North = function(config)
35924 config.region = 'north';
35925 config.cursor = 'n-resize';
35927 Roo.bootstrap.layout.Split.call(this, config);
35931 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35932 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35933 this.split.el.addClass("roo-layout-split-v");
35935 var size = config.initialSize || config.height;
35936 if(typeof size != "undefined"){
35937 this.el.setHeight(size);
35940 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35942 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35946 getBox : function(){
35947 if(this.collapsed){
35948 return this.collapsedEl.getBox();
35950 var box = this.el.getBox();
35952 box.height += this.split.el.getHeight();
35957 updateBox : function(box){
35958 if(this.split && !this.collapsed){
35959 box.height -= this.split.el.getHeight();
35960 this.split.el.setLeft(box.x);
35961 this.split.el.setTop(box.y+box.height);
35962 this.split.el.setWidth(box.width);
35964 if(this.collapsed){
35965 this.updateBody(box.width, null);
35967 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35975 Roo.bootstrap.layout.South = function(config){
35976 config.region = 'south';
35977 config.cursor = 's-resize';
35978 Roo.bootstrap.layout.Split.call(this, config);
35980 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35981 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35982 this.split.el.addClass("roo-layout-split-v");
35984 var size = config.initialSize || config.height;
35985 if(typeof size != "undefined"){
35986 this.el.setHeight(size);
35990 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35991 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35992 getBox : function(){
35993 if(this.collapsed){
35994 return this.collapsedEl.getBox();
35996 var box = this.el.getBox();
35998 var sh = this.split.el.getHeight();
36005 updateBox : function(box){
36006 if(this.split && !this.collapsed){
36007 var sh = this.split.el.getHeight();
36010 this.split.el.setLeft(box.x);
36011 this.split.el.setTop(box.y-sh);
36012 this.split.el.setWidth(box.width);
36014 if(this.collapsed){
36015 this.updateBody(box.width, null);
36017 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36021 Roo.bootstrap.layout.East = function(config){
36022 config.region = "east";
36023 config.cursor = "e-resize";
36024 Roo.bootstrap.layout.Split.call(this, config);
36026 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36027 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36028 this.split.el.addClass("roo-layout-split-h");
36030 var size = config.initialSize || config.width;
36031 if(typeof size != "undefined"){
36032 this.el.setWidth(size);
36035 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36036 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36037 getBox : function(){
36038 if(this.collapsed){
36039 return this.collapsedEl.getBox();
36041 var box = this.el.getBox();
36043 var sw = this.split.el.getWidth();
36050 updateBox : function(box){
36051 if(this.split && !this.collapsed){
36052 var sw = this.split.el.getWidth();
36054 this.split.el.setLeft(box.x);
36055 this.split.el.setTop(box.y);
36056 this.split.el.setHeight(box.height);
36059 if(this.collapsed){
36060 this.updateBody(null, box.height);
36062 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36066 Roo.bootstrap.layout.West = function(config){
36067 config.region = "west";
36068 config.cursor = "w-resize";
36070 Roo.bootstrap.layout.Split.call(this, config);
36072 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36073 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36074 this.split.el.addClass("roo-layout-split-h");
36078 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36079 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36081 onRender: function(ctr, pos)
36083 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36084 var size = this.config.initialSize || this.config.width;
36085 if(typeof size != "undefined"){
36086 this.el.setWidth(size);
36090 getBox : function(){
36091 if(this.collapsed){
36092 return this.collapsedEl.getBox();
36094 var box = this.el.getBox();
36096 box.width += this.split.el.getWidth();
36101 updateBox : function(box){
36102 if(this.split && !this.collapsed){
36103 var sw = this.split.el.getWidth();
36105 this.split.el.setLeft(box.x+box.width);
36106 this.split.el.setTop(box.y);
36107 this.split.el.setHeight(box.height);
36109 if(this.collapsed){
36110 this.updateBody(null, box.height);
36112 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36115 Roo.namespace("Roo.bootstrap.panel");/*
36117 * Ext JS Library 1.1.1
36118 * Copyright(c) 2006-2007, Ext JS, LLC.
36120 * Originally Released Under LGPL - original licence link has changed is not relivant.
36123 * <script type="text/javascript">
36126 * @class Roo.ContentPanel
36127 * @extends Roo.util.Observable
36128 * A basic ContentPanel element.
36129 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36130 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36131 * @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
36132 * @cfg {Boolean} closable True if the panel can be closed/removed
36133 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36134 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36135 * @cfg {Toolbar} toolbar A toolbar for this panel
36136 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36137 * @cfg {String} title The title for this panel
36138 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36139 * @cfg {String} url Calls {@link #setUrl} with this value
36140 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36141 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36142 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36143 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36144 * @cfg {Boolean} badges render the badges
36147 * Create a new ContentPanel.
36148 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36149 * @param {String/Object} config A string to set only the title or a config object
36150 * @param {String} content (optional) Set the HTML content for this panel
36151 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36153 Roo.bootstrap.panel.Content = function( config){
36155 this.tpl = config.tpl || false;
36157 var el = config.el;
36158 var content = config.content;
36160 if(config.autoCreate){ // xtype is available if this is called from factory
36163 this.el = Roo.get(el);
36164 if(!this.el && config && config.autoCreate){
36165 if(typeof config.autoCreate == "object"){
36166 if(!config.autoCreate.id){
36167 config.autoCreate.id = config.id||el;
36169 this.el = Roo.DomHelper.append(document.body,
36170 config.autoCreate, true);
36172 var elcfg = { tag: "div",
36173 cls: "roo-layout-inactive-content",
36177 elcfg.html = config.html;
36181 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36184 this.closable = false;
36185 this.loaded = false;
36186 this.active = false;
36189 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36191 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36193 this.wrapEl = this.el; //this.el.wrap();
36195 if (config.toolbar.items) {
36196 ti = config.toolbar.items ;
36197 delete config.toolbar.items ;
36201 this.toolbar.render(this.wrapEl, 'before');
36202 for(var i =0;i < ti.length;i++) {
36203 // Roo.log(['add child', items[i]]);
36204 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36206 this.toolbar.items = nitems;
36207 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36208 delete config.toolbar;
36212 // xtype created footer. - not sure if will work as we normally have to render first..
36213 if (this.footer && !this.footer.el && this.footer.xtype) {
36214 if (!this.wrapEl) {
36215 this.wrapEl = this.el.wrap();
36218 this.footer.container = this.wrapEl.createChild();
36220 this.footer = Roo.factory(this.footer, Roo);
36225 if(typeof config == "string"){
36226 this.title = config;
36228 Roo.apply(this, config);
36232 this.resizeEl = Roo.get(this.resizeEl, true);
36234 this.resizeEl = this.el;
36236 // handle view.xtype
36244 * Fires when this panel is activated.
36245 * @param {Roo.ContentPanel} this
36249 * @event deactivate
36250 * Fires when this panel is activated.
36251 * @param {Roo.ContentPanel} this
36253 "deactivate" : true,
36257 * Fires when this panel is resized if fitToFrame is true.
36258 * @param {Roo.ContentPanel} this
36259 * @param {Number} width The width after any component adjustments
36260 * @param {Number} height The height after any component adjustments
36266 * Fires when this tab is created
36267 * @param {Roo.ContentPanel} this
36278 if(this.autoScroll){
36279 this.resizeEl.setStyle("overflow", "auto");
36281 // fix randome scrolling
36282 //this.el.on('scroll', function() {
36283 // Roo.log('fix random scolling');
36284 // this.scrollTo('top',0);
36287 content = content || this.content;
36289 this.setContent(content);
36291 if(config && config.url){
36292 this.setUrl(this.url, this.params, this.loadOnce);
36297 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36299 if (this.view && typeof(this.view.xtype) != 'undefined') {
36300 this.view.el = this.el.appendChild(document.createElement("div"));
36301 this.view = Roo.factory(this.view);
36302 this.view.render && this.view.render(false, '');
36306 this.fireEvent('render', this);
36309 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36313 setRegion : function(region){
36314 this.region = region;
36315 this.setActiveClass(region && !this.background);
36319 setActiveClass: function(state)
36322 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36323 this.el.setStyle('position','relative');
36325 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36326 this.el.setStyle('position', 'absolute');
36331 * Returns the toolbar for this Panel if one was configured.
36332 * @return {Roo.Toolbar}
36334 getToolbar : function(){
36335 return this.toolbar;
36338 setActiveState : function(active)
36340 this.active = active;
36341 this.setActiveClass(active);
36343 this.fireEvent("deactivate", this);
36345 this.fireEvent("activate", this);
36349 * Updates this panel's element
36350 * @param {String} content The new content
36351 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36353 setContent : function(content, loadScripts){
36354 this.el.update(content, loadScripts);
36357 ignoreResize : function(w, h){
36358 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36361 this.lastSize = {width: w, height: h};
36366 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36367 * @return {Roo.UpdateManager} The UpdateManager
36369 getUpdateManager : function(){
36370 return this.el.getUpdateManager();
36373 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36374 * @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:
36377 url: "your-url.php",
36378 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36379 callback: yourFunction,
36380 scope: yourObject, //(optional scope)
36383 text: "Loading...",
36388 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36389 * 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.
36390 * @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}
36391 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36392 * @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.
36393 * @return {Roo.ContentPanel} this
36396 var um = this.el.getUpdateManager();
36397 um.update.apply(um, arguments);
36403 * 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.
36404 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36405 * @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)
36406 * @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)
36407 * @return {Roo.UpdateManager} The UpdateManager
36409 setUrl : function(url, params, loadOnce){
36410 if(this.refreshDelegate){
36411 this.removeListener("activate", this.refreshDelegate);
36413 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36414 this.on("activate", this.refreshDelegate);
36415 return this.el.getUpdateManager();
36418 _handleRefresh : function(url, params, loadOnce){
36419 if(!loadOnce || !this.loaded){
36420 var updater = this.el.getUpdateManager();
36421 updater.update(url, params, this._setLoaded.createDelegate(this));
36425 _setLoaded : function(){
36426 this.loaded = true;
36430 * Returns this panel's id
36433 getId : function(){
36438 * Returns this panel's element - used by regiosn to add.
36439 * @return {Roo.Element}
36441 getEl : function(){
36442 return this.wrapEl || this.el;
36447 adjustForComponents : function(width, height)
36449 //Roo.log('adjustForComponents ');
36450 if(this.resizeEl != this.el){
36451 width -= this.el.getFrameWidth('lr');
36452 height -= this.el.getFrameWidth('tb');
36455 var te = this.toolbar.getEl();
36456 te.setWidth(width);
36457 height -= te.getHeight();
36460 var te = this.footer.getEl();
36461 te.setWidth(width);
36462 height -= te.getHeight();
36466 if(this.adjustments){
36467 width += this.adjustments[0];
36468 height += this.adjustments[1];
36470 return {"width": width, "height": height};
36473 setSize : function(width, height){
36474 if(this.fitToFrame && !this.ignoreResize(width, height)){
36475 if(this.fitContainer && this.resizeEl != this.el){
36476 this.el.setSize(width, height);
36478 var size = this.adjustForComponents(width, height);
36479 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36480 this.fireEvent('resize', this, size.width, size.height);
36485 * Returns this panel's title
36488 getTitle : function(){
36490 if (typeof(this.title) != 'object') {
36495 for (var k in this.title) {
36496 if (!this.title.hasOwnProperty(k)) {
36500 if (k.indexOf('-') >= 0) {
36501 var s = k.split('-');
36502 for (var i = 0; i<s.length; i++) {
36503 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36506 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36513 * Set this panel's title
36514 * @param {String} title
36516 setTitle : function(title){
36517 this.title = title;
36519 this.region.updatePanelTitle(this, title);
36524 * Returns true is this panel was configured to be closable
36525 * @return {Boolean}
36527 isClosable : function(){
36528 return this.closable;
36531 beforeSlide : function(){
36533 this.resizeEl.clip();
36536 afterSlide : function(){
36538 this.resizeEl.unclip();
36542 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36543 * Will fail silently if the {@link #setUrl} method has not been called.
36544 * This does not activate the panel, just updates its content.
36546 refresh : function(){
36547 if(this.refreshDelegate){
36548 this.loaded = false;
36549 this.refreshDelegate();
36554 * Destroys this panel
36556 destroy : function(){
36557 this.el.removeAllListeners();
36558 var tempEl = document.createElement("span");
36559 tempEl.appendChild(this.el.dom);
36560 tempEl.innerHTML = "";
36566 * form - if the content panel contains a form - this is a reference to it.
36567 * @type {Roo.form.Form}
36571 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36572 * This contains a reference to it.
36578 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36588 * @param {Object} cfg Xtype definition of item to add.
36592 getChildContainer: function () {
36593 return this.getEl();
36598 var ret = new Roo.factory(cfg);
36603 if (cfg.xtype.match(/^Form$/)) {
36606 //if (this.footer) {
36607 // el = this.footer.container.insertSibling(false, 'before');
36609 el = this.el.createChild();
36612 this.form = new Roo.form.Form(cfg);
36615 if ( this.form.allItems.length) {
36616 this.form.render(el.dom);
36620 // should only have one of theses..
36621 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36622 // views.. should not be just added - used named prop 'view''
36624 cfg.el = this.el.appendChild(document.createElement("div"));
36627 var ret = new Roo.factory(cfg);
36629 ret.render && ret.render(false, ''); // render blank..
36639 * @class Roo.bootstrap.panel.Grid
36640 * @extends Roo.bootstrap.panel.Content
36642 * Create a new GridPanel.
36643 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36644 * @param {Object} config A the config object
36650 Roo.bootstrap.panel.Grid = function(config)
36654 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36655 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36657 config.el = this.wrapper;
36658 //this.el = this.wrapper;
36660 if (config.container) {
36661 // ctor'ed from a Border/panel.grid
36664 this.wrapper.setStyle("overflow", "hidden");
36665 this.wrapper.addClass('roo-grid-container');
36670 if(config.toolbar){
36671 var tool_el = this.wrapper.createChild();
36672 this.toolbar = Roo.factory(config.toolbar);
36674 if (config.toolbar.items) {
36675 ti = config.toolbar.items ;
36676 delete config.toolbar.items ;
36680 this.toolbar.render(tool_el);
36681 for(var i =0;i < ti.length;i++) {
36682 // Roo.log(['add child', items[i]]);
36683 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36685 this.toolbar.items = nitems;
36687 delete config.toolbar;
36690 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36691 config.grid.scrollBody = true;;
36692 config.grid.monitorWindowResize = false; // turn off autosizing
36693 config.grid.autoHeight = false;
36694 config.grid.autoWidth = false;
36696 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36698 if (config.background) {
36699 // render grid on panel activation (if panel background)
36700 this.on('activate', function(gp) {
36701 if (!gp.grid.rendered) {
36702 gp.grid.render(this.wrapper);
36703 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36708 this.grid.render(this.wrapper);
36709 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36712 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36713 // ??? needed ??? config.el = this.wrapper;
36718 // xtype created footer. - not sure if will work as we normally have to render first..
36719 if (this.footer && !this.footer.el && this.footer.xtype) {
36721 var ctr = this.grid.getView().getFooterPanel(true);
36722 this.footer.dataSource = this.grid.dataSource;
36723 this.footer = Roo.factory(this.footer, Roo);
36724 this.footer.render(ctr);
36734 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36735 getId : function(){
36736 return this.grid.id;
36740 * Returns the grid for this panel
36741 * @return {Roo.bootstrap.Table}
36743 getGrid : function(){
36747 setSize : function(width, height){
36748 if(!this.ignoreResize(width, height)){
36749 var grid = this.grid;
36750 var size = this.adjustForComponents(width, height);
36751 var gridel = grid.getGridEl();
36752 gridel.setSize(size.width, size.height);
36754 var thd = grid.getGridEl().select('thead',true).first();
36755 var tbd = grid.getGridEl().select('tbody', true).first();
36757 tbd.setSize(width, height - thd.getHeight());
36766 beforeSlide : function(){
36767 this.grid.getView().scroller.clip();
36770 afterSlide : function(){
36771 this.grid.getView().scroller.unclip();
36774 destroy : function(){
36775 this.grid.destroy();
36777 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36782 * @class Roo.bootstrap.panel.Nest
36783 * @extends Roo.bootstrap.panel.Content
36785 * Create a new Panel, that can contain a layout.Border.
36788 * @param {Roo.BorderLayout} layout The layout for this panel
36789 * @param {String/Object} config A string to set only the title or a config object
36791 Roo.bootstrap.panel.Nest = function(config)
36793 // construct with only one argument..
36794 /* FIXME - implement nicer consturctors
36795 if (layout.layout) {
36797 layout = config.layout;
36798 delete config.layout;
36800 if (layout.xtype && !layout.getEl) {
36801 // then layout needs constructing..
36802 layout = Roo.factory(layout, Roo);
36806 config.el = config.layout.getEl();
36808 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36810 config.layout.monitorWindowResize = false; // turn off autosizing
36811 this.layout = config.layout;
36812 this.layout.getEl().addClass("roo-layout-nested-layout");
36819 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36821 setSize : function(width, height){
36822 if(!this.ignoreResize(width, height)){
36823 var size = this.adjustForComponents(width, height);
36824 var el = this.layout.getEl();
36825 if (size.height < 1) {
36826 el.setWidth(size.width);
36828 el.setSize(size.width, size.height);
36830 var touch = el.dom.offsetWidth;
36831 this.layout.layout();
36832 // ie requires a double layout on the first pass
36833 if(Roo.isIE && !this.initialized){
36834 this.initialized = true;
36835 this.layout.layout();
36840 // activate all subpanels if not currently active..
36842 setActiveState : function(active){
36843 this.active = active;
36844 this.setActiveClass(active);
36847 this.fireEvent("deactivate", this);
36851 this.fireEvent("activate", this);
36852 // not sure if this should happen before or after..
36853 if (!this.layout) {
36854 return; // should not happen..
36857 for (var r in this.layout.regions) {
36858 reg = this.layout.getRegion(r);
36859 if (reg.getActivePanel()) {
36860 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36861 reg.setActivePanel(reg.getActivePanel());
36864 if (!reg.panels.length) {
36867 reg.showPanel(reg.getPanel(0));
36876 * Returns the nested BorderLayout for this panel
36877 * @return {Roo.BorderLayout}
36879 getLayout : function(){
36880 return this.layout;
36884 * Adds a xtype elements to the layout of the nested panel
36888 xtype : 'ContentPanel',
36895 xtype : 'NestedLayoutPanel',
36901 items : [ ... list of content panels or nested layout panels.. ]
36905 * @param {Object} cfg Xtype definition of item to add.
36907 addxtype : function(cfg) {
36908 return this.layout.addxtype(cfg);
36913 * Ext JS Library 1.1.1
36914 * Copyright(c) 2006-2007, Ext JS, LLC.
36916 * Originally Released Under LGPL - original licence link has changed is not relivant.
36919 * <script type="text/javascript">
36922 * @class Roo.TabPanel
36923 * @extends Roo.util.Observable
36924 * A lightweight tab container.
36928 // basic tabs 1, built from existing content
36929 var tabs = new Roo.TabPanel("tabs1");
36930 tabs.addTab("script", "View Script");
36931 tabs.addTab("markup", "View Markup");
36932 tabs.activate("script");
36934 // more advanced tabs, built from javascript
36935 var jtabs = new Roo.TabPanel("jtabs");
36936 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36938 // set up the UpdateManager
36939 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36940 var updater = tab2.getUpdateManager();
36941 updater.setDefaultUrl("ajax1.htm");
36942 tab2.on('activate', updater.refresh, updater, true);
36944 // Use setUrl for Ajax loading
36945 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36946 tab3.setUrl("ajax2.htm", null, true);
36949 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36952 jtabs.activate("jtabs-1");
36955 * Create a new TabPanel.
36956 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36957 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36959 Roo.bootstrap.panel.Tabs = function(config){
36961 * The container element for this TabPanel.
36962 * @type Roo.Element
36964 this.el = Roo.get(config.el);
36967 if(typeof config == "boolean"){
36968 this.tabPosition = config ? "bottom" : "top";
36970 Roo.apply(this, config);
36974 if(this.tabPosition == "bottom"){
36975 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36976 this.el.addClass("roo-tabs-bottom");
36978 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36979 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36980 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36982 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36984 if(this.tabPosition != "bottom"){
36985 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36986 * @type Roo.Element
36988 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36989 this.el.addClass("roo-tabs-top");
36993 this.bodyEl.setStyle("position", "relative");
36995 this.active = null;
36996 this.activateDelegate = this.activate.createDelegate(this);
37001 * Fires when the active tab changes
37002 * @param {Roo.TabPanel} this
37003 * @param {Roo.TabPanelItem} activePanel The new active tab
37007 * @event beforetabchange
37008 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37009 * @param {Roo.TabPanel} this
37010 * @param {Object} e Set cancel to true on this object to cancel the tab change
37011 * @param {Roo.TabPanelItem} tab The tab being changed to
37013 "beforetabchange" : true
37016 Roo.EventManager.onWindowResize(this.onResize, this);
37017 this.cpad = this.el.getPadding("lr");
37018 this.hiddenCount = 0;
37021 // toolbar on the tabbar support...
37022 if (this.toolbar) {
37023 alert("no toolbar support yet");
37024 this.toolbar = false;
37026 var tcfg = this.toolbar;
37027 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37028 this.toolbar = new Roo.Toolbar(tcfg);
37029 if (Roo.isSafari) {
37030 var tbl = tcfg.container.child('table', true);
37031 tbl.setAttribute('width', '100%');
37039 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37042 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37044 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37046 tabPosition : "top",
37048 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37050 currentTabWidth : 0,
37052 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37056 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37060 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37062 preferredTabWidth : 175,
37064 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37066 resizeTabs : false,
37068 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37070 monitorResize : true,
37072 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37077 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37078 * @param {String} id The id of the div to use <b>or create</b>
37079 * @param {String} text The text for the tab
37080 * @param {String} content (optional) Content to put in the TabPanelItem body
37081 * @param {Boolean} closable (optional) True to create a close icon on the tab
37082 * @return {Roo.TabPanelItem} The created TabPanelItem
37084 addTab : function(id, text, content, closable, tpl)
37086 var item = new Roo.bootstrap.panel.TabItem({
37090 closable : closable,
37093 this.addTabItem(item);
37095 item.setContent(content);
37101 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37102 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37103 * @return {Roo.TabPanelItem}
37105 getTab : function(id){
37106 return this.items[id];
37110 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37111 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37113 hideTab : function(id){
37114 var t = this.items[id];
37117 this.hiddenCount++;
37118 this.autoSizeTabs();
37123 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37124 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37126 unhideTab : function(id){
37127 var t = this.items[id];
37129 t.setHidden(false);
37130 this.hiddenCount--;
37131 this.autoSizeTabs();
37136 * Adds an existing {@link Roo.TabPanelItem}.
37137 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37139 addTabItem : function(item){
37140 this.items[item.id] = item;
37141 this.items.push(item);
37142 // if(this.resizeTabs){
37143 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37144 // this.autoSizeTabs();
37146 // item.autoSize();
37151 * Removes a {@link Roo.TabPanelItem}.
37152 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37154 removeTab : function(id){
37155 var items = this.items;
37156 var tab = items[id];
37157 if(!tab) { return; }
37158 var index = items.indexOf(tab);
37159 if(this.active == tab && items.length > 1){
37160 var newTab = this.getNextAvailable(index);
37165 this.stripEl.dom.removeChild(tab.pnode.dom);
37166 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37167 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37169 items.splice(index, 1);
37170 delete this.items[tab.id];
37171 tab.fireEvent("close", tab);
37172 tab.purgeListeners();
37173 this.autoSizeTabs();
37176 getNextAvailable : function(start){
37177 var items = this.items;
37179 // look for a next tab that will slide over to
37180 // replace the one being removed
37181 while(index < items.length){
37182 var item = items[++index];
37183 if(item && !item.isHidden()){
37187 // if one isn't found select the previous tab (on the left)
37190 var item = items[--index];
37191 if(item && !item.isHidden()){
37199 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37200 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37202 disableTab : function(id){
37203 var tab = this.items[id];
37204 if(tab && this.active != tab){
37210 * Enables a {@link Roo.TabPanelItem} that is disabled.
37211 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37213 enableTab : function(id){
37214 var tab = this.items[id];
37219 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37220 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37221 * @return {Roo.TabPanelItem} The TabPanelItem.
37223 activate : function(id){
37224 var tab = this.items[id];
37228 if(tab == this.active || tab.disabled){
37232 this.fireEvent("beforetabchange", this, e, tab);
37233 if(e.cancel !== true && !tab.disabled){
37235 this.active.hide();
37237 this.active = this.items[id];
37238 this.active.show();
37239 this.fireEvent("tabchange", this, this.active);
37245 * Gets the active {@link Roo.TabPanelItem}.
37246 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37248 getActiveTab : function(){
37249 return this.active;
37253 * Updates the tab body element to fit the height of the container element
37254 * for overflow scrolling
37255 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37257 syncHeight : function(targetHeight){
37258 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37259 var bm = this.bodyEl.getMargins();
37260 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37261 this.bodyEl.setHeight(newHeight);
37265 onResize : function(){
37266 if(this.monitorResize){
37267 this.autoSizeTabs();
37272 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37274 beginUpdate : function(){
37275 this.updating = true;
37279 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37281 endUpdate : function(){
37282 this.updating = false;
37283 this.autoSizeTabs();
37287 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37289 autoSizeTabs : function(){
37290 var count = this.items.length;
37291 var vcount = count - this.hiddenCount;
37292 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37295 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37296 var availWidth = Math.floor(w / vcount);
37297 var b = this.stripBody;
37298 if(b.getWidth() > w){
37299 var tabs = this.items;
37300 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37301 if(availWidth < this.minTabWidth){
37302 /*if(!this.sleft){ // incomplete scrolling code
37303 this.createScrollButtons();
37306 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37309 if(this.currentTabWidth < this.preferredTabWidth){
37310 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37316 * Returns the number of tabs in this TabPanel.
37319 getCount : function(){
37320 return this.items.length;
37324 * Resizes all the tabs to the passed width
37325 * @param {Number} The new width
37327 setTabWidth : function(width){
37328 this.currentTabWidth = width;
37329 for(var i = 0, len = this.items.length; i < len; i++) {
37330 if(!this.items[i].isHidden()) {
37331 this.items[i].setWidth(width);
37337 * Destroys this TabPanel
37338 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37340 destroy : function(removeEl){
37341 Roo.EventManager.removeResizeListener(this.onResize, this);
37342 for(var i = 0, len = this.items.length; i < len; i++){
37343 this.items[i].purgeListeners();
37345 if(removeEl === true){
37346 this.el.update("");
37351 createStrip : function(container)
37353 var strip = document.createElement("nav");
37354 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37355 container.appendChild(strip);
37359 createStripList : function(strip)
37361 // div wrapper for retard IE
37362 // returns the "tr" element.
37363 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37364 //'<div class="x-tabs-strip-wrap">'+
37365 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37366 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37367 return strip.firstChild; //.firstChild.firstChild.firstChild;
37369 createBody : function(container)
37371 var body = document.createElement("div");
37372 Roo.id(body, "tab-body");
37373 //Roo.fly(body).addClass("x-tabs-body");
37374 Roo.fly(body).addClass("tab-content");
37375 container.appendChild(body);
37378 createItemBody :function(bodyEl, id){
37379 var body = Roo.getDom(id);
37381 body = document.createElement("div");
37384 //Roo.fly(body).addClass("x-tabs-item-body");
37385 Roo.fly(body).addClass("tab-pane");
37386 bodyEl.insertBefore(body, bodyEl.firstChild);
37390 createStripElements : function(stripEl, text, closable, tpl)
37392 var td = document.createElement("li"); // was td..
37395 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37398 stripEl.appendChild(td);
37400 td.className = "x-tabs-closable";
37401 if(!this.closeTpl){
37402 this.closeTpl = new Roo.Template(
37403 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37404 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37405 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37408 var el = this.closeTpl.overwrite(td, {"text": text});
37409 var close = el.getElementsByTagName("div")[0];
37410 var inner = el.getElementsByTagName("em")[0];
37411 return {"el": el, "close": close, "inner": inner};
37414 // not sure what this is..
37415 // if(!this.tabTpl){
37416 //this.tabTpl = new Roo.Template(
37417 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37418 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37420 // this.tabTpl = new Roo.Template(
37421 // '<a href="#">' +
37422 // '<span unselectable="on"' +
37423 // (this.disableTooltips ? '' : ' title="{text}"') +
37424 // ' >{text}</span></a>'
37430 var template = tpl || this.tabTpl || false;
37434 template = new Roo.Template(
37436 '<span unselectable="on"' +
37437 (this.disableTooltips ? '' : ' title="{text}"') +
37438 ' >{text}</span></a>'
37442 switch (typeof(template)) {
37446 template = new Roo.Template(template);
37452 var el = template.overwrite(td, {"text": text});
37454 var inner = el.getElementsByTagName("span")[0];
37456 return {"el": el, "inner": inner};
37464 * @class Roo.TabPanelItem
37465 * @extends Roo.util.Observable
37466 * Represents an individual item (tab plus body) in a TabPanel.
37467 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37468 * @param {String} id The id of this TabPanelItem
37469 * @param {String} text The text for the tab of this TabPanelItem
37470 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37472 Roo.bootstrap.panel.TabItem = function(config){
37474 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37475 * @type Roo.TabPanel
37477 this.tabPanel = config.panel;
37479 * The id for this TabPanelItem
37482 this.id = config.id;
37484 this.disabled = false;
37486 this.text = config.text;
37488 this.loaded = false;
37489 this.closable = config.closable;
37492 * The body element for this TabPanelItem.
37493 * @type Roo.Element
37495 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37496 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37497 this.bodyEl.setStyle("display", "block");
37498 this.bodyEl.setStyle("zoom", "1");
37499 //this.hideAction();
37501 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37503 this.el = Roo.get(els.el);
37504 this.inner = Roo.get(els.inner, true);
37505 this.textEl = Roo.get(this.el.dom.firstChild, true);
37506 this.pnode = Roo.get(els.el.parentNode, true);
37507 this.el.on("mousedown", this.onTabMouseDown, this);
37508 this.el.on("click", this.onTabClick, this);
37510 if(config.closable){
37511 var c = Roo.get(els.close, true);
37512 c.dom.title = this.closeText;
37513 c.addClassOnOver("close-over");
37514 c.on("click", this.closeClick, this);
37520 * Fires when this tab becomes the active tab.
37521 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37522 * @param {Roo.TabPanelItem} this
37526 * @event beforeclose
37527 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37528 * @param {Roo.TabPanelItem} this
37529 * @param {Object} e Set cancel to true on this object to cancel the close.
37531 "beforeclose": true,
37534 * Fires when this tab is closed.
37535 * @param {Roo.TabPanelItem} this
37539 * @event deactivate
37540 * Fires when this tab is no longer the active tab.
37541 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37542 * @param {Roo.TabPanelItem} this
37544 "deactivate" : true
37546 this.hidden = false;
37548 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37551 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37553 purgeListeners : function(){
37554 Roo.util.Observable.prototype.purgeListeners.call(this);
37555 this.el.removeAllListeners();
37558 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37561 this.pnode.addClass("active");
37564 this.tabPanel.stripWrap.repaint();
37566 this.fireEvent("activate", this.tabPanel, this);
37570 * Returns true if this tab is the active tab.
37571 * @return {Boolean}
37573 isActive : function(){
37574 return this.tabPanel.getActiveTab() == this;
37578 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37581 this.pnode.removeClass("active");
37583 this.fireEvent("deactivate", this.tabPanel, this);
37586 hideAction : function(){
37587 this.bodyEl.hide();
37588 this.bodyEl.setStyle("position", "absolute");
37589 this.bodyEl.setLeft("-20000px");
37590 this.bodyEl.setTop("-20000px");
37593 showAction : function(){
37594 this.bodyEl.setStyle("position", "relative");
37595 this.bodyEl.setTop("");
37596 this.bodyEl.setLeft("");
37597 this.bodyEl.show();
37601 * Set the tooltip for the tab.
37602 * @param {String} tooltip The tab's tooltip
37604 setTooltip : function(text){
37605 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37606 this.textEl.dom.qtip = text;
37607 this.textEl.dom.removeAttribute('title');
37609 this.textEl.dom.title = text;
37613 onTabClick : function(e){
37614 e.preventDefault();
37615 this.tabPanel.activate(this.id);
37618 onTabMouseDown : function(e){
37619 e.preventDefault();
37620 this.tabPanel.activate(this.id);
37623 getWidth : function(){
37624 return this.inner.getWidth();
37627 setWidth : function(width){
37628 var iwidth = width - this.pnode.getPadding("lr");
37629 this.inner.setWidth(iwidth);
37630 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37631 this.pnode.setWidth(width);
37635 * Show or hide the tab
37636 * @param {Boolean} hidden True to hide or false to show.
37638 setHidden : function(hidden){
37639 this.hidden = hidden;
37640 this.pnode.setStyle("display", hidden ? "none" : "");
37644 * Returns true if this tab is "hidden"
37645 * @return {Boolean}
37647 isHidden : function(){
37648 return this.hidden;
37652 * Returns the text for this tab
37655 getText : function(){
37659 autoSize : function(){
37660 //this.el.beginMeasure();
37661 this.textEl.setWidth(1);
37663 * #2804 [new] Tabs in Roojs
37664 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37666 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37667 //this.el.endMeasure();
37671 * Sets the text for the tab (Note: this also sets the tooltip text)
37672 * @param {String} text The tab's text and tooltip
37674 setText : function(text){
37676 this.textEl.update(text);
37677 this.setTooltip(text);
37678 //if(!this.tabPanel.resizeTabs){
37679 // this.autoSize();
37683 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37685 activate : function(){
37686 this.tabPanel.activate(this.id);
37690 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37692 disable : function(){
37693 if(this.tabPanel.active != this){
37694 this.disabled = true;
37695 this.pnode.addClass("disabled");
37700 * Enables this TabPanelItem if it was previously disabled.
37702 enable : function(){
37703 this.disabled = false;
37704 this.pnode.removeClass("disabled");
37708 * Sets the content for this TabPanelItem.
37709 * @param {String} content The content
37710 * @param {Boolean} loadScripts true to look for and load scripts
37712 setContent : function(content, loadScripts){
37713 this.bodyEl.update(content, loadScripts);
37717 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37718 * @return {Roo.UpdateManager} The UpdateManager
37720 getUpdateManager : function(){
37721 return this.bodyEl.getUpdateManager();
37725 * Set a URL to be used to load the content for this TabPanelItem.
37726 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37727 * @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)
37728 * @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)
37729 * @return {Roo.UpdateManager} The UpdateManager
37731 setUrl : function(url, params, loadOnce){
37732 if(this.refreshDelegate){
37733 this.un('activate', this.refreshDelegate);
37735 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37736 this.on("activate", this.refreshDelegate);
37737 return this.bodyEl.getUpdateManager();
37741 _handleRefresh : function(url, params, loadOnce){
37742 if(!loadOnce || !this.loaded){
37743 var updater = this.bodyEl.getUpdateManager();
37744 updater.update(url, params, this._setLoaded.createDelegate(this));
37749 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37750 * Will fail silently if the setUrl method has not been called.
37751 * This does not activate the panel, just updates its content.
37753 refresh : function(){
37754 if(this.refreshDelegate){
37755 this.loaded = false;
37756 this.refreshDelegate();
37761 _setLoaded : function(){
37762 this.loaded = true;
37766 closeClick : function(e){
37769 this.fireEvent("beforeclose", this, o);
37770 if(o.cancel !== true){
37771 this.tabPanel.removeTab(this.id);
37775 * The text displayed in the tooltip for the close icon.
37778 closeText : "Close this tab"