4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
537 this.weightClass = ["btn-default",
549 * When a butotn is pressed
550 * @param {Roo.bootstrap.Button} this
551 * @param {Roo.EventObject} e
556 * After the button has been toggles
557 * @param {Roo.EventObject} e
558 * @param {boolean} pressed (also available as button.pressed)
564 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
582 preventDefault: true,
591 getAutoCreate : function(){
599 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
600 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
605 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
607 if (this.toggle == true) {
610 cls: 'slider-frame roo-button',
615 'data-off-text':'OFF',
616 cls: 'slider-button',
622 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
623 cfg.cls += ' '+this.weight;
632 cfg["aria-hidden"] = true;
634 cfg.html = "×";
640 if (this.theme==='default') {
641 cfg.cls = 'btn roo-button';
643 //if (this.parentType != 'Navbar') {
644 this.weight = this.weight.length ? this.weight : 'default';
646 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
648 cfg.cls += ' btn-' + this.weight;
650 } else if (this.theme==='glow') {
653 cfg.cls = 'btn-glow roo-button';
655 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
657 cfg.cls += ' ' + this.weight;
663 this.cls += ' inverse';
668 cfg.cls += ' active';
672 cfg.disabled = 'disabled';
676 Roo.log('changing to ul' );
678 this.glyphicon = 'caret';
681 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
683 //gsRoo.log(this.parentType);
684 if (this.parentType === 'Navbar' && !this.parent().bar) {
685 Roo.log('changing to li?');
694 href : this.href || '#'
697 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
698 cfg.cls += ' dropdown';
705 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
707 if (this.glyphicon) {
708 cfg.html = ' ' + cfg.html;
713 cls: 'glyphicon glyphicon-' + this.glyphicon
723 // cfg.cls='btn roo-button';
727 var value = cfg.html;
732 cls: 'glyphicon glyphicon-' + this.glyphicon,
751 cfg.cls += ' dropdown';
752 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
755 if (cfg.tag !== 'a' && this.href !== '') {
756 throw "Tag must be a to set href.";
757 } else if (this.href.length > 0) {
758 cfg.href = this.href;
761 if(this.removeClass){
766 cfg.target = this.target;
771 initEvents: function() {
772 // Roo.log('init events?');
773 // Roo.log(this.el.dom);
776 if (typeof (this.menu) != 'undefined') {
777 this.menu.parentType = this.xtype;
778 this.menu.triggerEl = this.el;
779 this.addxtype(Roo.apply({}, this.menu));
783 if (this.el.hasClass('roo-button')) {
784 this.el.on('click', this.onClick, this);
786 this.el.select('.roo-button').on('click', this.onClick, this);
789 if(this.removeClass){
790 this.el.on('click', this.onClick, this);
793 this.el.enableDisplayMode();
796 onClick : function(e)
803 Roo.log('button on click ');
804 if(this.preventDefault){
807 if (this.pressed === true || this.pressed === false) {
808 this.pressed = !this.pressed;
809 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
810 this.fireEvent('toggle', this, e, this.pressed);
814 this.fireEvent('click', this, e);
818 * Enables this button
822 this.disabled = false;
823 this.el.removeClass('disabled');
827 * Disable this button
831 this.disabled = true;
832 this.el.addClass('disabled');
835 * sets the active state on/off,
836 * @param {Boolean} state (optional) Force a particular state
838 setActive : function(v) {
840 this.el[v ? 'addClass' : 'removeClass']('active');
843 * toggles the current active state
845 toggleActive : function()
847 var active = this.el.hasClass('active');
848 this.setActive(!active);
852 setText : function(str)
854 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
858 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
869 setWeight : function(str)
871 this.el.removeClass(this.weightClass);
872 this.el.addClass('btn-' + str);
886 * @class Roo.bootstrap.Column
887 * @extends Roo.bootstrap.Component
888 * Bootstrap Column class
889 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
890 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
891 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
892 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
893 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
894 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
895 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
896 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
899 * @cfg {Boolean} hidden (true|false) hide the element
900 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
901 * @cfg {String} fa (ban|check|...) font awesome icon
902 * @cfg {Number} fasize (1|2|....) font awsome size
904 * @cfg {String} icon (info-sign|check|...) glyphicon name
906 * @cfg {String} html content of column.
909 * Create a new Column
910 * @param {Object} config The config object
913 Roo.bootstrap.Column = function(config){
914 Roo.bootstrap.Column.superclass.constructor.call(this, config);
917 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
935 getAutoCreate : function(){
936 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
944 ['xs','sm','md','lg'].map(function(size){
945 //Roo.log( size + ':' + settings[size]);
947 if (settings[size+'off'] !== false) {
948 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
951 if (settings[size] === false) {
955 if (!settings[size]) { // 0 = hidden
956 cfg.cls += ' hidden-' + size;
959 cfg.cls += ' col-' + size + '-' + settings[size];
964 cfg.cls += ' hidden';
967 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
968 cfg.cls +=' alert alert-' + this.alert;
972 if (this.html.length) {
973 cfg.html = this.html;
977 if (this.fasize > 1) {
978 fasize = ' fa-' + this.fasize + 'x';
980 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
985 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1004 * @class Roo.bootstrap.Container
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Container class
1007 * @cfg {Boolean} jumbotron is it a jumbotron element
1008 * @cfg {String} html content of element
1009 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1010 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
1011 * @cfg {String} header content of header (for panel)
1012 * @cfg {String} footer content of footer (for panel)
1013 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1014 * @cfg {String} tag (header|aside|section) type of HTML tag.
1015 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1016 * @cfg {String} fa font awesome icon
1017 * @cfg {String} icon (info-sign|check|...) glyphicon name
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {Boolean} expandable (true|false) default false
1020 * @cfg {Boolean} expanded (true|false) default true
1021 * @cfg {String} rheader contet on the right of header
1022 * @cfg {Boolean} clickable (true|false) default false
1026 * Create a new Container
1027 * @param {Object} config The config object
1030 Roo.bootstrap.Container = function(config){
1031 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1037 * After the panel has been expand
1039 * @param {Roo.bootstrap.Container} this
1044 * After the panel has been collapsed
1046 * @param {Roo.bootstrap.Container} this
1051 * When a element is chick
1052 * @param {Roo.bootstrap.Container} this
1053 * @param {Roo.EventObject} e
1059 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1077 getChildContainer : function() {
1083 if (this.panel.length) {
1084 return this.el.select('.panel-body',true).first();
1091 getAutoCreate : function(){
1094 tag : this.tag || 'div',
1098 if (this.jumbotron) {
1099 cfg.cls = 'jumbotron';
1104 // - this is applied by the parent..
1106 // cfg.cls = this.cls + '';
1109 if (this.sticky.length) {
1111 var bd = Roo.get(document.body);
1112 if (!bd.hasClass('bootstrap-sticky')) {
1113 bd.addClass('bootstrap-sticky');
1114 Roo.select('html',true).setStyle('height', '100%');
1117 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1121 if (this.well.length) {
1122 switch (this.well) {
1125 cfg.cls +=' well well-' +this.well;
1134 cfg.cls += ' hidden';
1138 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1139 cfg.cls +=' alert alert-' + this.alert;
1144 if (this.panel.length) {
1145 cfg.cls += ' panel panel-' + this.panel;
1147 if (this.header.length) {
1151 if(this.expandable){
1153 cfg.cls = cfg.cls + ' expandable';
1157 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1165 cls : 'panel-title',
1166 html : (this.expandable ? ' ' : '') + this.header
1170 cls: 'panel-header-right',
1176 cls : 'panel-heading',
1177 style : this.expandable ? 'cursor: pointer' : '',
1185 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1190 if (this.footer.length) {
1192 cls : 'panel-footer',
1201 body.html = this.html || cfg.html;
1202 // prefix with the icons..
1204 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1207 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1212 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1213 cfg.cls = 'container';
1219 initEvents: function()
1221 if(this.expandable){
1222 var headerEl = this.headerEl();
1225 headerEl.on('click', this.onToggleClick, this);
1230 this.el.on('click', this.onClick, this);
1235 onToggleClick : function()
1237 var headerEl = this.headerEl();
1253 if(this.fireEvent('expand', this)) {
1255 this.expanded = true;
1257 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1259 this.el.select('.panel-body',true).first().removeClass('hide');
1261 var toggleEl = this.toggleEl();
1267 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1272 collapse : function()
1274 if(this.fireEvent('collapse', this)) {
1276 this.expanded = false;
1278 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1279 this.el.select('.panel-body',true).first().addClass('hide');
1281 var toggleEl = this.toggleEl();
1287 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1291 toggleEl : function()
1293 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1297 return this.el.select('.panel-heading .fa',true).first();
1300 headerEl : function()
1302 if(!this.el || !this.panel.length || !this.header.length){
1306 return this.el.select('.panel-heading',true).first()
1311 if(!this.el || !this.panel.length){
1315 return this.el.select('.panel-body',true).first()
1318 titleEl : function()
1320 if(!this.el || !this.panel.length || !this.header.length){
1324 return this.el.select('.panel-title',true).first();
1327 setTitle : function(v)
1329 var titleEl = this.titleEl();
1335 titleEl.dom.innerHTML = v;
1338 getTitle : function()
1341 var titleEl = this.titleEl();
1347 return titleEl.dom.innerHTML;
1350 setRightTitle : function(v)
1352 var t = this.el.select('.panel-header-right',true).first();
1358 t.dom.innerHTML = v;
1361 onClick : function(e)
1365 this.fireEvent('click', this, e);
1379 * @class Roo.bootstrap.Img
1380 * @extends Roo.bootstrap.Component
1381 * Bootstrap Img class
1382 * @cfg {Boolean} imgResponsive false | true
1383 * @cfg {String} border rounded | circle | thumbnail
1384 * @cfg {String} src image source
1385 * @cfg {String} alt image alternative text
1386 * @cfg {String} href a tag href
1387 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1388 * @cfg {String} xsUrl xs image source
1389 * @cfg {String} smUrl sm image source
1390 * @cfg {String} mdUrl md image source
1391 * @cfg {String} lgUrl lg image source
1394 * Create a new Input
1395 * @param {Object} config The config object
1398 Roo.bootstrap.Img = function(config){
1399 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1405 * The img click event for the img.
1406 * @param {Roo.EventObject} e
1412 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1414 imgResponsive: true,
1424 getAutoCreate : function()
1426 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1427 return this.createSingleImg();
1432 cls: 'roo-image-responsive-group',
1437 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1439 if(!_this[size + 'Url']){
1445 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1446 html: _this.html || cfg.html,
1447 src: _this[size + 'Url']
1450 img.cls += ' roo-image-responsive-' + size;
1452 var s = ['xs', 'sm', 'md', 'lg'];
1454 s.splice(s.indexOf(size), 1);
1456 Roo.each(s, function(ss){
1457 img.cls += ' hidden-' + ss;
1460 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1461 cfg.cls += ' img-' + _this.border;
1465 cfg.alt = _this.alt;
1478 a.target = _this.target;
1482 cfg.cn.push((_this.href) ? a : img);
1489 createSingleImg : function()
1493 cls: (this.imgResponsive) ? 'img-responsive' : '',
1495 src : 'about:blank' // just incase src get's set to undefined?!?
1498 cfg.html = this.html || cfg.html;
1500 cfg.src = this.src || cfg.src;
1502 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1503 cfg.cls += ' img-' + this.border;
1520 a.target = this.target;
1525 return (this.href) ? a : cfg;
1528 initEvents: function()
1531 this.el.on('click', this.onClick, this);
1536 onClick : function(e)
1538 Roo.log('img onclick');
1539 this.fireEvent('click', this, e);
1542 * Sets the url of the image - used to update it
1543 * @param {String} url the url of the image
1546 setSrc : function(url)
1550 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1551 this.el.dom.src = url;
1555 this.el.select('img', true).first().dom.src = url;
1571 * @class Roo.bootstrap.Link
1572 * @extends Roo.bootstrap.Component
1573 * Bootstrap Link Class
1574 * @cfg {String} alt image alternative text
1575 * @cfg {String} href a tag href
1576 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1577 * @cfg {String} html the content of the link.
1578 * @cfg {String} anchor name for the anchor link
1579 * @cfg {String} fa - favicon
1581 * @cfg {Boolean} preventDefault (true | false) default false
1585 * Create a new Input
1586 * @param {Object} config The config object
1589 Roo.bootstrap.Link = function(config){
1590 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1596 * The img click event for the img.
1597 * @param {Roo.EventObject} e
1603 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1607 preventDefault: false,
1613 getAutoCreate : function()
1615 var html = this.html || '';
1617 if (this.fa !== false) {
1618 html = '<i class="fa fa-' + this.fa + '"></i>';
1623 // anchor's do not require html/href...
1624 if (this.anchor === false) {
1626 cfg.href = this.href || '#';
1628 cfg.name = this.anchor;
1629 if (this.html !== false || this.fa !== false) {
1632 if (this.href !== false) {
1633 cfg.href = this.href;
1637 if(this.alt !== false){
1642 if(this.target !== false) {
1643 cfg.target = this.target;
1649 initEvents: function() {
1651 if(!this.href || this.preventDefault){
1652 this.el.on('click', this.onClick, this);
1656 onClick : function(e)
1658 if(this.preventDefault){
1661 //Roo.log('img onclick');
1662 this.fireEvent('click', this, e);
1675 * @class Roo.bootstrap.Header
1676 * @extends Roo.bootstrap.Component
1677 * Bootstrap Header class
1678 * @cfg {String} html content of header
1679 * @cfg {Number} level (1|2|3|4|5|6) default 1
1682 * Create a new Header
1683 * @param {Object} config The config object
1687 Roo.bootstrap.Header = function(config){
1688 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1691 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1699 getAutoCreate : function(){
1704 tag: 'h' + (1 *this.level),
1705 html: this.html || ''
1717 * Ext JS Library 1.1.1
1718 * Copyright(c) 2006-2007, Ext JS, LLC.
1720 * Originally Released Under LGPL - original licence link has changed is not relivant.
1723 * <script type="text/javascript">
1727 * @class Roo.bootstrap.MenuMgr
1728 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1731 Roo.bootstrap.MenuMgr = function(){
1732 var menus, active, groups = {}, attached = false, lastShow = new Date();
1734 // private - called when first menu is created
1737 active = new Roo.util.MixedCollection();
1738 Roo.get(document).addKeyListener(27, function(){
1739 if(active.length > 0){
1747 if(active && active.length > 0){
1748 var c = active.clone();
1758 if(active.length < 1){
1759 Roo.get(document).un("mouseup", onMouseDown);
1767 var last = active.last();
1768 lastShow = new Date();
1771 Roo.get(document).on("mouseup", onMouseDown);
1776 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1777 m.parentMenu.activeChild = m;
1778 }else if(last && last.isVisible()){
1779 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1784 function onBeforeHide(m){
1786 m.activeChild.hide();
1788 if(m.autoHideTimer){
1789 clearTimeout(m.autoHideTimer);
1790 delete m.autoHideTimer;
1795 function onBeforeShow(m){
1796 var pm = m.parentMenu;
1797 if(!pm && !m.allowOtherMenus){
1799 }else if(pm && pm.activeChild && active != m){
1800 pm.activeChild.hide();
1804 // private this should really trigger on mouseup..
1805 function onMouseDown(e){
1806 Roo.log("on Mouse Up");
1808 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1809 Roo.log("MenuManager hideAll");
1818 function onBeforeCheck(mi, state){
1820 var g = groups[mi.group];
1821 for(var i = 0, l = g.length; i < l; i++){
1823 g[i].setChecked(false);
1832 * Hides all menus that are currently visible
1834 hideAll : function(){
1839 register : function(menu){
1843 menus[menu.id] = menu;
1844 menu.on("beforehide", onBeforeHide);
1845 menu.on("hide", onHide);
1846 menu.on("beforeshow", onBeforeShow);
1847 menu.on("show", onShow);
1849 if(g && menu.events["checkchange"]){
1853 groups[g].push(menu);
1854 menu.on("checkchange", onCheck);
1859 * Returns a {@link Roo.menu.Menu} object
1860 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1861 * be used to generate and return a new Menu instance.
1863 get : function(menu){
1864 if(typeof menu == "string"){ // menu id
1866 }else if(menu.events){ // menu instance
1869 /*else if(typeof menu.length == 'number'){ // array of menu items?
1870 return new Roo.bootstrap.Menu({items:menu});
1871 }else{ // otherwise, must be a config
1872 return new Roo.bootstrap.Menu(menu);
1879 unregister : function(menu){
1880 delete menus[menu.id];
1881 menu.un("beforehide", onBeforeHide);
1882 menu.un("hide", onHide);
1883 menu.un("beforeshow", onBeforeShow);
1884 menu.un("show", onShow);
1886 if(g && menu.events["checkchange"]){
1887 groups[g].remove(menu);
1888 menu.un("checkchange", onCheck);
1893 registerCheckable : function(menuItem){
1894 var g = menuItem.group;
1899 groups[g].push(menuItem);
1900 menuItem.on("beforecheckchange", onBeforeCheck);
1905 unregisterCheckable : function(menuItem){
1906 var g = menuItem.group;
1908 groups[g].remove(menuItem);
1909 menuItem.un("beforecheckchange", onBeforeCheck);
1921 * @class Roo.bootstrap.Menu
1922 * @extends Roo.bootstrap.Component
1923 * Bootstrap Menu class - container for MenuItems
1924 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1925 * @cfg {bool} hidden if the menu should be hidden when rendered.
1926 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1927 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1931 * @param {Object} config The config object
1935 Roo.bootstrap.Menu = function(config){
1936 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1937 if (this.registerMenu && this.type != 'treeview') {
1938 Roo.bootstrap.MenuMgr.register(this);
1943 * Fires before this menu is displayed
1944 * @param {Roo.menu.Menu} this
1949 * Fires before this menu is hidden
1950 * @param {Roo.menu.Menu} this
1955 * Fires after this menu is displayed
1956 * @param {Roo.menu.Menu} this
1961 * Fires after this menu is hidden
1962 * @param {Roo.menu.Menu} this
1967 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1968 * @param {Roo.menu.Menu} this
1969 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1970 * @param {Roo.EventObject} e
1975 * Fires when the mouse is hovering over this menu
1976 * @param {Roo.menu.Menu} this
1977 * @param {Roo.EventObject} e
1978 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1983 * Fires when the mouse exits this menu
1984 * @param {Roo.menu.Menu} this
1985 * @param {Roo.EventObject} e
1986 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1991 * Fires when a menu item contained in this menu is clicked
1992 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1993 * @param {Roo.EventObject} e
1997 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2000 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2004 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2007 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2009 registerMenu : true,
2011 menuItems :false, // stores the menu items..
2021 getChildContainer : function() {
2025 getAutoCreate : function(){
2027 //if (['right'].indexOf(this.align)!==-1) {
2028 // cfg.cn[1].cls += ' pull-right'
2034 cls : 'dropdown-menu' ,
2035 style : 'z-index:1000'
2039 if (this.type === 'submenu') {
2040 cfg.cls = 'submenu active';
2042 if (this.type === 'treeview') {
2043 cfg.cls = 'treeview-menu';
2048 initEvents : function() {
2050 // Roo.log("ADD event");
2051 // Roo.log(this.triggerEl.dom);
2053 this.triggerEl.on('click', this.onTriggerClick, this);
2055 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2057 this.triggerEl.addClass('dropdown-toggle');
2060 this.el.on('touchstart' , this.onTouch, this);
2062 this.el.on('click' , this.onClick, this);
2064 this.el.on("mouseover", this.onMouseOver, this);
2065 this.el.on("mouseout", this.onMouseOut, this);
2069 findTargetItem : function(e)
2071 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2075 //Roo.log(t); Roo.log(t.id);
2077 //Roo.log(this.menuitems);
2078 return this.menuitems.get(t.id);
2080 //return this.items.get(t.menuItemId);
2086 onTouch : function(e)
2088 Roo.log("menu.onTouch");
2089 //e.stopEvent(); this make the user popdown broken
2093 onClick : function(e)
2095 Roo.log("menu.onClick");
2097 var t = this.findTargetItem(e);
2098 if(!t || t.isContainer){
2103 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2104 if(t == this.activeItem && t.shouldDeactivate(e)){
2105 this.activeItem.deactivate();
2106 delete this.activeItem;
2110 this.setActiveItem(t, true);
2118 Roo.log('pass click event');
2122 this.fireEvent("click", this, t, e);
2126 if(!t.href.length || t.href == '#'){
2127 (function() { _this.hide(); }).defer(100);
2132 onMouseOver : function(e){
2133 var t = this.findTargetItem(e);
2136 // if(t.canActivate && !t.disabled){
2137 // this.setActiveItem(t, true);
2141 this.fireEvent("mouseover", this, e, t);
2143 isVisible : function(){
2144 return !this.hidden;
2146 onMouseOut : function(e){
2147 var t = this.findTargetItem(e);
2150 // if(t == this.activeItem && t.shouldDeactivate(e)){
2151 // this.activeItem.deactivate();
2152 // delete this.activeItem;
2155 this.fireEvent("mouseout", this, e, t);
2160 * Displays this menu relative to another element
2161 * @param {String/HTMLElement/Roo.Element} element The element to align to
2162 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2163 * the element (defaults to this.defaultAlign)
2164 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2166 show : function(el, pos, parentMenu){
2167 this.parentMenu = parentMenu;
2171 this.fireEvent("beforeshow", this);
2172 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2175 * Displays this menu at a specific xy position
2176 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2177 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2179 showAt : function(xy, parentMenu, /* private: */_e){
2180 this.parentMenu = parentMenu;
2185 this.fireEvent("beforeshow", this);
2186 //xy = this.el.adjustForConstraints(xy);
2190 this.hideMenuItems();
2191 this.hidden = false;
2192 this.triggerEl.addClass('open');
2194 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2195 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2198 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2203 this.fireEvent("show", this);
2209 this.doFocus.defer(50, this);
2213 doFocus : function(){
2215 this.focusEl.focus();
2220 * Hides this menu and optionally all parent menus
2221 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2223 hide : function(deep)
2226 this.hideMenuItems();
2227 if(this.el && this.isVisible()){
2228 this.fireEvent("beforehide", this);
2229 if(this.activeItem){
2230 this.activeItem.deactivate();
2231 this.activeItem = null;
2233 this.triggerEl.removeClass('open');;
2235 this.fireEvent("hide", this);
2237 if(deep === true && this.parentMenu){
2238 this.parentMenu.hide(true);
2242 onTriggerClick : function(e)
2244 Roo.log('trigger click');
2246 var target = e.getTarget();
2248 Roo.log(target.nodeName.toLowerCase());
2250 if(target.nodeName.toLowerCase() === 'i'){
2256 onTriggerPress : function(e)
2258 Roo.log('trigger press');
2259 //Roo.log(e.getTarget());
2260 // Roo.log(this.triggerEl.dom);
2262 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2263 var pel = Roo.get(e.getTarget());
2264 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2265 Roo.log('is treeview or dropdown?');
2269 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2273 if (this.isVisible()) {
2278 this.show(this.triggerEl, false, false);
2281 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2288 hideMenuItems : function()
2290 Roo.log("hide Menu Items");
2294 //$(backdrop).remove()
2295 this.el.select('.open',true).each(function(aa) {
2297 aa.removeClass('open');
2298 //var parent = getParent($(this))
2299 //var relatedTarget = { relatedTarget: this }
2301 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2302 //if (e.isDefaultPrevented()) return
2303 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2306 addxtypeChild : function (tree, cntr) {
2307 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2309 this.menuitems.add(comp);
2330 * @class Roo.bootstrap.MenuItem
2331 * @extends Roo.bootstrap.Component
2332 * Bootstrap MenuItem class
2333 * @cfg {String} html the menu label
2334 * @cfg {String} href the link
2335 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2336 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2337 * @cfg {Boolean} active used on sidebars to highlight active itesm
2338 * @cfg {String} fa favicon to show on left of menu item.
2339 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2343 * Create a new MenuItem
2344 * @param {Object} config The config object
2348 Roo.bootstrap.MenuItem = function(config){
2349 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2354 * The raw click event for the entire grid.
2355 * @param {Roo.bootstrap.MenuItem} this
2356 * @param {Roo.EventObject} e
2362 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2366 preventDefault: false,
2367 isContainer : false,
2371 getAutoCreate : function(){
2373 if(this.isContainer){
2376 cls: 'dropdown-menu-item'
2390 if (this.fa !== false) {
2393 cls : 'fa fa-' + this.fa
2402 cls: 'dropdown-menu-item',
2405 if (this.parent().type == 'treeview') {
2406 cfg.cls = 'treeview-menu';
2409 cfg.cls += ' active';
2414 anc.href = this.href || cfg.cn[0].href ;
2415 ctag.html = this.html || cfg.cn[0].html ;
2419 initEvents: function()
2421 if (this.parent().type == 'treeview') {
2422 this.el.select('a').on('click', this.onClick, this);
2426 this.menu.parentType = this.xtype;
2427 this.menu.triggerEl = this.el;
2428 this.menu = this.addxtype(Roo.apply({}, this.menu));
2432 onClick : function(e)
2434 Roo.log('item on click ');
2436 if(this.preventDefault){
2439 //this.parent().hideMenuItems();
2441 this.fireEvent('click', this, e);
2460 * @class Roo.bootstrap.MenuSeparator
2461 * @extends Roo.bootstrap.Component
2462 * Bootstrap MenuSeparator class
2465 * Create a new MenuItem
2466 * @param {Object} config The config object
2470 Roo.bootstrap.MenuSeparator = function(config){
2471 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2474 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2476 getAutoCreate : function(){
2495 * @class Roo.bootstrap.Modal
2496 * @extends Roo.bootstrap.Component
2497 * Bootstrap Modal class
2498 * @cfg {String} title Title of dialog
2499 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2500 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2501 * @cfg {Boolean} specificTitle default false
2502 * @cfg {Array} buttons Array of buttons or standard button set..
2503 * @cfg {String} buttonPosition (left|right|center) default right
2504 * @cfg {Boolean} animate default true
2505 * @cfg {Boolean} allow_close default true
2506 * @cfg {Boolean} fitwindow default false
2507 * @cfg {String} size (sm|lg) default empty
2511 * Create a new Modal Dialog
2512 * @param {Object} config The config object
2515 Roo.bootstrap.Modal = function(config){
2516 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2521 * The raw btnclick event for the button
2522 * @param {Roo.EventObject} e
2527 * Fire when dialog resize
2528 * @param {Roo.bootstrap.Modal} this
2529 * @param {Roo.EventObject} e
2533 this.buttons = this.buttons || [];
2536 this.tmpl = Roo.factory(this.tmpl);
2541 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2543 title : 'test dialog',
2553 specificTitle: false,
2555 buttonPosition: 'right',
2574 onRender : function(ct, position)
2576 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2579 var cfg = Roo.apply({}, this.getAutoCreate());
2582 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2584 //if (!cfg.name.length) {
2588 cfg.cls += ' ' + this.cls;
2591 cfg.style = this.style;
2593 this.el = Roo.get(document.body).createChild(cfg, position);
2595 //var type = this.el.dom.type;
2598 if(this.tabIndex !== undefined){
2599 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2602 this.dialogEl = this.el.select('.modal-dialog',true).first();
2603 this.bodyEl = this.el.select('.modal-body',true).first();
2604 this.closeEl = this.el.select('.modal-header .close', true).first();
2605 this.headerEl = this.el.select('.modal-header',true).first();
2606 this.titleEl = this.el.select('.modal-title',true).first();
2607 this.footerEl = this.el.select('.modal-footer',true).first();
2609 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2610 this.maskEl.enableDisplayMode("block");
2612 //this.el.addClass("x-dlg-modal");
2614 if (this.buttons.length) {
2615 Roo.each(this.buttons, function(bb) {
2616 var b = Roo.apply({}, bb);
2617 b.xns = b.xns || Roo.bootstrap;
2618 b.xtype = b.xtype || 'Button';
2619 if (typeof(b.listeners) == 'undefined') {
2620 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2623 var btn = Roo.factory(b);
2625 btn.render(this.el.select('.modal-footer div').first());
2629 // render the children.
2632 if(typeof(this.items) != 'undefined'){
2633 var items = this.items;
2636 for(var i =0;i < items.length;i++) {
2637 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2641 this.items = nitems;
2643 // where are these used - they used to be body/close/footer
2647 //this.el.addClass([this.fieldClass, this.cls]);
2651 getAutoCreate : function(){
2656 html : this.html || ''
2661 cls : 'modal-title',
2665 if(this.specificTitle){
2671 if (this.allow_close) {
2683 if(this.size.length){
2684 size = 'modal-' + this.size;
2689 style : 'display: none',
2692 cls: "modal-dialog " + size,
2695 cls : "modal-content",
2698 cls : 'modal-header',
2703 cls : 'modal-footer',
2707 cls: 'btn-' + this.buttonPosition
2724 modal.cls += ' fade';
2730 getChildContainer : function() {
2735 getButtonContainer : function() {
2736 return this.el.select('.modal-footer div',true).first();
2739 initEvents : function()
2741 if (this.allow_close) {
2742 this.closeEl.on('click', this.hide, this);
2744 Roo.EventManager.onWindowResize(this.resize, this, true);
2751 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2752 if (this.fitwindow) {
2753 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2754 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2759 setSize : function(w,h)
2769 if (!this.rendered) {
2773 this.el.setStyle('display', 'block');
2775 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2778 this.el.addClass('in');
2781 this.el.addClass('in');
2785 // not sure how we can show data in here..
2787 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2790 Roo.get(document.body).addClass("x-body-masked");
2792 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2793 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2798 this.fireEvent('show', this);
2800 // set zindex here - otherwise it appears to be ignored...
2801 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2804 this.items.forEach( function(e) {
2805 e.layout ? e.layout() : false;
2813 if(this.fireEvent("beforehide", this) !== false){
2815 Roo.get(document.body).removeClass("x-body-masked");
2816 this.el.removeClass('in');
2817 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2819 if(this.animate){ // why
2821 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2823 this.el.setStyle('display', 'none');
2825 this.fireEvent('hide', this);
2829 addButton : function(str, cb)
2833 var b = Roo.apply({}, { html : str } );
2834 b.xns = b.xns || Roo.bootstrap;
2835 b.xtype = b.xtype || 'Button';
2836 if (typeof(b.listeners) == 'undefined') {
2837 b.listeners = { click : cb.createDelegate(this) };
2840 var btn = Roo.factory(b);
2842 btn.render(this.el.select('.modal-footer div').first());
2848 setDefaultButton : function(btn)
2850 //this.el.select('.modal-footer').()
2854 resizeTo: function(w,h)
2858 this.dialogEl.setWidth(w);
2859 if (this.diff === false) {
2860 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2863 this.bodyEl.setHeight(h-this.diff);
2865 this.fireEvent('resize', this);
2868 setContentSize : function(w, h)
2872 onButtonClick: function(btn,e)
2875 this.fireEvent('btnclick', btn.name, e);
2878 * Set the title of the Dialog
2879 * @param {String} str new Title
2881 setTitle: function(str) {
2882 this.titleEl.dom.innerHTML = str;
2885 * Set the body of the Dialog
2886 * @param {String} str new Title
2888 setBody: function(str) {
2889 this.bodyEl.dom.innerHTML = str;
2892 * Set the body of the Dialog using the template
2893 * @param {Obj} data - apply this data to the template and replace the body contents.
2895 applyBody: function(obj)
2898 Roo.log("Error - using apply Body without a template");
2901 this.tmpl.overwrite(this.bodyEl, obj);
2907 Roo.apply(Roo.bootstrap.Modal, {
2909 * Button config that displays a single OK button
2918 * Button config that displays Yes and No buttons
2934 * Button config that displays OK and Cancel buttons
2949 * Button config that displays Yes, No and Cancel buttons
2973 * messagebox - can be used as a replace
2977 * @class Roo.MessageBox
2978 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2982 Roo.Msg.alert('Status', 'Changes saved successfully.');
2984 // Prompt for user data:
2985 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2987 // process text value...
2991 // Show a dialog using config options:
2993 title:'Save Changes?',
2994 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2995 buttons: Roo.Msg.YESNOCANCEL,
3002 Roo.bootstrap.MessageBox = function(){
3003 var dlg, opt, mask, waitTimer;
3004 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3005 var buttons, activeTextEl, bwidth;
3009 var handleButton = function(button){
3011 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3015 var handleHide = function(){
3017 dlg.el.removeClass(opt.cls);
3020 // Roo.TaskMgr.stop(waitTimer);
3021 // waitTimer = null;
3026 var updateButtons = function(b){
3029 buttons["ok"].hide();
3030 buttons["cancel"].hide();
3031 buttons["yes"].hide();
3032 buttons["no"].hide();
3033 //dlg.footer.dom.style.display = 'none';
3036 dlg.footerEl.dom.style.display = '';
3037 for(var k in buttons){
3038 if(typeof buttons[k] != "function"){
3041 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3042 width += buttons[k].el.getWidth()+15;
3052 var handleEsc = function(d, k, e){
3053 if(opt && opt.closable !== false){
3063 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3064 * @return {Roo.BasicDialog} The BasicDialog element
3066 getDialog : function(){
3068 dlg = new Roo.bootstrap.Modal( {
3071 //constraintoviewport:false,
3073 //collapsible : false,
3078 //buttonAlign:"center",
3079 closeClick : function(){
3080 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3083 handleButton("cancel");
3088 dlg.on("hide", handleHide);
3090 //dlg.addKeyListener(27, handleEsc);
3092 this.buttons = buttons;
3093 var bt = this.buttonText;
3094 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3095 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3096 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3097 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3099 bodyEl = dlg.bodyEl.createChild({
3101 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3102 '<textarea class="roo-mb-textarea"></textarea>' +
3103 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3105 msgEl = bodyEl.dom.firstChild;
3106 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3107 textboxEl.enableDisplayMode();
3108 textboxEl.addKeyListener([10,13], function(){
3109 if(dlg.isVisible() && opt && opt.buttons){
3112 }else if(opt.buttons.yes){
3113 handleButton("yes");
3117 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3118 textareaEl.enableDisplayMode();
3119 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3120 progressEl.enableDisplayMode();
3122 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3123 //var pf = progressEl.dom.firstChild;
3125 //pp = Roo.get(pf.firstChild);
3126 //pp.setHeight(pf.offsetHeight);
3134 * Updates the message box body text
3135 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3136 * the XHTML-compliant non-breaking space character '&#160;')
3137 * @return {Roo.MessageBox} This message box
3139 updateText : function(text)
3141 if(!dlg.isVisible() && !opt.width){
3142 dlg.dialogEl.setWidth(this.maxWidth);
3143 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3145 msgEl.innerHTML = text || ' ';
3147 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3148 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3150 Math.min(opt.width || cw , this.maxWidth),
3151 Math.max(opt.minWidth || this.minWidth, bwidth)
3154 activeTextEl.setWidth(w);
3156 if(dlg.isVisible()){
3157 dlg.fixedcenter = false;
3159 // to big, make it scroll. = But as usual stupid IE does not support
3162 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3163 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3164 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3166 bodyEl.dom.style.height = '';
3167 bodyEl.dom.style.overflowY = '';
3170 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3172 bodyEl.dom.style.overflowX = '';
3175 dlg.setContentSize(w, bodyEl.getHeight());
3176 if(dlg.isVisible()){
3177 dlg.fixedcenter = true;
3183 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3184 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3185 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3186 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3187 * @return {Roo.MessageBox} This message box
3189 updateProgress : function(value, text){
3191 this.updateText(text);
3193 if (pp) { // weird bug on my firefox - for some reason this is not defined
3194 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3200 * Returns true if the message box is currently displayed
3201 * @return {Boolean} True if the message box is visible, else false
3203 isVisible : function(){
3204 return dlg && dlg.isVisible();
3208 * Hides the message box if it is displayed
3211 if(this.isVisible()){
3217 * Displays a new message box, or reinitializes an existing message box, based on the config options
3218 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3219 * The following config object properties are supported:
3221 Property Type Description
3222 ---------- --------------- ------------------------------------------------------------------------------------
3223 animEl String/Element An id or Element from which the message box should animate as it opens and
3224 closes (defaults to undefined)
3225 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3226 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3227 closable Boolean False to hide the top-right close button (defaults to true). Note that
3228 progress and wait dialogs will ignore this property and always hide the
3229 close button as they can only be closed programmatically.
3230 cls String A custom CSS class to apply to the message box element
3231 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3232 displayed (defaults to 75)
3233 fn Function A callback function to execute after closing the dialog. The arguments to the
3234 function will be btn (the name of the button that was clicked, if applicable,
3235 e.g. "ok"), and text (the value of the active text field, if applicable).
3236 Progress and wait dialogs will ignore this option since they do not respond to
3237 user actions and can only be closed programmatically, so any required function
3238 should be called by the same code after it closes the dialog.
3239 icon String A CSS class that provides a background image to be used as an icon for
3240 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3241 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3242 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3243 modal Boolean False to allow user interaction with the page while the message box is
3244 displayed (defaults to true)
3245 msg String A string that will replace the existing message box body text (defaults
3246 to the XHTML-compliant non-breaking space character ' ')
3247 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3248 progress Boolean True to display a progress bar (defaults to false)
3249 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3250 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3251 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3252 title String The title text
3253 value String The string value to set into the active textbox element if displayed
3254 wait Boolean True to display a progress bar (defaults to false)
3255 width Number The width of the dialog in pixels
3262 msg: 'Please enter your address:',
3264 buttons: Roo.MessageBox.OKCANCEL,
3267 animEl: 'addAddressBtn'
3270 * @param {Object} config Configuration options
3271 * @return {Roo.MessageBox} This message box
3273 show : function(options)
3276 // this causes nightmares if you show one dialog after another
3277 // especially on callbacks..
3279 if(this.isVisible()){
3282 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3283 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3284 Roo.log("New Dialog Message:" + options.msg )
3285 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3286 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3289 var d = this.getDialog();
3291 d.setTitle(opt.title || " ");
3292 d.closeEl.setDisplayed(opt.closable !== false);
3293 activeTextEl = textboxEl;
3294 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3299 textareaEl.setHeight(typeof opt.multiline == "number" ?
3300 opt.multiline : this.defaultTextHeight);
3301 activeTextEl = textareaEl;
3310 progressEl.setDisplayed(opt.progress === true);
3311 this.updateProgress(0);
3312 activeTextEl.dom.value = opt.value || "";
3314 dlg.setDefaultButton(activeTextEl);
3316 var bs = opt.buttons;
3320 }else if(bs && bs.yes){
3321 db = buttons["yes"];
3323 dlg.setDefaultButton(db);
3325 bwidth = updateButtons(opt.buttons);
3326 this.updateText(opt.msg);
3328 d.el.addClass(opt.cls);
3330 d.proxyDrag = opt.proxyDrag === true;
3331 d.modal = opt.modal !== false;
3332 d.mask = opt.modal !== false ? mask : false;
3334 // force it to the end of the z-index stack so it gets a cursor in FF
3335 document.body.appendChild(dlg.el.dom);
3336 d.animateTarget = null;
3337 d.show(options.animEl);
3343 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3344 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3345 * and closing the message box when the process is complete.
3346 * @param {String} title The title bar text
3347 * @param {String} msg The message box body text
3348 * @return {Roo.MessageBox} This message box
3350 progress : function(title, msg){
3357 minWidth: this.minProgressWidth,
3364 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3365 * If a callback function is passed it will be called after the user clicks the button, and the
3366 * id of the button that was clicked will be passed as the only parameter to the callback
3367 * (could also be the top-right close button).
3368 * @param {String} title The title bar text
3369 * @param {String} msg The message box body text
3370 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3371 * @param {Object} scope (optional) The scope of the callback function
3372 * @return {Roo.MessageBox} This message box
3374 alert : function(title, msg, fn, scope)
3389 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3390 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3391 * You are responsible for closing the message box when the process is complete.
3392 * @param {String} msg The message box body text
3393 * @param {String} title (optional) The title bar text
3394 * @return {Roo.MessageBox} This message box
3396 wait : function(msg, title){
3407 waitTimer = Roo.TaskMgr.start({
3409 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3417 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3418 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3419 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3420 * @param {String} title The title bar text
3421 * @param {String} msg The message box body text
3422 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3423 * @param {Object} scope (optional) The scope of the callback function
3424 * @return {Roo.MessageBox} This message box
3426 confirm : function(title, msg, fn, scope){
3430 buttons: this.YESNO,
3439 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3440 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3441 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3442 * (could also be the top-right close button) and the text that was entered will be passed as the two
3443 * parameters to the callback.
3444 * @param {String} title The title bar text
3445 * @param {String} msg The message box body text
3446 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3447 * @param {Object} scope (optional) The scope of the callback function
3448 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3449 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3450 * @return {Roo.MessageBox} This message box
3452 prompt : function(title, msg, fn, scope, multiline){
3456 buttons: this.OKCANCEL,
3461 multiline: multiline,
3468 * Button config that displays a single OK button
3473 * Button config that displays Yes and No buttons
3476 YESNO : {yes:true, no:true},
3478 * Button config that displays OK and Cancel buttons
3481 OKCANCEL : {ok:true, cancel:true},
3483 * Button config that displays Yes, No and Cancel buttons
3486 YESNOCANCEL : {yes:true, no:true, cancel:true},
3489 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3492 defaultTextHeight : 75,
3494 * The maximum width in pixels of the message box (defaults to 600)
3499 * The minimum width in pixels of the message box (defaults to 100)
3504 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3505 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3508 minProgressWidth : 250,
3510 * An object containing the default button text strings that can be overriden for localized language support.
3511 * Supported properties are: ok, cancel, yes and no.
3512 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3525 * Shorthand for {@link Roo.MessageBox}
3527 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3528 Roo.Msg = Roo.Msg || Roo.MessageBox;
3537 * @class Roo.bootstrap.Navbar
3538 * @extends Roo.bootstrap.Component
3539 * Bootstrap Navbar class
3542 * Create a new Navbar
3543 * @param {Object} config The config object
3547 Roo.bootstrap.Navbar = function(config){
3548 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3552 * @event beforetoggle
3553 * Fire before toggle the menu
3554 * @param {Roo.EventObject} e
3556 "beforetoggle" : true
3560 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3569 getAutoCreate : function(){
3572 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3576 initEvents :function ()
3578 //Roo.log(this.el.select('.navbar-toggle',true));
3579 this.el.select('.navbar-toggle',true).on('click', function() {
3580 if(this.fireEvent('beforetoggle', this) !== false){
3581 this.el.select('.navbar-collapse',true).toggleClass('in');
3591 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3593 var size = this.el.getSize();
3594 this.maskEl.setSize(size.width, size.height);
3595 this.maskEl.enableDisplayMode("block");
3604 getChildContainer : function()
3606 if (this.el.select('.collapse').getCount()) {
3607 return this.el.select('.collapse',true).first();
3640 * @class Roo.bootstrap.NavSimplebar
3641 * @extends Roo.bootstrap.Navbar
3642 * Bootstrap Sidebar class
3644 * @cfg {Boolean} inverse is inverted color
3646 * @cfg {String} type (nav | pills | tabs)
3647 * @cfg {Boolean} arrangement stacked | justified
3648 * @cfg {String} align (left | right) alignment
3650 * @cfg {Boolean} main (true|false) main nav bar? default false
3651 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3653 * @cfg {String} tag (header|footer|nav|div) default is nav
3659 * Create a new Sidebar
3660 * @param {Object} config The config object
3664 Roo.bootstrap.NavSimplebar = function(config){
3665 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3684 getAutoCreate : function(){
3688 tag : this.tag || 'div',
3701 this.type = this.type || 'nav';
3702 if (['tabs','pills'].indexOf(this.type)!==-1) {
3703 cfg.cn[0].cls += ' nav-' + this.type
3707 if (this.type!=='nav') {
3708 Roo.log('nav type must be nav/tabs/pills')
3710 cfg.cn[0].cls += ' navbar-nav'
3716 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3717 cfg.cn[0].cls += ' nav-' + this.arrangement;
3721 if (this.align === 'right') {
3722 cfg.cn[0].cls += ' navbar-right';
3726 cfg.cls += ' navbar-inverse';
3753 * @class Roo.bootstrap.NavHeaderbar
3754 * @extends Roo.bootstrap.NavSimplebar
3755 * Bootstrap Sidebar class
3757 * @cfg {String} brand what is brand
3758 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3759 * @cfg {String} brand_href href of the brand
3760 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3761 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3762 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3763 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3766 * Create a new Sidebar
3767 * @param {Object} config The config object
3771 Roo.bootstrap.NavHeaderbar = function(config){
3772 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3776 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3783 desktopCenter : false,
3786 getAutoCreate : function(){
3789 tag: this.nav || 'nav',
3796 if (this.desktopCenter) {
3797 cn.push({cls : 'container', cn : []});
3804 cls: 'navbar-header',
3809 cls: 'navbar-toggle',
3810 'data-toggle': 'collapse',
3815 html: 'Toggle navigation'
3837 cls: 'collapse navbar-collapse',
3841 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3843 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3844 cfg.cls += ' navbar-' + this.position;
3846 // tag can override this..
3848 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3851 if (this.brand !== '') {
3854 href: this.brand_href ? this.brand_href : '#',
3855 cls: 'navbar-brand',
3863 cfg.cls += ' main-nav';
3871 getHeaderChildContainer : function()
3873 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3874 return this.el.select('.navbar-header',true).first();
3877 return this.getChildContainer();
3881 initEvents : function()
3883 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3885 if (this.autohide) {
3890 Roo.get(document).on('scroll',function(e) {
3891 var ns = Roo.get(document).getScroll().top;
3892 var os = prevScroll;
3896 ft.removeClass('slideDown');
3897 ft.addClass('slideUp');
3900 ft.removeClass('slideUp');
3901 ft.addClass('slideDown');
3922 * @class Roo.bootstrap.NavSidebar
3923 * @extends Roo.bootstrap.Navbar
3924 * Bootstrap Sidebar class
3927 * Create a new Sidebar
3928 * @param {Object} config The config object
3932 Roo.bootstrap.NavSidebar = function(config){
3933 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3936 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3938 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3940 getAutoCreate : function(){
3945 cls: 'sidebar sidebar-nav'
3967 * @class Roo.bootstrap.NavGroup
3968 * @extends Roo.bootstrap.Component
3969 * Bootstrap NavGroup class
3970 * @cfg {String} align (left|right)
3971 * @cfg {Boolean} inverse
3972 * @cfg {String} type (nav|pills|tab) default nav
3973 * @cfg {String} navId - reference Id for navbar.
3977 * Create a new nav group
3978 * @param {Object} config The config object
3981 Roo.bootstrap.NavGroup = function(config){
3982 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3985 Roo.bootstrap.NavGroup.register(this);
3989 * Fires when the active item changes
3990 * @param {Roo.bootstrap.NavGroup} this
3991 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3992 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3999 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4010 getAutoCreate : function()
4012 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4019 if (['tabs','pills'].indexOf(this.type)!==-1) {
4020 cfg.cls += ' nav-' + this.type
4022 if (this.type!=='nav') {
4023 Roo.log('nav type must be nav/tabs/pills')
4025 cfg.cls += ' navbar-nav'
4028 if (this.parent().sidebar) {
4031 cls: 'dashboard-menu sidebar-menu'
4037 if (this.form === true) {
4043 if (this.align === 'right') {
4044 cfg.cls += ' navbar-right';
4046 cfg.cls += ' navbar-left';
4050 if (this.align === 'right') {
4051 cfg.cls += ' navbar-right';
4055 cfg.cls += ' navbar-inverse';
4063 * sets the active Navigation item
4064 * @param {Roo.bootstrap.NavItem} the new current navitem
4066 setActiveItem : function(item)
4069 Roo.each(this.navItems, function(v){
4074 v.setActive(false, true);
4081 item.setActive(true, true);
4082 this.fireEvent('changed', this, item, prev);
4087 * gets the active Navigation item
4088 * @return {Roo.bootstrap.NavItem} the current navitem
4090 getActive : function()
4094 Roo.each(this.navItems, function(v){
4105 indexOfNav : function()
4109 Roo.each(this.navItems, function(v,i){
4120 * adds a Navigation item
4121 * @param {Roo.bootstrap.NavItem} the navitem to add
4123 addItem : function(cfg)
4125 var cn = new Roo.bootstrap.NavItem(cfg);
4127 cn.parentId = this.id;
4128 cn.onRender(this.el, null);
4132 * register a Navigation item
4133 * @param {Roo.bootstrap.NavItem} the navitem to add
4135 register : function(item)
4137 this.navItems.push( item);
4138 item.navId = this.navId;
4143 * clear all the Navigation item
4146 clearAll : function()
4149 this.el.dom.innerHTML = '';
4152 getNavItem: function(tabId)
4155 Roo.each(this.navItems, function(e) {
4156 if (e.tabId == tabId) {
4166 setActiveNext : function()
4168 var i = this.indexOfNav(this.getActive());
4169 if (i > this.navItems.length) {
4172 this.setActiveItem(this.navItems[i+1]);
4174 setActivePrev : function()
4176 var i = this.indexOfNav(this.getActive());
4180 this.setActiveItem(this.navItems[i-1]);
4182 clearWasActive : function(except) {
4183 Roo.each(this.navItems, function(e) {
4184 if (e.tabId != except.tabId && e.was_active) {
4185 e.was_active = false;
4192 getWasActive : function ()
4195 Roo.each(this.navItems, function(e) {
4210 Roo.apply(Roo.bootstrap.NavGroup, {
4214 * register a Navigation Group
4215 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4217 register : function(navgrp)
4219 this.groups[navgrp.navId] = navgrp;
4223 * fetch a Navigation Group based on the navigation ID
4224 * @param {string} the navgroup to add
4225 * @returns {Roo.bootstrap.NavGroup} the navgroup
4227 get: function(navId) {
4228 if (typeof(this.groups[navId]) == 'undefined') {
4230 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4232 return this.groups[navId] ;
4247 * @class Roo.bootstrap.NavItem
4248 * @extends Roo.bootstrap.Component
4249 * Bootstrap Navbar.NavItem class
4250 * @cfg {String} href link to
4251 * @cfg {String} html content of button
4252 * @cfg {String} badge text inside badge
4253 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4254 * @cfg {String} glyphicon name of glyphicon
4255 * @cfg {String} icon name of font awesome icon
4256 * @cfg {Boolean} active Is item active
4257 * @cfg {Boolean} disabled Is item disabled
4259 * @cfg {Boolean} preventDefault (true | false) default false
4260 * @cfg {String} tabId the tab that this item activates.
4261 * @cfg {String} tagtype (a|span) render as a href or span?
4262 * @cfg {Boolean} animateRef (true|false) link to element default false
4265 * Create a new Navbar Item
4266 * @param {Object} config The config object
4268 Roo.bootstrap.NavItem = function(config){
4269 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4274 * The raw click event for the entire grid.
4275 * @param {Roo.EventObject} e
4280 * Fires when the active item active state changes
4281 * @param {Roo.bootstrap.NavItem} this
4282 * @param {boolean} state the new state
4288 * Fires when scroll to element
4289 * @param {Roo.bootstrap.NavItem} this
4290 * @param {Object} options
4291 * @param {Roo.EventObject} e
4299 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4307 preventDefault : false,
4314 getAutoCreate : function(){
4323 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4325 if (this.disabled) {
4326 cfg.cls += ' disabled';
4329 if (this.href || this.html || this.glyphicon || this.icon) {
4333 href : this.href || "#",
4334 html: this.html || ''
4339 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4342 if(this.glyphicon) {
4343 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4348 cfg.cn[0].html += " <span class='caret'></span>";
4352 if (this.badge !== '') {
4354 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4362 initEvents: function()
4364 if (typeof (this.menu) != 'undefined') {
4365 this.menu.parentType = this.xtype;
4366 this.menu.triggerEl = this.el;
4367 this.menu = this.addxtype(Roo.apply({}, this.menu));
4370 this.el.select('a',true).on('click', this.onClick, this);
4372 if(this.tagtype == 'span'){
4373 this.el.select('span',true).on('click', this.onClick, this);
4376 // at this point parent should be available..
4377 this.parent().register(this);
4380 onClick : function(e)
4382 if (e.getTarget('.dropdown-menu-item')) {
4383 // did you click on a menu itemm.... - then don't trigger onclick..
4388 this.preventDefault ||
4391 Roo.log("NavItem - prevent Default?");
4395 if (this.disabled) {
4399 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4400 if (tg && tg.transition) {
4401 Roo.log("waiting for the transitionend");
4407 //Roo.log("fire event clicked");
4408 if(this.fireEvent('click', this, e) === false){
4412 if(this.tagtype == 'span'){
4416 //Roo.log(this.href);
4417 var ael = this.el.select('a',true).first();
4420 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4421 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4422 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4423 return; // ignore... - it's a 'hash' to another page.
4425 Roo.log("NavItem - prevent Default?");
4427 this.scrollToElement(e);
4431 var p = this.parent();
4433 if (['tabs','pills'].indexOf(p.type)!==-1) {
4434 if (typeof(p.setActiveItem) !== 'undefined') {
4435 p.setActiveItem(this);
4439 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4440 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4441 // remove the collapsed menu expand...
4442 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4446 isActive: function () {
4449 setActive : function(state, fire, is_was_active)
4451 if (this.active && !state && this.navId) {
4452 this.was_active = true;
4453 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4455 nv.clearWasActive(this);
4459 this.active = state;
4462 this.el.removeClass('active');
4463 } else if (!this.el.hasClass('active')) {
4464 this.el.addClass('active');
4467 this.fireEvent('changed', this, state);
4470 // show a panel if it's registered and related..
4472 if (!this.navId || !this.tabId || !state || is_was_active) {
4476 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4480 var pan = tg.getPanelByName(this.tabId);
4484 // if we can not flip to new panel - go back to old nav highlight..
4485 if (false == tg.showPanel(pan)) {
4486 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4488 var onav = nv.getWasActive();
4490 onav.setActive(true, false, true);
4499 // this should not be here...
4500 setDisabled : function(state)
4502 this.disabled = state;
4504 this.el.removeClass('disabled');
4505 } else if (!this.el.hasClass('disabled')) {
4506 this.el.addClass('disabled');
4512 * Fetch the element to display the tooltip on.
4513 * @return {Roo.Element} defaults to this.el
4515 tooltipEl : function()
4517 return this.el.select('' + this.tagtype + '', true).first();
4520 scrollToElement : function(e)
4522 var c = document.body;
4525 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4527 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4528 c = document.documentElement;
4531 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4537 var o = target.calcOffsetsTo(c);
4544 this.fireEvent('scrollto', this, options, e);
4546 Roo.get(c).scrollTo('top', options.value, true);
4559 * <span> icon </span>
4560 * <span> text </span>
4561 * <span>badge </span>
4565 * @class Roo.bootstrap.NavSidebarItem
4566 * @extends Roo.bootstrap.NavItem
4567 * Bootstrap Navbar.NavSidebarItem class
4568 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4569 * {bool} open is the menu open
4571 * Create a new Navbar Button
4572 * @param {Object} config The config object
4574 Roo.bootstrap.NavSidebarItem = function(config){
4575 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4580 * The raw click event for the entire grid.
4581 * @param {Roo.EventObject} e
4586 * Fires when the active item active state changes
4587 * @param {Roo.bootstrap.NavSidebarItem} this
4588 * @param {boolean} state the new state
4596 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4598 badgeWeight : 'default',
4602 getAutoCreate : function(){
4607 href : this.href || '#',
4619 html : this.html || ''
4624 cfg.cls += ' active';
4627 if (this.disabled) {
4628 cfg.cls += ' disabled';
4631 cfg.cls += ' open x-open';
4634 if (this.glyphicon || this.icon) {
4635 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4636 a.cn.push({ tag : 'i', cls : c }) ;
4641 if (this.badge !== '') {
4643 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4647 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4648 a.cls += 'dropdown-toggle treeview' ;
4656 initEvents : function()
4658 if (typeof (this.menu) != 'undefined') {
4659 this.menu.parentType = this.xtype;
4660 this.menu.triggerEl = this.el;
4661 this.menu = this.addxtype(Roo.apply({}, this.menu));
4664 this.el.on('click', this.onClick, this);
4667 if(this.badge !== ''){
4669 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4674 onClick : function(e)
4681 if(this.preventDefault){
4685 this.fireEvent('click', this);
4688 disable : function()
4690 this.setDisabled(true);
4695 this.setDisabled(false);
4698 setDisabled : function(state)
4700 if(this.disabled == state){
4704 this.disabled = state;
4707 this.el.addClass('disabled');
4711 this.el.removeClass('disabled');
4716 setActive : function(state)
4718 if(this.active == state){
4722 this.active = state;
4725 this.el.addClass('active');
4729 this.el.removeClass('active');
4734 isActive: function ()
4739 setBadge : function(str)
4745 this.badgeEl.dom.innerHTML = str;
4762 * @class Roo.bootstrap.Row
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Row class (contains columns...)
4768 * @param {Object} config The config object
4771 Roo.bootstrap.Row = function(config){
4772 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4775 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4777 getAutoCreate : function(){
4796 * @class Roo.bootstrap.Element
4797 * @extends Roo.bootstrap.Component
4798 * Bootstrap Element class
4799 * @cfg {String} html contents of the element
4800 * @cfg {String} tag tag of the element
4801 * @cfg {String} cls class of the element
4802 * @cfg {Boolean} preventDefault (true|false) default false
4803 * @cfg {Boolean} clickable (true|false) default false
4806 * Create a new Element
4807 * @param {Object} config The config object
4810 Roo.bootstrap.Element = function(config){
4811 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4817 * When a element is chick
4818 * @param {Roo.bootstrap.Element} this
4819 * @param {Roo.EventObject} e
4825 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4830 preventDefault: false,
4833 getAutoCreate : function(){
4844 initEvents: function()
4846 Roo.bootstrap.Element.superclass.initEvents.call(this);
4849 this.el.on('click', this.onClick, this);
4854 onClick : function(e)
4856 if(this.preventDefault){
4860 this.fireEvent('click', this, e);
4863 getValue : function()
4865 return this.el.dom.innerHTML;
4868 setValue : function(value)
4870 this.el.dom.innerHTML = value;
4885 * @class Roo.bootstrap.Pagination
4886 * @extends Roo.bootstrap.Component
4887 * Bootstrap Pagination class
4888 * @cfg {String} size xs | sm | md | lg
4889 * @cfg {Boolean} inverse false | true
4892 * Create a new Pagination
4893 * @param {Object} config The config object
4896 Roo.bootstrap.Pagination = function(config){
4897 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4900 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4906 getAutoCreate : function(){
4912 cfg.cls += ' inverse';
4918 cfg.cls += " " + this.cls;
4936 * @class Roo.bootstrap.PaginationItem
4937 * @extends Roo.bootstrap.Component
4938 * Bootstrap PaginationItem class
4939 * @cfg {String} html text
4940 * @cfg {String} href the link
4941 * @cfg {Boolean} preventDefault (true | false) default true
4942 * @cfg {Boolean} active (true | false) default false
4943 * @cfg {Boolean} disabled default false
4947 * Create a new PaginationItem
4948 * @param {Object} config The config object
4952 Roo.bootstrap.PaginationItem = function(config){
4953 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4958 * The raw click event for the entire grid.
4959 * @param {Roo.EventObject} e
4965 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4969 preventDefault: true,
4974 getAutoCreate : function(){
4980 href : this.href ? this.href : '#',
4981 html : this.html ? this.html : ''
4991 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4995 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5001 initEvents: function() {
5003 this.el.on('click', this.onClick, this);
5006 onClick : function(e)
5008 Roo.log('PaginationItem on click ');
5009 if(this.preventDefault){
5017 this.fireEvent('click', this, e);
5033 * @class Roo.bootstrap.Slider
5034 * @extends Roo.bootstrap.Component
5035 * Bootstrap Slider class
5038 * Create a new Slider
5039 * @param {Object} config The config object
5042 Roo.bootstrap.Slider = function(config){
5043 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5046 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5048 getAutoCreate : function(){
5052 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5056 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5068 * Ext JS Library 1.1.1
5069 * Copyright(c) 2006-2007, Ext JS, LLC.
5071 * Originally Released Under LGPL - original licence link has changed is not relivant.
5074 * <script type="text/javascript">
5079 * @class Roo.grid.ColumnModel
5080 * @extends Roo.util.Observable
5081 * This is the default implementation of a ColumnModel used by the Grid. It defines
5082 * the columns in the grid.
5085 var colModel = new Roo.grid.ColumnModel([
5086 {header: "Ticker", width: 60, sortable: true, locked: true},
5087 {header: "Company Name", width: 150, sortable: true},
5088 {header: "Market Cap.", width: 100, sortable: true},
5089 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5090 {header: "Employees", width: 100, sortable: true, resizable: false}
5095 * The config options listed for this class are options which may appear in each
5096 * individual column definition.
5097 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5099 * @param {Object} config An Array of column config objects. See this class's
5100 * config objects for details.
5102 Roo.grid.ColumnModel = function(config){
5104 * The config passed into the constructor
5106 this.config = config;
5109 // if no id, create one
5110 // if the column does not have a dataIndex mapping,
5111 // map it to the order it is in the config
5112 for(var i = 0, len = config.length; i < len; i++){
5114 if(typeof c.dataIndex == "undefined"){
5117 if(typeof c.renderer == "string"){
5118 c.renderer = Roo.util.Format[c.renderer];
5120 if(typeof c.id == "undefined"){
5123 if(c.editor && c.editor.xtype){
5124 c.editor = Roo.factory(c.editor, Roo.grid);
5126 if(c.editor && c.editor.isFormField){
5127 c.editor = new Roo.grid.GridEditor(c.editor);
5129 this.lookup[c.id] = c;
5133 * The width of columns which have no width specified (defaults to 100)
5136 this.defaultWidth = 100;
5139 * Default sortable of columns which have no sortable specified (defaults to false)
5142 this.defaultSortable = false;
5146 * @event widthchange
5147 * Fires when the width of a column changes.
5148 * @param {ColumnModel} this
5149 * @param {Number} columnIndex The column index
5150 * @param {Number} newWidth The new width
5152 "widthchange": true,
5154 * @event headerchange
5155 * Fires when the text of a header changes.
5156 * @param {ColumnModel} this
5157 * @param {Number} columnIndex The column index
5158 * @param {Number} newText The new header text
5160 "headerchange": true,
5162 * @event hiddenchange
5163 * Fires when a column is hidden or "unhidden".
5164 * @param {ColumnModel} this
5165 * @param {Number} columnIndex The column index
5166 * @param {Boolean} hidden true if hidden, false otherwise
5168 "hiddenchange": true,
5170 * @event columnmoved
5171 * Fires when a column is moved.
5172 * @param {ColumnModel} this
5173 * @param {Number} oldIndex
5174 * @param {Number} newIndex
5176 "columnmoved" : true,
5178 * @event columlockchange
5179 * Fires when a column's locked state is changed
5180 * @param {ColumnModel} this
5181 * @param {Number} colIndex
5182 * @param {Boolean} locked true if locked
5184 "columnlockchange" : true
5186 Roo.grid.ColumnModel.superclass.constructor.call(this);
5188 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5190 * @cfg {String} header The header text to display in the Grid view.
5193 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5194 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5195 * specified, the column's index is used as an index into the Record's data Array.
5198 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5199 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5202 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5203 * Defaults to the value of the {@link #defaultSortable} property.
5204 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5207 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5210 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5213 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5216 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5219 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5220 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5221 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5222 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5225 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5228 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5231 * @cfg {String} cursor (Optional)
5234 * @cfg {String} tooltip (Optional)
5237 * @cfg {Number} xs (Optional)
5240 * @cfg {Number} sm (Optional)
5243 * @cfg {Number} md (Optional)
5246 * @cfg {Number} lg (Optional)
5249 * Returns the id of the column at the specified index.
5250 * @param {Number} index The column index
5251 * @return {String} the id
5253 getColumnId : function(index){
5254 return this.config[index].id;
5258 * Returns the column for a specified id.
5259 * @param {String} id The column id
5260 * @return {Object} the column
5262 getColumnById : function(id){
5263 return this.lookup[id];
5268 * Returns the column for a specified dataIndex.
5269 * @param {String} dataIndex The column dataIndex
5270 * @return {Object|Boolean} the column or false if not found
5272 getColumnByDataIndex: function(dataIndex){
5273 var index = this.findColumnIndex(dataIndex);
5274 return index > -1 ? this.config[index] : false;
5278 * Returns the index for a specified column id.
5279 * @param {String} id The column id
5280 * @return {Number} the index, or -1 if not found
5282 getIndexById : function(id){
5283 for(var i = 0, len = this.config.length; i < len; i++){
5284 if(this.config[i].id == id){
5292 * Returns the index for a specified column dataIndex.
5293 * @param {String} dataIndex The column dataIndex
5294 * @return {Number} the index, or -1 if not found
5297 findColumnIndex : function(dataIndex){
5298 for(var i = 0, len = this.config.length; i < len; i++){
5299 if(this.config[i].dataIndex == dataIndex){
5307 moveColumn : function(oldIndex, newIndex){
5308 var c = this.config[oldIndex];
5309 this.config.splice(oldIndex, 1);
5310 this.config.splice(newIndex, 0, c);
5311 this.dataMap = null;
5312 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5315 isLocked : function(colIndex){
5316 return this.config[colIndex].locked === true;
5319 setLocked : function(colIndex, value, suppressEvent){
5320 if(this.isLocked(colIndex) == value){
5323 this.config[colIndex].locked = value;
5325 this.fireEvent("columnlockchange", this, colIndex, value);
5329 getTotalLockedWidth : function(){
5331 for(var i = 0; i < this.config.length; i++){
5332 if(this.isLocked(i) && !this.isHidden(i)){
5333 this.totalWidth += this.getColumnWidth(i);
5339 getLockedCount : function(){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 if(!this.isLocked(i)){
5346 return this.config.length;
5350 * Returns the number of columns.
5353 getColumnCount : function(visibleOnly){
5354 if(visibleOnly === true){
5356 for(var i = 0, len = this.config.length; i < len; i++){
5357 if(!this.isHidden(i)){
5363 return this.config.length;
5367 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5368 * @param {Function} fn
5369 * @param {Object} scope (optional)
5370 * @return {Array} result
5372 getColumnsBy : function(fn, scope){
5374 for(var i = 0, len = this.config.length; i < len; i++){
5375 var c = this.config[i];
5376 if(fn.call(scope||this, c, i) === true){
5384 * Returns true if the specified column is sortable.
5385 * @param {Number} col The column index
5388 isSortable : function(col){
5389 if(typeof this.config[col].sortable == "undefined"){
5390 return this.defaultSortable;
5392 return this.config[col].sortable;
5396 * Returns the rendering (formatting) function defined for the column.
5397 * @param {Number} col The column index.
5398 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5400 getRenderer : function(col){
5401 if(!this.config[col].renderer){
5402 return Roo.grid.ColumnModel.defaultRenderer;
5404 return this.config[col].renderer;
5408 * Sets the rendering (formatting) function for a column.
5409 * @param {Number} col The column index
5410 * @param {Function} fn The function to use to process the cell's raw data
5411 * to return HTML markup for the grid view. The render function is called with
5412 * the following parameters:<ul>
5413 * <li>Data value.</li>
5414 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5415 * <li>css A CSS style string to apply to the table cell.</li>
5416 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5417 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5418 * <li>Row index</li>
5419 * <li>Column index</li>
5420 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5422 setRenderer : function(col, fn){
5423 this.config[col].renderer = fn;
5427 * Returns the width for the specified column.
5428 * @param {Number} col The column index
5431 getColumnWidth : function(col){
5432 return this.config[col].width * 1 || this.defaultWidth;
5436 * Sets the width for a column.
5437 * @param {Number} col The column index
5438 * @param {Number} width The new width
5440 setColumnWidth : function(col, width, suppressEvent){
5441 this.config[col].width = width;
5442 this.totalWidth = null;
5444 this.fireEvent("widthchange", this, col, width);
5449 * Returns the total width of all columns.
5450 * @param {Boolean} includeHidden True to include hidden column widths
5453 getTotalWidth : function(includeHidden){
5454 if(!this.totalWidth){
5455 this.totalWidth = 0;
5456 for(var i = 0, len = this.config.length; i < len; i++){
5457 if(includeHidden || !this.isHidden(i)){
5458 this.totalWidth += this.getColumnWidth(i);
5462 return this.totalWidth;
5466 * Returns the header for the specified column.
5467 * @param {Number} col The column index
5470 getColumnHeader : function(col){
5471 return this.config[col].header;
5475 * Sets the header for a column.
5476 * @param {Number} col The column index
5477 * @param {String} header The new header
5479 setColumnHeader : function(col, header){
5480 this.config[col].header = header;
5481 this.fireEvent("headerchange", this, col, header);
5485 * Returns the tooltip for the specified column.
5486 * @param {Number} col The column index
5489 getColumnTooltip : function(col){
5490 return this.config[col].tooltip;
5493 * Sets the tooltip for a column.
5494 * @param {Number} col The column index
5495 * @param {String} tooltip The new tooltip
5497 setColumnTooltip : function(col, tooltip){
5498 this.config[col].tooltip = tooltip;
5502 * Returns the dataIndex for the specified column.
5503 * @param {Number} col The column index
5506 getDataIndex : function(col){
5507 return this.config[col].dataIndex;
5511 * Sets the dataIndex for a column.
5512 * @param {Number} col The column index
5513 * @param {Number} dataIndex The new dataIndex
5515 setDataIndex : function(col, dataIndex){
5516 this.config[col].dataIndex = dataIndex;
5522 * Returns true if the cell is editable.
5523 * @param {Number} colIndex The column index
5524 * @param {Number} rowIndex The row index - this is nto actually used..?
5527 isCellEditable : function(colIndex, rowIndex){
5528 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5532 * Returns the editor defined for the cell/column.
5533 * return false or null to disable editing.
5534 * @param {Number} colIndex The column index
5535 * @param {Number} rowIndex The row index
5538 getCellEditor : function(colIndex, rowIndex){
5539 return this.config[colIndex].editor;
5543 * Sets if a column is editable.
5544 * @param {Number} col The column index
5545 * @param {Boolean} editable True if the column is editable
5547 setEditable : function(col, editable){
5548 this.config[col].editable = editable;
5553 * Returns true if the column is hidden.
5554 * @param {Number} colIndex The column index
5557 isHidden : function(colIndex){
5558 return this.config[colIndex].hidden;
5563 * Returns true if the column width cannot be changed
5565 isFixed : function(colIndex){
5566 return this.config[colIndex].fixed;
5570 * Returns true if the column can be resized
5573 isResizable : function(colIndex){
5574 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5577 * Sets if a column is hidden.
5578 * @param {Number} colIndex The column index
5579 * @param {Boolean} hidden True if the column is hidden
5581 setHidden : function(colIndex, hidden){
5582 this.config[colIndex].hidden = hidden;
5583 this.totalWidth = null;
5584 this.fireEvent("hiddenchange", this, colIndex, hidden);
5588 * Sets the editor for a column.
5589 * @param {Number} col The column index
5590 * @param {Object} editor The editor object
5592 setEditor : function(col, editor){
5593 this.config[col].editor = editor;
5597 Roo.grid.ColumnModel.defaultRenderer = function(value)
5599 if(typeof value == "object") {
5602 if(typeof value == "string" && value.length < 1){
5606 return String.format("{0}", value);
5609 // Alias for backwards compatibility
5610 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5613 * Ext JS Library 1.1.1
5614 * Copyright(c) 2006-2007, Ext JS, LLC.
5616 * Originally Released Under LGPL - original licence link has changed is not relivant.
5619 * <script type="text/javascript">
5623 * @class Roo.LoadMask
5624 * A simple utility class for generically masking elements while loading data. If the element being masked has
5625 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5626 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5627 * element's UpdateManager load indicator and will be destroyed after the initial load.
5629 * Create a new LoadMask
5630 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5631 * @param {Object} config The config object
5633 Roo.LoadMask = function(el, config){
5634 this.el = Roo.get(el);
5635 Roo.apply(this, config);
5637 this.store.on('beforeload', this.onBeforeLoad, this);
5638 this.store.on('load', this.onLoad, this);
5639 this.store.on('loadexception', this.onLoadException, this);
5640 this.removeMask = false;
5642 var um = this.el.getUpdateManager();
5643 um.showLoadIndicator = false; // disable the default indicator
5644 um.on('beforeupdate', this.onBeforeLoad, this);
5645 um.on('update', this.onLoad, this);
5646 um.on('failure', this.onLoad, this);
5647 this.removeMask = true;
5651 Roo.LoadMask.prototype = {
5653 * @cfg {Boolean} removeMask
5654 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5655 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5659 * The text to display in a centered loading message box (defaults to 'Loading...')
5663 * @cfg {String} msgCls
5664 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5666 msgCls : 'x-mask-loading',
5669 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5675 * Disables the mask to prevent it from being displayed
5677 disable : function(){
5678 this.disabled = true;
5682 * Enables the mask so that it can be displayed
5684 enable : function(){
5685 this.disabled = false;
5688 onLoadException : function()
5692 if (typeof(arguments[3]) != 'undefined') {
5693 Roo.MessageBox.alert("Error loading",arguments[3]);
5697 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5698 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5705 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5710 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5714 onBeforeLoad : function(){
5716 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5721 destroy : function(){
5723 this.store.un('beforeload', this.onBeforeLoad, this);
5724 this.store.un('load', this.onLoad, this);
5725 this.store.un('loadexception', this.onLoadException, this);
5727 var um = this.el.getUpdateManager();
5728 um.un('beforeupdate', this.onBeforeLoad, this);
5729 um.un('update', this.onLoad, this);
5730 um.un('failure', this.onLoad, this);
5741 * @class Roo.bootstrap.Table
5742 * @extends Roo.bootstrap.Component
5743 * Bootstrap Table class
5744 * @cfg {String} cls table class
5745 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5746 * @cfg {String} bgcolor Specifies the background color for a table
5747 * @cfg {Number} border Specifies whether the table cells should have borders or not
5748 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5749 * @cfg {Number} cellspacing Specifies the space between cells
5750 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5751 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5752 * @cfg {String} sortable Specifies that the table should be sortable
5753 * @cfg {String} summary Specifies a summary of the content of a table
5754 * @cfg {Number} width Specifies the width of a table
5755 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5757 * @cfg {boolean} striped Should the rows be alternative striped
5758 * @cfg {boolean} bordered Add borders to the table
5759 * @cfg {boolean} hover Add hover highlighting
5760 * @cfg {boolean} condensed Format condensed
5761 * @cfg {boolean} responsive Format condensed
5762 * @cfg {Boolean} loadMask (true|false) default false
5763 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5764 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5765 * @cfg {Boolean} rowSelection (true|false) default false
5766 * @cfg {Boolean} cellSelection (true|false) default false
5767 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5768 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5769 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5773 * Create a new Table
5774 * @param {Object} config The config object
5777 Roo.bootstrap.Table = function(config){
5778 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5783 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5784 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5785 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5786 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5788 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5790 this.sm.grid = this;
5791 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5792 this.sm = this.selModel;
5793 this.sm.xmodule = this.xmodule || false;
5796 if (this.cm && typeof(this.cm.config) == 'undefined') {
5797 this.colModel = new Roo.grid.ColumnModel(this.cm);
5798 this.cm = this.colModel;
5799 this.cm.xmodule = this.xmodule || false;
5802 this.store= Roo.factory(this.store, Roo.data);
5803 this.ds = this.store;
5804 this.ds.xmodule = this.xmodule || false;
5807 if (this.footer && this.store) {
5808 this.footer.dataSource = this.ds;
5809 this.footer = Roo.factory(this.footer);
5816 * Fires when a cell is clicked
5817 * @param {Roo.bootstrap.Table} this
5818 * @param {Roo.Element} el
5819 * @param {Number} rowIndex
5820 * @param {Number} columnIndex
5821 * @param {Roo.EventObject} e
5825 * @event celldblclick
5826 * Fires when a cell is double clicked
5827 * @param {Roo.bootstrap.Table} this
5828 * @param {Roo.Element} el
5829 * @param {Number} rowIndex
5830 * @param {Number} columnIndex
5831 * @param {Roo.EventObject} e
5833 "celldblclick" : true,
5836 * Fires when a row is clicked
5837 * @param {Roo.bootstrap.Table} this
5838 * @param {Roo.Element} el
5839 * @param {Number} rowIndex
5840 * @param {Roo.EventObject} e
5844 * @event rowdblclick
5845 * Fires when a row is double clicked
5846 * @param {Roo.bootstrap.Table} this
5847 * @param {Roo.Element} el
5848 * @param {Number} rowIndex
5849 * @param {Roo.EventObject} e
5851 "rowdblclick" : true,
5854 * Fires when a mouseover occur
5855 * @param {Roo.bootstrap.Table} this
5856 * @param {Roo.Element} el
5857 * @param {Number} rowIndex
5858 * @param {Number} columnIndex
5859 * @param {Roo.EventObject} e
5864 * Fires when a mouseout occur
5865 * @param {Roo.bootstrap.Table} this
5866 * @param {Roo.Element} el
5867 * @param {Number} rowIndex
5868 * @param {Number} columnIndex
5869 * @param {Roo.EventObject} e
5874 * Fires when a row is rendered, so you can change add a style to it.
5875 * @param {Roo.bootstrap.Table} this
5876 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5880 * @event rowsrendered
5881 * Fires when all the rows have been rendered
5882 * @param {Roo.bootstrap.Table} this
5884 'rowsrendered' : true,
5886 * @event contextmenu
5887 * The raw contextmenu event for the entire grid.
5888 * @param {Roo.EventObject} e
5890 "contextmenu" : true,
5892 * @event rowcontextmenu
5893 * Fires when a row is right clicked
5894 * @param {Roo.bootstrap.Table} this
5895 * @param {Number} rowIndex
5896 * @param {Roo.EventObject} e
5898 "rowcontextmenu" : true,
5900 * @event cellcontextmenu
5901 * Fires when a cell is right clicked
5902 * @param {Roo.bootstrap.Table} this
5903 * @param {Number} rowIndex
5904 * @param {Number} cellIndex
5905 * @param {Roo.EventObject} e
5907 "cellcontextmenu" : true,
5909 * @event headercontextmenu
5910 * Fires when a header is right clicked
5911 * @param {Roo.bootstrap.Table} this
5912 * @param {Number} columnIndex
5913 * @param {Roo.EventObject} e
5915 "headercontextmenu" : true
5919 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5945 rowSelection : false,
5946 cellSelection : false,
5949 // Roo.Element - the tbody
5951 // Roo.Element - thead element
5954 container: false, // used by gridpanel...
5958 getAutoCreate : function()
5960 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5967 if (this.scrollBody) {
5968 cfg.cls += ' table-body-fixed';
5971 cfg.cls += ' table-striped';
5975 cfg.cls += ' table-hover';
5977 if (this.bordered) {
5978 cfg.cls += ' table-bordered';
5980 if (this.condensed) {
5981 cfg.cls += ' table-condensed';
5983 if (this.responsive) {
5984 cfg.cls += ' table-responsive';
5988 cfg.cls+= ' ' +this.cls;
5991 // this lot should be simplifed...
5994 cfg.align=this.align;
5997 cfg.bgcolor=this.bgcolor;
6000 cfg.border=this.border;
6002 if (this.cellpadding) {
6003 cfg.cellpadding=this.cellpadding;
6005 if (this.cellspacing) {
6006 cfg.cellspacing=this.cellspacing;
6009 cfg.frame=this.frame;
6012 cfg.rules=this.rules;
6014 if (this.sortable) {
6015 cfg.sortable=this.sortable;
6018 cfg.summary=this.summary;
6021 cfg.width=this.width;
6024 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6027 if(this.store || this.cm){
6028 if(this.headerShow){
6029 cfg.cn.push(this.renderHeader());
6032 cfg.cn.push(this.renderBody());
6034 if(this.footerShow){
6035 cfg.cn.push(this.renderFooter());
6037 // where does this come from?
6038 //cfg.cls+= ' TableGrid';
6041 return { cn : [ cfg ] };
6044 initEvents : function()
6046 if(!this.store || !this.cm){
6049 if (this.selModel) {
6050 this.selModel.initEvents();
6054 //Roo.log('initEvents with ds!!!!');
6056 this.mainBody = this.el.select('tbody', true).first();
6057 this.mainHead = this.el.select('thead', true).first();
6064 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6065 e.on('click', _this.sort, _this);
6068 this.mainBody.on("click", this.onClick, this);
6069 this.mainBody.on("dblclick", this.onDblClick, this);
6071 // why is this done????? = it breaks dialogs??
6072 //this.parent().el.setStyle('position', 'relative');
6076 this.footer.parentId = this.id;
6077 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6080 this.el.select('tfoot tr td').first().addClass('hide');
6084 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6086 this.store.on('load', this.onLoad, this);
6087 this.store.on('beforeload', this.onBeforeLoad, this);
6088 this.store.on('update', this.onUpdate, this);
6089 this.store.on('add', this.onAdd, this);
6090 this.store.on("clear", this.clear, this);
6092 this.el.on("contextmenu", this.onContextMenu, this);
6094 this.mainBody.on('scroll', this.onBodyScroll, this);
6099 onContextMenu : function(e, t)
6101 this.processEvent("contextmenu", e);
6104 processEvent : function(name, e)
6106 if (name != 'touchstart' ) {
6107 this.fireEvent(name, e);
6110 var t = e.getTarget();
6112 var cell = Roo.get(t);
6118 if(cell.findParent('tfoot', false, true)){
6122 if(cell.findParent('thead', false, true)){
6124 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6125 cell = Roo.get(t).findParent('th', false, true);
6127 Roo.log("failed to find th in thead?");
6128 Roo.log(e.getTarget());
6133 var cellIndex = cell.dom.cellIndex;
6135 var ename = name == 'touchstart' ? 'click' : name;
6136 this.fireEvent("header" + ename, this, cellIndex, e);
6141 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6142 cell = Roo.get(t).findParent('td', false, true);
6144 Roo.log("failed to find th in tbody?");
6145 Roo.log(e.getTarget());
6150 var row = cell.findParent('tr', false, true);
6151 var cellIndex = cell.dom.cellIndex;
6152 var rowIndex = row.dom.rowIndex - 1;
6156 this.fireEvent("row" + name, this, rowIndex, e);
6160 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6166 onMouseover : function(e, el)
6168 var cell = Roo.get(el);
6174 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6175 cell = cell.findParent('td', false, true);
6178 var row = cell.findParent('tr', false, true);
6179 var cellIndex = cell.dom.cellIndex;
6180 var rowIndex = row.dom.rowIndex - 1; // start from 0
6182 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6186 onMouseout : function(e, el)
6188 var cell = Roo.get(el);
6194 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6195 cell = cell.findParent('td', false, true);
6198 var row = cell.findParent('tr', false, true);
6199 var cellIndex = cell.dom.cellIndex;
6200 var rowIndex = row.dom.rowIndex - 1; // start from 0
6202 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6206 onClick : function(e, el)
6208 var cell = Roo.get(el);
6210 if(!cell || (!this.cellSelection && !this.rowSelection)){
6214 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6215 cell = cell.findParent('td', false, true);
6218 if(!cell || typeof(cell) == 'undefined'){
6222 var row = cell.findParent('tr', false, true);
6224 if(!row || typeof(row) == 'undefined'){
6228 var cellIndex = cell.dom.cellIndex;
6229 var rowIndex = this.getRowIndex(row);
6231 // why??? - should these not be based on SelectionModel?
6232 if(this.cellSelection){
6233 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6236 if(this.rowSelection){
6237 this.fireEvent('rowclick', this, row, rowIndex, e);
6243 onDblClick : function(e,el)
6245 var cell = Roo.get(el);
6247 if(!cell || (!this.cellSelection && !this.rowSelection)){
6251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6252 cell = cell.findParent('td', false, true);
6255 if(!cell || typeof(cell) == 'undefined'){
6259 var row = cell.findParent('tr', false, true);
6261 if(!row || typeof(row) == 'undefined'){
6265 var cellIndex = cell.dom.cellIndex;
6266 var rowIndex = this.getRowIndex(row);
6268 if(this.cellSelection){
6269 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6272 if(this.rowSelection){
6273 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6277 sort : function(e,el)
6279 var col = Roo.get(el);
6281 if(!col.hasClass('sortable')){
6285 var sort = col.attr('sort');
6288 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6292 this.store.sortInfo = {field : sort, direction : dir};
6295 Roo.log("calling footer first");
6296 this.footer.onClick('first');
6299 this.store.load({ params : { start : 0 } });
6303 renderHeader : function()
6311 this.totalWidth = 0;
6313 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6315 var config = cm.config[i];
6320 html: cm.getColumnHeader(i)
6325 if(typeof(config.sortable) != 'undefined' && config.sortable){
6327 c.html = '<i class="glyphicon"></i>' + c.html;
6330 if(typeof(config.lgHeader) != 'undefined'){
6331 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6334 if(typeof(config.mdHeader) != 'undefined'){
6335 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6338 if(typeof(config.smHeader) != 'undefined'){
6339 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6342 if(typeof(config.xsHeader) != 'undefined'){
6343 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6350 if(typeof(config.tooltip) != 'undefined'){
6351 c.tooltip = config.tooltip;
6354 if(typeof(config.colspan) != 'undefined'){
6355 c.colspan = config.colspan;
6358 if(typeof(config.hidden) != 'undefined' && config.hidden){
6359 c.style += ' display:none;';
6362 if(typeof(config.dataIndex) != 'undefined'){
6363 c.sort = config.dataIndex;
6368 if(typeof(config.align) != 'undefined' && config.align.length){
6369 c.style += ' text-align:' + config.align + ';';
6372 if(typeof(config.width) != 'undefined'){
6373 c.style += ' width:' + config.width + 'px;';
6374 this.totalWidth += config.width;
6376 this.totalWidth += 100; // assume minimum of 100 per column?
6379 if(typeof(config.cls) != 'undefined'){
6380 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6383 ['xs','sm','md','lg'].map(function(size){
6385 if(typeof(config[size]) == 'undefined'){
6389 if (!config[size]) { // 0 = hidden
6390 c.cls += ' hidden-' + size;
6394 c.cls += ' col-' + size + '-' + config[size];
6404 renderBody : function()
6414 colspan : this.cm.getColumnCount()
6424 renderFooter : function()
6434 colspan : this.cm.getColumnCount()
6448 // Roo.log('ds onload');
6453 var ds = this.store;
6455 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6456 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6457 if (_this.store.sortInfo) {
6459 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6460 e.select('i', true).addClass(['glyphicon-arrow-up']);
6463 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6464 e.select('i', true).addClass(['glyphicon-arrow-down']);
6469 var tbody = this.mainBody;
6471 if(ds.getCount() > 0){
6472 ds.data.each(function(d,rowIndex){
6473 var row = this.renderRow(cm, ds, rowIndex);
6475 tbody.createChild(row);
6479 if(row.cellObjects.length){
6480 Roo.each(row.cellObjects, function(r){
6481 _this.renderCellObject(r);
6488 Roo.each(this.el.select('tbody td', true).elements, function(e){
6489 e.on('mouseover', _this.onMouseover, _this);
6492 Roo.each(this.el.select('tbody td', true).elements, function(e){
6493 e.on('mouseout', _this.onMouseout, _this);
6495 this.fireEvent('rowsrendered', this);
6496 //if(this.loadMask){
6497 // this.maskEl.hide();
6504 onUpdate : function(ds,record)
6506 this.refreshRow(record);
6510 onRemove : function(ds, record, index, isUpdate){
6511 if(isUpdate !== true){
6512 this.fireEvent("beforerowremoved", this, index, record);
6514 var bt = this.mainBody.dom;
6516 var rows = this.el.select('tbody > tr', true).elements;
6518 if(typeof(rows[index]) != 'undefined'){
6519 bt.removeChild(rows[index].dom);
6522 // if(bt.rows[index]){
6523 // bt.removeChild(bt.rows[index]);
6526 if(isUpdate !== true){
6527 //this.stripeRows(index);
6528 //this.syncRowHeights(index, index);
6530 this.fireEvent("rowremoved", this, index, record);
6534 onAdd : function(ds, records, rowIndex)
6536 //Roo.log('on Add called');
6537 // - note this does not handle multiple adding very well..
6538 var bt = this.mainBody.dom;
6539 for (var i =0 ; i < records.length;i++) {
6540 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6541 //Roo.log(records[i]);
6542 //Roo.log(this.store.getAt(rowIndex+i));
6543 this.insertRow(this.store, rowIndex + i, false);
6550 refreshRow : function(record){
6551 var ds = this.store, index;
6552 if(typeof record == 'number'){
6554 record = ds.getAt(index);
6556 index = ds.indexOf(record);
6558 this.insertRow(ds, index, true);
6560 this.onRemove(ds, record, index+1, true);
6562 //this.syncRowHeights(index, index);
6564 this.fireEvent("rowupdated", this, index, record);
6567 insertRow : function(dm, rowIndex, isUpdate){
6570 this.fireEvent("beforerowsinserted", this, rowIndex);
6572 //var s = this.getScrollState();
6573 var row = this.renderRow(this.cm, this.store, rowIndex);
6574 // insert before rowIndex..
6575 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6579 if(row.cellObjects.length){
6580 Roo.each(row.cellObjects, function(r){
6581 _this.renderCellObject(r);
6586 this.fireEvent("rowsinserted", this, rowIndex);
6587 //this.syncRowHeights(firstRow, lastRow);
6588 //this.stripeRows(firstRow);
6595 getRowDom : function(rowIndex)
6597 var rows = this.el.select('tbody > tr', true).elements;
6599 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6602 // returns the object tree for a tr..
6605 renderRow : function(cm, ds, rowIndex)
6608 var d = ds.getAt(rowIndex);
6615 var cellObjects = [];
6617 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6618 var config = cm.config[i];
6620 var renderer = cm.getRenderer(i);
6624 if(typeof(renderer) !== 'undefined'){
6625 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6627 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6628 // and are rendered into the cells after the row is rendered - using the id for the element.
6630 if(typeof(value) === 'object'){
6640 rowIndex : rowIndex,
6645 this.fireEvent('rowclass', this, rowcfg);
6649 cls : rowcfg.rowClass,
6651 html: (typeof(value) === 'object') ? '' : value
6658 if(typeof(config.colspan) != 'undefined'){
6659 td.colspan = config.colspan;
6662 if(typeof(config.hidden) != 'undefined' && config.hidden){
6663 td.style += ' display:none;';
6666 if(typeof(config.align) != 'undefined' && config.align.length){
6667 td.style += ' text-align:' + config.align + ';';
6670 if(typeof(config.width) != 'undefined'){
6671 td.style += ' width:' + config.width + 'px;';
6674 if(typeof(config.cursor) != 'undefined'){
6675 td.style += ' cursor:' + config.cursor + ';';
6678 if(typeof(config.cls) != 'undefined'){
6679 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6682 ['xs','sm','md','lg'].map(function(size){
6684 if(typeof(config[size]) == 'undefined'){
6688 if (!config[size]) { // 0 = hidden
6689 td.cls += ' hidden-' + size;
6693 td.cls += ' col-' + size + '-' + config[size];
6701 row.cellObjects = cellObjects;
6709 onBeforeLoad : function()
6711 //Roo.log('ds onBeforeLoad');
6715 //if(this.loadMask){
6716 // this.maskEl.show();
6724 this.el.select('tbody', true).first().dom.innerHTML = '';
6727 * Show or hide a row.
6728 * @param {Number} rowIndex to show or hide
6729 * @param {Boolean} state hide
6731 setRowVisibility : function(rowIndex, state)
6733 var bt = this.mainBody.dom;
6735 var rows = this.el.select('tbody > tr', true).elements;
6737 if(typeof(rows[rowIndex]) == 'undefined'){
6740 rows[rowIndex].dom.style.display = state ? '' : 'none';
6744 getSelectionModel : function(){
6746 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6748 return this.selModel;
6751 * Render the Roo.bootstrap object from renderder
6753 renderCellObject : function(r)
6757 var t = r.cfg.render(r.container);
6760 Roo.each(r.cfg.cn, function(c){
6762 container: t.getChildContainer(),
6765 _this.renderCellObject(child);
6770 getRowIndex : function(row)
6774 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6785 * Returns the grid's underlying element = used by panel.Grid
6786 * @return {Element} The element
6788 getGridEl : function(){
6792 * Forces a resize - used by panel.Grid
6793 * @return {Element} The element
6795 autoSize : function()
6797 //var ctr = Roo.get(this.container.dom.parentElement);
6798 var ctr = Roo.get(this.el.dom);
6800 var thd = this.getGridEl().select('thead',true).first();
6801 var tbd = this.getGridEl().select('tbody', true).first();
6802 var tfd = this.getGridEl().select('tfoot', true).first();
6804 var cw = ctr.getWidth();
6808 tbd.setSize(ctr.getWidth(),
6809 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6811 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6814 cw = Math.max(cw, this.totalWidth);
6815 this.getGridEl().select('tr',true).setWidth(cw);
6816 // resize 'expandable coloumn?
6818 return; // we doe not have a view in this design..
6821 onBodyScroll: function()
6823 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6824 this.mainHead.setStyle({
6825 'position' : 'relative',
6826 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6831 var scrollHeight = this.mainBody.dom.scrollHeight;
6833 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6835 var height = this.mainBody.getHeight();
6837 if(scrollHeight - height == scrollTop) {
6839 var total = this.ds.getTotalCount();
6841 if(this.footer.cursor + this.footer.pageSize < total){
6843 this.footer.ds.load({
6845 start : this.footer.cursor + this.footer.pageSize,
6846 limit : this.footer.pageSize
6867 * @class Roo.bootstrap.TableCell
6868 * @extends Roo.bootstrap.Component
6869 * Bootstrap TableCell class
6870 * @cfg {String} html cell contain text
6871 * @cfg {String} cls cell class
6872 * @cfg {String} tag cell tag (td|th) default td
6873 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6874 * @cfg {String} align Aligns the content in a cell
6875 * @cfg {String} axis Categorizes cells
6876 * @cfg {String} bgcolor Specifies the background color of a cell
6877 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6878 * @cfg {Number} colspan Specifies the number of columns a cell should span
6879 * @cfg {String} headers Specifies one or more header cells a cell is related to
6880 * @cfg {Number} height Sets the height of a cell
6881 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6882 * @cfg {Number} rowspan Sets the number of rows a cell should span
6883 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6884 * @cfg {String} valign Vertical aligns the content in a cell
6885 * @cfg {Number} width Specifies the width of a cell
6888 * Create a new TableCell
6889 * @param {Object} config The config object
6892 Roo.bootstrap.TableCell = function(config){
6893 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6896 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6916 getAutoCreate : function(){
6917 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6937 cfg.align=this.align
6943 cfg.bgcolor=this.bgcolor
6946 cfg.charoff=this.charoff
6949 cfg.colspan=this.colspan
6952 cfg.headers=this.headers
6955 cfg.height=this.height
6958 cfg.nowrap=this.nowrap
6961 cfg.rowspan=this.rowspan
6964 cfg.scope=this.scope
6967 cfg.valign=this.valign
6970 cfg.width=this.width
6989 * @class Roo.bootstrap.TableRow
6990 * @extends Roo.bootstrap.Component
6991 * Bootstrap TableRow class
6992 * @cfg {String} cls row class
6993 * @cfg {String} align Aligns the content in a table row
6994 * @cfg {String} bgcolor Specifies a background color for a table row
6995 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6996 * @cfg {String} valign Vertical aligns the content in a table row
6999 * Create a new TableRow
7000 * @param {Object} config The config object
7003 Roo.bootstrap.TableRow = function(config){
7004 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7007 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7015 getAutoCreate : function(){
7016 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7026 cfg.align = this.align;
7029 cfg.bgcolor = this.bgcolor;
7032 cfg.charoff = this.charoff;
7035 cfg.valign = this.valign;
7053 * @class Roo.bootstrap.TableBody
7054 * @extends Roo.bootstrap.Component
7055 * Bootstrap TableBody class
7056 * @cfg {String} cls element class
7057 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7058 * @cfg {String} align Aligns the content inside the element
7059 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7060 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7063 * Create a new TableBody
7064 * @param {Object} config The config object
7067 Roo.bootstrap.TableBody = function(config){
7068 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7071 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7079 getAutoCreate : function(){
7080 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7094 cfg.align = this.align;
7097 cfg.charoff = this.charoff;
7100 cfg.valign = this.valign;
7107 // initEvents : function()
7114 // this.store = Roo.factory(this.store, Roo.data);
7115 // this.store.on('load', this.onLoad, this);
7117 // this.store.load();
7121 // onLoad: function ()
7123 // this.fireEvent('load', this);
7133 * Ext JS Library 1.1.1
7134 * Copyright(c) 2006-2007, Ext JS, LLC.
7136 * Originally Released Under LGPL - original licence link has changed is not relivant.
7139 * <script type="text/javascript">
7142 // as we use this in bootstrap.
7143 Roo.namespace('Roo.form');
7145 * @class Roo.form.Action
7146 * Internal Class used to handle form actions
7148 * @param {Roo.form.BasicForm} el The form element or its id
7149 * @param {Object} config Configuration options
7154 // define the action interface
7155 Roo.form.Action = function(form, options){
7157 this.options = options || {};
7160 * Client Validation Failed
7163 Roo.form.Action.CLIENT_INVALID = 'client';
7165 * Server Validation Failed
7168 Roo.form.Action.SERVER_INVALID = 'server';
7170 * Connect to Server Failed
7173 Roo.form.Action.CONNECT_FAILURE = 'connect';
7175 * Reading Data from Server Failed
7178 Roo.form.Action.LOAD_FAILURE = 'load';
7180 Roo.form.Action.prototype = {
7182 failureType : undefined,
7183 response : undefined,
7187 run : function(options){
7192 success : function(response){
7197 handleResponse : function(response){
7201 // default connection failure
7202 failure : function(response){
7204 this.response = response;
7205 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7206 this.form.afterAction(this, false);
7209 processResponse : function(response){
7210 this.response = response;
7211 if(!response.responseText){
7214 this.result = this.handleResponse(response);
7218 // utility functions used internally
7219 getUrl : function(appendParams){
7220 var url = this.options.url || this.form.url || this.form.el.dom.action;
7222 var p = this.getParams();
7224 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7230 getMethod : function(){
7231 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7234 getParams : function(){
7235 var bp = this.form.baseParams;
7236 var p = this.options.params;
7238 if(typeof p == "object"){
7239 p = Roo.urlEncode(Roo.applyIf(p, bp));
7240 }else if(typeof p == 'string' && bp){
7241 p += '&' + Roo.urlEncode(bp);
7244 p = Roo.urlEncode(bp);
7249 createCallback : function(){
7251 success: this.success,
7252 failure: this.failure,
7254 timeout: (this.form.timeout*1000),
7255 upload: this.form.fileUpload ? this.success : undefined
7260 Roo.form.Action.Submit = function(form, options){
7261 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7264 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7267 haveProgress : false,
7268 uploadComplete : false,
7270 // uploadProgress indicator.
7271 uploadProgress : function()
7273 if (!this.form.progressUrl) {
7277 if (!this.haveProgress) {
7278 Roo.MessageBox.progress("Uploading", "Uploading");
7280 if (this.uploadComplete) {
7281 Roo.MessageBox.hide();
7285 this.haveProgress = true;
7287 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7289 var c = new Roo.data.Connection();
7291 url : this.form.progressUrl,
7296 success : function(req){
7297 //console.log(data);
7301 rdata = Roo.decode(req.responseText)
7303 Roo.log("Invalid data from server..");
7307 if (!rdata || !rdata.success) {
7309 Roo.MessageBox.alert(Roo.encode(rdata));
7312 var data = rdata.data;
7314 if (this.uploadComplete) {
7315 Roo.MessageBox.hide();
7320 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7321 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7324 this.uploadProgress.defer(2000,this);
7327 failure: function(data) {
7328 Roo.log('progress url failed ');
7339 // run get Values on the form, so it syncs any secondary forms.
7340 this.form.getValues();
7342 var o = this.options;
7343 var method = this.getMethod();
7344 var isPost = method == 'POST';
7345 if(o.clientValidation === false || this.form.isValid()){
7347 if (this.form.progressUrl) {
7348 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7349 (new Date() * 1) + '' + Math.random());
7354 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7355 form:this.form.el.dom,
7356 url:this.getUrl(!isPost),
7358 params:isPost ? this.getParams() : null,
7359 isUpload: this.form.fileUpload
7362 this.uploadProgress();
7364 }else if (o.clientValidation !== false){ // client validation failed
7365 this.failureType = Roo.form.Action.CLIENT_INVALID;
7366 this.form.afterAction(this, false);
7370 success : function(response)
7372 this.uploadComplete= true;
7373 if (this.haveProgress) {
7374 Roo.MessageBox.hide();
7378 var result = this.processResponse(response);
7379 if(result === true || result.success){
7380 this.form.afterAction(this, true);
7384 this.form.markInvalid(result.errors);
7385 this.failureType = Roo.form.Action.SERVER_INVALID;
7387 this.form.afterAction(this, false);
7389 failure : function(response)
7391 this.uploadComplete= true;
7392 if (this.haveProgress) {
7393 Roo.MessageBox.hide();
7396 this.response = response;
7397 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7398 this.form.afterAction(this, false);
7401 handleResponse : function(response){
7402 if(this.form.errorReader){
7403 var rs = this.form.errorReader.read(response);
7406 for(var i = 0, len = rs.records.length; i < len; i++) {
7407 var r = rs.records[i];
7411 if(errors.length < 1){
7415 success : rs.success,
7421 ret = Roo.decode(response.responseText);
7425 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7435 Roo.form.Action.Load = function(form, options){
7436 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7437 this.reader = this.form.reader;
7440 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7445 Roo.Ajax.request(Roo.apply(
7446 this.createCallback(), {
7447 method:this.getMethod(),
7448 url:this.getUrl(false),
7449 params:this.getParams()
7453 success : function(response){
7455 var result = this.processResponse(response);
7456 if(result === true || !result.success || !result.data){
7457 this.failureType = Roo.form.Action.LOAD_FAILURE;
7458 this.form.afterAction(this, false);
7461 this.form.clearInvalid();
7462 this.form.setValues(result.data);
7463 this.form.afterAction(this, true);
7466 handleResponse : function(response){
7467 if(this.form.reader){
7468 var rs = this.form.reader.read(response);
7469 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7471 success : rs.success,
7475 return Roo.decode(response.responseText);
7479 Roo.form.Action.ACTION_TYPES = {
7480 'load' : Roo.form.Action.Load,
7481 'submit' : Roo.form.Action.Submit
7490 * @class Roo.bootstrap.Form
7491 * @extends Roo.bootstrap.Component
7492 * Bootstrap Form class
7493 * @cfg {String} method GET | POST (default POST)
7494 * @cfg {String} labelAlign top | left (default top)
7495 * @cfg {String} align left | right - for navbars
7496 * @cfg {Boolean} loadMask load mask when submit (default true)
7501 * @param {Object} config The config object
7505 Roo.bootstrap.Form = function(config){
7506 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7508 Roo.bootstrap.Form.popover.apply();
7512 * @event clientvalidation
7513 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7514 * @param {Form} this
7515 * @param {Boolean} valid true if the form has passed client-side validation
7517 clientvalidation: true,
7519 * @event beforeaction
7520 * Fires before any action is performed. Return false to cancel the action.
7521 * @param {Form} this
7522 * @param {Action} action The action to be performed
7526 * @event actionfailed
7527 * Fires when an action fails.
7528 * @param {Form} this
7529 * @param {Action} action The action that failed
7531 actionfailed : true,
7533 * @event actioncomplete
7534 * Fires when an action is completed.
7535 * @param {Form} this
7536 * @param {Action} action The action that completed
7538 actioncomplete : true
7543 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7546 * @cfg {String} method
7547 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7552 * The URL to use for form actions if one isn't supplied in the action options.
7555 * @cfg {Boolean} fileUpload
7556 * Set to true if this form is a file upload.
7560 * @cfg {Object} baseParams
7561 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7565 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7569 * @cfg {Sting} align (left|right) for navbar forms
7574 activeAction : null,
7577 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7578 * element by passing it or its id or mask the form itself by passing in true.
7581 waitMsgTarget : false,
7586 * @cfg {Boolean} errorMask (true|false) default false
7590 getAutoCreate : function(){
7594 method : this.method || 'POST',
7595 id : this.id || Roo.id(),
7598 if (this.parent().xtype.match(/^Nav/)) {
7599 cfg.cls = 'navbar-form navbar-' + this.align;
7603 if (this.labelAlign == 'left' ) {
7604 cfg.cls += ' form-horizontal';
7610 initEvents : function()
7612 this.el.on('submit', this.onSubmit, this);
7613 // this was added as random key presses on the form where triggering form submit.
7614 this.el.on('keypress', function(e) {
7615 if (e.getCharCode() != 13) {
7618 // we might need to allow it for textareas.. and some other items.
7619 // check e.getTarget().
7621 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7625 Roo.log("keypress blocked");
7633 onSubmit : function(e){
7638 * Returns true if client-side validation on the form is successful.
7641 isValid : function(){
7642 var items = this.getItems();
7646 items.each(function(f){
7653 if(!target && f.el.isVisible(true)){
7659 if(this.errorMask && !valid){
7660 Roo.bootstrap.Form.popover.mask(this, target);
7667 * Returns true if any fields in this form have changed since their original load.
7670 isDirty : function(){
7672 var items = this.getItems();
7673 items.each(function(f){
7683 * Performs a predefined action (submit or load) or custom actions you define on this form.
7684 * @param {String} actionName The name of the action type
7685 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7686 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7687 * accept other config options):
7689 Property Type Description
7690 ---------------- --------------- ----------------------------------------------------------------------------------
7691 url String The url for the action (defaults to the form's url)
7692 method String The form method to use (defaults to the form's method, or POST if not defined)
7693 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7694 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7695 validate the form on the client (defaults to false)
7697 * @return {BasicForm} this
7699 doAction : function(action, options){
7700 if(typeof action == 'string'){
7701 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7703 if(this.fireEvent('beforeaction', this, action) !== false){
7704 this.beforeAction(action);
7705 action.run.defer(100, action);
7711 beforeAction : function(action){
7712 var o = action.options;
7715 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7717 // not really supported yet.. ??
7719 //if(this.waitMsgTarget === true){
7720 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7721 //}else if(this.waitMsgTarget){
7722 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7723 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7725 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7731 afterAction : function(action, success){
7732 this.activeAction = null;
7733 var o = action.options;
7735 //if(this.waitMsgTarget === true){
7737 //}else if(this.waitMsgTarget){
7738 // this.waitMsgTarget.unmask();
7740 // Roo.MessageBox.updateProgress(1);
7741 // Roo.MessageBox.hide();
7748 Roo.callback(o.success, o.scope, [this, action]);
7749 this.fireEvent('actioncomplete', this, action);
7753 // failure condition..
7754 // we have a scenario where updates need confirming.
7755 // eg. if a locking scenario exists..
7756 // we look for { errors : { needs_confirm : true }} in the response.
7758 (typeof(action.result) != 'undefined') &&
7759 (typeof(action.result.errors) != 'undefined') &&
7760 (typeof(action.result.errors.needs_confirm) != 'undefined')
7763 Roo.log("not supported yet");
7766 Roo.MessageBox.confirm(
7767 "Change requires confirmation",
7768 action.result.errorMsg,
7773 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7783 Roo.callback(o.failure, o.scope, [this, action]);
7784 // show an error message if no failed handler is set..
7785 if (!this.hasListener('actionfailed')) {
7786 Roo.log("need to add dialog support");
7788 Roo.MessageBox.alert("Error",
7789 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7790 action.result.errorMsg :
7791 "Saving Failed, please check your entries or try again"
7796 this.fireEvent('actionfailed', this, action);
7801 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7802 * @param {String} id The value to search for
7805 findField : function(id){
7806 var items = this.getItems();
7807 var field = items.get(id);
7809 items.each(function(f){
7810 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7817 return field || null;
7820 * Mark fields in this form invalid in bulk.
7821 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7822 * @return {BasicForm} this
7824 markInvalid : function(errors){
7825 if(errors instanceof Array){
7826 for(var i = 0, len = errors.length; i < len; i++){
7827 var fieldError = errors[i];
7828 var f = this.findField(fieldError.id);
7830 f.markInvalid(fieldError.msg);
7836 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7837 field.markInvalid(errors[id]);
7841 //Roo.each(this.childForms || [], function (f) {
7842 // f.markInvalid(errors);
7849 * Set values for fields in this form in bulk.
7850 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7851 * @return {BasicForm} this
7853 setValues : function(values){
7854 if(values instanceof Array){ // array of objects
7855 for(var i = 0, len = values.length; i < len; i++){
7857 var f = this.findField(v.id);
7859 f.setValue(v.value);
7860 if(this.trackResetOnLoad){
7861 f.originalValue = f.getValue();
7865 }else{ // object hash
7868 if(typeof values[id] != 'function' && (field = this.findField(id))){
7870 if (field.setFromData &&
7872 field.displayField &&
7873 // combos' with local stores can
7874 // be queried via setValue()
7875 // to set their value..
7876 (field.store && !field.store.isLocal)
7880 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7881 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7882 field.setFromData(sd);
7885 field.setValue(values[id]);
7889 if(this.trackResetOnLoad){
7890 field.originalValue = field.getValue();
7896 //Roo.each(this.childForms || [], function (f) {
7897 // f.setValues(values);
7904 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7905 * they are returned as an array.
7906 * @param {Boolean} asString
7909 getValues : function(asString){
7910 //if (this.childForms) {
7911 // copy values from the child forms
7912 // Roo.each(this.childForms, function (f) {
7913 // this.setValues(f.getValues());
7919 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7920 if(asString === true){
7923 return Roo.urlDecode(fs);
7927 * Returns the fields in this form as an object with key/value pairs.
7928 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7931 getFieldValues : function(with_hidden)
7933 var items = this.getItems();
7935 items.each(function(f){
7939 var v = f.getValue();
7940 if (f.inputType =='radio') {
7941 if (typeof(ret[f.getName()]) == 'undefined') {
7942 ret[f.getName()] = ''; // empty..
7945 if (!f.el.dom.checked) {
7953 // not sure if this supported any more..
7954 if ((typeof(v) == 'object') && f.getRawValue) {
7955 v = f.getRawValue() ; // dates..
7957 // combo boxes where name != hiddenName...
7958 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7959 ret[f.name] = f.getRawValue();
7961 ret[f.getName()] = v;
7968 * Clears all invalid messages in this form.
7969 * @return {BasicForm} this
7971 clearInvalid : function(){
7972 var items = this.getItems();
7974 items.each(function(f){
7985 * @return {BasicForm} this
7988 var items = this.getItems();
7989 items.each(function(f){
7993 Roo.each(this.childForms || [], function (f) {
8000 getItems : function()
8002 var r=new Roo.util.MixedCollection(false, function(o){
8003 return o.id || (o.id = Roo.id());
8005 var iter = function(el) {
8012 Roo.each(el.items,function(e) {
8029 Roo.apply(Roo.bootstrap.Form, {
8056 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8057 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8058 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8059 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8062 this.maskEl.top.enableDisplayMode("block");
8063 this.maskEl.left.enableDisplayMode("block");
8064 this.maskEl.bottom.enableDisplayMode("block");
8065 this.maskEl.right.enableDisplayMode("block");
8067 this.toolTip = new Roo.bootstrap.Tooltip({
8068 cls : 'roo-form-error-popover',
8070 'left' : ['r-l', [-2,0], 'right'],
8071 'right' : ['l-r', [2,0], 'left'],
8072 'bottom' : ['tl-bl', [0,2], 'top'],
8073 'top' : [ 'bl-tl', [0,-2], 'bottom']
8077 this.toolTip.render(Roo.get(document.body));
8079 this.toolTip.el.enableDisplayMode("block");
8081 Roo.get(document.body).on('click', function(){
8085 this.isApplied = true
8088 mask : function(form, target)
8092 this.target = target;
8094 if(!this.form.errorMask || !target.el){
8098 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8100 var ot = this.target.el.calcOffsetsTo(scrollable);
8102 var scrollTo = ot[1] - 100;
8104 var maxScroll = Roo.lib.Dom.getDocumentHeight() - Roo.lib.Dom.getViewportHeight();
8106 scrollTo = Math.min(scrollTo, maxScroll);
8108 scrollable.scrollTo('top', scrollTo);
8110 var box = this.target.el.getBox();
8112 var zIndex = Roo.bootstrap.Modal.zIndex++;
8114 this.maskEl.top.setStyle('position', 'fixed');
8115 this.maskEl.top.setStyle('z-index', zIndex);
8116 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8117 this.maskEl.top.setXY([0, 0]);
8118 this.maskEl.top.show();
8120 this.maskEl.left.setStyle('position', 'fixed');
8121 this.maskEl.left.setStyle('z-index', zIndex);
8122 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8123 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8124 this.maskEl.left.show();
8126 this.maskEl.bottom.setStyle('position', 'fixed');
8127 this.maskEl.bottom.setStyle('z-index', zIndex);
8128 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8129 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8130 this.maskEl.bottom.show();
8132 this.maskEl.right.setStyle('position', 'fixed');
8133 this.maskEl.right.setStyle('z-index', zIndex);
8134 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8135 this.maskEl.right.setXY([0, box.y - this.padding]);
8136 this.maskEl.right.show();
8139 this.toolTip.bindEl = this.target.el;
8141 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8143 var tip = this.target.blankText;
8145 if(this.target.getValue() !== '' && this.target.regexText.length){
8146 tip = this.target.regexText;
8149 this.toolTip.show(tip);
8151 this.intervalID = window.setInterval(function() {
8152 Roo.bootstrap.Form.popover.unmask();
8155 window.onwheel = function(){ return false;};
8157 (function(){ this.isMasked = true; }).defer(500, this);
8165 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8169 this.maskEl.top.setStyle('position', 'absolute');
8170 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8171 this.maskEl.top.hide();
8173 this.maskEl.left.setStyle('position', 'absolute');
8174 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8175 this.maskEl.left.hide();
8177 this.maskEl.bottom.setStyle('position', 'absolute');
8178 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8179 this.maskEl.bottom.hide();
8181 this.maskEl.right.setStyle('position', 'absolute');
8182 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8183 this.maskEl.right.hide();
8185 this.toolTip.hide();
8187 this.toolTip.el.hide();
8189 window.onwheel = function(){ return true;};
8191 if(this.intervalID){
8192 window.clearInterval(this.intervalID);
8193 this.intervalID = false;
8196 this.isMasked = false;
8206 * Ext JS Library 1.1.1
8207 * Copyright(c) 2006-2007, Ext JS, LLC.
8209 * Originally Released Under LGPL - original licence link has changed is not relivant.
8212 * <script type="text/javascript">
8215 * @class Roo.form.VTypes
8216 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8219 Roo.form.VTypes = function(){
8220 // closure these in so they are only created once.
8221 var alpha = /^[a-zA-Z_]+$/;
8222 var alphanum = /^[a-zA-Z0-9_]+$/;
8223 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8224 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8226 // All these messages and functions are configurable
8229 * The function used to validate email addresses
8230 * @param {String} value The email address
8232 'email' : function(v){
8233 return email.test(v);
8236 * The error text to display when the email validation function returns false
8239 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8241 * The keystroke filter mask to be applied on email input
8244 'emailMask' : /[a-z0-9_\.\-@]/i,
8247 * The function used to validate URLs
8248 * @param {String} value The URL
8250 'url' : function(v){
8254 * The error text to display when the url validation function returns false
8257 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8260 * The function used to validate alpha values
8261 * @param {String} value The value
8263 'alpha' : function(v){
8264 return alpha.test(v);
8267 * The error text to display when the alpha validation function returns false
8270 'alphaText' : 'This field should only contain letters and _',
8272 * The keystroke filter mask to be applied on alpha input
8275 'alphaMask' : /[a-z_]/i,
8278 * The function used to validate alphanumeric values
8279 * @param {String} value The value
8281 'alphanum' : function(v){
8282 return alphanum.test(v);
8285 * The error text to display when the alphanumeric validation function returns false
8288 'alphanumText' : 'This field should only contain letters, numbers and _',
8290 * The keystroke filter mask to be applied on alphanumeric input
8293 'alphanumMask' : /[a-z0-9_]/i
8303 * @class Roo.bootstrap.Input
8304 * @extends Roo.bootstrap.Component
8305 * Bootstrap Input class
8306 * @cfg {Boolean} disabled is it disabled
8307 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8308 * @cfg {String} name name of the input
8309 * @cfg {string} fieldLabel - the label associated
8310 * @cfg {string} placeholder - placeholder to put in text.
8311 * @cfg {string} before - input group add on before
8312 * @cfg {string} after - input group add on after
8313 * @cfg {string} size - (lg|sm) or leave empty..
8314 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8315 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8316 * @cfg {Number} md colspan out of 12 for computer-sized screens
8317 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8318 * @cfg {string} value default value of the input
8319 * @cfg {Number} labelWidth set the width of label
8320 * @cfg {Number} labellg set the width of label (1-12)
8321 * @cfg {Number} labelmd set the width of label (1-12)
8322 * @cfg {Number} labelsm set the width of label (1-12)
8323 * @cfg {Number} labelxs set the width of label (1-12)
8324 * @cfg {String} labelAlign (top|left)
8325 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8326 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8327 * @cfg {String} indicatorpos (left|right) default left
8329 * @cfg {String} align (left|center|right) Default left
8330 * @cfg {Boolean} forceFeedback (true|false) Default false
8336 * Create a new Input
8337 * @param {Object} config The config object
8340 Roo.bootstrap.Input = function(config){
8342 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8347 * Fires when this field receives input focus.
8348 * @param {Roo.form.Field} this
8353 * Fires when this field loses input focus.
8354 * @param {Roo.form.Field} this
8359 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8360 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8361 * @param {Roo.form.Field} this
8362 * @param {Roo.EventObject} e The event object
8367 * Fires just before the field blurs if the field value has changed.
8368 * @param {Roo.form.Field} this
8369 * @param {Mixed} newValue The new value
8370 * @param {Mixed} oldValue The original value
8375 * Fires after the field has been marked as invalid.
8376 * @param {Roo.form.Field} this
8377 * @param {String} msg The validation message
8382 * Fires after the field has been validated with no errors.
8383 * @param {Roo.form.Field} this
8388 * Fires after the key up
8389 * @param {Roo.form.Field} this
8390 * @param {Roo.EventObject} e The event Object
8396 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8398 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8399 automatic validation (defaults to "keyup").
8401 validationEvent : "keyup",
8403 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8405 validateOnBlur : true,
8407 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8409 validationDelay : 250,
8411 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8413 focusClass : "x-form-focus", // not needed???
8417 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8419 invalidClass : "has-warning",
8422 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8424 validClass : "has-success",
8427 * @cfg {Boolean} hasFeedback (true|false) default true
8432 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8434 invalidFeedbackClass : "glyphicon-warning-sign",
8437 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8439 validFeedbackClass : "glyphicon-ok",
8442 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8444 selectOnFocus : false,
8447 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8451 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8456 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8458 disableKeyFilter : false,
8461 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8465 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8469 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8471 blankText : "Please complete this mandatory field",
8474 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8478 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8480 maxLength : Number.MAX_VALUE,
8482 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8484 minLengthText : "The minimum length for this field is {0}",
8486 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8488 maxLengthText : "The maximum length for this field is {0}",
8492 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8493 * If available, this function will be called only after the basic validators all return true, and will be passed the
8494 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8498 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8499 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8500 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8504 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8508 autocomplete: false,
8527 formatedValue : false,
8528 forceFeedback : false,
8530 indicatorpos : 'left',
8537 parentLabelAlign : function()
8540 while (parent.parent()) {
8541 parent = parent.parent();
8542 if (typeof(parent.labelAlign) !='undefined') {
8543 return parent.labelAlign;
8550 getAutoCreate : function()
8552 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8558 if(this.inputType != 'hidden'){
8559 cfg.cls = 'form-group' //input-group
8565 type : this.inputType,
8567 cls : 'form-control',
8568 placeholder : this.placeholder || '',
8569 autocomplete : this.autocomplete || 'new-password'
8573 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8576 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8577 input.maxLength = this.maxLength;
8580 if (this.disabled) {
8581 input.disabled=true;
8584 if (this.readOnly) {
8585 input.readonly=true;
8589 input.name = this.name;
8593 input.cls += ' input-' + this.size;
8597 ['xs','sm','md','lg'].map(function(size){
8598 if (settings[size]) {
8599 cfg.cls += ' col-' + size + '-' + settings[size];
8603 var inputblock = input;
8607 cls: 'glyphicon form-control-feedback'
8610 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8613 cls : 'has-feedback',
8621 if (this.before || this.after) {
8624 cls : 'input-group',
8628 if (this.before && typeof(this.before) == 'string') {
8630 inputblock.cn.push({
8632 cls : 'roo-input-before input-group-addon',
8636 if (this.before && typeof(this.before) == 'object') {
8637 this.before = Roo.factory(this.before);
8639 inputblock.cn.push({
8641 cls : 'roo-input-before input-group-' +
8642 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8646 inputblock.cn.push(input);
8648 if (this.after && typeof(this.after) == 'string') {
8649 inputblock.cn.push({
8651 cls : 'roo-input-after input-group-addon',
8655 if (this.after && typeof(this.after) == 'object') {
8656 this.after = Roo.factory(this.after);
8658 inputblock.cn.push({
8660 cls : 'roo-input-after input-group-' +
8661 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8665 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8666 inputblock.cls += ' has-feedback';
8667 inputblock.cn.push(feedback);
8671 if (align ==='left' && this.fieldLabel.length) {
8673 cfg.cls += ' roo-form-group-label-left';
8678 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8679 tooltip : 'This field is required'
8684 cls : 'control-label',
8685 html : this.fieldLabel
8696 var labelCfg = cfg.cn[1];
8697 var contentCfg = cfg.cn[2];
8699 if(this.indicatorpos == 'right'){
8704 cls : 'control-label',
8705 html : this.fieldLabel
8710 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8711 tooltip : 'This field is required'
8722 labelCfg = cfg.cn[0];
8723 contentCfg = cfg.cn[2];
8727 if(this.labelWidth > 12){
8728 labelCfg.style = "width: " + this.labelWidth + 'px';
8731 if(this.labelWidth < 13 && this.labelmd == 0){
8732 this.labelmd = this.labelWidth;
8735 if(this.labellg > 0){
8736 labelCfg.cls += ' col-lg-' + this.labellg;
8737 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8740 if(this.labelmd > 0){
8741 labelCfg.cls += ' col-md-' + this.labelmd;
8742 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8745 if(this.labelsm > 0){
8746 labelCfg.cls += ' col-sm-' + this.labelsm;
8747 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8750 if(this.labelxs > 0){
8751 labelCfg.cls += ' col-xs-' + this.labelxs;
8752 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8756 } else if ( this.fieldLabel.length) {
8761 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8762 tooltip : 'This field is required'
8766 //cls : 'input-group-addon',
8767 html : this.fieldLabel
8775 if(this.indicatorpos == 'right'){
8780 //cls : 'input-group-addon',
8781 html : this.fieldLabel
8786 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8787 tooltip : 'This field is required'
8807 if (this.parentType === 'Navbar' && this.parent().bar) {
8808 cfg.cls += ' navbar-form';
8811 if (this.parentType === 'NavGroup') {
8812 cfg.cls += ' navbar-form';
8820 * return the real input element.
8822 inputEl: function ()
8824 return this.el.select('input.form-control',true).first();
8827 tooltipEl : function()
8829 return this.inputEl();
8832 indicatorEl : function()
8834 var indicator = this.el.select('i.roo-required-indicator',true).first();
8844 setDisabled : function(v)
8846 var i = this.inputEl().dom;
8848 i.removeAttribute('disabled');
8852 i.setAttribute('disabled','true');
8854 initEvents : function()
8857 this.inputEl().on("keydown" , this.fireKey, this);
8858 this.inputEl().on("focus", this.onFocus, this);
8859 this.inputEl().on("blur", this.onBlur, this);
8861 this.inputEl().relayEvent('keyup', this);
8863 this.indicator = this.indicatorEl();
8866 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8867 this.indicator.hide();
8870 // reference to original value for reset
8871 this.originalValue = this.getValue();
8872 //Roo.form.TextField.superclass.initEvents.call(this);
8873 if(this.validationEvent == 'keyup'){
8874 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8875 this.inputEl().on('keyup', this.filterValidation, this);
8877 else if(this.validationEvent !== false){
8878 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8881 if(this.selectOnFocus){
8882 this.on("focus", this.preFocus, this);
8885 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8886 this.inputEl().on("keypress", this.filterKeys, this);
8888 this.inputEl().relayEvent('keypress', this);
8891 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8892 this.el.on("click", this.autoSize, this);
8895 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8896 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8899 if (typeof(this.before) == 'object') {
8900 this.before.render(this.el.select('.roo-input-before',true).first());
8902 if (typeof(this.after) == 'object') {
8903 this.after.render(this.el.select('.roo-input-after',true).first());
8908 filterValidation : function(e){
8909 if(!e.isNavKeyPress()){
8910 this.validationTask.delay(this.validationDelay);
8914 * Validates the field value
8915 * @return {Boolean} True if the value is valid, else false
8917 validate : function(){
8918 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8919 if(this.disabled || this.validateValue(this.getRawValue())){
8930 * Validates a value according to the field's validation rules and marks the field as invalid
8931 * if the validation fails
8932 * @param {Mixed} value The value to validate
8933 * @return {Boolean} True if the value is valid, else false
8935 validateValue : function(value){
8936 if(value.length < 1) { // if it's blank
8937 if(this.allowBlank){
8943 if(value.length < this.minLength){
8946 if(value.length > this.maxLength){
8950 var vt = Roo.form.VTypes;
8951 if(!vt[this.vtype](value, this)){
8955 if(typeof this.validator == "function"){
8956 var msg = this.validator(value);
8962 if(this.regex && !this.regex.test(value)){
8972 fireKey : function(e){
8973 //Roo.log('field ' + e.getKey());
8974 if(e.isNavKeyPress()){
8975 this.fireEvent("specialkey", this, e);
8978 focus : function (selectText){
8980 this.inputEl().focus();
8981 if(selectText === true){
8982 this.inputEl().dom.select();
8988 onFocus : function(){
8989 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8990 // this.el.addClass(this.focusClass);
8993 this.hasFocus = true;
8994 this.startValue = this.getValue();
8995 this.fireEvent("focus", this);
8999 beforeBlur : Roo.emptyFn,
9003 onBlur : function(){
9005 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9006 //this.el.removeClass(this.focusClass);
9008 this.hasFocus = false;
9009 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9012 var v = this.getValue();
9013 if(String(v) !== String(this.startValue)){
9014 this.fireEvent('change', this, v, this.startValue);
9016 this.fireEvent("blur", this);
9020 * Resets the current field value to the originally loaded value and clears any validation messages
9023 this.setValue(this.originalValue);
9027 * Returns the name of the field
9028 * @return {Mixed} name The name field
9030 getName: function(){
9034 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9035 * @return {Mixed} value The field value
9037 getValue : function(){
9039 var v = this.inputEl().getValue();
9044 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9045 * @return {Mixed} value The field value
9047 getRawValue : function(){
9048 var v = this.inputEl().getValue();
9054 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9055 * @param {Mixed} value The value to set
9057 setRawValue : function(v){
9058 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9061 selectText : function(start, end){
9062 var v = this.getRawValue();
9064 start = start === undefined ? 0 : start;
9065 end = end === undefined ? v.length : end;
9066 var d = this.inputEl().dom;
9067 if(d.setSelectionRange){
9068 d.setSelectionRange(start, end);
9069 }else if(d.createTextRange){
9070 var range = d.createTextRange();
9071 range.moveStart("character", start);
9072 range.moveEnd("character", v.length-end);
9079 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9080 * @param {Mixed} value The value to set
9082 setValue : function(v){
9085 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9091 processValue : function(value){
9092 if(this.stripCharsRe){
9093 var newValue = value.replace(this.stripCharsRe, '');
9094 if(newValue !== value){
9095 this.setRawValue(newValue);
9102 preFocus : function(){
9104 if(this.selectOnFocus){
9105 this.inputEl().dom.select();
9108 filterKeys : function(e){
9110 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9113 var c = e.getCharCode(), cc = String.fromCharCode(c);
9114 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9117 if(!this.maskRe.test(cc)){
9122 * Clear any invalid styles/messages for this field
9124 clearInvalid : function(){
9126 if(!this.el || this.preventMark){ // not rendered
9131 this.el.removeClass(this.invalidClass);
9133 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9135 var feedback = this.el.select('.form-control-feedback', true).first();
9138 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9143 this.fireEvent('valid', this);
9147 * Mark this field as valid
9149 markValid : function()
9151 if(!this.el || this.preventMark){ // not rendered...
9155 this.el.removeClass([this.invalidClass, this.validClass]);
9157 var feedback = this.el.select('.form-control-feedback', true).first();
9160 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9167 if(this.allowBlank && !this.getRawValue().length){
9172 this.indicator.hide();
9175 this.el.addClass(this.validClass);
9177 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9179 var feedback = this.el.select('.form-control-feedback', true).first();
9182 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9183 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9188 this.fireEvent('valid', this);
9192 * Mark this field as invalid
9193 * @param {String} msg The validation message
9195 markInvalid : function(msg)
9197 if(!this.el || this.preventMark){ // not rendered
9201 this.el.removeClass([this.invalidClass, this.validClass]);
9203 var feedback = this.el.select('.form-control-feedback', true).first();
9206 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9213 if(this.allowBlank && !this.getRawValue().length){
9218 this.indicator.show();
9221 this.el.addClass(this.invalidClass);
9223 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9225 var feedback = this.el.select('.form-control-feedback', true).first();
9228 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9230 if(this.getValue().length || this.forceFeedback){
9231 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9238 this.fireEvent('invalid', this, msg);
9241 SafariOnKeyDown : function(event)
9243 // this is a workaround for a password hang bug on chrome/ webkit.
9244 if (this.inputEl().dom.type != 'password') {
9248 var isSelectAll = false;
9250 if(this.inputEl().dom.selectionEnd > 0){
9251 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9253 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9254 event.preventDefault();
9259 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9261 event.preventDefault();
9262 // this is very hacky as keydown always get's upper case.
9264 var cc = String.fromCharCode(event.getCharCode());
9265 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9269 adjustWidth : function(tag, w){
9270 tag = tag.toLowerCase();
9271 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9272 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9276 if(tag == 'textarea'){
9279 }else if(Roo.isOpera){
9283 if(tag == 'textarea'){
9302 * @class Roo.bootstrap.TextArea
9303 * @extends Roo.bootstrap.Input
9304 * Bootstrap TextArea class
9305 * @cfg {Number} cols Specifies the visible width of a text area
9306 * @cfg {Number} rows Specifies the visible number of lines in a text area
9307 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9308 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9309 * @cfg {string} html text
9312 * Create a new TextArea
9313 * @param {Object} config The config object
9316 Roo.bootstrap.TextArea = function(config){
9317 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9321 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9331 getAutoCreate : function(){
9333 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9344 value : this.value || '',
9345 html: this.html || '',
9346 cls : 'form-control',
9347 placeholder : this.placeholder || ''
9351 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9352 input.maxLength = this.maxLength;
9356 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9360 input.cols = this.cols;
9363 if (this.readOnly) {
9364 input.readonly = true;
9368 input.name = this.name;
9372 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9376 ['xs','sm','md','lg'].map(function(size){
9377 if (settings[size]) {
9378 cfg.cls += ' col-' + size + '-' + settings[size];
9382 var inputblock = input;
9384 if(this.hasFeedback && !this.allowBlank){
9388 cls: 'glyphicon form-control-feedback'
9392 cls : 'has-feedback',
9401 if (this.before || this.after) {
9404 cls : 'input-group',
9408 inputblock.cn.push({
9410 cls : 'input-group-addon',
9415 inputblock.cn.push(input);
9417 if(this.hasFeedback && !this.allowBlank){
9418 inputblock.cls += ' has-feedback';
9419 inputblock.cn.push(feedback);
9423 inputblock.cn.push({
9425 cls : 'input-group-addon',
9432 if (align ==='left' && this.fieldLabel.length) {
9437 cls : 'control-label',
9438 html : this.fieldLabel
9449 if(this.labelWidth > 12){
9450 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9453 if(this.labelWidth < 13 && this.labelmd == 0){
9454 this.labelmd = this.labelWidth;
9457 if(this.labellg > 0){
9458 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9459 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9462 if(this.labelmd > 0){
9463 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9464 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9467 if(this.labelsm > 0){
9468 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9469 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9472 if(this.labelxs > 0){
9473 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9474 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9477 } else if ( this.fieldLabel.length) {
9482 //cls : 'input-group-addon',
9483 html : this.fieldLabel
9501 if (this.disabled) {
9502 input.disabled=true;
9509 * return the real textarea element.
9511 inputEl: function ()
9513 return this.el.select('textarea.form-control',true).first();
9517 * Clear any invalid styles/messages for this field
9519 clearInvalid : function()
9522 if(!this.el || this.preventMark){ // not rendered
9526 var label = this.el.select('label', true).first();
9527 var icon = this.el.select('i.fa-star', true).first();
9533 this.el.removeClass(this.invalidClass);
9535 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9537 var feedback = this.el.select('.form-control-feedback', true).first();
9540 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9545 this.fireEvent('valid', this);
9549 * Mark this field as valid
9551 markValid : function()
9553 if(!this.el || this.preventMark){ // not rendered
9557 this.el.removeClass([this.invalidClass, this.validClass]);
9559 var feedback = this.el.select('.form-control-feedback', true).first();
9562 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9565 if(this.disabled || this.allowBlank){
9569 var label = this.el.select('label', true).first();
9570 var icon = this.el.select('i.fa-star', true).first();
9576 this.el.addClass(this.validClass);
9578 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9580 var feedback = this.el.select('.form-control-feedback', true).first();
9583 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9584 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9589 this.fireEvent('valid', this);
9593 * Mark this field as invalid
9594 * @param {String} msg The validation message
9596 markInvalid : function(msg)
9598 if(!this.el || this.preventMark){ // not rendered
9602 this.el.removeClass([this.invalidClass, this.validClass]);
9604 var feedback = this.el.select('.form-control-feedback', true).first();
9607 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9610 if(this.disabled || this.allowBlank){
9614 var label = this.el.select('label', true).first();
9615 var icon = this.el.select('i.fa-star', true).first();
9617 if(!this.getValue().length && label && !icon){
9618 this.el.createChild({
9620 cls : 'text-danger fa fa-lg fa-star',
9621 tooltip : 'This field is required',
9622 style : 'margin-right:5px;'
9626 this.el.addClass(this.invalidClass);
9628 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9630 var feedback = this.el.select('.form-control-feedback', true).first();
9633 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9635 if(this.getValue().length || this.forceFeedback){
9636 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9643 this.fireEvent('invalid', this, msg);
9651 * trigger field - base class for combo..
9656 * @class Roo.bootstrap.TriggerField
9657 * @extends Roo.bootstrap.Input
9658 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9659 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9660 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9661 * for which you can provide a custom implementation. For example:
9663 var trigger = new Roo.bootstrap.TriggerField();
9664 trigger.onTriggerClick = myTriggerFn;
9665 trigger.applyTo('my-field');
9668 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9669 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9670 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9671 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9672 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9675 * Create a new TriggerField.
9676 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9677 * to the base TextField)
9679 Roo.bootstrap.TriggerField = function(config){
9680 this.mimicing = false;
9681 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9684 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9686 * @cfg {String} triggerClass A CSS class to apply to the trigger
9689 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9694 * @cfg {Boolean} removable (true|false) special filter default false
9698 /** @cfg {Boolean} grow @hide */
9699 /** @cfg {Number} growMin @hide */
9700 /** @cfg {Number} growMax @hide */
9706 autoSize: Roo.emptyFn,
9713 actionMode : 'wrap',
9718 getAutoCreate : function(){
9720 var align = this.labelAlign || this.parentLabelAlign();
9725 cls: 'form-group' //input-group
9732 type : this.inputType,
9733 cls : 'form-control',
9734 autocomplete: 'new-password',
9735 placeholder : this.placeholder || ''
9739 input.name = this.name;
9742 input.cls += ' input-' + this.size;
9745 if (this.disabled) {
9746 input.disabled=true;
9749 var inputblock = input;
9751 if(this.hasFeedback && !this.allowBlank){
9755 cls: 'glyphicon form-control-feedback'
9758 if(this.removable && !this.editable && !this.tickable){
9760 cls : 'has-feedback',
9766 cls : 'roo-combo-removable-btn close'
9773 cls : 'has-feedback',
9782 if(this.removable && !this.editable && !this.tickable){
9784 cls : 'roo-removable',
9790 cls : 'roo-combo-removable-btn close'
9797 if (this.before || this.after) {
9800 cls : 'input-group',
9804 inputblock.cn.push({
9806 cls : 'input-group-addon',
9811 inputblock.cn.push(input);
9813 if(this.hasFeedback && !this.allowBlank){
9814 inputblock.cls += ' has-feedback';
9815 inputblock.cn.push(feedback);
9819 inputblock.cn.push({
9821 cls : 'input-group-addon',
9834 cls: 'form-hidden-field'
9848 cls: 'form-hidden-field'
9852 cls: 'roo-select2-choices',
9856 cls: 'roo-select2-search-field',
9869 cls: 'roo-select2-container input-group',
9874 // cls: 'typeahead typeahead-long dropdown-menu',
9875 // style: 'display:none'
9880 if(!this.multiple && this.showToggleBtn){
9886 if (this.caret != false) {
9889 cls: 'fa fa-' + this.caret
9896 cls : 'input-group-addon btn dropdown-toggle',
9901 cls: 'combobox-clear',
9915 combobox.cls += ' roo-select2-container-multi';
9918 if (align ==='left' && this.fieldLabel.length) {
9920 cfg.cls += ' roo-form-group-label-left';
9925 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9926 tooltip : 'This field is required'
9931 cls : 'control-label',
9932 html : this.fieldLabel
9944 var labelCfg = cfg.cn[1];
9945 var contentCfg = cfg.cn[2];
9947 if(this.indicatorpos == 'right'){
9952 cls : 'control-label',
9956 html : this.fieldLabel
9960 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9961 tooltip : 'This field is required'
9974 labelCfg = cfg.cn[0];
9975 contentCfg = cfg.cn[1];
9978 if(this.labelWidth > 12){
9979 labelCfg.style = "width: " + this.labelWidth + 'px';
9982 if(this.labelWidth < 13 && this.labelmd == 0){
9983 this.labelmd = this.labelWidth;
9986 if(this.labellg > 0){
9987 labelCfg.cls += ' col-lg-' + this.labellg;
9988 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9991 if(this.labelmd > 0){
9992 labelCfg.cls += ' col-md-' + this.labelmd;
9993 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9996 if(this.labelsm > 0){
9997 labelCfg.cls += ' col-sm-' + this.labelsm;
9998 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10001 if(this.labelxs > 0){
10002 labelCfg.cls += ' col-xs-' + this.labelxs;
10003 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10006 } else if ( this.fieldLabel.length) {
10007 // Roo.log(" label");
10011 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10012 tooltip : 'This field is required'
10016 //cls : 'input-group-addon',
10017 html : this.fieldLabel
10025 if(this.indicatorpos == 'right'){
10033 html : this.fieldLabel
10037 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10038 tooltip : 'This field is required'
10051 // Roo.log(" no label && no align");
10058 ['xs','sm','md','lg'].map(function(size){
10059 if (settings[size]) {
10060 cfg.cls += ' col-' + size + '-' + settings[size];
10071 onResize : function(w, h){
10072 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10073 // if(typeof w == 'number'){
10074 // var x = w - this.trigger.getWidth();
10075 // this.inputEl().setWidth(this.adjustWidth('input', x));
10076 // this.trigger.setStyle('left', x+'px');
10081 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10084 getResizeEl : function(){
10085 return this.inputEl();
10089 getPositionEl : function(){
10090 return this.inputEl();
10094 alignErrorIcon : function(){
10095 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10099 initEvents : function(){
10103 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10104 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10105 if(!this.multiple && this.showToggleBtn){
10106 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10107 if(this.hideTrigger){
10108 this.trigger.setDisplayed(false);
10110 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10114 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10117 if(this.removable && !this.editable && !this.tickable){
10118 var close = this.closeTriggerEl();
10121 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10122 close.on('click', this.removeBtnClick, this, close);
10126 //this.trigger.addClassOnOver('x-form-trigger-over');
10127 //this.trigger.addClassOnClick('x-form-trigger-click');
10130 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10134 closeTriggerEl : function()
10136 var close = this.el.select('.roo-combo-removable-btn', true).first();
10137 return close ? close : false;
10140 removeBtnClick : function(e, h, el)
10142 e.preventDefault();
10144 if(this.fireEvent("remove", this) !== false){
10146 this.fireEvent("afterremove", this)
10150 createList : function()
10152 this.list = Roo.get(document.body).createChild({
10154 cls: 'typeahead typeahead-long dropdown-menu',
10155 style: 'display:none'
10158 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10163 initTrigger : function(){
10168 onDestroy : function(){
10170 this.trigger.removeAllListeners();
10171 // this.trigger.remove();
10174 // this.wrap.remove();
10176 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10180 onFocus : function(){
10181 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10183 if(!this.mimicing){
10184 this.wrap.addClass('x-trigger-wrap-focus');
10185 this.mimicing = true;
10186 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10187 if(this.monitorTab){
10188 this.el.on("keydown", this.checkTab, this);
10195 checkTab : function(e){
10196 if(e.getKey() == e.TAB){
10197 this.triggerBlur();
10202 onBlur : function(){
10207 mimicBlur : function(e, t){
10209 if(!this.wrap.contains(t) && this.validateBlur()){
10210 this.triggerBlur();
10216 triggerBlur : function(){
10217 this.mimicing = false;
10218 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10219 if(this.monitorTab){
10220 this.el.un("keydown", this.checkTab, this);
10222 //this.wrap.removeClass('x-trigger-wrap-focus');
10223 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10227 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10228 validateBlur : function(e, t){
10233 onDisable : function(){
10234 this.inputEl().dom.disabled = true;
10235 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10237 // this.wrap.addClass('x-item-disabled');
10242 onEnable : function(){
10243 this.inputEl().dom.disabled = false;
10244 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10246 // this.el.removeClass('x-item-disabled');
10251 onShow : function(){
10252 var ae = this.getActionEl();
10255 ae.dom.style.display = '';
10256 ae.dom.style.visibility = 'visible';
10262 onHide : function(){
10263 var ae = this.getActionEl();
10264 ae.dom.style.display = 'none';
10268 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10269 * by an implementing function.
10271 * @param {EventObject} e
10273 onTriggerClick : Roo.emptyFn
10277 * Ext JS Library 1.1.1
10278 * Copyright(c) 2006-2007, Ext JS, LLC.
10280 * Originally Released Under LGPL - original licence link has changed is not relivant.
10283 * <script type="text/javascript">
10288 * @class Roo.data.SortTypes
10290 * Defines the default sorting (casting?) comparison functions used when sorting data.
10292 Roo.data.SortTypes = {
10294 * Default sort that does nothing
10295 * @param {Mixed} s The value being converted
10296 * @return {Mixed} The comparison value
10298 none : function(s){
10303 * The regular expression used to strip tags
10307 stripTagsRE : /<\/?[^>]+>/gi,
10310 * Strips all HTML tags to sort on text only
10311 * @param {Mixed} s The value being converted
10312 * @return {String} The comparison value
10314 asText : function(s){
10315 return String(s).replace(this.stripTagsRE, "");
10319 * Strips all HTML tags to sort on text only - Case insensitive
10320 * @param {Mixed} s The value being converted
10321 * @return {String} The comparison value
10323 asUCText : function(s){
10324 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10328 * Case insensitive string
10329 * @param {Mixed} s The value being converted
10330 * @return {String} The comparison value
10332 asUCString : function(s) {
10333 return String(s).toUpperCase();
10338 * @param {Mixed} s The value being converted
10339 * @return {Number} The comparison value
10341 asDate : function(s) {
10345 if(s instanceof Date){
10346 return s.getTime();
10348 return Date.parse(String(s));
10353 * @param {Mixed} s The value being converted
10354 * @return {Float} The comparison value
10356 asFloat : function(s) {
10357 var val = parseFloat(String(s).replace(/,/g, ""));
10366 * @param {Mixed} s The value being converted
10367 * @return {Number} The comparison value
10369 asInt : function(s) {
10370 var val = parseInt(String(s).replace(/,/g, ""));
10378 * Ext JS Library 1.1.1
10379 * Copyright(c) 2006-2007, Ext JS, LLC.
10381 * Originally Released Under LGPL - original licence link has changed is not relivant.
10384 * <script type="text/javascript">
10388 * @class Roo.data.Record
10389 * Instances of this class encapsulate both record <em>definition</em> information, and record
10390 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10391 * to access Records cached in an {@link Roo.data.Store} object.<br>
10393 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10394 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10397 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10399 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10400 * {@link #create}. The parameters are the same.
10401 * @param {Array} data An associative Array of data values keyed by the field name.
10402 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10403 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10404 * not specified an integer id is generated.
10406 Roo.data.Record = function(data, id){
10407 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10412 * Generate a constructor for a specific record layout.
10413 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10414 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10415 * Each field definition object may contain the following properties: <ul>
10416 * <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,
10417 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10418 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10419 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10420 * is being used, then this is a string containing the javascript expression to reference the data relative to
10421 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10422 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10423 * this may be omitted.</p></li>
10424 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10425 * <ul><li>auto (Default, implies no conversion)</li>
10430 * <li>date</li></ul></p></li>
10431 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10432 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10433 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10434 * by the Reader into an object that will be stored in the Record. It is passed the
10435 * following parameters:<ul>
10436 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10438 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10440 * <br>usage:<br><pre><code>
10441 var TopicRecord = Roo.data.Record.create(
10442 {name: 'title', mapping: 'topic_title'},
10443 {name: 'author', mapping: 'username'},
10444 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10445 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10446 {name: 'lastPoster', mapping: 'user2'},
10447 {name: 'excerpt', mapping: 'post_text'}
10450 var myNewRecord = new TopicRecord({
10451 title: 'Do my job please',
10454 lastPost: new Date(),
10455 lastPoster: 'Animal',
10456 excerpt: 'No way dude!'
10458 myStore.add(myNewRecord);
10463 Roo.data.Record.create = function(o){
10464 var f = function(){
10465 f.superclass.constructor.apply(this, arguments);
10467 Roo.extend(f, Roo.data.Record);
10468 var p = f.prototype;
10469 p.fields = new Roo.util.MixedCollection(false, function(field){
10472 for(var i = 0, len = o.length; i < len; i++){
10473 p.fields.add(new Roo.data.Field(o[i]));
10475 f.getField = function(name){
10476 return p.fields.get(name);
10481 Roo.data.Record.AUTO_ID = 1000;
10482 Roo.data.Record.EDIT = 'edit';
10483 Roo.data.Record.REJECT = 'reject';
10484 Roo.data.Record.COMMIT = 'commit';
10486 Roo.data.Record.prototype = {
10488 * Readonly flag - true if this record has been modified.
10497 join : function(store){
10498 this.store = store;
10502 * Set the named field to the specified value.
10503 * @param {String} name The name of the field to set.
10504 * @param {Object} value The value to set the field to.
10506 set : function(name, value){
10507 if(this.data[name] == value){
10511 if(!this.modified){
10512 this.modified = {};
10514 if(typeof this.modified[name] == 'undefined'){
10515 this.modified[name] = this.data[name];
10517 this.data[name] = value;
10518 if(!this.editing && this.store){
10519 this.store.afterEdit(this);
10524 * Get the value of the named field.
10525 * @param {String} name The name of the field to get the value of.
10526 * @return {Object} The value of the field.
10528 get : function(name){
10529 return this.data[name];
10533 beginEdit : function(){
10534 this.editing = true;
10535 this.modified = {};
10539 cancelEdit : function(){
10540 this.editing = false;
10541 delete this.modified;
10545 endEdit : function(){
10546 this.editing = false;
10547 if(this.dirty && this.store){
10548 this.store.afterEdit(this);
10553 * Usually called by the {@link Roo.data.Store} which owns the Record.
10554 * Rejects all changes made to the Record since either creation, or the last commit operation.
10555 * Modified fields are reverted to their original values.
10557 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10558 * of reject operations.
10560 reject : function(){
10561 var m = this.modified;
10563 if(typeof m[n] != "function"){
10564 this.data[n] = m[n];
10567 this.dirty = false;
10568 delete this.modified;
10569 this.editing = false;
10571 this.store.afterReject(this);
10576 * Usually called by the {@link Roo.data.Store} which owns the Record.
10577 * Commits all changes made to the Record since either creation, or the last commit operation.
10579 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10580 * of commit operations.
10582 commit : function(){
10583 this.dirty = false;
10584 delete this.modified;
10585 this.editing = false;
10587 this.store.afterCommit(this);
10592 hasError : function(){
10593 return this.error != null;
10597 clearError : function(){
10602 * Creates a copy of this record.
10603 * @param {String} id (optional) A new record id if you don't want to use this record's id
10606 copy : function(newId) {
10607 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10611 * Ext JS Library 1.1.1
10612 * Copyright(c) 2006-2007, Ext JS, LLC.
10614 * Originally Released Under LGPL - original licence link has changed is not relivant.
10617 * <script type="text/javascript">
10623 * @class Roo.data.Store
10624 * @extends Roo.util.Observable
10625 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10626 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10628 * 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
10629 * has no knowledge of the format of the data returned by the Proxy.<br>
10631 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10632 * instances from the data object. These records are cached and made available through accessor functions.
10634 * Creates a new Store.
10635 * @param {Object} config A config object containing the objects needed for the Store to access data,
10636 * and read the data into Records.
10638 Roo.data.Store = function(config){
10639 this.data = new Roo.util.MixedCollection(false);
10640 this.data.getKey = function(o){
10643 this.baseParams = {};
10645 this.paramNames = {
10650 "multisort" : "_multisort"
10653 if(config && config.data){
10654 this.inlineData = config.data;
10655 delete config.data;
10658 Roo.apply(this, config);
10660 if(this.reader){ // reader passed
10661 this.reader = Roo.factory(this.reader, Roo.data);
10662 this.reader.xmodule = this.xmodule || false;
10663 if(!this.recordType){
10664 this.recordType = this.reader.recordType;
10666 if(this.reader.onMetaChange){
10667 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10671 if(this.recordType){
10672 this.fields = this.recordType.prototype.fields;
10674 this.modified = [];
10678 * @event datachanged
10679 * Fires when the data cache has changed, and a widget which is using this Store
10680 * as a Record cache should refresh its view.
10681 * @param {Store} this
10683 datachanged : true,
10685 * @event metachange
10686 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10687 * @param {Store} this
10688 * @param {Object} meta The JSON metadata
10693 * Fires when Records have been added to the Store
10694 * @param {Store} this
10695 * @param {Roo.data.Record[]} records The array of Records added
10696 * @param {Number} index The index at which the record(s) were added
10701 * Fires when a Record has been removed from the Store
10702 * @param {Store} this
10703 * @param {Roo.data.Record} record The Record that was removed
10704 * @param {Number} index The index at which the record was removed
10709 * Fires when a Record has been updated
10710 * @param {Store} this
10711 * @param {Roo.data.Record} record The Record that was updated
10712 * @param {String} operation The update operation being performed. Value may be one of:
10714 Roo.data.Record.EDIT
10715 Roo.data.Record.REJECT
10716 Roo.data.Record.COMMIT
10722 * Fires when the data cache has been cleared.
10723 * @param {Store} this
10727 * @event beforeload
10728 * Fires before a request is made for a new data object. If the beforeload handler returns false
10729 * the load action will be canceled.
10730 * @param {Store} this
10731 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10735 * @event beforeloadadd
10736 * Fires after a new set of Records has been loaded.
10737 * @param {Store} this
10738 * @param {Roo.data.Record[]} records The Records that were loaded
10739 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10741 beforeloadadd : true,
10744 * Fires after a new set of Records has been loaded, before they are added to the store.
10745 * @param {Store} this
10746 * @param {Roo.data.Record[]} records The Records that were loaded
10747 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10748 * @params {Object} return from reader
10752 * @event loadexception
10753 * Fires if an exception occurs in the Proxy during loading.
10754 * Called with the signature of the Proxy's "loadexception" event.
10755 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10758 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10759 * @param {Object} load options
10760 * @param {Object} jsonData from your request (normally this contains the Exception)
10762 loadexception : true
10766 this.proxy = Roo.factory(this.proxy, Roo.data);
10767 this.proxy.xmodule = this.xmodule || false;
10768 this.relayEvents(this.proxy, ["loadexception"]);
10770 this.sortToggle = {};
10771 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10773 Roo.data.Store.superclass.constructor.call(this);
10775 if(this.inlineData){
10776 this.loadData(this.inlineData);
10777 delete this.inlineData;
10781 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10783 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10784 * without a remote query - used by combo/forms at present.
10788 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10791 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10794 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10795 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10798 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10799 * on any HTTP request
10802 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10805 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10809 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10810 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10812 remoteSort : false,
10815 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10816 * loaded or when a record is removed. (defaults to false).
10818 pruneModifiedRecords : false,
10821 lastOptions : null,
10824 * Add Records to the Store and fires the add event.
10825 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10827 add : function(records){
10828 records = [].concat(records);
10829 for(var i = 0, len = records.length; i < len; i++){
10830 records[i].join(this);
10832 var index = this.data.length;
10833 this.data.addAll(records);
10834 this.fireEvent("add", this, records, index);
10838 * Remove a Record from the Store and fires the remove event.
10839 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10841 remove : function(record){
10842 var index = this.data.indexOf(record);
10843 this.data.removeAt(index);
10844 if(this.pruneModifiedRecords){
10845 this.modified.remove(record);
10847 this.fireEvent("remove", this, record, index);
10851 * Remove all Records from the Store and fires the clear event.
10853 removeAll : function(){
10855 if(this.pruneModifiedRecords){
10856 this.modified = [];
10858 this.fireEvent("clear", this);
10862 * Inserts Records to the Store at the given index and fires the add event.
10863 * @param {Number} index The start index at which to insert the passed Records.
10864 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10866 insert : function(index, records){
10867 records = [].concat(records);
10868 for(var i = 0, len = records.length; i < len; i++){
10869 this.data.insert(index, records[i]);
10870 records[i].join(this);
10872 this.fireEvent("add", this, records, index);
10876 * Get the index within the cache of the passed Record.
10877 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10878 * @return {Number} The index of the passed Record. Returns -1 if not found.
10880 indexOf : function(record){
10881 return this.data.indexOf(record);
10885 * Get the index within the cache of the Record with the passed id.
10886 * @param {String} id The id of the Record to find.
10887 * @return {Number} The index of the Record. Returns -1 if not found.
10889 indexOfId : function(id){
10890 return this.data.indexOfKey(id);
10894 * Get the Record with the specified id.
10895 * @param {String} id The id of the Record to find.
10896 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10898 getById : function(id){
10899 return this.data.key(id);
10903 * Get the Record at the specified index.
10904 * @param {Number} index The index of the Record to find.
10905 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10907 getAt : function(index){
10908 return this.data.itemAt(index);
10912 * Returns a range of Records between specified indices.
10913 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10914 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10915 * @return {Roo.data.Record[]} An array of Records
10917 getRange : function(start, end){
10918 return this.data.getRange(start, end);
10922 storeOptions : function(o){
10923 o = Roo.apply({}, o);
10926 this.lastOptions = o;
10930 * Loads the Record cache from the configured Proxy using the configured Reader.
10932 * If using remote paging, then the first load call must specify the <em>start</em>
10933 * and <em>limit</em> properties in the options.params property to establish the initial
10934 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10936 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10937 * and this call will return before the new data has been loaded. Perform any post-processing
10938 * in a callback function, or in a "load" event handler.</strong>
10940 * @param {Object} options An object containing properties which control loading options:<ul>
10941 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10942 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10943 * passed the following arguments:<ul>
10944 * <li>r : Roo.data.Record[]</li>
10945 * <li>options: Options object from the load call</li>
10946 * <li>success: Boolean success indicator</li></ul></li>
10947 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10948 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10951 load : function(options){
10952 options = options || {};
10953 if(this.fireEvent("beforeload", this, options) !== false){
10954 this.storeOptions(options);
10955 var p = Roo.apply(options.params || {}, this.baseParams);
10956 // if meta was not loaded from remote source.. try requesting it.
10957 if (!this.reader.metaFromRemote) {
10958 p._requestMeta = 1;
10960 if(this.sortInfo && this.remoteSort){
10961 var pn = this.paramNames;
10962 p[pn["sort"]] = this.sortInfo.field;
10963 p[pn["dir"]] = this.sortInfo.direction;
10965 if (this.multiSort) {
10966 var pn = this.paramNames;
10967 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10970 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10975 * Reloads the Record cache from the configured Proxy using the configured Reader and
10976 * the options from the last load operation performed.
10977 * @param {Object} options (optional) An object containing properties which may override the options
10978 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10979 * the most recently used options are reused).
10981 reload : function(options){
10982 this.load(Roo.applyIf(options||{}, this.lastOptions));
10986 // Called as a callback by the Reader during a load operation.
10987 loadRecords : function(o, options, success){
10988 if(!o || success === false){
10989 if(success !== false){
10990 this.fireEvent("load", this, [], options, o);
10992 if(options.callback){
10993 options.callback.call(options.scope || this, [], options, false);
10997 // if data returned failure - throw an exception.
10998 if (o.success === false) {
10999 // show a message if no listener is registered.
11000 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11001 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11003 // loadmask wil be hooked into this..
11004 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11007 var r = o.records, t = o.totalRecords || r.length;
11009 this.fireEvent("beforeloadadd", this, r, options, o);
11011 if(!options || options.add !== true){
11012 if(this.pruneModifiedRecords){
11013 this.modified = [];
11015 for(var i = 0, len = r.length; i < len; i++){
11019 this.data = this.snapshot;
11020 delete this.snapshot;
11023 this.data.addAll(r);
11024 this.totalLength = t;
11026 this.fireEvent("datachanged", this);
11028 this.totalLength = Math.max(t, this.data.length+r.length);
11032 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11034 var e = new Roo.data.Record({});
11036 e.set(this.parent.displayField, this.parent.emptyTitle);
11037 e.set(this.parent.valueField, '');
11042 this.fireEvent("load", this, r, options, o);
11043 if(options.callback){
11044 options.callback.call(options.scope || this, r, options, true);
11050 * Loads data from a passed data block. A Reader which understands the format of the data
11051 * must have been configured in the constructor.
11052 * @param {Object} data The data block from which to read the Records. The format of the data expected
11053 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11054 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11056 loadData : function(o, append){
11057 var r = this.reader.readRecords(o);
11058 this.loadRecords(r, {add: append}, true);
11062 * Gets the number of cached records.
11064 * <em>If using paging, this may not be the total size of the dataset. If the data object
11065 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11066 * the data set size</em>
11068 getCount : function(){
11069 return this.data.length || 0;
11073 * Gets the total number of records in the dataset as returned by the server.
11075 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11076 * the dataset size</em>
11078 getTotalCount : function(){
11079 return this.totalLength || 0;
11083 * Returns the sort state of the Store as an object with two properties:
11085 field {String} The name of the field by which the Records are sorted
11086 direction {String} The sort order, "ASC" or "DESC"
11089 getSortState : function(){
11090 return this.sortInfo;
11094 applySort : function(){
11095 if(this.sortInfo && !this.remoteSort){
11096 var s = this.sortInfo, f = s.field;
11097 var st = this.fields.get(f).sortType;
11098 var fn = function(r1, r2){
11099 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11100 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11102 this.data.sort(s.direction, fn);
11103 if(this.snapshot && this.snapshot != this.data){
11104 this.snapshot.sort(s.direction, fn);
11110 * Sets the default sort column and order to be used by the next load operation.
11111 * @param {String} fieldName The name of the field to sort by.
11112 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11114 setDefaultSort : function(field, dir){
11115 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11119 * Sort the Records.
11120 * If remote sorting is used, the sort is performed on the server, and the cache is
11121 * reloaded. If local sorting is used, the cache is sorted internally.
11122 * @param {String} fieldName The name of the field to sort by.
11123 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11125 sort : function(fieldName, dir){
11126 var f = this.fields.get(fieldName);
11128 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11130 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11131 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11136 this.sortToggle[f.name] = dir;
11137 this.sortInfo = {field: f.name, direction: dir};
11138 if(!this.remoteSort){
11140 this.fireEvent("datachanged", this);
11142 this.load(this.lastOptions);
11147 * Calls the specified function for each of the Records in the cache.
11148 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11149 * Returning <em>false</em> aborts and exits the iteration.
11150 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11152 each : function(fn, scope){
11153 this.data.each(fn, scope);
11157 * Gets all records modified since the last commit. Modified records are persisted across load operations
11158 * (e.g., during paging).
11159 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11161 getModifiedRecords : function(){
11162 return this.modified;
11166 createFilterFn : function(property, value, anyMatch){
11167 if(!value.exec){ // not a regex
11168 value = String(value);
11169 if(value.length == 0){
11172 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11174 return function(r){
11175 return value.test(r.data[property]);
11180 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11181 * @param {String} property A field on your records
11182 * @param {Number} start The record index to start at (defaults to 0)
11183 * @param {Number} end The last record index to include (defaults to length - 1)
11184 * @return {Number} The sum
11186 sum : function(property, start, end){
11187 var rs = this.data.items, v = 0;
11188 start = start || 0;
11189 end = (end || end === 0) ? end : rs.length-1;
11191 for(var i = start; i <= end; i++){
11192 v += (rs[i].data[property] || 0);
11198 * Filter the records by a specified property.
11199 * @param {String} field A field on your records
11200 * @param {String/RegExp} value Either a string that the field
11201 * should start with or a RegExp to test against the field
11202 * @param {Boolean} anyMatch True to match any part not just the beginning
11204 filter : function(property, value, anyMatch){
11205 var fn = this.createFilterFn(property, value, anyMatch);
11206 return fn ? this.filterBy(fn) : this.clearFilter();
11210 * Filter by a function. The specified function will be called with each
11211 * record in this data source. If the function returns true the record is included,
11212 * otherwise it is filtered.
11213 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11214 * @param {Object} scope (optional) The scope of the function (defaults to this)
11216 filterBy : function(fn, scope){
11217 this.snapshot = this.snapshot || this.data;
11218 this.data = this.queryBy(fn, scope||this);
11219 this.fireEvent("datachanged", this);
11223 * Query the records by a specified property.
11224 * @param {String} field A field on your records
11225 * @param {String/RegExp} value Either a string that the field
11226 * should start with or a RegExp to test against the field
11227 * @param {Boolean} anyMatch True to match any part not just the beginning
11228 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11230 query : function(property, value, anyMatch){
11231 var fn = this.createFilterFn(property, value, anyMatch);
11232 return fn ? this.queryBy(fn) : this.data.clone();
11236 * Query by a function. The specified function will be called with each
11237 * record in this data source. If the function returns true the record is included
11239 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11240 * @param {Object} scope (optional) The scope of the function (defaults to this)
11241 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11243 queryBy : function(fn, scope){
11244 var data = this.snapshot || this.data;
11245 return data.filterBy(fn, scope||this);
11249 * Collects unique values for a particular dataIndex from this store.
11250 * @param {String} dataIndex The property to collect
11251 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11252 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11253 * @return {Array} An array of the unique values
11255 collect : function(dataIndex, allowNull, bypassFilter){
11256 var d = (bypassFilter === true && this.snapshot) ?
11257 this.snapshot.items : this.data.items;
11258 var v, sv, r = [], l = {};
11259 for(var i = 0, len = d.length; i < len; i++){
11260 v = d[i].data[dataIndex];
11262 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11271 * Revert to a view of the Record cache with no filtering applied.
11272 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11274 clearFilter : function(suppressEvent){
11275 if(this.snapshot && this.snapshot != this.data){
11276 this.data = this.snapshot;
11277 delete this.snapshot;
11278 if(suppressEvent !== true){
11279 this.fireEvent("datachanged", this);
11285 afterEdit : function(record){
11286 if(this.modified.indexOf(record) == -1){
11287 this.modified.push(record);
11289 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11293 afterReject : function(record){
11294 this.modified.remove(record);
11295 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11299 afterCommit : function(record){
11300 this.modified.remove(record);
11301 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11305 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11306 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11308 commitChanges : function(){
11309 var m = this.modified.slice(0);
11310 this.modified = [];
11311 for(var i = 0, len = m.length; i < len; i++){
11317 * Cancel outstanding changes on all changed records.
11319 rejectChanges : function(){
11320 var m = this.modified.slice(0);
11321 this.modified = [];
11322 for(var i = 0, len = m.length; i < len; i++){
11327 onMetaChange : function(meta, rtype, o){
11328 this.recordType = rtype;
11329 this.fields = rtype.prototype.fields;
11330 delete this.snapshot;
11331 this.sortInfo = meta.sortInfo || this.sortInfo;
11332 this.modified = [];
11333 this.fireEvent('metachange', this, this.reader.meta);
11336 moveIndex : function(data, type)
11338 var index = this.indexOf(data);
11340 var newIndex = index + type;
11344 this.insert(newIndex, data);
11349 * Ext JS Library 1.1.1
11350 * Copyright(c) 2006-2007, Ext JS, LLC.
11352 * Originally Released Under LGPL - original licence link has changed is not relivant.
11355 * <script type="text/javascript">
11359 * @class Roo.data.SimpleStore
11360 * @extends Roo.data.Store
11361 * Small helper class to make creating Stores from Array data easier.
11362 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11363 * @cfg {Array} fields An array of field definition objects, or field name strings.
11364 * @cfg {Array} data The multi-dimensional array of data
11366 * @param {Object} config
11368 Roo.data.SimpleStore = function(config){
11369 Roo.data.SimpleStore.superclass.constructor.call(this, {
11371 reader: new Roo.data.ArrayReader({
11374 Roo.data.Record.create(config.fields)
11376 proxy : new Roo.data.MemoryProxy(config.data)
11380 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11382 * Ext JS Library 1.1.1
11383 * Copyright(c) 2006-2007, Ext JS, LLC.
11385 * Originally Released Under LGPL - original licence link has changed is not relivant.
11388 * <script type="text/javascript">
11393 * @extends Roo.data.Store
11394 * @class Roo.data.JsonStore
11395 * Small helper class to make creating Stores for JSON data easier. <br/>
11397 var store = new Roo.data.JsonStore({
11398 url: 'get-images.php',
11400 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11403 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11404 * JsonReader and HttpProxy (unless inline data is provided).</b>
11405 * @cfg {Array} fields An array of field definition objects, or field name strings.
11407 * @param {Object} config
11409 Roo.data.JsonStore = function(c){
11410 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11411 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11412 reader: new Roo.data.JsonReader(c, c.fields)
11415 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11417 * Ext JS Library 1.1.1
11418 * Copyright(c) 2006-2007, Ext JS, LLC.
11420 * Originally Released Under LGPL - original licence link has changed is not relivant.
11423 * <script type="text/javascript">
11427 Roo.data.Field = function(config){
11428 if(typeof config == "string"){
11429 config = {name: config};
11431 Roo.apply(this, config);
11434 this.type = "auto";
11437 var st = Roo.data.SortTypes;
11438 // named sortTypes are supported, here we look them up
11439 if(typeof this.sortType == "string"){
11440 this.sortType = st[this.sortType];
11443 // set default sortType for strings and dates
11444 if(!this.sortType){
11447 this.sortType = st.asUCString;
11450 this.sortType = st.asDate;
11453 this.sortType = st.none;
11458 var stripRe = /[\$,%]/g;
11460 // prebuilt conversion function for this field, instead of
11461 // switching every time we're reading a value
11463 var cv, dateFormat = this.dateFormat;
11468 cv = function(v){ return v; };
11471 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11475 return v !== undefined && v !== null && v !== '' ?
11476 parseInt(String(v).replace(stripRe, ""), 10) : '';
11481 return v !== undefined && v !== null && v !== '' ?
11482 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11487 cv = function(v){ return v === true || v === "true" || v == 1; };
11494 if(v instanceof Date){
11498 if(dateFormat == "timestamp"){
11499 return new Date(v*1000);
11501 return Date.parseDate(v, dateFormat);
11503 var parsed = Date.parse(v);
11504 return parsed ? new Date(parsed) : null;
11513 Roo.data.Field.prototype = {
11521 * Ext JS Library 1.1.1
11522 * Copyright(c) 2006-2007, Ext JS, LLC.
11524 * Originally Released Under LGPL - original licence link has changed is not relivant.
11527 * <script type="text/javascript">
11530 // Base class for reading structured data from a data source. This class is intended to be
11531 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11534 * @class Roo.data.DataReader
11535 * Base class for reading structured data from a data source. This class is intended to be
11536 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11539 Roo.data.DataReader = function(meta, recordType){
11543 this.recordType = recordType instanceof Array ?
11544 Roo.data.Record.create(recordType) : recordType;
11547 Roo.data.DataReader.prototype = {
11549 * Create an empty record
11550 * @param {Object} data (optional) - overlay some values
11551 * @return {Roo.data.Record} record created.
11553 newRow : function(d) {
11555 this.recordType.prototype.fields.each(function(c) {
11557 case 'int' : da[c.name] = 0; break;
11558 case 'date' : da[c.name] = new Date(); break;
11559 case 'float' : da[c.name] = 0.0; break;
11560 case 'boolean' : da[c.name] = false; break;
11561 default : da[c.name] = ""; break;
11565 return new this.recordType(Roo.apply(da, d));
11570 * Ext JS Library 1.1.1
11571 * Copyright(c) 2006-2007, Ext JS, LLC.
11573 * Originally Released Under LGPL - original licence link has changed is not relivant.
11576 * <script type="text/javascript">
11580 * @class Roo.data.DataProxy
11581 * @extends Roo.data.Observable
11582 * This class is an abstract base class for implementations which provide retrieval of
11583 * unformatted data objects.<br>
11585 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11586 * (of the appropriate type which knows how to parse the data object) to provide a block of
11587 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11589 * Custom implementations must implement the load method as described in
11590 * {@link Roo.data.HttpProxy#load}.
11592 Roo.data.DataProxy = function(){
11595 * @event beforeload
11596 * Fires before a network request is made to retrieve a data object.
11597 * @param {Object} This DataProxy object.
11598 * @param {Object} params The params parameter to the load function.
11603 * Fires before the load method's callback is called.
11604 * @param {Object} This DataProxy object.
11605 * @param {Object} o The data object.
11606 * @param {Object} arg The callback argument object passed to the load function.
11610 * @event loadexception
11611 * Fires if an Exception occurs during data retrieval.
11612 * @param {Object} This DataProxy object.
11613 * @param {Object} o The data object.
11614 * @param {Object} arg The callback argument object passed to the load function.
11615 * @param {Object} e The Exception.
11617 loadexception : true
11619 Roo.data.DataProxy.superclass.constructor.call(this);
11622 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11625 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11629 * Ext JS Library 1.1.1
11630 * Copyright(c) 2006-2007, Ext JS, LLC.
11632 * Originally Released Under LGPL - original licence link has changed is not relivant.
11635 * <script type="text/javascript">
11638 * @class Roo.data.MemoryProxy
11639 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11640 * to the Reader when its load method is called.
11642 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11644 Roo.data.MemoryProxy = function(data){
11648 Roo.data.MemoryProxy.superclass.constructor.call(this);
11652 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11655 * Load data from the requested source (in this case an in-memory
11656 * data object passed to the constructor), read the data object into
11657 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11658 * process that block using the passed callback.
11659 * @param {Object} params This parameter is not used by the MemoryProxy class.
11660 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11661 * object into a block of Roo.data.Records.
11662 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11663 * The function must be passed <ul>
11664 * <li>The Record block object</li>
11665 * <li>The "arg" argument from the load function</li>
11666 * <li>A boolean success indicator</li>
11668 * @param {Object} scope The scope in which to call the callback
11669 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11671 load : function(params, reader, callback, scope, arg){
11672 params = params || {};
11675 result = reader.readRecords(this.data);
11677 this.fireEvent("loadexception", this, arg, null, e);
11678 callback.call(scope, null, arg, false);
11681 callback.call(scope, result, arg, true);
11685 update : function(params, records){
11690 * Ext JS Library 1.1.1
11691 * Copyright(c) 2006-2007, Ext JS, LLC.
11693 * Originally Released Under LGPL - original licence link has changed is not relivant.
11696 * <script type="text/javascript">
11699 * @class Roo.data.HttpProxy
11700 * @extends Roo.data.DataProxy
11701 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11702 * configured to reference a certain URL.<br><br>
11704 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11705 * from which the running page was served.<br><br>
11707 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11709 * Be aware that to enable the browser to parse an XML document, the server must set
11710 * the Content-Type header in the HTTP response to "text/xml".
11712 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11713 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11714 * will be used to make the request.
11716 Roo.data.HttpProxy = function(conn){
11717 Roo.data.HttpProxy.superclass.constructor.call(this);
11718 // is conn a conn config or a real conn?
11720 this.useAjax = !conn || !conn.events;
11724 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11725 // thse are take from connection...
11728 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11731 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11732 * extra parameters to each request made by this object. (defaults to undefined)
11735 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11736 * to each request made by this object. (defaults to undefined)
11739 * @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)
11742 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11745 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11751 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11755 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11756 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11757 * a finer-grained basis than the DataProxy events.
11759 getConnection : function(){
11760 return this.useAjax ? Roo.Ajax : this.conn;
11764 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11765 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11766 * process that block using the passed callback.
11767 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11768 * for the request to the remote server.
11769 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11770 * object into a block of Roo.data.Records.
11771 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11772 * The function must be passed <ul>
11773 * <li>The Record block object</li>
11774 * <li>The "arg" argument from the load function</li>
11775 * <li>A boolean success indicator</li>
11777 * @param {Object} scope The scope in which to call the callback
11778 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11780 load : function(params, reader, callback, scope, arg){
11781 if(this.fireEvent("beforeload", this, params) !== false){
11783 params : params || {},
11785 callback : callback,
11790 callback : this.loadResponse,
11794 Roo.applyIf(o, this.conn);
11795 if(this.activeRequest){
11796 Roo.Ajax.abort(this.activeRequest);
11798 this.activeRequest = Roo.Ajax.request(o);
11800 this.conn.request(o);
11803 callback.call(scope||this, null, arg, false);
11808 loadResponse : function(o, success, response){
11809 delete this.activeRequest;
11811 this.fireEvent("loadexception", this, o, response);
11812 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11817 result = o.reader.read(response);
11819 this.fireEvent("loadexception", this, o, response, e);
11820 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11824 this.fireEvent("load", this, o, o.request.arg);
11825 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11829 update : function(dataSet){
11834 updateResponse : function(dataSet){
11839 * Ext JS Library 1.1.1
11840 * Copyright(c) 2006-2007, Ext JS, LLC.
11842 * Originally Released Under LGPL - original licence link has changed is not relivant.
11845 * <script type="text/javascript">
11849 * @class Roo.data.ScriptTagProxy
11850 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11851 * other than the originating domain of the running page.<br><br>
11853 * <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
11854 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11856 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11857 * source code that is used as the source inside a <script> tag.<br><br>
11859 * In order for the browser to process the returned data, the server must wrap the data object
11860 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11861 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11862 * depending on whether the callback name was passed:
11865 boolean scriptTag = false;
11866 String cb = request.getParameter("callback");
11869 response.setContentType("text/javascript");
11871 response.setContentType("application/x-json");
11873 Writer out = response.getWriter();
11875 out.write(cb + "(");
11877 out.print(dataBlock.toJsonString());
11884 * @param {Object} config A configuration object.
11886 Roo.data.ScriptTagProxy = function(config){
11887 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11888 Roo.apply(this, config);
11889 this.head = document.getElementsByTagName("head")[0];
11892 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11894 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11896 * @cfg {String} url The URL from which to request the data object.
11899 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11903 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11904 * the server the name of the callback function set up by the load call to process the returned data object.
11905 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11906 * javascript output which calls this named function passing the data object as its only parameter.
11908 callbackParam : "callback",
11910 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11911 * name to the request.
11916 * Load data from the configured URL, read the data object into
11917 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11918 * process that block using the passed callback.
11919 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11920 * for the request to the remote server.
11921 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11922 * object into a block of Roo.data.Records.
11923 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11924 * The function must be passed <ul>
11925 * <li>The Record block object</li>
11926 * <li>The "arg" argument from the load function</li>
11927 * <li>A boolean success indicator</li>
11929 * @param {Object} scope The scope in which to call the callback
11930 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11932 load : function(params, reader, callback, scope, arg){
11933 if(this.fireEvent("beforeload", this, params) !== false){
11935 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11937 var url = this.url;
11938 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11940 url += "&_dc=" + (new Date().getTime());
11942 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11945 cb : "stcCallback"+transId,
11946 scriptId : "stcScript"+transId,
11950 callback : callback,
11956 window[trans.cb] = function(o){
11957 conn.handleResponse(o, trans);
11960 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11962 if(this.autoAbort !== false){
11966 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11968 var script = document.createElement("script");
11969 script.setAttribute("src", url);
11970 script.setAttribute("type", "text/javascript");
11971 script.setAttribute("id", trans.scriptId);
11972 this.head.appendChild(script);
11974 this.trans = trans;
11976 callback.call(scope||this, null, arg, false);
11981 isLoading : function(){
11982 return this.trans ? true : false;
11986 * Abort the current server request.
11988 abort : function(){
11989 if(this.isLoading()){
11990 this.destroyTrans(this.trans);
11995 destroyTrans : function(trans, isLoaded){
11996 this.head.removeChild(document.getElementById(trans.scriptId));
11997 clearTimeout(trans.timeoutId);
11999 window[trans.cb] = undefined;
12001 delete window[trans.cb];
12004 // if hasn't been loaded, wait for load to remove it to prevent script error
12005 window[trans.cb] = function(){
12006 window[trans.cb] = undefined;
12008 delete window[trans.cb];
12015 handleResponse : function(o, trans){
12016 this.trans = false;
12017 this.destroyTrans(trans, true);
12020 result = trans.reader.readRecords(o);
12022 this.fireEvent("loadexception", this, o, trans.arg, e);
12023 trans.callback.call(trans.scope||window, null, trans.arg, false);
12026 this.fireEvent("load", this, o, trans.arg);
12027 trans.callback.call(trans.scope||window, result, trans.arg, true);
12031 handleFailure : function(trans){
12032 this.trans = false;
12033 this.destroyTrans(trans, false);
12034 this.fireEvent("loadexception", this, null, trans.arg);
12035 trans.callback.call(trans.scope||window, null, trans.arg, false);
12039 * Ext JS Library 1.1.1
12040 * Copyright(c) 2006-2007, Ext JS, LLC.
12042 * Originally Released Under LGPL - original licence link has changed is not relivant.
12045 * <script type="text/javascript">
12049 * @class Roo.data.JsonReader
12050 * @extends Roo.data.DataReader
12051 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12052 * based on mappings in a provided Roo.data.Record constructor.
12054 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12055 * in the reply previously.
12060 var RecordDef = Roo.data.Record.create([
12061 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12062 {name: 'occupation'} // This field will use "occupation" as the mapping.
12064 var myReader = new Roo.data.JsonReader({
12065 totalProperty: "results", // The property which contains the total dataset size (optional)
12066 root: "rows", // The property which contains an Array of row objects
12067 id: "id" // The property within each row object that provides an ID for the record (optional)
12071 * This would consume a JSON file like this:
12073 { 'results': 2, 'rows': [
12074 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12075 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12078 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12079 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12080 * paged from the remote server.
12081 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12082 * @cfg {String} root name of the property which contains the Array of row objects.
12083 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12084 * @cfg {Array} fields Array of field definition objects
12086 * Create a new JsonReader
12087 * @param {Object} meta Metadata configuration options
12088 * @param {Object} recordType Either an Array of field definition objects,
12089 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12091 Roo.data.JsonReader = function(meta, recordType){
12094 // set some defaults:
12095 Roo.applyIf(meta, {
12096 totalProperty: 'total',
12097 successProperty : 'success',
12102 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12104 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12107 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12108 * Used by Store query builder to append _requestMeta to params.
12111 metaFromRemote : false,
12113 * This method is only used by a DataProxy which has retrieved data from a remote server.
12114 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12115 * @return {Object} data A data block which is used by an Roo.data.Store object as
12116 * a cache of Roo.data.Records.
12118 read : function(response){
12119 var json = response.responseText;
12121 var o = /* eval:var:o */ eval("("+json+")");
12123 throw {message: "JsonReader.read: Json object not found"};
12129 this.metaFromRemote = true;
12130 this.meta = o.metaData;
12131 this.recordType = Roo.data.Record.create(o.metaData.fields);
12132 this.onMetaChange(this.meta, this.recordType, o);
12134 return this.readRecords(o);
12137 // private function a store will implement
12138 onMetaChange : function(meta, recordType, o){
12145 simpleAccess: function(obj, subsc) {
12152 getJsonAccessor: function(){
12154 return function(expr) {
12156 return(re.test(expr))
12157 ? new Function("obj", "return obj." + expr)
12162 return Roo.emptyFn;
12167 * Create a data block containing Roo.data.Records from an XML document.
12168 * @param {Object} o An object which contains an Array of row objects in the property specified
12169 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12170 * which contains the total size of the dataset.
12171 * @return {Object} data A data block which is used by an Roo.data.Store object as
12172 * a cache of Roo.data.Records.
12174 readRecords : function(o){
12176 * After any data loads, the raw JSON data is available for further custom processing.
12180 var s = this.meta, Record = this.recordType,
12181 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12183 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12185 if(s.totalProperty) {
12186 this.getTotal = this.getJsonAccessor(s.totalProperty);
12188 if(s.successProperty) {
12189 this.getSuccess = this.getJsonAccessor(s.successProperty);
12191 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12193 var g = this.getJsonAccessor(s.id);
12194 this.getId = function(rec) {
12196 return (r === undefined || r === "") ? null : r;
12199 this.getId = function(){return null;};
12202 for(var jj = 0; jj < fl; jj++){
12204 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12205 this.ef[jj] = this.getJsonAccessor(map);
12209 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12210 if(s.totalProperty){
12211 var vt = parseInt(this.getTotal(o), 10);
12216 if(s.successProperty){
12217 var vs = this.getSuccess(o);
12218 if(vs === false || vs === 'false'){
12223 for(var i = 0; i < c; i++){
12226 var id = this.getId(n);
12227 for(var j = 0; j < fl; j++){
12229 var v = this.ef[j](n);
12231 Roo.log('missing convert for ' + f.name);
12235 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12237 var record = new Record(values, id);
12239 records[i] = record;
12245 totalRecords : totalRecords
12250 * Ext JS Library 1.1.1
12251 * Copyright(c) 2006-2007, Ext JS, LLC.
12253 * Originally Released Under LGPL - original licence link has changed is not relivant.
12256 * <script type="text/javascript">
12260 * @class Roo.data.ArrayReader
12261 * @extends Roo.data.DataReader
12262 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12263 * Each element of that Array represents a row of data fields. The
12264 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12265 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12269 var RecordDef = Roo.data.Record.create([
12270 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12271 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12273 var myReader = new Roo.data.ArrayReader({
12274 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12278 * This would consume an Array like this:
12280 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12282 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12284 * Create a new JsonReader
12285 * @param {Object} meta Metadata configuration options.
12286 * @param {Object} recordType Either an Array of field definition objects
12287 * as specified to {@link Roo.data.Record#create},
12288 * or an {@link Roo.data.Record} object
12289 * created using {@link Roo.data.Record#create}.
12291 Roo.data.ArrayReader = function(meta, recordType){
12292 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12295 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12297 * Create a data block containing Roo.data.Records from an XML document.
12298 * @param {Object} o An Array of row objects which represents the dataset.
12299 * @return {Object} data A data block which is used by an Roo.data.Store object as
12300 * a cache of Roo.data.Records.
12302 readRecords : function(o){
12303 var sid = this.meta ? this.meta.id : null;
12304 var recordType = this.recordType, fields = recordType.prototype.fields;
12307 for(var i = 0; i < root.length; i++){
12310 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12311 for(var j = 0, jlen = fields.length; j < jlen; j++){
12312 var f = fields.items[j];
12313 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12314 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12316 values[f.name] = v;
12318 var record = new recordType(values, id);
12320 records[records.length] = record;
12324 totalRecords : records.length
12333 * @class Roo.bootstrap.ComboBox
12334 * @extends Roo.bootstrap.TriggerField
12335 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12336 * @cfg {Boolean} append (true|false) default false
12337 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12338 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12339 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12340 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12341 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12342 * @cfg {Boolean} animate default true
12343 * @cfg {Boolean} emptyResultText only for touch device
12344 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12345 * @cfg {String} emptyTitle default ''
12347 * Create a new ComboBox.
12348 * @param {Object} config Configuration options
12350 Roo.bootstrap.ComboBox = function(config){
12351 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12355 * Fires when the dropdown list is expanded
12356 * @param {Roo.bootstrap.ComboBox} combo This combo box
12361 * Fires when the dropdown list is collapsed
12362 * @param {Roo.bootstrap.ComboBox} combo This combo box
12366 * @event beforeselect
12367 * Fires before a list item is selected. Return false to cancel the selection.
12368 * @param {Roo.bootstrap.ComboBox} combo This combo box
12369 * @param {Roo.data.Record} record The data record returned from the underlying store
12370 * @param {Number} index The index of the selected item in the dropdown list
12372 'beforeselect' : true,
12375 * Fires when a list item is selected
12376 * @param {Roo.bootstrap.ComboBox} combo This combo box
12377 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12378 * @param {Number} index The index of the selected item in the dropdown list
12382 * @event beforequery
12383 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12384 * The event object passed has these properties:
12385 * @param {Roo.bootstrap.ComboBox} combo This combo box
12386 * @param {String} query The query
12387 * @param {Boolean} forceAll true to force "all" query
12388 * @param {Boolean} cancel true to cancel the query
12389 * @param {Object} e The query event object
12391 'beforequery': true,
12394 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12395 * @param {Roo.bootstrap.ComboBox} combo This combo box
12400 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12401 * @param {Roo.bootstrap.ComboBox} combo This combo box
12402 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12407 * Fires when the remove value from the combobox array
12408 * @param {Roo.bootstrap.ComboBox} combo This combo box
12412 * @event afterremove
12413 * Fires when the remove value from the combobox array
12414 * @param {Roo.bootstrap.ComboBox} combo This combo box
12416 'afterremove' : true,
12418 * @event specialfilter
12419 * Fires when specialfilter
12420 * @param {Roo.bootstrap.ComboBox} combo This combo box
12422 'specialfilter' : true,
12425 * Fires when tick the element
12426 * @param {Roo.bootstrap.ComboBox} combo This combo box
12430 * @event touchviewdisplay
12431 * Fires when touch view require special display (default is using displayField)
12432 * @param {Roo.bootstrap.ComboBox} combo This combo box
12433 * @param {Object} cfg set html .
12435 'touchviewdisplay' : true
12440 this.tickItems = [];
12442 this.selectedIndex = -1;
12443 if(this.mode == 'local'){
12444 if(config.queryDelay === undefined){
12445 this.queryDelay = 10;
12447 if(config.minChars === undefined){
12453 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12456 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12457 * rendering into an Roo.Editor, defaults to false)
12460 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12461 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12464 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12467 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12468 * the dropdown list (defaults to undefined, with no header element)
12472 * @cfg {String/Roo.Template} tpl The template to use to render the output
12476 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12478 listWidth: undefined,
12480 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12481 * mode = 'remote' or 'text' if mode = 'local')
12483 displayField: undefined,
12486 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12487 * mode = 'remote' or 'value' if mode = 'local').
12488 * Note: use of a valueField requires the user make a selection
12489 * in order for a value to be mapped.
12491 valueField: undefined,
12493 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12498 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12499 * field's data value (defaults to the underlying DOM element's name)
12501 hiddenName: undefined,
12503 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12507 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12509 selectedClass: 'active',
12512 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12516 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12517 * anchor positions (defaults to 'tl-bl')
12519 listAlign: 'tl-bl?',
12521 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12525 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12526 * query specified by the allQuery config option (defaults to 'query')
12528 triggerAction: 'query',
12530 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12531 * (defaults to 4, does not apply if editable = false)
12535 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12536 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12540 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12541 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12545 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12546 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12550 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12551 * when editable = true (defaults to false)
12553 selectOnFocus:false,
12555 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12557 queryParam: 'query',
12559 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12560 * when mode = 'remote' (defaults to 'Loading...')
12562 loadingText: 'Loading...',
12564 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12568 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12572 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12573 * traditional select (defaults to true)
12577 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12581 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12585 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12586 * listWidth has a higher value)
12590 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12591 * allow the user to set arbitrary text into the field (defaults to false)
12593 forceSelection:false,
12595 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12596 * if typeAhead = true (defaults to 250)
12598 typeAheadDelay : 250,
12600 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12601 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12603 valueNotFoundText : undefined,
12605 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12607 blockFocus : false,
12610 * @cfg {Boolean} disableClear Disable showing of clear button.
12612 disableClear : false,
12614 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12616 alwaysQuery : false,
12619 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12624 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12626 invalidClass : "has-warning",
12629 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12631 validClass : "has-success",
12634 * @cfg {Boolean} specialFilter (true|false) special filter default false
12636 specialFilter : false,
12639 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12641 mobileTouchView : true,
12644 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12646 useNativeIOS : false,
12648 ios_options : false,
12660 btnPosition : 'right',
12661 triggerList : true,
12662 showToggleBtn : true,
12664 emptyResultText: 'Empty',
12665 triggerText : 'Select',
12668 // element that contains real text value.. (when hidden is used..)
12670 getAutoCreate : function()
12675 * Render classic select for iso
12678 if(Roo.isIOS && this.useNativeIOS){
12679 cfg = this.getAutoCreateNativeIOS();
12687 if(Roo.isTouch && this.mobileTouchView){
12688 cfg = this.getAutoCreateTouchView();
12695 if(!this.tickable){
12696 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12697 if(this.name == 'info_year_invest_id_display_name'){
12698 Roo.log('cfg.................................................');
12705 * ComboBox with tickable selections
12708 var align = this.labelAlign || this.parentLabelAlign();
12711 cls : 'form-group roo-combobox-tickable' //input-group
12714 var btn_text_select = '';
12715 var btn_text_done = '';
12716 var btn_text_cancel = '';
12718 if (this.btn_text_show) {
12719 btn_text_select = 'Select';
12720 btn_text_done = 'Done';
12721 btn_text_cancel = 'Cancel';
12726 cls : 'tickable-buttons',
12731 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12732 //html : this.triggerText
12733 html: btn_text_select
12739 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12741 html: btn_text_done
12747 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12749 html: btn_text_cancel
12755 buttons.cn.unshift({
12757 cls: 'roo-select2-search-field-input'
12763 Roo.each(buttons.cn, function(c){
12765 c.cls += ' btn-' + _this.size;
12768 if (_this.disabled) {
12779 cls: 'form-hidden-field'
12783 cls: 'roo-select2-choices',
12787 cls: 'roo-select2-search-field',
12798 cls: 'roo-select2-container input-group roo-select2-container-multi',
12803 // cls: 'typeahead typeahead-long dropdown-menu',
12804 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12809 if(this.hasFeedback && !this.allowBlank){
12813 cls: 'glyphicon form-control-feedback'
12816 combobox.cn.push(feedback);
12820 if (align ==='left' && this.fieldLabel.length) {
12822 cfg.cls += ' roo-form-group-label-left';
12827 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12828 tooltip : 'This field is required'
12833 cls : 'control-label',
12834 html : this.fieldLabel
12846 var labelCfg = cfg.cn[1];
12847 var contentCfg = cfg.cn[2];
12850 if(this.indicatorpos == 'right'){
12856 cls : 'control-label',
12860 html : this.fieldLabel
12864 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12865 tooltip : 'This field is required'
12880 labelCfg = cfg.cn[0];
12881 contentCfg = cfg.cn[1];
12885 if(this.labelWidth > 12){
12886 labelCfg.style = "width: " + this.labelWidth + 'px';
12889 if(this.labelWidth < 13 && this.labelmd == 0){
12890 this.labelmd = this.labelWidth;
12893 if(this.labellg > 0){
12894 labelCfg.cls += ' col-lg-' + this.labellg;
12895 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12898 if(this.labelmd > 0){
12899 labelCfg.cls += ' col-md-' + this.labelmd;
12900 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12903 if(this.labelsm > 0){
12904 labelCfg.cls += ' col-sm-' + this.labelsm;
12905 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12908 if(this.labelxs > 0){
12909 labelCfg.cls += ' col-xs-' + this.labelxs;
12910 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12914 } else if ( this.fieldLabel.length) {
12915 // Roo.log(" label");
12919 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12920 tooltip : 'This field is required'
12924 //cls : 'input-group-addon',
12925 html : this.fieldLabel
12933 if(this.indicatorpos == 'right'){
12941 html : this.fieldLabel
12945 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12946 tooltip : 'This field is required'
12959 // Roo.log(" no label && no align");
12966 ['xs','sm','md','lg'].map(function(size){
12967 if (settings[size]) {
12968 cfg.cls += ' col-' + size + '-' + settings[size];
12976 _initEventsCalled : false,
12979 initEvents: function()
12981 if (this._initEventsCalled) { // as we call render... prevent looping...
12984 this._initEventsCalled = true;
12987 throw "can not find store for combo";
12990 this.store = Roo.factory(this.store, Roo.data);
12991 this.store.parent = this;
12993 // if we are building from html. then this element is so complex, that we can not really
12994 // use the rendered HTML.
12995 // so we have to trash and replace the previous code.
12996 if (Roo.XComponent.build_from_html) {
12998 // remove this element....
12999 var e = this.el.dom, k=0;
13000 while (e ) { e = e.previousSibling; ++k;}
13005 this.rendered = false;
13007 this.render(this.parent().getChildContainer(true), k);
13013 if(Roo.isIOS && this.useNativeIOS){
13014 this.initIOSView();
13022 if(Roo.isTouch && this.mobileTouchView){
13023 this.initTouchView();
13028 this.initTickableEvents();
13032 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13034 if(this.hiddenName){
13036 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13038 this.hiddenField.dom.value =
13039 this.hiddenValue !== undefined ? this.hiddenValue :
13040 this.value !== undefined ? this.value : '';
13042 // prevent input submission
13043 this.el.dom.removeAttribute('name');
13044 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13049 // this.el.dom.setAttribute('autocomplete', 'off');
13052 var cls = 'x-combo-list';
13054 //this.list = new Roo.Layer({
13055 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13061 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13062 _this.list.setWidth(lw);
13065 this.list.on('mouseover', this.onViewOver, this);
13066 this.list.on('mousemove', this.onViewMove, this);
13068 this.list.on('scroll', this.onViewScroll, this);
13071 this.list.swallowEvent('mousewheel');
13072 this.assetHeight = 0;
13075 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13076 this.assetHeight += this.header.getHeight();
13079 this.innerList = this.list.createChild({cls:cls+'-inner'});
13080 this.innerList.on('mouseover', this.onViewOver, this);
13081 this.innerList.on('mousemove', this.onViewMove, this);
13082 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13084 if(this.allowBlank && !this.pageSize && !this.disableClear){
13085 this.footer = this.list.createChild({cls:cls+'-ft'});
13086 this.pageTb = new Roo.Toolbar(this.footer);
13090 this.footer = this.list.createChild({cls:cls+'-ft'});
13091 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13092 {pageSize: this.pageSize});
13096 if (this.pageTb && this.allowBlank && !this.disableClear) {
13098 this.pageTb.add(new Roo.Toolbar.Fill(), {
13099 cls: 'x-btn-icon x-btn-clear',
13101 handler: function()
13104 _this.clearValue();
13105 _this.onSelect(false, -1);
13110 this.assetHeight += this.footer.getHeight();
13115 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13118 this.view = new Roo.View(this.list, this.tpl, {
13119 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13121 //this.view.wrapEl.setDisplayed(false);
13122 this.view.on('click', this.onViewClick, this);
13125 this.store.on('beforeload', this.onBeforeLoad, this);
13126 this.store.on('load', this.onLoad, this);
13127 this.store.on('loadexception', this.onLoadException, this);
13129 if(this.resizable){
13130 this.resizer = new Roo.Resizable(this.list, {
13131 pinned:true, handles:'se'
13133 this.resizer.on('resize', function(r, w, h){
13134 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13135 this.listWidth = w;
13136 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13137 this.restrictHeight();
13139 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13142 if(!this.editable){
13143 this.editable = true;
13144 this.setEditable(false);
13149 if (typeof(this.events.add.listeners) != 'undefined') {
13151 this.addicon = this.wrap.createChild(
13152 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13154 this.addicon.on('click', function(e) {
13155 this.fireEvent('add', this);
13158 if (typeof(this.events.edit.listeners) != 'undefined') {
13160 this.editicon = this.wrap.createChild(
13161 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13162 if (this.addicon) {
13163 this.editicon.setStyle('margin-left', '40px');
13165 this.editicon.on('click', function(e) {
13167 // we fire even if inothing is selected..
13168 this.fireEvent('edit', this, this.lastData );
13174 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13175 "up" : function(e){
13176 this.inKeyMode = true;
13180 "down" : function(e){
13181 if(!this.isExpanded()){
13182 this.onTriggerClick();
13184 this.inKeyMode = true;
13189 "enter" : function(e){
13190 // this.onViewClick();
13194 if(this.fireEvent("specialkey", this, e)){
13195 this.onViewClick(false);
13201 "esc" : function(e){
13205 "tab" : function(e){
13208 if(this.fireEvent("specialkey", this, e)){
13209 this.onViewClick(false);
13217 doRelay : function(foo, bar, hname){
13218 if(hname == 'down' || this.scope.isExpanded()){
13219 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13228 this.queryDelay = Math.max(this.queryDelay || 10,
13229 this.mode == 'local' ? 10 : 250);
13232 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13234 if(this.typeAhead){
13235 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13237 if(this.editable !== false){
13238 this.inputEl().on("keyup", this.onKeyUp, this);
13240 if(this.forceSelection){
13241 this.inputEl().on('blur', this.doForce, this);
13245 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13246 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13250 initTickableEvents: function()
13254 if(this.hiddenName){
13256 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13258 this.hiddenField.dom.value =
13259 this.hiddenValue !== undefined ? this.hiddenValue :
13260 this.value !== undefined ? this.value : '';
13262 // prevent input submission
13263 this.el.dom.removeAttribute('name');
13264 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13269 // this.list = this.el.select('ul.dropdown-menu',true).first();
13271 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13272 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13273 if(this.triggerList){
13274 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13277 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13278 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13280 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13281 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13283 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13284 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13286 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13287 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13288 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13291 this.cancelBtn.hide();
13296 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13297 _this.list.setWidth(lw);
13300 this.list.on('mouseover', this.onViewOver, this);
13301 this.list.on('mousemove', this.onViewMove, this);
13303 this.list.on('scroll', this.onViewScroll, this);
13306 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>';
13309 this.view = new Roo.View(this.list, this.tpl, {
13310 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13313 //this.view.wrapEl.setDisplayed(false);
13314 this.view.on('click', this.onViewClick, this);
13318 this.store.on('beforeload', this.onBeforeLoad, this);
13319 this.store.on('load', this.onLoad, this);
13320 this.store.on('loadexception', this.onLoadException, this);
13323 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13324 "up" : function(e){
13325 this.inKeyMode = true;
13329 "down" : function(e){
13330 this.inKeyMode = true;
13334 "enter" : function(e){
13335 if(this.fireEvent("specialkey", this, e)){
13336 this.onViewClick(false);
13342 "esc" : function(e){
13343 this.onTickableFooterButtonClick(e, false, false);
13346 "tab" : function(e){
13347 this.fireEvent("specialkey", this, e);
13349 this.onTickableFooterButtonClick(e, false, false);
13356 doRelay : function(e, fn, key){
13357 if(this.scope.isExpanded()){
13358 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13367 this.queryDelay = Math.max(this.queryDelay || 10,
13368 this.mode == 'local' ? 10 : 250);
13371 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13373 if(this.typeAhead){
13374 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13377 if(this.editable !== false){
13378 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13381 this.indicator = this.indicatorEl();
13383 if(this.indicator){
13384 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13385 this.indicator.hide();
13390 onDestroy : function(){
13392 this.view.setStore(null);
13393 this.view.el.removeAllListeners();
13394 this.view.el.remove();
13395 this.view.purgeListeners();
13398 this.list.dom.innerHTML = '';
13402 this.store.un('beforeload', this.onBeforeLoad, this);
13403 this.store.un('load', this.onLoad, this);
13404 this.store.un('loadexception', this.onLoadException, this);
13406 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13410 fireKey : function(e){
13411 if(e.isNavKeyPress() && !this.list.isVisible()){
13412 this.fireEvent("specialkey", this, e);
13417 onResize: function(w, h){
13418 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13420 // if(typeof w != 'number'){
13421 // // we do not handle it!?!?
13424 // var tw = this.trigger.getWidth();
13425 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13426 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13428 // this.inputEl().setWidth( this.adjustWidth('input', x));
13430 // //this.trigger.setStyle('left', x+'px');
13432 // if(this.list && this.listWidth === undefined){
13433 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13434 // this.list.setWidth(lw);
13435 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13443 * Allow or prevent the user from directly editing the field text. If false is passed,
13444 * the user will only be able to select from the items defined in the dropdown list. This method
13445 * is the runtime equivalent of setting the 'editable' config option at config time.
13446 * @param {Boolean} value True to allow the user to directly edit the field text
13448 setEditable : function(value){
13449 if(value == this.editable){
13452 this.editable = value;
13454 this.inputEl().dom.setAttribute('readOnly', true);
13455 this.inputEl().on('mousedown', this.onTriggerClick, this);
13456 this.inputEl().addClass('x-combo-noedit');
13458 this.inputEl().dom.setAttribute('readOnly', false);
13459 this.inputEl().un('mousedown', this.onTriggerClick, this);
13460 this.inputEl().removeClass('x-combo-noedit');
13466 onBeforeLoad : function(combo,opts){
13467 if(!this.hasFocus){
13471 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13473 this.restrictHeight();
13474 this.selectedIndex = -1;
13478 onLoad : function(){
13480 this.hasQuery = false;
13482 if(!this.hasFocus){
13486 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13487 this.loading.hide();
13490 if(this.store.getCount() > 0){
13493 this.restrictHeight();
13494 if(this.lastQuery == this.allQuery){
13495 if(this.editable && !this.tickable){
13496 this.inputEl().dom.select();
13500 !this.selectByValue(this.value, true) &&
13503 !this.store.lastOptions ||
13504 typeof(this.store.lastOptions.add) == 'undefined' ||
13505 this.store.lastOptions.add != true
13508 this.select(0, true);
13511 if(this.autoFocus){
13514 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13515 this.taTask.delay(this.typeAheadDelay);
13519 this.onEmptyResults();
13525 onLoadException : function()
13527 this.hasQuery = false;
13529 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13530 this.loading.hide();
13533 if(this.tickable && this.editable){
13538 // only causes errors at present
13539 //Roo.log(this.store.reader.jsonData);
13540 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13542 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13548 onTypeAhead : function(){
13549 if(this.store.getCount() > 0){
13550 var r = this.store.getAt(0);
13551 var newValue = r.data[this.displayField];
13552 var len = newValue.length;
13553 var selStart = this.getRawValue().length;
13555 if(selStart != len){
13556 this.setRawValue(newValue);
13557 this.selectText(selStart, newValue.length);
13563 onSelect : function(record, index){
13565 if(this.fireEvent('beforeselect', this, record, index) !== false){
13567 this.setFromData(index > -1 ? record.data : false);
13570 this.fireEvent('select', this, record, index);
13575 * Returns the currently selected field value or empty string if no value is set.
13576 * @return {String} value The selected value
13578 getValue : function()
13580 if(Roo.isIOS && this.useNativeIOS){
13581 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13585 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13588 if(this.valueField){
13589 return typeof this.value != 'undefined' ? this.value : '';
13591 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13595 getRawValue : function()
13597 if(Roo.isIOS && this.useNativeIOS){
13598 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13601 var v = this.inputEl().getValue();
13607 * Clears any text/value currently set in the field
13609 clearValue : function(){
13611 if(this.hiddenField){
13612 this.hiddenField.dom.value = '';
13615 this.setRawValue('');
13616 this.lastSelectionText = '';
13617 this.lastData = false;
13619 var close = this.closeTriggerEl();
13630 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13631 * will be displayed in the field. If the value does not match the data value of an existing item,
13632 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13633 * Otherwise the field will be blank (although the value will still be set).
13634 * @param {String} value The value to match
13636 setValue : function(v)
13638 if(Roo.isIOS && this.useNativeIOS){
13639 this.setIOSValue(v);
13649 if(this.valueField){
13650 var r = this.findRecord(this.valueField, v);
13652 text = r.data[this.displayField];
13653 }else if(this.valueNotFoundText !== undefined){
13654 text = this.valueNotFoundText;
13657 this.lastSelectionText = text;
13658 if(this.hiddenField){
13659 this.hiddenField.dom.value = v;
13661 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13664 var close = this.closeTriggerEl();
13667 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13673 * @property {Object} the last set data for the element
13678 * Sets the value of the field based on a object which is related to the record format for the store.
13679 * @param {Object} value the value to set as. or false on reset?
13681 setFromData : function(o){
13688 var dv = ''; // display value
13689 var vv = ''; // value value..
13691 if (this.displayField) {
13692 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13694 // this is an error condition!!!
13695 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13698 if(this.valueField){
13699 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13702 var close = this.closeTriggerEl();
13705 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13708 if(this.hiddenField){
13709 this.hiddenField.dom.value = vv;
13711 this.lastSelectionText = dv;
13712 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13716 // no hidden field.. - we store the value in 'value', but still display
13717 // display field!!!!
13718 this.lastSelectionText = dv;
13719 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13726 reset : function(){
13727 // overridden so that last data is reset..
13734 this.setValue(this.originalValue);
13735 //this.clearInvalid();
13736 this.lastData = false;
13738 this.view.clearSelections();
13744 findRecord : function(prop, value){
13746 if(this.store.getCount() > 0){
13747 this.store.each(function(r){
13748 if(r.data[prop] == value){
13758 getName: function()
13760 // returns hidden if it's set..
13761 if (!this.rendered) {return ''};
13762 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13766 onViewMove : function(e, t){
13767 this.inKeyMode = false;
13771 onViewOver : function(e, t){
13772 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13775 var item = this.view.findItemFromChild(t);
13778 var index = this.view.indexOf(item);
13779 this.select(index, false);
13784 onViewClick : function(view, doFocus, el, e)
13786 var index = this.view.getSelectedIndexes()[0];
13788 var r = this.store.getAt(index);
13792 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13799 Roo.each(this.tickItems, function(v,k){
13801 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13803 _this.tickItems.splice(k, 1);
13805 if(typeof(e) == 'undefined' && view == false){
13806 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13818 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13819 this.tickItems.push(r.data);
13822 if(typeof(e) == 'undefined' && view == false){
13823 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13830 this.onSelect(r, index);
13832 if(doFocus !== false && !this.blockFocus){
13833 this.inputEl().focus();
13838 restrictHeight : function(){
13839 //this.innerList.dom.style.height = '';
13840 //var inner = this.innerList.dom;
13841 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13842 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13843 //this.list.beginUpdate();
13844 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13845 this.list.alignTo(this.inputEl(), this.listAlign);
13846 this.list.alignTo(this.inputEl(), this.listAlign);
13847 //this.list.endUpdate();
13851 onEmptyResults : function(){
13853 if(this.tickable && this.editable){
13854 this.restrictHeight();
13862 * Returns true if the dropdown list is expanded, else false.
13864 isExpanded : function(){
13865 return this.list.isVisible();
13869 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13870 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13871 * @param {String} value The data value of the item to select
13872 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13873 * selected item if it is not currently in view (defaults to true)
13874 * @return {Boolean} True if the value matched an item in the list, else false
13876 selectByValue : function(v, scrollIntoView){
13877 if(v !== undefined && v !== null){
13878 var r = this.findRecord(this.valueField || this.displayField, v);
13880 this.select(this.store.indexOf(r), scrollIntoView);
13888 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13889 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13890 * @param {Number} index The zero-based index of the list item to select
13891 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13892 * selected item if it is not currently in view (defaults to true)
13894 select : function(index, scrollIntoView){
13895 this.selectedIndex = index;
13896 this.view.select(index);
13897 if(scrollIntoView !== false){
13898 var el = this.view.getNode(index);
13900 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13903 this.list.scrollChildIntoView(el, false);
13909 selectNext : function(){
13910 var ct = this.store.getCount();
13912 if(this.selectedIndex == -1){
13914 }else if(this.selectedIndex < ct-1){
13915 this.select(this.selectedIndex+1);
13921 selectPrev : function(){
13922 var ct = this.store.getCount();
13924 if(this.selectedIndex == -1){
13926 }else if(this.selectedIndex != 0){
13927 this.select(this.selectedIndex-1);
13933 onKeyUp : function(e){
13934 if(this.editable !== false && !e.isSpecialKey()){
13935 this.lastKey = e.getKey();
13936 this.dqTask.delay(this.queryDelay);
13941 validateBlur : function(){
13942 return !this.list || !this.list.isVisible();
13946 initQuery : function(){
13948 var v = this.getRawValue();
13950 if(this.tickable && this.editable){
13951 v = this.tickableInputEl().getValue();
13958 doForce : function(){
13959 if(this.inputEl().dom.value.length > 0){
13960 this.inputEl().dom.value =
13961 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13967 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13968 * query allowing the query action to be canceled if needed.
13969 * @param {String} query The SQL query to execute
13970 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13971 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13972 * saved in the current store (defaults to false)
13974 doQuery : function(q, forceAll){
13976 if(q === undefined || q === null){
13981 forceAll: forceAll,
13985 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13990 forceAll = qe.forceAll;
13991 if(forceAll === true || (q.length >= this.minChars)){
13993 this.hasQuery = true;
13995 if(this.lastQuery != q || this.alwaysQuery){
13996 this.lastQuery = q;
13997 if(this.mode == 'local'){
13998 this.selectedIndex = -1;
14000 this.store.clearFilter();
14003 if(this.specialFilter){
14004 this.fireEvent('specialfilter', this);
14009 this.store.filter(this.displayField, q);
14012 this.store.fireEvent("datachanged", this.store);
14019 this.store.baseParams[this.queryParam] = q;
14021 var options = {params : this.getParams(q)};
14024 options.add = true;
14025 options.params.start = this.page * this.pageSize;
14028 this.store.load(options);
14031 * this code will make the page width larger, at the beginning, the list not align correctly,
14032 * we should expand the list on onLoad
14033 * so command out it
14038 this.selectedIndex = -1;
14043 this.loadNext = false;
14047 getParams : function(q){
14049 //p[this.queryParam] = q;
14053 p.limit = this.pageSize;
14059 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14061 collapse : function(){
14062 if(!this.isExpanded()){
14068 this.hasFocus = false;
14072 this.cancelBtn.hide();
14073 this.trigger.show();
14076 this.tickableInputEl().dom.value = '';
14077 this.tickableInputEl().blur();
14082 Roo.get(document).un('mousedown', this.collapseIf, this);
14083 Roo.get(document).un('mousewheel', this.collapseIf, this);
14084 if (!this.editable) {
14085 Roo.get(document).un('keydown', this.listKeyPress, this);
14087 this.fireEvent('collapse', this);
14093 collapseIf : function(e){
14094 var in_combo = e.within(this.el);
14095 var in_list = e.within(this.list);
14096 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14098 if (in_combo || in_list || is_list) {
14099 //e.stopPropagation();
14104 this.onTickableFooterButtonClick(e, false, false);
14112 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14114 expand : function(){
14116 if(this.isExpanded() || !this.hasFocus){
14120 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14121 this.list.setWidth(lw);
14127 this.restrictHeight();
14131 this.tickItems = Roo.apply([], this.item);
14134 this.cancelBtn.show();
14135 this.trigger.hide();
14138 this.tickableInputEl().focus();
14143 Roo.get(document).on('mousedown', this.collapseIf, this);
14144 Roo.get(document).on('mousewheel', this.collapseIf, this);
14145 if (!this.editable) {
14146 Roo.get(document).on('keydown', this.listKeyPress, this);
14149 this.fireEvent('expand', this);
14153 // Implements the default empty TriggerField.onTriggerClick function
14154 onTriggerClick : function(e)
14156 Roo.log('trigger click');
14158 if(this.disabled || !this.triggerList){
14163 this.loadNext = false;
14165 if(this.isExpanded()){
14167 if (!this.blockFocus) {
14168 this.inputEl().focus();
14172 this.hasFocus = true;
14173 if(this.triggerAction == 'all') {
14174 this.doQuery(this.allQuery, true);
14176 this.doQuery(this.getRawValue());
14178 if (!this.blockFocus) {
14179 this.inputEl().focus();
14184 onTickableTriggerClick : function(e)
14191 this.loadNext = false;
14192 this.hasFocus = true;
14194 if(this.triggerAction == 'all') {
14195 this.doQuery(this.allQuery, true);
14197 this.doQuery(this.getRawValue());
14201 onSearchFieldClick : function(e)
14203 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14204 this.onTickableFooterButtonClick(e, false, false);
14208 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14213 this.loadNext = false;
14214 this.hasFocus = true;
14216 if(this.triggerAction == 'all') {
14217 this.doQuery(this.allQuery, true);
14219 this.doQuery(this.getRawValue());
14223 listKeyPress : function(e)
14225 //Roo.log('listkeypress');
14226 // scroll to first matching element based on key pres..
14227 if (e.isSpecialKey()) {
14230 var k = String.fromCharCode(e.getKey()).toUpperCase();
14233 var csel = this.view.getSelectedNodes();
14234 var cselitem = false;
14236 var ix = this.view.indexOf(csel[0]);
14237 cselitem = this.store.getAt(ix);
14238 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14244 this.store.each(function(v) {
14246 // start at existing selection.
14247 if (cselitem.id == v.id) {
14253 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14254 match = this.store.indexOf(v);
14260 if (match === false) {
14261 return true; // no more action?
14264 this.view.select(match);
14265 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14266 sn.scrollIntoView(sn.dom.parentNode, false);
14269 onViewScroll : function(e, t){
14271 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){
14275 this.hasQuery = true;
14277 this.loading = this.list.select('.loading', true).first();
14279 if(this.loading === null){
14280 this.list.createChild({
14282 cls: 'loading roo-select2-more-results roo-select2-active',
14283 html: 'Loading more results...'
14286 this.loading = this.list.select('.loading', true).first();
14288 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14290 this.loading.hide();
14293 this.loading.show();
14298 this.loadNext = true;
14300 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14305 addItem : function(o)
14307 var dv = ''; // display value
14309 if (this.displayField) {
14310 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14312 // this is an error condition!!!
14313 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14320 var choice = this.choices.createChild({
14322 cls: 'roo-select2-search-choice',
14331 cls: 'roo-select2-search-choice-close fa fa-times',
14336 }, this.searchField);
14338 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14340 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14348 this.inputEl().dom.value = '';
14353 onRemoveItem : function(e, _self, o)
14355 e.preventDefault();
14357 this.lastItem = Roo.apply([], this.item);
14359 var index = this.item.indexOf(o.data) * 1;
14362 Roo.log('not this item?!');
14366 this.item.splice(index, 1);
14371 this.fireEvent('remove', this, e);
14377 syncValue : function()
14379 if(!this.item.length){
14386 Roo.each(this.item, function(i){
14387 if(_this.valueField){
14388 value.push(i[_this.valueField]);
14395 this.value = value.join(',');
14397 if(this.hiddenField){
14398 this.hiddenField.dom.value = this.value;
14401 this.store.fireEvent("datachanged", this.store);
14406 clearItem : function()
14408 if(!this.multiple){
14414 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14422 if(this.tickable && !Roo.isTouch){
14423 this.view.refresh();
14427 inputEl: function ()
14429 if(Roo.isIOS && this.useNativeIOS){
14430 return this.el.select('select.roo-ios-select', true).first();
14433 if(Roo.isTouch && this.mobileTouchView){
14434 return this.el.select('input.form-control',true).first();
14438 return this.searchField;
14441 return this.el.select('input.form-control',true).first();
14444 onTickableFooterButtonClick : function(e, btn, el)
14446 e.preventDefault();
14448 this.lastItem = Roo.apply([], this.item);
14450 if(btn && btn.name == 'cancel'){
14451 this.tickItems = Roo.apply([], this.item);
14460 Roo.each(this.tickItems, function(o){
14468 validate : function()
14470 var v = this.getRawValue();
14473 v = this.getValue();
14476 if(this.disabled || this.allowBlank || v.length){
14481 this.markInvalid();
14485 tickableInputEl : function()
14487 if(!this.tickable || !this.editable){
14488 return this.inputEl();
14491 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14495 getAutoCreateTouchView : function()
14500 cls: 'form-group' //input-group
14506 type : this.inputType,
14507 cls : 'form-control x-combo-noedit',
14508 autocomplete: 'new-password',
14509 placeholder : this.placeholder || '',
14514 input.name = this.name;
14518 input.cls += ' input-' + this.size;
14521 if (this.disabled) {
14522 input.disabled = true;
14533 inputblock.cls += ' input-group';
14535 inputblock.cn.unshift({
14537 cls : 'input-group-addon',
14542 if(this.removable && !this.multiple){
14543 inputblock.cls += ' roo-removable';
14545 inputblock.cn.push({
14548 cls : 'roo-combo-removable-btn close'
14552 if(this.hasFeedback && !this.allowBlank){
14554 inputblock.cls += ' has-feedback';
14556 inputblock.cn.push({
14558 cls: 'glyphicon form-control-feedback'
14565 inputblock.cls += (this.before) ? '' : ' input-group';
14567 inputblock.cn.push({
14569 cls : 'input-group-addon',
14580 cls: 'form-hidden-field'
14594 cls: 'form-hidden-field'
14598 cls: 'roo-select2-choices',
14602 cls: 'roo-select2-search-field',
14615 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14621 if(!this.multiple && this.showToggleBtn){
14628 if (this.caret != false) {
14631 cls: 'fa fa-' + this.caret
14638 cls : 'input-group-addon btn dropdown-toggle',
14643 cls: 'combobox-clear',
14657 combobox.cls += ' roo-select2-container-multi';
14660 var align = this.labelAlign || this.parentLabelAlign();
14662 if (align ==='left' && this.fieldLabel.length) {
14667 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14668 tooltip : 'This field is required'
14672 cls : 'control-label',
14673 html : this.fieldLabel
14684 var labelCfg = cfg.cn[1];
14685 var contentCfg = cfg.cn[2];
14688 if(this.indicatorpos == 'right'){
14692 cls : 'control-label',
14693 html : this.fieldLabel,
14697 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14698 tooltip : 'This field is required'
14711 labelCfg = cfg.cn[0];
14712 contentCfg = cfg.cn[2];
14714 if(this.labelWidth > 12){
14715 labelCfg.style = "width: " + this.labelWidth + 'px';
14718 if(this.labelWidth < 13 && this.labelmd == 0){
14719 this.labelmd = this.labelWidth;
14722 if(this.labellg > 0){
14723 labelCfg.cls += ' col-lg-' + this.labellg;
14724 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14727 if(this.labelmd > 0){
14728 labelCfg.cls += ' col-md-' + this.labelmd;
14729 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14732 if(this.labelsm > 0){
14733 labelCfg.cls += ' col-sm-' + this.labelsm;
14734 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14737 if(this.labelxs > 0){
14738 labelCfg.cls += ' col-xs-' + this.labelxs;
14739 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14743 } else if ( this.fieldLabel.length) {
14747 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14748 tooltip : 'This field is required'
14752 cls : 'control-label',
14753 html : this.fieldLabel
14764 if(this.indicatorpos == 'right'){
14768 cls : 'control-label',
14769 html : this.fieldLabel,
14773 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14774 tooltip : 'This field is required'
14791 var settings = this;
14793 ['xs','sm','md','lg'].map(function(size){
14794 if (settings[size]) {
14795 cfg.cls += ' col-' + size + '-' + settings[size];
14802 initTouchView : function()
14804 this.renderTouchView();
14806 this.touchViewEl.on('scroll', function(){
14807 this.el.dom.scrollTop = 0;
14810 this.originalValue = this.getValue();
14812 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14814 this.inputEl().on("click", this.showTouchView, this);
14815 if (this.triggerEl) {
14816 this.triggerEl.on("click", this.showTouchView, this);
14820 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14821 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14823 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14825 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14826 this.store.on('load', this.onTouchViewLoad, this);
14827 this.store.on('loadexception', this.onTouchViewLoadException, this);
14829 if(this.hiddenName){
14831 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14833 this.hiddenField.dom.value =
14834 this.hiddenValue !== undefined ? this.hiddenValue :
14835 this.value !== undefined ? this.value : '';
14837 this.el.dom.removeAttribute('name');
14838 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14842 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14843 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14846 if(this.removable && !this.multiple){
14847 var close = this.closeTriggerEl();
14849 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14850 close.on('click', this.removeBtnClick, this, close);
14854 * fix the bug in Safari iOS8
14856 this.inputEl().on("focus", function(e){
14857 document.activeElement.blur();
14865 renderTouchView : function()
14867 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14868 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14870 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14871 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14873 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14874 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14875 this.touchViewBodyEl.setStyle('overflow', 'auto');
14877 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14878 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14880 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14881 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14885 showTouchView : function()
14891 this.touchViewHeaderEl.hide();
14893 if(this.modalTitle.length){
14894 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14895 this.touchViewHeaderEl.show();
14898 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14899 this.touchViewEl.show();
14901 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14902 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14903 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14905 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14907 if(this.modalTitle.length){
14908 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14911 this.touchViewBodyEl.setHeight(bodyHeight);
14915 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14917 this.touchViewEl.addClass('in');
14920 this.doTouchViewQuery();
14924 hideTouchView : function()
14926 this.touchViewEl.removeClass('in');
14930 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14932 this.touchViewEl.setStyle('display', 'none');
14937 setTouchViewValue : function()
14944 Roo.each(this.tickItems, function(o){
14949 this.hideTouchView();
14952 doTouchViewQuery : function()
14961 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14965 if(!this.alwaysQuery || this.mode == 'local'){
14966 this.onTouchViewLoad();
14973 onTouchViewBeforeLoad : function(combo,opts)
14979 onTouchViewLoad : function()
14981 if(this.store.getCount() < 1){
14982 this.onTouchViewEmptyResults();
14986 this.clearTouchView();
14988 var rawValue = this.getRawValue();
14990 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14992 this.tickItems = [];
14994 this.store.data.each(function(d, rowIndex){
14995 var row = this.touchViewListGroup.createChild(template);
14997 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14998 row.addClass(d.data.cls);
15001 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15004 html : d.data[this.displayField]
15007 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15008 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15011 row.removeClass('selected');
15012 if(!this.multiple && this.valueField &&
15013 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15016 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15017 row.addClass('selected');
15020 if(this.multiple && this.valueField &&
15021 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15025 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15026 this.tickItems.push(d.data);
15029 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15033 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15035 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15037 if(this.modalTitle.length){
15038 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15041 var listHeight = this.touchViewListGroup.getHeight();
15045 if(firstChecked && listHeight > bodyHeight){
15046 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15051 onTouchViewLoadException : function()
15053 this.hideTouchView();
15056 onTouchViewEmptyResults : function()
15058 this.clearTouchView();
15060 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15062 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15066 clearTouchView : function()
15068 this.touchViewListGroup.dom.innerHTML = '';
15071 onTouchViewClick : function(e, el, o)
15073 e.preventDefault();
15076 var rowIndex = o.rowIndex;
15078 var r = this.store.getAt(rowIndex);
15080 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15082 if(!this.multiple){
15083 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15084 c.dom.removeAttribute('checked');
15087 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15089 this.setFromData(r.data);
15091 var close = this.closeTriggerEl();
15097 this.hideTouchView();
15099 this.fireEvent('select', this, r, rowIndex);
15104 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15105 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15106 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15110 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15111 this.addItem(r.data);
15112 this.tickItems.push(r.data);
15116 getAutoCreateNativeIOS : function()
15119 cls: 'form-group' //input-group,
15124 cls : 'roo-ios-select'
15128 combobox.name = this.name;
15131 if (this.disabled) {
15132 combobox.disabled = true;
15135 var settings = this;
15137 ['xs','sm','md','lg'].map(function(size){
15138 if (settings[size]) {
15139 cfg.cls += ' col-' + size + '-' + settings[size];
15149 initIOSView : function()
15151 this.store.on('load', this.onIOSViewLoad, this);
15156 onIOSViewLoad : function()
15158 if(this.store.getCount() < 1){
15162 this.clearIOSView();
15164 if(this.allowBlank) {
15166 var default_text = '-- SELECT --';
15168 var opt = this.inputEl().createChild({
15171 html : default_text
15175 o[this.valueField] = 0;
15176 o[this.displayField] = default_text;
15178 this.ios_options.push({
15185 this.store.data.each(function(d, rowIndex){
15189 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15190 html = d.data[this.displayField];
15195 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15196 value = d.data[this.valueField];
15205 if(this.value == d.data[this.valueField]){
15206 option['selected'] = true;
15209 var opt = this.inputEl().createChild(option);
15211 this.ios_options.push({
15218 this.inputEl().on('change', function(){
15219 this.fireEvent('select', this);
15224 clearIOSView: function()
15226 this.inputEl().dom.innerHTML = '';
15228 this.ios_options = [];
15231 setIOSValue: function(v)
15235 if(!this.ios_options){
15239 Roo.each(this.ios_options, function(opts){
15241 opts.el.dom.removeAttribute('selected');
15243 if(opts.data[this.valueField] != v){
15247 opts.el.dom.setAttribute('selected', true);
15253 * @cfg {Boolean} grow
15257 * @cfg {Number} growMin
15261 * @cfg {Number} growMax
15270 Roo.apply(Roo.bootstrap.ComboBox, {
15274 cls: 'modal-header',
15296 cls: 'list-group-item',
15300 cls: 'roo-combobox-list-group-item-value'
15304 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15318 listItemCheckbox : {
15320 cls: 'list-group-item',
15324 cls: 'roo-combobox-list-group-item-value'
15328 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15344 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15349 cls: 'modal-footer',
15357 cls: 'col-xs-6 text-left',
15360 cls: 'btn btn-danger roo-touch-view-cancel',
15366 cls: 'col-xs-6 text-right',
15369 cls: 'btn btn-success roo-touch-view-ok',
15380 Roo.apply(Roo.bootstrap.ComboBox, {
15382 touchViewTemplate : {
15384 cls: 'modal fade roo-combobox-touch-view',
15388 cls: 'modal-dialog',
15389 style : 'position:fixed', // we have to fix position....
15393 cls: 'modal-content',
15395 Roo.bootstrap.ComboBox.header,
15396 Roo.bootstrap.ComboBox.body,
15397 Roo.bootstrap.ComboBox.footer
15406 * Ext JS Library 1.1.1
15407 * Copyright(c) 2006-2007, Ext JS, LLC.
15409 * Originally Released Under LGPL - original licence link has changed is not relivant.
15412 * <script type="text/javascript">
15417 * @extends Roo.util.Observable
15418 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15419 * This class also supports single and multi selection modes. <br>
15420 * Create a data model bound view:
15422 var store = new Roo.data.Store(...);
15424 var view = new Roo.View({
15426 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15428 singleSelect: true,
15429 selectedClass: "ydataview-selected",
15433 // listen for node click?
15434 view.on("click", function(vw, index, node, e){
15435 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15439 dataModel.load("foobar.xml");
15441 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15443 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15444 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15446 * Note: old style constructor is still suported (container, template, config)
15449 * Create a new View
15450 * @param {Object} config The config object
15453 Roo.View = function(config, depreciated_tpl, depreciated_config){
15455 this.parent = false;
15457 if (typeof(depreciated_tpl) == 'undefined') {
15458 // new way.. - universal constructor.
15459 Roo.apply(this, config);
15460 this.el = Roo.get(this.el);
15463 this.el = Roo.get(config);
15464 this.tpl = depreciated_tpl;
15465 Roo.apply(this, depreciated_config);
15467 this.wrapEl = this.el.wrap().wrap();
15468 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15471 if(typeof(this.tpl) == "string"){
15472 this.tpl = new Roo.Template(this.tpl);
15474 // support xtype ctors..
15475 this.tpl = new Roo.factory(this.tpl, Roo);
15479 this.tpl.compile();
15484 * @event beforeclick
15485 * Fires before a click is processed. Returns false to cancel the default action.
15486 * @param {Roo.View} this
15487 * @param {Number} index The index of the target node
15488 * @param {HTMLElement} node The target node
15489 * @param {Roo.EventObject} e The raw event object
15491 "beforeclick" : true,
15494 * Fires when a template node is clicked.
15495 * @param {Roo.View} this
15496 * @param {Number} index The index of the target node
15497 * @param {HTMLElement} node The target node
15498 * @param {Roo.EventObject} e The raw event object
15503 * Fires when a template node is double clicked.
15504 * @param {Roo.View} this
15505 * @param {Number} index The index of the target node
15506 * @param {HTMLElement} node The target node
15507 * @param {Roo.EventObject} e The raw event object
15511 * @event contextmenu
15512 * Fires when a template node is right clicked.
15513 * @param {Roo.View} this
15514 * @param {Number} index The index of the target node
15515 * @param {HTMLElement} node The target node
15516 * @param {Roo.EventObject} e The raw event object
15518 "contextmenu" : true,
15520 * @event selectionchange
15521 * Fires when the selected nodes change.
15522 * @param {Roo.View} this
15523 * @param {Array} selections Array of the selected nodes
15525 "selectionchange" : true,
15528 * @event beforeselect
15529 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15530 * @param {Roo.View} this
15531 * @param {HTMLElement} node The node to be selected
15532 * @param {Array} selections Array of currently selected nodes
15534 "beforeselect" : true,
15536 * @event preparedata
15537 * Fires on every row to render, to allow you to change the data.
15538 * @param {Roo.View} this
15539 * @param {Object} data to be rendered (change this)
15541 "preparedata" : true
15549 "click": this.onClick,
15550 "dblclick": this.onDblClick,
15551 "contextmenu": this.onContextMenu,
15555 this.selections = [];
15557 this.cmp = new Roo.CompositeElementLite([]);
15559 this.store = Roo.factory(this.store, Roo.data);
15560 this.setStore(this.store, true);
15563 if ( this.footer && this.footer.xtype) {
15565 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15567 this.footer.dataSource = this.store;
15568 this.footer.container = fctr;
15569 this.footer = Roo.factory(this.footer, Roo);
15570 fctr.insertFirst(this.el);
15572 // this is a bit insane - as the paging toolbar seems to detach the el..
15573 // dom.parentNode.parentNode.parentNode
15574 // they get detached?
15578 Roo.View.superclass.constructor.call(this);
15583 Roo.extend(Roo.View, Roo.util.Observable, {
15586 * @cfg {Roo.data.Store} store Data store to load data from.
15591 * @cfg {String|Roo.Element} el The container element.
15596 * @cfg {String|Roo.Template} tpl The template used by this View
15600 * @cfg {String} dataName the named area of the template to use as the data area
15601 * Works with domtemplates roo-name="name"
15605 * @cfg {String} selectedClass The css class to add to selected nodes
15607 selectedClass : "x-view-selected",
15609 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15614 * @cfg {String} text to display on mask (default Loading)
15618 * @cfg {Boolean} multiSelect Allow multiple selection
15620 multiSelect : false,
15622 * @cfg {Boolean} singleSelect Allow single selection
15624 singleSelect: false,
15627 * @cfg {Boolean} toggleSelect - selecting
15629 toggleSelect : false,
15632 * @cfg {Boolean} tickable - selecting
15637 * Returns the element this view is bound to.
15638 * @return {Roo.Element}
15640 getEl : function(){
15641 return this.wrapEl;
15647 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15649 refresh : function(){
15650 //Roo.log('refresh');
15653 // if we are using something like 'domtemplate', then
15654 // the what gets used is:
15655 // t.applySubtemplate(NAME, data, wrapping data..)
15656 // the outer template then get' applied with
15657 // the store 'extra data'
15658 // and the body get's added to the
15659 // roo-name="data" node?
15660 // <span class='roo-tpl-{name}'></span> ?????
15664 this.clearSelections();
15665 this.el.update("");
15667 var records = this.store.getRange();
15668 if(records.length < 1) {
15670 // is this valid?? = should it render a template??
15672 this.el.update(this.emptyText);
15676 if (this.dataName) {
15677 this.el.update(t.apply(this.store.meta)); //????
15678 el = this.el.child('.roo-tpl-' + this.dataName);
15681 for(var i = 0, len = records.length; i < len; i++){
15682 var data = this.prepareData(records[i].data, i, records[i]);
15683 this.fireEvent("preparedata", this, data, i, records[i]);
15685 var d = Roo.apply({}, data);
15688 Roo.apply(d, {'roo-id' : Roo.id()});
15692 Roo.each(this.parent.item, function(item){
15693 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15696 Roo.apply(d, {'roo-data-checked' : 'checked'});
15700 html[html.length] = Roo.util.Format.trim(
15702 t.applySubtemplate(this.dataName, d, this.store.meta) :
15709 el.update(html.join(""));
15710 this.nodes = el.dom.childNodes;
15711 this.updateIndexes(0);
15716 * Function to override to reformat the data that is sent to
15717 * the template for each node.
15718 * DEPRICATED - use the preparedata event handler.
15719 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15720 * a JSON object for an UpdateManager bound view).
15722 prepareData : function(data, index, record)
15724 this.fireEvent("preparedata", this, data, index, record);
15728 onUpdate : function(ds, record){
15729 // Roo.log('on update');
15730 this.clearSelections();
15731 var index = this.store.indexOf(record);
15732 var n = this.nodes[index];
15733 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15734 n.parentNode.removeChild(n);
15735 this.updateIndexes(index, index);
15741 onAdd : function(ds, records, index)
15743 //Roo.log(['on Add', ds, records, index] );
15744 this.clearSelections();
15745 if(this.nodes.length == 0){
15749 var n = this.nodes[index];
15750 for(var i = 0, len = records.length; i < len; i++){
15751 var d = this.prepareData(records[i].data, i, records[i]);
15753 this.tpl.insertBefore(n, d);
15756 this.tpl.append(this.el, d);
15759 this.updateIndexes(index);
15762 onRemove : function(ds, record, index){
15763 // Roo.log('onRemove');
15764 this.clearSelections();
15765 var el = this.dataName ?
15766 this.el.child('.roo-tpl-' + this.dataName) :
15769 el.dom.removeChild(this.nodes[index]);
15770 this.updateIndexes(index);
15774 * Refresh an individual node.
15775 * @param {Number} index
15777 refreshNode : function(index){
15778 this.onUpdate(this.store, this.store.getAt(index));
15781 updateIndexes : function(startIndex, endIndex){
15782 var ns = this.nodes;
15783 startIndex = startIndex || 0;
15784 endIndex = endIndex || ns.length - 1;
15785 for(var i = startIndex; i <= endIndex; i++){
15786 ns[i].nodeIndex = i;
15791 * Changes the data store this view uses and refresh the view.
15792 * @param {Store} store
15794 setStore : function(store, initial){
15795 if(!initial && this.store){
15796 this.store.un("datachanged", this.refresh);
15797 this.store.un("add", this.onAdd);
15798 this.store.un("remove", this.onRemove);
15799 this.store.un("update", this.onUpdate);
15800 this.store.un("clear", this.refresh);
15801 this.store.un("beforeload", this.onBeforeLoad);
15802 this.store.un("load", this.onLoad);
15803 this.store.un("loadexception", this.onLoad);
15807 store.on("datachanged", this.refresh, this);
15808 store.on("add", this.onAdd, this);
15809 store.on("remove", this.onRemove, this);
15810 store.on("update", this.onUpdate, this);
15811 store.on("clear", this.refresh, this);
15812 store.on("beforeload", this.onBeforeLoad, this);
15813 store.on("load", this.onLoad, this);
15814 store.on("loadexception", this.onLoad, this);
15822 * onbeforeLoad - masks the loading area.
15825 onBeforeLoad : function(store,opts)
15827 //Roo.log('onBeforeLoad');
15829 this.el.update("");
15831 this.el.mask(this.mask ? this.mask : "Loading" );
15833 onLoad : function ()
15840 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15841 * @param {HTMLElement} node
15842 * @return {HTMLElement} The template node
15844 findItemFromChild : function(node){
15845 var el = this.dataName ?
15846 this.el.child('.roo-tpl-' + this.dataName,true) :
15849 if(!node || node.parentNode == el){
15852 var p = node.parentNode;
15853 while(p && p != el){
15854 if(p.parentNode == el){
15863 onClick : function(e){
15864 var item = this.findItemFromChild(e.getTarget());
15866 var index = this.indexOf(item);
15867 if(this.onItemClick(item, index, e) !== false){
15868 this.fireEvent("click", this, index, item, e);
15871 this.clearSelections();
15876 onContextMenu : function(e){
15877 var item = this.findItemFromChild(e.getTarget());
15879 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15884 onDblClick : function(e){
15885 var item = this.findItemFromChild(e.getTarget());
15887 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15891 onItemClick : function(item, index, e)
15893 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15896 if (this.toggleSelect) {
15897 var m = this.isSelected(item) ? 'unselect' : 'select';
15900 _t[m](item, true, false);
15903 if(this.multiSelect || this.singleSelect){
15904 if(this.multiSelect && e.shiftKey && this.lastSelection){
15905 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15907 this.select(item, this.multiSelect && e.ctrlKey);
15908 this.lastSelection = item;
15911 if(!this.tickable){
15912 e.preventDefault();
15920 * Get the number of selected nodes.
15923 getSelectionCount : function(){
15924 return this.selections.length;
15928 * Get the currently selected nodes.
15929 * @return {Array} An array of HTMLElements
15931 getSelectedNodes : function(){
15932 return this.selections;
15936 * Get the indexes of the selected nodes.
15939 getSelectedIndexes : function(){
15940 var indexes = [], s = this.selections;
15941 for(var i = 0, len = s.length; i < len; i++){
15942 indexes.push(s[i].nodeIndex);
15948 * Clear all selections
15949 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15951 clearSelections : function(suppressEvent){
15952 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15953 this.cmp.elements = this.selections;
15954 this.cmp.removeClass(this.selectedClass);
15955 this.selections = [];
15956 if(!suppressEvent){
15957 this.fireEvent("selectionchange", this, this.selections);
15963 * Returns true if the passed node is selected
15964 * @param {HTMLElement/Number} node The node or node index
15965 * @return {Boolean}
15967 isSelected : function(node){
15968 var s = this.selections;
15972 node = this.getNode(node);
15973 return s.indexOf(node) !== -1;
15978 * @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
15979 * @param {Boolean} keepExisting (optional) true to keep existing selections
15980 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15982 select : function(nodeInfo, keepExisting, suppressEvent){
15983 if(nodeInfo instanceof Array){
15985 this.clearSelections(true);
15987 for(var i = 0, len = nodeInfo.length; i < len; i++){
15988 this.select(nodeInfo[i], true, true);
15992 var node = this.getNode(nodeInfo);
15993 if(!node || this.isSelected(node)){
15994 return; // already selected.
15997 this.clearSelections(true);
16000 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16001 Roo.fly(node).addClass(this.selectedClass);
16002 this.selections.push(node);
16003 if(!suppressEvent){
16004 this.fireEvent("selectionchange", this, this.selections);
16012 * @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
16013 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16014 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16016 unselect : function(nodeInfo, keepExisting, suppressEvent)
16018 if(nodeInfo instanceof Array){
16019 Roo.each(this.selections, function(s) {
16020 this.unselect(s, nodeInfo);
16024 var node = this.getNode(nodeInfo);
16025 if(!node || !this.isSelected(node)){
16026 //Roo.log("not selected");
16027 return; // not selected.
16031 Roo.each(this.selections, function(s) {
16033 Roo.fly(node).removeClass(this.selectedClass);
16040 this.selections= ns;
16041 this.fireEvent("selectionchange", this, this.selections);
16045 * Gets a template node.
16046 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16047 * @return {HTMLElement} The node or null if it wasn't found
16049 getNode : function(nodeInfo){
16050 if(typeof nodeInfo == "string"){
16051 return document.getElementById(nodeInfo);
16052 }else if(typeof nodeInfo == "number"){
16053 return this.nodes[nodeInfo];
16059 * Gets a range template nodes.
16060 * @param {Number} startIndex
16061 * @param {Number} endIndex
16062 * @return {Array} An array of nodes
16064 getNodes : function(start, end){
16065 var ns = this.nodes;
16066 start = start || 0;
16067 end = typeof end == "undefined" ? ns.length - 1 : end;
16070 for(var i = start; i <= end; i++){
16074 for(var i = start; i >= end; i--){
16082 * Finds the index of the passed node
16083 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16084 * @return {Number} The index of the node or -1
16086 indexOf : function(node){
16087 node = this.getNode(node);
16088 if(typeof node.nodeIndex == "number"){
16089 return node.nodeIndex;
16091 var ns = this.nodes;
16092 for(var i = 0, len = ns.length; i < len; i++){
16103 * based on jquery fullcalendar
16107 Roo.bootstrap = Roo.bootstrap || {};
16109 * @class Roo.bootstrap.Calendar
16110 * @extends Roo.bootstrap.Component
16111 * Bootstrap Calendar class
16112 * @cfg {Boolean} loadMask (true|false) default false
16113 * @cfg {Object} header generate the user specific header of the calendar, default false
16116 * Create a new Container
16117 * @param {Object} config The config object
16122 Roo.bootstrap.Calendar = function(config){
16123 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16127 * Fires when a date is selected
16128 * @param {DatePicker} this
16129 * @param {Date} date The selected date
16133 * @event monthchange
16134 * Fires when the displayed month changes
16135 * @param {DatePicker} this
16136 * @param {Date} date The selected month
16138 'monthchange': true,
16140 * @event evententer
16141 * Fires when mouse over an event
16142 * @param {Calendar} this
16143 * @param {event} Event
16145 'evententer': true,
16147 * @event eventleave
16148 * Fires when the mouse leaves an
16149 * @param {Calendar} this
16152 'eventleave': true,
16154 * @event eventclick
16155 * Fires when the mouse click an
16156 * @param {Calendar} this
16165 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16168 * @cfg {Number} startDay
16169 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16177 getAutoCreate : function(){
16180 var fc_button = function(name, corner, style, content ) {
16181 return Roo.apply({},{
16183 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16185 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16188 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16199 style : 'width:100%',
16206 cls : 'fc-header-left',
16208 fc_button('prev', 'left', 'arrow', '‹' ),
16209 fc_button('next', 'right', 'arrow', '›' ),
16210 { tag: 'span', cls: 'fc-header-space' },
16211 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16219 cls : 'fc-header-center',
16223 cls: 'fc-header-title',
16226 html : 'month / year'
16234 cls : 'fc-header-right',
16236 /* fc_button('month', 'left', '', 'month' ),
16237 fc_button('week', '', '', 'week' ),
16238 fc_button('day', 'right', '', 'day' )
16250 header = this.header;
16253 var cal_heads = function() {
16255 // fixme - handle this.
16257 for (var i =0; i < Date.dayNames.length; i++) {
16258 var d = Date.dayNames[i];
16261 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16262 html : d.substring(0,3)
16266 ret[0].cls += ' fc-first';
16267 ret[6].cls += ' fc-last';
16270 var cal_cell = function(n) {
16273 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16278 cls: 'fc-day-number',
16282 cls: 'fc-day-content',
16286 style: 'position: relative;' // height: 17px;
16298 var cal_rows = function() {
16301 for (var r = 0; r < 6; r++) {
16308 for (var i =0; i < Date.dayNames.length; i++) {
16309 var d = Date.dayNames[i];
16310 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16313 row.cn[0].cls+=' fc-first';
16314 row.cn[0].cn[0].style = 'min-height:90px';
16315 row.cn[6].cls+=' fc-last';
16319 ret[0].cls += ' fc-first';
16320 ret[4].cls += ' fc-prev-last';
16321 ret[5].cls += ' fc-last';
16328 cls: 'fc-border-separate',
16329 style : 'width:100%',
16337 cls : 'fc-first fc-last',
16355 cls : 'fc-content',
16356 style : "position: relative;",
16359 cls : 'fc-view fc-view-month fc-grid',
16360 style : 'position: relative',
16361 unselectable : 'on',
16364 cls : 'fc-event-container',
16365 style : 'position:absolute;z-index:8;top:0;left:0;'
16383 initEvents : function()
16386 throw "can not find store for calendar";
16392 style: "text-align:center",
16396 style: "background-color:white;width:50%;margin:250 auto",
16400 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16411 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16413 var size = this.el.select('.fc-content', true).first().getSize();
16414 this.maskEl.setSize(size.width, size.height);
16415 this.maskEl.enableDisplayMode("block");
16416 if(!this.loadMask){
16417 this.maskEl.hide();
16420 this.store = Roo.factory(this.store, Roo.data);
16421 this.store.on('load', this.onLoad, this);
16422 this.store.on('beforeload', this.onBeforeLoad, this);
16426 this.cells = this.el.select('.fc-day',true);
16427 //Roo.log(this.cells);
16428 this.textNodes = this.el.query('.fc-day-number');
16429 this.cells.addClassOnOver('fc-state-hover');
16431 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16432 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16433 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16434 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16436 this.on('monthchange', this.onMonthChange, this);
16438 this.update(new Date().clearTime());
16441 resize : function() {
16442 var sz = this.el.getSize();
16444 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16445 this.el.select('.fc-day-content div',true).setHeight(34);
16450 showPrevMonth : function(e){
16451 this.update(this.activeDate.add("mo", -1));
16453 showToday : function(e){
16454 this.update(new Date().clearTime());
16457 showNextMonth : function(e){
16458 this.update(this.activeDate.add("mo", 1));
16462 showPrevYear : function(){
16463 this.update(this.activeDate.add("y", -1));
16467 showNextYear : function(){
16468 this.update(this.activeDate.add("y", 1));
16473 update : function(date)
16475 var vd = this.activeDate;
16476 this.activeDate = date;
16477 // if(vd && this.el){
16478 // var t = date.getTime();
16479 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16480 // Roo.log('using add remove');
16482 // this.fireEvent('monthchange', this, date);
16484 // this.cells.removeClass("fc-state-highlight");
16485 // this.cells.each(function(c){
16486 // if(c.dateValue == t){
16487 // c.addClass("fc-state-highlight");
16488 // setTimeout(function(){
16489 // try{c.dom.firstChild.focus();}catch(e){}
16499 var days = date.getDaysInMonth();
16501 var firstOfMonth = date.getFirstDateOfMonth();
16502 var startingPos = firstOfMonth.getDay()-this.startDay;
16504 if(startingPos < this.startDay){
16508 var pm = date.add(Date.MONTH, -1);
16509 var prevStart = pm.getDaysInMonth()-startingPos;
16511 this.cells = this.el.select('.fc-day',true);
16512 this.textNodes = this.el.query('.fc-day-number');
16513 this.cells.addClassOnOver('fc-state-hover');
16515 var cells = this.cells.elements;
16516 var textEls = this.textNodes;
16518 Roo.each(cells, function(cell){
16519 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16522 days += startingPos;
16524 // convert everything to numbers so it's fast
16525 var day = 86400000;
16526 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16529 //Roo.log(prevStart);
16531 var today = new Date().clearTime().getTime();
16532 var sel = date.clearTime().getTime();
16533 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16534 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16535 var ddMatch = this.disabledDatesRE;
16536 var ddText = this.disabledDatesText;
16537 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16538 var ddaysText = this.disabledDaysText;
16539 var format = this.format;
16541 var setCellClass = function(cal, cell){
16545 //Roo.log('set Cell Class');
16547 var t = d.getTime();
16551 cell.dateValue = t;
16553 cell.className += " fc-today";
16554 cell.className += " fc-state-highlight";
16555 cell.title = cal.todayText;
16558 // disable highlight in other month..
16559 //cell.className += " fc-state-highlight";
16564 cell.className = " fc-state-disabled";
16565 cell.title = cal.minText;
16569 cell.className = " fc-state-disabled";
16570 cell.title = cal.maxText;
16574 if(ddays.indexOf(d.getDay()) != -1){
16575 cell.title = ddaysText;
16576 cell.className = " fc-state-disabled";
16579 if(ddMatch && format){
16580 var fvalue = d.dateFormat(format);
16581 if(ddMatch.test(fvalue)){
16582 cell.title = ddText.replace("%0", fvalue);
16583 cell.className = " fc-state-disabled";
16587 if (!cell.initialClassName) {
16588 cell.initialClassName = cell.dom.className;
16591 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16596 for(; i < startingPos; i++) {
16597 textEls[i].innerHTML = (++prevStart);
16598 d.setDate(d.getDate()+1);
16600 cells[i].className = "fc-past fc-other-month";
16601 setCellClass(this, cells[i]);
16606 for(; i < days; i++){
16607 intDay = i - startingPos + 1;
16608 textEls[i].innerHTML = (intDay);
16609 d.setDate(d.getDate()+1);
16611 cells[i].className = ''; // "x-date-active";
16612 setCellClass(this, cells[i]);
16616 for(; i < 42; i++) {
16617 textEls[i].innerHTML = (++extraDays);
16618 d.setDate(d.getDate()+1);
16620 cells[i].className = "fc-future fc-other-month";
16621 setCellClass(this, cells[i]);
16624 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16626 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16628 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16629 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16631 if(totalRows != 6){
16632 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16633 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16636 this.fireEvent('monthchange', this, date);
16640 if(!this.internalRender){
16641 var main = this.el.dom.firstChild;
16642 var w = main.offsetWidth;
16643 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16644 Roo.fly(main).setWidth(w);
16645 this.internalRender = true;
16646 // opera does not respect the auto grow header center column
16647 // then, after it gets a width opera refuses to recalculate
16648 // without a second pass
16649 if(Roo.isOpera && !this.secondPass){
16650 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16651 this.secondPass = true;
16652 this.update.defer(10, this, [date]);
16659 findCell : function(dt) {
16660 dt = dt.clearTime().getTime();
16662 this.cells.each(function(c){
16663 //Roo.log("check " +c.dateValue + '?=' + dt);
16664 if(c.dateValue == dt){
16674 findCells : function(ev) {
16675 var s = ev.start.clone().clearTime().getTime();
16677 var e= ev.end.clone().clearTime().getTime();
16680 this.cells.each(function(c){
16681 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16683 if(c.dateValue > e){
16686 if(c.dateValue < s){
16695 // findBestRow: function(cells)
16699 // for (var i =0 ; i < cells.length;i++) {
16700 // ret = Math.max(cells[i].rows || 0,ret);
16707 addItem : function(ev)
16709 // look for vertical location slot in
16710 var cells = this.findCells(ev);
16712 // ev.row = this.findBestRow(cells);
16714 // work out the location.
16718 for(var i =0; i < cells.length; i++) {
16720 cells[i].row = cells[0].row;
16723 cells[i].row = cells[i].row + 1;
16733 if (crow.start.getY() == cells[i].getY()) {
16735 crow.end = cells[i];
16752 cells[0].events.push(ev);
16754 this.calevents.push(ev);
16757 clearEvents: function() {
16759 if(!this.calevents){
16763 Roo.each(this.cells.elements, function(c){
16769 Roo.each(this.calevents, function(e) {
16770 Roo.each(e.els, function(el) {
16771 el.un('mouseenter' ,this.onEventEnter, this);
16772 el.un('mouseleave' ,this.onEventLeave, this);
16777 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16783 renderEvents: function()
16787 this.cells.each(function(c) {
16796 if(c.row != c.events.length){
16797 r = 4 - (4 - (c.row - c.events.length));
16800 c.events = ev.slice(0, r);
16801 c.more = ev.slice(r);
16803 if(c.more.length && c.more.length == 1){
16804 c.events.push(c.more.pop());
16807 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16811 this.cells.each(function(c) {
16813 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16816 for (var e = 0; e < c.events.length; e++){
16817 var ev = c.events[e];
16818 var rows = ev.rows;
16820 for(var i = 0; i < rows.length; i++) {
16822 // how many rows should it span..
16825 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16826 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16828 unselectable : "on",
16831 cls: 'fc-event-inner',
16835 // cls: 'fc-event-time',
16836 // html : cells.length > 1 ? '' : ev.time
16840 cls: 'fc-event-title',
16841 html : String.format('{0}', ev.title)
16848 cls: 'ui-resizable-handle ui-resizable-e',
16849 html : '  '
16856 cfg.cls += ' fc-event-start';
16858 if ((i+1) == rows.length) {
16859 cfg.cls += ' fc-event-end';
16862 var ctr = _this.el.select('.fc-event-container',true).first();
16863 var cg = ctr.createChild(cfg);
16865 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16866 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16868 var r = (c.more.length) ? 1 : 0;
16869 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16870 cg.setWidth(ebox.right - sbox.x -2);
16872 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16873 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16874 cg.on('click', _this.onEventClick, _this, ev);
16885 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16886 style : 'position: absolute',
16887 unselectable : "on",
16890 cls: 'fc-event-inner',
16894 cls: 'fc-event-title',
16902 cls: 'ui-resizable-handle ui-resizable-e',
16903 html : '  '
16909 var ctr = _this.el.select('.fc-event-container',true).first();
16910 var cg = ctr.createChild(cfg);
16912 var sbox = c.select('.fc-day-content',true).first().getBox();
16913 var ebox = c.select('.fc-day-content',true).first().getBox();
16915 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16916 cg.setWidth(ebox.right - sbox.x -2);
16918 cg.on('click', _this.onMoreEventClick, _this, c.more);
16928 onEventEnter: function (e, el,event,d) {
16929 this.fireEvent('evententer', this, el, event);
16932 onEventLeave: function (e, el,event,d) {
16933 this.fireEvent('eventleave', this, el, event);
16936 onEventClick: function (e, el,event,d) {
16937 this.fireEvent('eventclick', this, el, event);
16940 onMonthChange: function () {
16944 onMoreEventClick: function(e, el, more)
16948 this.calpopover.placement = 'right';
16949 this.calpopover.setTitle('More');
16951 this.calpopover.setContent('');
16953 var ctr = this.calpopover.el.select('.popover-content', true).first();
16955 Roo.each(more, function(m){
16957 cls : 'fc-event-hori fc-event-draggable',
16960 var cg = ctr.createChild(cfg);
16962 cg.on('click', _this.onEventClick, _this, m);
16965 this.calpopover.show(el);
16970 onLoad: function ()
16972 this.calevents = [];
16975 if(this.store.getCount() > 0){
16976 this.store.data.each(function(d){
16979 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16980 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16981 time : d.data.start_time,
16982 title : d.data.title,
16983 description : d.data.description,
16984 venue : d.data.venue
16989 this.renderEvents();
16991 if(this.calevents.length && this.loadMask){
16992 this.maskEl.hide();
16996 onBeforeLoad: function()
16998 this.clearEvents();
17000 this.maskEl.show();
17014 * @class Roo.bootstrap.Popover
17015 * @extends Roo.bootstrap.Component
17016 * Bootstrap Popover class
17017 * @cfg {String} html contents of the popover (or false to use children..)
17018 * @cfg {String} title of popover (or false to hide)
17019 * @cfg {String} placement how it is placed
17020 * @cfg {String} trigger click || hover (or false to trigger manually)
17021 * @cfg {String} over what (parent or false to trigger manually.)
17022 * @cfg {Number} delay - delay before showing
17025 * Create a new Popover
17026 * @param {Object} config The config object
17029 Roo.bootstrap.Popover = function(config){
17030 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17036 * After the popover show
17038 * @param {Roo.bootstrap.Popover} this
17043 * After the popover hide
17045 * @param {Roo.bootstrap.Popover} this
17051 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17053 title: 'Fill in a title',
17056 placement : 'right',
17057 trigger : 'hover', // hover
17063 can_build_overlaid : false,
17065 getChildContainer : function()
17067 return this.el.select('.popover-content',true).first();
17070 getAutoCreate : function(){
17073 cls : 'popover roo-dynamic',
17074 style: 'display:block',
17080 cls : 'popover-inner',
17084 cls: 'popover-title',
17088 cls : 'popover-content',
17099 setTitle: function(str)
17102 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17104 setContent: function(str)
17107 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17109 // as it get's added to the bottom of the page.
17110 onRender : function(ct, position)
17112 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17114 var cfg = Roo.apply({}, this.getAutoCreate());
17118 cfg.cls += ' ' + this.cls;
17121 cfg.style = this.style;
17123 //Roo.log("adding to ");
17124 this.el = Roo.get(document.body).createChild(cfg, position);
17125 // Roo.log(this.el);
17130 initEvents : function()
17132 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17133 this.el.enableDisplayMode('block');
17135 if (this.over === false) {
17138 if (this.triggers === false) {
17141 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17142 var triggers = this.trigger ? this.trigger.split(' ') : [];
17143 Roo.each(triggers, function(trigger) {
17145 if (trigger == 'click') {
17146 on_el.on('click', this.toggle, this);
17147 } else if (trigger != 'manual') {
17148 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17149 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17151 on_el.on(eventIn ,this.enter, this);
17152 on_el.on(eventOut, this.leave, this);
17163 toggle : function () {
17164 this.hoverState == 'in' ? this.leave() : this.enter();
17167 enter : function () {
17169 clearTimeout(this.timeout);
17171 this.hoverState = 'in';
17173 if (!this.delay || !this.delay.show) {
17178 this.timeout = setTimeout(function () {
17179 if (_t.hoverState == 'in') {
17182 }, this.delay.show)
17185 leave : function() {
17186 clearTimeout(this.timeout);
17188 this.hoverState = 'out';
17190 if (!this.delay || !this.delay.hide) {
17195 this.timeout = setTimeout(function () {
17196 if (_t.hoverState == 'out') {
17199 }, this.delay.hide)
17202 show : function (on_el)
17205 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17209 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17210 if (this.html !== false) {
17211 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17213 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17214 if (!this.title.length) {
17215 this.el.select('.popover-title',true).hide();
17218 var placement = typeof this.placement == 'function' ?
17219 this.placement.call(this, this.el, on_el) :
17222 var autoToken = /\s?auto?\s?/i;
17223 var autoPlace = autoToken.test(placement);
17225 placement = placement.replace(autoToken, '') || 'top';
17229 //this.el.setXY([0,0]);
17231 this.el.dom.style.display='block';
17232 this.el.addClass(placement);
17234 //this.el.appendTo(on_el);
17236 var p = this.getPosition();
17237 var box = this.el.getBox();
17242 var align = Roo.bootstrap.Popover.alignment[placement];
17243 this.el.alignTo(on_el, align[0],align[1]);
17244 //var arrow = this.el.select('.arrow',true).first();
17245 //arrow.set(align[2],
17247 this.el.addClass('in');
17250 if (this.el.hasClass('fade')) {
17254 this.hoverState = 'in';
17256 this.fireEvent('show', this);
17261 this.el.setXY([0,0]);
17262 this.el.removeClass('in');
17264 this.hoverState = null;
17266 this.fireEvent('hide', this);
17271 Roo.bootstrap.Popover.alignment = {
17272 'left' : ['r-l', [-10,0], 'right'],
17273 'right' : ['l-r', [10,0], 'left'],
17274 'bottom' : ['t-b', [0,10], 'top'],
17275 'top' : [ 'b-t', [0,-10], 'bottom']
17286 * @class Roo.bootstrap.Progress
17287 * @extends Roo.bootstrap.Component
17288 * Bootstrap Progress class
17289 * @cfg {Boolean} striped striped of the progress bar
17290 * @cfg {Boolean} active animated of the progress bar
17294 * Create a new Progress
17295 * @param {Object} config The config object
17298 Roo.bootstrap.Progress = function(config){
17299 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17302 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17307 getAutoCreate : function(){
17315 cfg.cls += ' progress-striped';
17319 cfg.cls += ' active';
17338 * @class Roo.bootstrap.ProgressBar
17339 * @extends Roo.bootstrap.Component
17340 * Bootstrap ProgressBar class
17341 * @cfg {Number} aria_valuenow aria-value now
17342 * @cfg {Number} aria_valuemin aria-value min
17343 * @cfg {Number} aria_valuemax aria-value max
17344 * @cfg {String} label label for the progress bar
17345 * @cfg {String} panel (success | info | warning | danger )
17346 * @cfg {String} role role of the progress bar
17347 * @cfg {String} sr_only text
17351 * Create a new ProgressBar
17352 * @param {Object} config The config object
17355 Roo.bootstrap.ProgressBar = function(config){
17356 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17359 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17363 aria_valuemax : 100,
17369 getAutoCreate : function()
17374 cls: 'progress-bar',
17375 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17387 cfg.role = this.role;
17390 if(this.aria_valuenow){
17391 cfg['aria-valuenow'] = this.aria_valuenow;
17394 if(this.aria_valuemin){
17395 cfg['aria-valuemin'] = this.aria_valuemin;
17398 if(this.aria_valuemax){
17399 cfg['aria-valuemax'] = this.aria_valuemax;
17402 if(this.label && !this.sr_only){
17403 cfg.html = this.label;
17407 cfg.cls += ' progress-bar-' + this.panel;
17413 update : function(aria_valuenow)
17415 this.aria_valuenow = aria_valuenow;
17417 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17432 * @class Roo.bootstrap.TabGroup
17433 * @extends Roo.bootstrap.Column
17434 * Bootstrap Column class
17435 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17436 * @cfg {Boolean} carousel true to make the group behave like a carousel
17437 * @cfg {Boolean} bullets show bullets for the panels
17438 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17439 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17440 * @cfg {Boolean} showarrow (true|false) show arrow default true
17443 * Create a new TabGroup
17444 * @param {Object} config The config object
17447 Roo.bootstrap.TabGroup = function(config){
17448 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17450 this.navId = Roo.id();
17453 Roo.bootstrap.TabGroup.register(this);
17457 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17460 transition : false,
17465 slideOnTouch : false,
17468 getAutoCreate : function()
17470 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17472 cfg.cls += ' tab-content';
17474 if (this.carousel) {
17475 cfg.cls += ' carousel slide';
17478 cls : 'carousel-inner',
17482 if(this.bullets && !Roo.isTouch){
17485 cls : 'carousel-bullets',
17489 if(this.bullets_cls){
17490 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17497 cfg.cn[0].cn.push(bullets);
17500 if(this.showarrow){
17501 cfg.cn[0].cn.push({
17503 class : 'carousel-arrow',
17507 class : 'carousel-prev',
17511 class : 'fa fa-chevron-left'
17517 class : 'carousel-next',
17521 class : 'fa fa-chevron-right'
17534 initEvents: function()
17536 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17537 // this.el.on("touchstart", this.onTouchStart, this);
17540 if(this.autoslide){
17543 this.slideFn = window.setInterval(function() {
17544 _this.showPanelNext();
17548 if(this.showarrow){
17549 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17550 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17556 // onTouchStart : function(e, el, o)
17558 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17562 // this.showPanelNext();
17566 getChildContainer : function()
17568 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17572 * register a Navigation item
17573 * @param {Roo.bootstrap.NavItem} the navitem to add
17575 register : function(item)
17577 this.tabs.push( item);
17578 item.navId = this.navId; // not really needed..
17583 getActivePanel : function()
17586 Roo.each(this.tabs, function(t) {
17596 getPanelByName : function(n)
17599 Roo.each(this.tabs, function(t) {
17600 if (t.tabId == n) {
17608 indexOfPanel : function(p)
17611 Roo.each(this.tabs, function(t,i) {
17612 if (t.tabId == p.tabId) {
17621 * show a specific panel
17622 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17623 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17625 showPanel : function (pan)
17627 if(this.transition || typeof(pan) == 'undefined'){
17628 Roo.log("waiting for the transitionend");
17632 if (typeof(pan) == 'number') {
17633 pan = this.tabs[pan];
17636 if (typeof(pan) == 'string') {
17637 pan = this.getPanelByName(pan);
17640 var cur = this.getActivePanel();
17643 Roo.log('pan or acitve pan is undefined');
17647 if (pan.tabId == this.getActivePanel().tabId) {
17651 if (false === cur.fireEvent('beforedeactivate')) {
17655 if(this.bullets > 0 && !Roo.isTouch){
17656 this.setActiveBullet(this.indexOfPanel(pan));
17659 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17661 this.transition = true;
17662 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17663 var lr = dir == 'next' ? 'left' : 'right';
17664 pan.el.addClass(dir); // or prev
17665 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17666 cur.el.addClass(lr); // or right
17667 pan.el.addClass(lr);
17670 cur.el.on('transitionend', function() {
17671 Roo.log("trans end?");
17673 pan.el.removeClass([lr,dir]);
17674 pan.setActive(true);
17676 cur.el.removeClass([lr]);
17677 cur.setActive(false);
17679 _this.transition = false;
17681 }, this, { single: true } );
17686 cur.setActive(false);
17687 pan.setActive(true);
17692 showPanelNext : function()
17694 var i = this.indexOfPanel(this.getActivePanel());
17696 if (i >= this.tabs.length - 1 && !this.autoslide) {
17700 if (i >= this.tabs.length - 1 && this.autoslide) {
17704 this.showPanel(this.tabs[i+1]);
17707 showPanelPrev : function()
17709 var i = this.indexOfPanel(this.getActivePanel());
17711 if (i < 1 && !this.autoslide) {
17715 if (i < 1 && this.autoslide) {
17716 i = this.tabs.length;
17719 this.showPanel(this.tabs[i-1]);
17723 addBullet: function()
17725 if(!this.bullets || Roo.isTouch){
17728 var ctr = this.el.select('.carousel-bullets',true).first();
17729 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17730 var bullet = ctr.createChild({
17731 cls : 'bullet bullet-' + i
17732 },ctr.dom.lastChild);
17737 bullet.on('click', (function(e, el, o, ii, t){
17739 e.preventDefault();
17741 this.showPanel(ii);
17743 if(this.autoslide && this.slideFn){
17744 clearInterval(this.slideFn);
17745 this.slideFn = window.setInterval(function() {
17746 _this.showPanelNext();
17750 }).createDelegate(this, [i, bullet], true));
17755 setActiveBullet : function(i)
17761 Roo.each(this.el.select('.bullet', true).elements, function(el){
17762 el.removeClass('selected');
17765 var bullet = this.el.select('.bullet-' + i, true).first();
17771 bullet.addClass('selected');
17782 Roo.apply(Roo.bootstrap.TabGroup, {
17786 * register a Navigation Group
17787 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17789 register : function(navgrp)
17791 this.groups[navgrp.navId] = navgrp;
17795 * fetch a Navigation Group based on the navigation ID
17796 * if one does not exist , it will get created.
17797 * @param {string} the navgroup to add
17798 * @returns {Roo.bootstrap.NavGroup} the navgroup
17800 get: function(navId) {
17801 if (typeof(this.groups[navId]) == 'undefined') {
17802 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17804 return this.groups[navId] ;
17819 * @class Roo.bootstrap.TabPanel
17820 * @extends Roo.bootstrap.Component
17821 * Bootstrap TabPanel class
17822 * @cfg {Boolean} active panel active
17823 * @cfg {String} html panel content
17824 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17825 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17826 * @cfg {String} href click to link..
17830 * Create a new TabPanel
17831 * @param {Object} config The config object
17834 Roo.bootstrap.TabPanel = function(config){
17835 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17839 * Fires when the active status changes
17840 * @param {Roo.bootstrap.TabPanel} this
17841 * @param {Boolean} state the new state
17846 * @event beforedeactivate
17847 * Fires before a tab is de-activated - can be used to do validation on a form.
17848 * @param {Roo.bootstrap.TabPanel} this
17849 * @return {Boolean} false if there is an error
17852 'beforedeactivate': true
17855 this.tabId = this.tabId || Roo.id();
17859 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17867 getAutoCreate : function(){
17870 // item is needed for carousel - not sure if it has any effect otherwise
17871 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17872 html: this.html || ''
17876 cfg.cls += ' active';
17880 cfg.tabId = this.tabId;
17887 initEvents: function()
17889 var p = this.parent();
17891 this.navId = this.navId || p.navId;
17893 if (typeof(this.navId) != 'undefined') {
17894 // not really needed.. but just in case.. parent should be a NavGroup.
17895 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17899 var i = tg.tabs.length - 1;
17901 if(this.active && tg.bullets > 0 && i < tg.bullets){
17902 tg.setActiveBullet(i);
17906 this.el.on('click', this.onClick, this);
17909 this.el.on("touchstart", this.onTouchStart, this);
17910 this.el.on("touchmove", this.onTouchMove, this);
17911 this.el.on("touchend", this.onTouchEnd, this);
17916 onRender : function(ct, position)
17918 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17921 setActive : function(state)
17923 Roo.log("panel - set active " + this.tabId + "=" + state);
17925 this.active = state;
17927 this.el.removeClass('active');
17929 } else if (!this.el.hasClass('active')) {
17930 this.el.addClass('active');
17933 this.fireEvent('changed', this, state);
17936 onClick : function(e)
17938 e.preventDefault();
17940 if(!this.href.length){
17944 window.location.href = this.href;
17953 onTouchStart : function(e)
17955 this.swiping = false;
17957 this.startX = e.browserEvent.touches[0].clientX;
17958 this.startY = e.browserEvent.touches[0].clientY;
17961 onTouchMove : function(e)
17963 this.swiping = true;
17965 this.endX = e.browserEvent.touches[0].clientX;
17966 this.endY = e.browserEvent.touches[0].clientY;
17969 onTouchEnd : function(e)
17976 var tabGroup = this.parent();
17978 if(this.endX > this.startX){ // swiping right
17979 tabGroup.showPanelPrev();
17983 if(this.startX > this.endX){ // swiping left
17984 tabGroup.showPanelNext();
18003 * @class Roo.bootstrap.DateField
18004 * @extends Roo.bootstrap.Input
18005 * Bootstrap DateField class
18006 * @cfg {Number} weekStart default 0
18007 * @cfg {String} viewMode default empty, (months|years)
18008 * @cfg {String} minViewMode default empty, (months|years)
18009 * @cfg {Number} startDate default -Infinity
18010 * @cfg {Number} endDate default Infinity
18011 * @cfg {Boolean} todayHighlight default false
18012 * @cfg {Boolean} todayBtn default false
18013 * @cfg {Boolean} calendarWeeks default false
18014 * @cfg {Object} daysOfWeekDisabled default empty
18015 * @cfg {Boolean} singleMode default false (true | false)
18017 * @cfg {Boolean} keyboardNavigation default true
18018 * @cfg {String} language default en
18021 * Create a new DateField
18022 * @param {Object} config The config object
18025 Roo.bootstrap.DateField = function(config){
18026 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18030 * Fires when this field show.
18031 * @param {Roo.bootstrap.DateField} this
18032 * @param {Mixed} date The date value
18037 * Fires when this field hide.
18038 * @param {Roo.bootstrap.DateField} this
18039 * @param {Mixed} date The date value
18044 * Fires when select a date.
18045 * @param {Roo.bootstrap.DateField} this
18046 * @param {Mixed} date The date value
18050 * @event beforeselect
18051 * Fires when before select a date.
18052 * @param {Roo.bootstrap.DateField} this
18053 * @param {Mixed} date The date value
18055 beforeselect : true
18059 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18062 * @cfg {String} format
18063 * The default date format string which can be overriden for localization support. The format must be
18064 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18068 * @cfg {String} altFormats
18069 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18070 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18072 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18080 todayHighlight : false,
18086 keyboardNavigation: true,
18088 calendarWeeks: false,
18090 startDate: -Infinity,
18094 daysOfWeekDisabled: [],
18098 singleMode : false,
18100 UTCDate: function()
18102 return new Date(Date.UTC.apply(Date, arguments));
18105 UTCToday: function()
18107 var today = new Date();
18108 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18111 getDate: function() {
18112 var d = this.getUTCDate();
18113 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18116 getUTCDate: function() {
18120 setDate: function(d) {
18121 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18124 setUTCDate: function(d) {
18126 this.setValue(this.formatDate(this.date));
18129 onRender: function(ct, position)
18132 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18134 this.language = this.language || 'en';
18135 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18136 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18138 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18139 this.format = this.format || 'm/d/y';
18140 this.isInline = false;
18141 this.isInput = true;
18142 this.component = this.el.select('.add-on', true).first() || false;
18143 this.component = (this.component && this.component.length === 0) ? false : this.component;
18144 this.hasInput = this.component && this.inputEl().length;
18146 if (typeof(this.minViewMode === 'string')) {
18147 switch (this.minViewMode) {
18149 this.minViewMode = 1;
18152 this.minViewMode = 2;
18155 this.minViewMode = 0;
18160 if (typeof(this.viewMode === 'string')) {
18161 switch (this.viewMode) {
18174 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18176 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18178 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18180 this.picker().on('mousedown', this.onMousedown, this);
18181 this.picker().on('click', this.onClick, this);
18183 this.picker().addClass('datepicker-dropdown');
18185 this.startViewMode = this.viewMode;
18187 if(this.singleMode){
18188 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18189 v.setVisibilityMode(Roo.Element.DISPLAY);
18193 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18194 v.setStyle('width', '189px');
18198 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18199 if(!this.calendarWeeks){
18204 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18205 v.attr('colspan', function(i, val){
18206 return parseInt(val) + 1;
18211 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18213 this.setStartDate(this.startDate);
18214 this.setEndDate(this.endDate);
18216 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18223 if(this.isInline) {
18228 picker : function()
18230 return this.pickerEl;
18231 // return this.el.select('.datepicker', true).first();
18234 fillDow: function()
18236 var dowCnt = this.weekStart;
18245 if(this.calendarWeeks){
18253 while (dowCnt < this.weekStart + 7) {
18257 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18261 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18264 fillMonths: function()
18267 var months = this.picker().select('>.datepicker-months td', true).first();
18269 months.dom.innerHTML = '';
18275 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18278 months.createChild(month);
18285 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;
18287 if (this.date < this.startDate) {
18288 this.viewDate = new Date(this.startDate);
18289 } else if (this.date > this.endDate) {
18290 this.viewDate = new Date(this.endDate);
18292 this.viewDate = new Date(this.date);
18300 var d = new Date(this.viewDate),
18301 year = d.getUTCFullYear(),
18302 month = d.getUTCMonth(),
18303 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18304 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18305 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18306 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18307 currentDate = this.date && this.date.valueOf(),
18308 today = this.UTCToday();
18310 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18312 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18314 // this.picker.select('>tfoot th.today').
18315 // .text(dates[this.language].today)
18316 // .toggle(this.todayBtn !== false);
18318 this.updateNavArrows();
18321 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18323 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18325 prevMonth.setUTCDate(day);
18327 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18329 var nextMonth = new Date(prevMonth);
18331 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18333 nextMonth = nextMonth.valueOf();
18335 var fillMonths = false;
18337 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18339 while(prevMonth.valueOf() < nextMonth) {
18342 if (prevMonth.getUTCDay() === this.weekStart) {
18344 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18352 if(this.calendarWeeks){
18353 // ISO 8601: First week contains first thursday.
18354 // ISO also states week starts on Monday, but we can be more abstract here.
18356 // Start of current week: based on weekstart/current date
18357 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18358 // Thursday of this week
18359 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18360 // First Thursday of year, year from thursday
18361 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18362 // Calendar week: ms between thursdays, div ms per day, div 7 days
18363 calWeek = (th - yth) / 864e5 / 7 + 1;
18365 fillMonths.cn.push({
18373 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18375 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18378 if (this.todayHighlight &&
18379 prevMonth.getUTCFullYear() == today.getFullYear() &&
18380 prevMonth.getUTCMonth() == today.getMonth() &&
18381 prevMonth.getUTCDate() == today.getDate()) {
18382 clsName += ' today';
18385 if (currentDate && prevMonth.valueOf() === currentDate) {
18386 clsName += ' active';
18389 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18390 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18391 clsName += ' disabled';
18394 fillMonths.cn.push({
18396 cls: 'day ' + clsName,
18397 html: prevMonth.getDate()
18400 prevMonth.setDate(prevMonth.getDate()+1);
18403 var currentYear = this.date && this.date.getUTCFullYear();
18404 var currentMonth = this.date && this.date.getUTCMonth();
18406 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18408 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18409 v.removeClass('active');
18411 if(currentYear === year && k === currentMonth){
18412 v.addClass('active');
18415 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18416 v.addClass('disabled');
18422 year = parseInt(year/10, 10) * 10;
18424 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18426 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18429 for (var i = -1; i < 11; i++) {
18430 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18432 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18440 showMode: function(dir)
18443 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18446 Roo.each(this.picker().select('>div',true).elements, function(v){
18447 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18450 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18455 if(this.isInline) {
18459 this.picker().removeClass(['bottom', 'top']);
18461 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18463 * place to the top of element!
18467 this.picker().addClass('top');
18468 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18473 this.picker().addClass('bottom');
18475 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18478 parseDate : function(value)
18480 if(!value || value instanceof Date){
18483 var v = Date.parseDate(value, this.format);
18484 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18485 v = Date.parseDate(value, 'Y-m-d');
18487 if(!v && this.altFormats){
18488 if(!this.altFormatsArray){
18489 this.altFormatsArray = this.altFormats.split("|");
18491 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18492 v = Date.parseDate(value, this.altFormatsArray[i]);
18498 formatDate : function(date, fmt)
18500 return (!date || !(date instanceof Date)) ?
18501 date : date.dateFormat(fmt || this.format);
18504 onFocus : function()
18506 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18510 onBlur : function()
18512 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18514 var d = this.inputEl().getValue();
18523 this.picker().show();
18527 this.fireEvent('show', this, this.date);
18532 if(this.isInline) {
18535 this.picker().hide();
18536 this.viewMode = this.startViewMode;
18539 this.fireEvent('hide', this, this.date);
18543 onMousedown: function(e)
18545 e.stopPropagation();
18546 e.preventDefault();
18551 Roo.bootstrap.DateField.superclass.keyup.call(this);
18555 setValue: function(v)
18557 if(this.fireEvent('beforeselect', this, v) !== false){
18558 var d = new Date(this.parseDate(v) ).clearTime();
18560 if(isNaN(d.getTime())){
18561 this.date = this.viewDate = '';
18562 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18566 v = this.formatDate(d);
18568 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18570 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18574 this.fireEvent('select', this, this.date);
18578 getValue: function()
18580 return this.formatDate(this.date);
18583 fireKey: function(e)
18585 if (!this.picker().isVisible()){
18586 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18592 var dateChanged = false,
18594 newDate, newViewDate;
18599 e.preventDefault();
18603 if (!this.keyboardNavigation) {
18606 dir = e.keyCode == 37 ? -1 : 1;
18609 newDate = this.moveYear(this.date, dir);
18610 newViewDate = this.moveYear(this.viewDate, dir);
18611 } else if (e.shiftKey){
18612 newDate = this.moveMonth(this.date, dir);
18613 newViewDate = this.moveMonth(this.viewDate, dir);
18615 newDate = new Date(this.date);
18616 newDate.setUTCDate(this.date.getUTCDate() + dir);
18617 newViewDate = new Date(this.viewDate);
18618 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18620 if (this.dateWithinRange(newDate)){
18621 this.date = newDate;
18622 this.viewDate = newViewDate;
18623 this.setValue(this.formatDate(this.date));
18625 e.preventDefault();
18626 dateChanged = true;
18631 if (!this.keyboardNavigation) {
18634 dir = e.keyCode == 38 ? -1 : 1;
18636 newDate = this.moveYear(this.date, dir);
18637 newViewDate = this.moveYear(this.viewDate, dir);
18638 } else if (e.shiftKey){
18639 newDate = this.moveMonth(this.date, dir);
18640 newViewDate = this.moveMonth(this.viewDate, dir);
18642 newDate = new Date(this.date);
18643 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18644 newViewDate = new Date(this.viewDate);
18645 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18647 if (this.dateWithinRange(newDate)){
18648 this.date = newDate;
18649 this.viewDate = newViewDate;
18650 this.setValue(this.formatDate(this.date));
18652 e.preventDefault();
18653 dateChanged = true;
18657 this.setValue(this.formatDate(this.date));
18659 e.preventDefault();
18662 this.setValue(this.formatDate(this.date));
18676 onClick: function(e)
18678 e.stopPropagation();
18679 e.preventDefault();
18681 var target = e.getTarget();
18683 if(target.nodeName.toLowerCase() === 'i'){
18684 target = Roo.get(target).dom.parentNode;
18687 var nodeName = target.nodeName;
18688 var className = target.className;
18689 var html = target.innerHTML;
18690 //Roo.log(nodeName);
18692 switch(nodeName.toLowerCase()) {
18694 switch(className) {
18700 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18701 switch(this.viewMode){
18703 this.viewDate = this.moveMonth(this.viewDate, dir);
18707 this.viewDate = this.moveYear(this.viewDate, dir);
18713 var date = new Date();
18714 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18716 this.setValue(this.formatDate(this.date));
18723 if (className.indexOf('disabled') < 0) {
18724 this.viewDate.setUTCDate(1);
18725 if (className.indexOf('month') > -1) {
18726 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18728 var year = parseInt(html, 10) || 0;
18729 this.viewDate.setUTCFullYear(year);
18733 if(this.singleMode){
18734 this.setValue(this.formatDate(this.viewDate));
18745 //Roo.log(className);
18746 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18747 var day = parseInt(html, 10) || 1;
18748 var year = this.viewDate.getUTCFullYear(),
18749 month = this.viewDate.getUTCMonth();
18751 if (className.indexOf('old') > -1) {
18758 } else if (className.indexOf('new') > -1) {
18766 //Roo.log([year,month,day]);
18767 this.date = this.UTCDate(year, month, day,0,0,0,0);
18768 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18770 //Roo.log(this.formatDate(this.date));
18771 this.setValue(this.formatDate(this.date));
18778 setStartDate: function(startDate)
18780 this.startDate = startDate || -Infinity;
18781 if (this.startDate !== -Infinity) {
18782 this.startDate = this.parseDate(this.startDate);
18785 this.updateNavArrows();
18788 setEndDate: function(endDate)
18790 this.endDate = endDate || Infinity;
18791 if (this.endDate !== Infinity) {
18792 this.endDate = this.parseDate(this.endDate);
18795 this.updateNavArrows();
18798 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18800 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18801 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18802 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18804 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18805 return parseInt(d, 10);
18808 this.updateNavArrows();
18811 updateNavArrows: function()
18813 if(this.singleMode){
18817 var d = new Date(this.viewDate),
18818 year = d.getUTCFullYear(),
18819 month = d.getUTCMonth();
18821 Roo.each(this.picker().select('.prev', true).elements, function(v){
18823 switch (this.viewMode) {
18826 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18832 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18839 Roo.each(this.picker().select('.next', true).elements, function(v){
18841 switch (this.viewMode) {
18844 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18850 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18858 moveMonth: function(date, dir)
18863 var new_date = new Date(date.valueOf()),
18864 day = new_date.getUTCDate(),
18865 month = new_date.getUTCMonth(),
18866 mag = Math.abs(dir),
18868 dir = dir > 0 ? 1 : -1;
18871 // If going back one month, make sure month is not current month
18872 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18874 return new_date.getUTCMonth() == month;
18876 // If going forward one month, make sure month is as expected
18877 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18879 return new_date.getUTCMonth() != new_month;
18881 new_month = month + dir;
18882 new_date.setUTCMonth(new_month);
18883 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18884 if (new_month < 0 || new_month > 11) {
18885 new_month = (new_month + 12) % 12;
18888 // For magnitudes >1, move one month at a time...
18889 for (var i=0; i<mag; i++) {
18890 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18891 new_date = this.moveMonth(new_date, dir);
18893 // ...then reset the day, keeping it in the new month
18894 new_month = new_date.getUTCMonth();
18895 new_date.setUTCDate(day);
18897 return new_month != new_date.getUTCMonth();
18900 // Common date-resetting loop -- if date is beyond end of month, make it
18903 new_date.setUTCDate(--day);
18904 new_date.setUTCMonth(new_month);
18909 moveYear: function(date, dir)
18911 return this.moveMonth(date, dir*12);
18914 dateWithinRange: function(date)
18916 return date >= this.startDate && date <= this.endDate;
18922 this.picker().remove();
18925 validateValue : function(value)
18927 if(value.length < 1) {
18928 if(this.allowBlank){
18934 if(value.length < this.minLength){
18937 if(value.length > this.maxLength){
18941 var vt = Roo.form.VTypes;
18942 if(!vt[this.vtype](value, this)){
18946 if(typeof this.validator == "function"){
18947 var msg = this.validator(value);
18953 if(this.regex && !this.regex.test(value)){
18957 if(typeof(this.parseDate(value)) == 'undefined'){
18961 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18965 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18975 Roo.apply(Roo.bootstrap.DateField, {
18986 html: '<i class="fa fa-arrow-left"/>'
18996 html: '<i class="fa fa-arrow-right"/>'
19038 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19039 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19040 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19041 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19042 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19055 navFnc: 'FullYear',
19060 navFnc: 'FullYear',
19065 Roo.apply(Roo.bootstrap.DateField, {
19069 cls: 'datepicker dropdown-menu roo-dynamic',
19073 cls: 'datepicker-days',
19077 cls: 'table-condensed',
19079 Roo.bootstrap.DateField.head,
19083 Roo.bootstrap.DateField.footer
19090 cls: 'datepicker-months',
19094 cls: 'table-condensed',
19096 Roo.bootstrap.DateField.head,
19097 Roo.bootstrap.DateField.content,
19098 Roo.bootstrap.DateField.footer
19105 cls: 'datepicker-years',
19109 cls: 'table-condensed',
19111 Roo.bootstrap.DateField.head,
19112 Roo.bootstrap.DateField.content,
19113 Roo.bootstrap.DateField.footer
19132 * @class Roo.bootstrap.TimeField
19133 * @extends Roo.bootstrap.Input
19134 * Bootstrap DateField class
19138 * Create a new TimeField
19139 * @param {Object} config The config object
19142 Roo.bootstrap.TimeField = function(config){
19143 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19147 * Fires when this field show.
19148 * @param {Roo.bootstrap.DateField} thisthis
19149 * @param {Mixed} date The date value
19154 * Fires when this field hide.
19155 * @param {Roo.bootstrap.DateField} this
19156 * @param {Mixed} date The date value
19161 * Fires when select a date.
19162 * @param {Roo.bootstrap.DateField} this
19163 * @param {Mixed} date The date value
19169 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19172 * @cfg {String} format
19173 * The default time format string which can be overriden for localization support. The format must be
19174 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19178 onRender: function(ct, position)
19181 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19183 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19185 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19187 this.pop = this.picker().select('>.datepicker-time',true).first();
19188 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19190 this.picker().on('mousedown', this.onMousedown, this);
19191 this.picker().on('click', this.onClick, this);
19193 this.picker().addClass('datepicker-dropdown');
19198 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19199 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19200 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19201 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19202 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19203 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19207 fireKey: function(e){
19208 if (!this.picker().isVisible()){
19209 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19215 e.preventDefault();
19223 this.onTogglePeriod();
19226 this.onIncrementMinutes();
19229 this.onDecrementMinutes();
19238 onClick: function(e) {
19239 e.stopPropagation();
19240 e.preventDefault();
19243 picker : function()
19245 return this.el.select('.datepicker', true).first();
19248 fillTime: function()
19250 var time = this.pop.select('tbody', true).first();
19252 time.dom.innerHTML = '';
19267 cls: 'hours-up glyphicon glyphicon-chevron-up'
19287 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19308 cls: 'timepicker-hour',
19323 cls: 'timepicker-minute',
19338 cls: 'btn btn-primary period',
19360 cls: 'hours-down glyphicon glyphicon-chevron-down'
19380 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19398 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19405 var hours = this.time.getHours();
19406 var minutes = this.time.getMinutes();
19419 hours = hours - 12;
19423 hours = '0' + hours;
19427 minutes = '0' + minutes;
19430 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19431 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19432 this.pop.select('button', true).first().dom.innerHTML = period;
19438 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19440 var cls = ['bottom'];
19442 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19449 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19454 this.picker().addClass(cls.join('-'));
19458 Roo.each(cls, function(c){
19460 _this.picker().setTop(_this.inputEl().getHeight());
19464 _this.picker().setTop(0 - _this.picker().getHeight());
19469 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19473 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19480 onFocus : function()
19482 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19486 onBlur : function()
19488 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19494 this.picker().show();
19499 this.fireEvent('show', this, this.date);
19504 this.picker().hide();
19507 this.fireEvent('hide', this, this.date);
19510 setTime : function()
19513 this.setValue(this.time.format(this.format));
19515 this.fireEvent('select', this, this.date);
19520 onMousedown: function(e){
19521 e.stopPropagation();
19522 e.preventDefault();
19525 onIncrementHours: function()
19527 Roo.log('onIncrementHours');
19528 this.time = this.time.add(Date.HOUR, 1);
19533 onDecrementHours: function()
19535 Roo.log('onDecrementHours');
19536 this.time = this.time.add(Date.HOUR, -1);
19540 onIncrementMinutes: function()
19542 Roo.log('onIncrementMinutes');
19543 this.time = this.time.add(Date.MINUTE, 1);
19547 onDecrementMinutes: function()
19549 Roo.log('onDecrementMinutes');
19550 this.time = this.time.add(Date.MINUTE, -1);
19554 onTogglePeriod: function()
19556 Roo.log('onTogglePeriod');
19557 this.time = this.time.add(Date.HOUR, 12);
19564 Roo.apply(Roo.bootstrap.TimeField, {
19594 cls: 'btn btn-info ok',
19606 Roo.apply(Roo.bootstrap.TimeField, {
19610 cls: 'datepicker dropdown-menu',
19614 cls: 'datepicker-time',
19618 cls: 'table-condensed',
19620 Roo.bootstrap.TimeField.content,
19621 Roo.bootstrap.TimeField.footer
19640 * @class Roo.bootstrap.MonthField
19641 * @extends Roo.bootstrap.Input
19642 * Bootstrap MonthField class
19644 * @cfg {String} language default en
19647 * Create a new MonthField
19648 * @param {Object} config The config object
19651 Roo.bootstrap.MonthField = function(config){
19652 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19657 * Fires when this field show.
19658 * @param {Roo.bootstrap.MonthField} this
19659 * @param {Mixed} date The date value
19664 * Fires when this field hide.
19665 * @param {Roo.bootstrap.MonthField} this
19666 * @param {Mixed} date The date value
19671 * Fires when select a date.
19672 * @param {Roo.bootstrap.MonthField} this
19673 * @param {String} oldvalue The old value
19674 * @param {String} newvalue The new value
19680 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19682 onRender: function(ct, position)
19685 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19687 this.language = this.language || 'en';
19688 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19689 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19691 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19692 this.isInline = false;
19693 this.isInput = true;
19694 this.component = this.el.select('.add-on', true).first() || false;
19695 this.component = (this.component && this.component.length === 0) ? false : this.component;
19696 this.hasInput = this.component && this.inputEL().length;
19698 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19700 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19702 this.picker().on('mousedown', this.onMousedown, this);
19703 this.picker().on('click', this.onClick, this);
19705 this.picker().addClass('datepicker-dropdown');
19707 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19708 v.setStyle('width', '189px');
19715 if(this.isInline) {
19721 setValue: function(v, suppressEvent)
19723 var o = this.getValue();
19725 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19729 if(suppressEvent !== true){
19730 this.fireEvent('select', this, o, v);
19735 getValue: function()
19740 onClick: function(e)
19742 e.stopPropagation();
19743 e.preventDefault();
19745 var target = e.getTarget();
19747 if(target.nodeName.toLowerCase() === 'i'){
19748 target = Roo.get(target).dom.parentNode;
19751 var nodeName = target.nodeName;
19752 var className = target.className;
19753 var html = target.innerHTML;
19755 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19759 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19761 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19767 picker : function()
19769 return this.pickerEl;
19772 fillMonths: function()
19775 var months = this.picker().select('>.datepicker-months td', true).first();
19777 months.dom.innerHTML = '';
19783 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19786 months.createChild(month);
19795 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19796 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19799 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19800 e.removeClass('active');
19802 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19803 e.addClass('active');
19810 if(this.isInline) {
19814 this.picker().removeClass(['bottom', 'top']);
19816 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19818 * place to the top of element!
19822 this.picker().addClass('top');
19823 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19828 this.picker().addClass('bottom');
19830 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19833 onFocus : function()
19835 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19839 onBlur : function()
19841 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19843 var d = this.inputEl().getValue();
19852 this.picker().show();
19853 this.picker().select('>.datepicker-months', true).first().show();
19857 this.fireEvent('show', this, this.date);
19862 if(this.isInline) {
19865 this.picker().hide();
19866 this.fireEvent('hide', this, this.date);
19870 onMousedown: function(e)
19872 e.stopPropagation();
19873 e.preventDefault();
19878 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19882 fireKey: function(e)
19884 if (!this.picker().isVisible()){
19885 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19896 e.preventDefault();
19900 dir = e.keyCode == 37 ? -1 : 1;
19902 this.vIndex = this.vIndex + dir;
19904 if(this.vIndex < 0){
19908 if(this.vIndex > 11){
19912 if(isNaN(this.vIndex)){
19916 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19922 dir = e.keyCode == 38 ? -1 : 1;
19924 this.vIndex = this.vIndex + dir * 4;
19926 if(this.vIndex < 0){
19930 if(this.vIndex > 11){
19934 if(isNaN(this.vIndex)){
19938 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19943 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19944 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19948 e.preventDefault();
19951 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19952 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19968 this.picker().remove();
19973 Roo.apply(Roo.bootstrap.MonthField, {
19992 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19993 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19998 Roo.apply(Roo.bootstrap.MonthField, {
20002 cls: 'datepicker dropdown-menu roo-dynamic',
20006 cls: 'datepicker-months',
20010 cls: 'table-condensed',
20012 Roo.bootstrap.DateField.content
20032 * @class Roo.bootstrap.CheckBox
20033 * @extends Roo.bootstrap.Input
20034 * Bootstrap CheckBox class
20036 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20037 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20038 * @cfg {String} boxLabel The text that appears beside the checkbox
20039 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20040 * @cfg {Boolean} checked initnal the element
20041 * @cfg {Boolean} inline inline the element (default false)
20042 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20045 * Create a new CheckBox
20046 * @param {Object} config The config object
20049 Roo.bootstrap.CheckBox = function(config){
20050 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20055 * Fires when the element is checked or unchecked.
20056 * @param {Roo.bootstrap.CheckBox} this This input
20057 * @param {Boolean} checked The new checked value
20064 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20066 inputType: 'checkbox',
20074 getAutoCreate : function()
20076 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20082 cfg.cls = 'form-group ' + this.inputType; //input-group
20085 cfg.cls += ' ' + this.inputType + '-inline';
20091 type : this.inputType,
20092 value : this.inputValue,
20093 cls : 'roo-' + this.inputType, //'form-box',
20094 placeholder : this.placeholder || ''
20098 if(this.inputType != 'radio'){
20102 cls : 'roo-hidden-value',
20103 value : this.checked ? this.valueOff : this.inputValue
20108 if (this.weight) { // Validity check?
20109 cfg.cls += " " + this.inputType + "-" + this.weight;
20112 if (this.disabled) {
20113 input.disabled=true;
20117 input.checked = this.checked;
20124 input.name = this.name;
20126 if(this.inputType != 'radio'){
20127 hidden.name = this.name;
20128 input.name = '_hidden_' + this.name;
20133 input.cls += ' input-' + this.size;
20138 ['xs','sm','md','lg'].map(function(size){
20139 if (settings[size]) {
20140 cfg.cls += ' col-' + size + '-' + settings[size];
20144 var inputblock = input;
20146 if (this.before || this.after) {
20149 cls : 'input-group',
20154 inputblock.cn.push({
20156 cls : 'input-group-addon',
20161 inputblock.cn.push(input);
20163 if(this.inputType != 'radio'){
20164 inputblock.cn.push(hidden);
20168 inputblock.cn.push({
20170 cls : 'input-group-addon',
20177 if (align ==='left' && this.fieldLabel.length) {
20178 // Roo.log("left and has label");
20183 cls : 'control-label',
20184 html : this.fieldLabel
20195 if(this.labelWidth > 12){
20196 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20199 if(this.labelWidth < 13 && this.labelmd == 0){
20200 this.labelmd = this.labelWidth;
20203 if(this.labellg > 0){
20204 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20205 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20208 if(this.labelmd > 0){
20209 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20210 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20213 if(this.labelsm > 0){
20214 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20215 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20218 if(this.labelxs > 0){
20219 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20220 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20223 } else if ( this.fieldLabel.length) {
20224 // Roo.log(" label");
20228 tag: this.boxLabel ? 'span' : 'label',
20230 cls: 'control-label box-input-label',
20231 //cls : 'input-group-addon',
20232 html : this.fieldLabel
20242 // Roo.log(" no label && no align");
20243 cfg.cn = [ inputblock ] ;
20249 var boxLabelCfg = {
20251 //'for': id, // box label is handled by onclick - so no for...
20253 html: this.boxLabel
20257 boxLabelCfg.tooltip = this.tooltip;
20260 cfg.cn.push(boxLabelCfg);
20263 if(this.inputType != 'radio'){
20264 cfg.cn.push(hidden);
20272 * return the real input element.
20274 inputEl: function ()
20276 return this.el.select('input.roo-' + this.inputType,true).first();
20278 hiddenEl: function ()
20280 return this.el.select('input.roo-hidden-value',true).first();
20283 labelEl: function()
20285 return this.el.select('label.control-label',true).first();
20287 /* depricated... */
20291 return this.labelEl();
20294 boxLabelEl: function()
20296 return this.el.select('label.box-label',true).first();
20299 initEvents : function()
20301 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20303 this.inputEl().on('click', this.onClick, this);
20305 if (this.boxLabel) {
20306 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20309 this.startValue = this.getValue();
20312 Roo.bootstrap.CheckBox.register(this);
20316 onClick : function()
20318 this.setChecked(!this.checked);
20321 setChecked : function(state,suppressEvent)
20323 this.startValue = this.getValue();
20325 if(this.inputType == 'radio'){
20327 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20328 e.dom.checked = false;
20331 this.inputEl().dom.checked = true;
20333 this.inputEl().dom.value = this.inputValue;
20335 if(suppressEvent !== true){
20336 this.fireEvent('check', this, true);
20344 this.checked = state;
20346 this.inputEl().dom.checked = state;
20349 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20351 if(suppressEvent !== true){
20352 this.fireEvent('check', this, state);
20358 getValue : function()
20360 if(this.inputType == 'radio'){
20361 return this.getGroupValue();
20364 return this.hiddenEl().dom.value;
20368 getGroupValue : function()
20370 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20374 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20377 setValue : function(v,suppressEvent)
20379 if(this.inputType == 'radio'){
20380 this.setGroupValue(v, suppressEvent);
20384 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20389 setGroupValue : function(v, suppressEvent)
20391 this.startValue = this.getValue();
20393 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20394 e.dom.checked = false;
20396 if(e.dom.value == v){
20397 e.dom.checked = true;
20401 if(suppressEvent !== true){
20402 this.fireEvent('check', this, true);
20410 validate : function()
20414 (this.inputType == 'radio' && this.validateRadio()) ||
20415 (this.inputType == 'checkbox' && this.validateCheckbox())
20421 this.markInvalid();
20425 validateRadio : function()
20427 if(this.allowBlank){
20433 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20434 if(!e.dom.checked){
20446 validateCheckbox : function()
20449 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20450 //return (this.getValue() == this.inputValue) ? true : false;
20453 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20461 for(var i in group){
20466 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20473 * Mark this field as valid
20475 markValid : function()
20479 this.fireEvent('valid', this);
20481 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20484 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20491 if(this.inputType == 'radio'){
20492 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20493 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20494 e.findParent('.form-group', false, true).addClass(_this.validClass);
20501 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20502 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20506 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20512 for(var i in group){
20513 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20514 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20519 * Mark this field as invalid
20520 * @param {String} msg The validation message
20522 markInvalid : function(msg)
20524 if(this.allowBlank){
20530 this.fireEvent('invalid', this, msg);
20532 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20535 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20539 label.markInvalid();
20542 if(this.inputType == 'radio'){
20543 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20544 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20545 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20552 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20553 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20557 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20563 for(var i in group){
20564 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20565 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20570 clearInvalid : function()
20572 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20574 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20576 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20579 label.iconEl.removeClass(label.validClass);
20580 label.iconEl.removeClass(label.invalidClass);
20584 disable : function()
20586 if(this.inputType != 'radio'){
20587 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20594 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20595 _this.getActionEl().addClass(this.disabledClass);
20596 e.dom.disabled = true;
20600 this.disabled = true;
20601 this.fireEvent("disable", this);
20605 enable : function()
20607 if(this.inputType != 'radio'){
20608 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20615 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20616 _this.getActionEl().removeClass(this.disabledClass);
20617 e.dom.disabled = false;
20621 this.disabled = false;
20622 this.fireEvent("enable", this);
20628 Roo.apply(Roo.bootstrap.CheckBox, {
20633 * register a CheckBox Group
20634 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20636 register : function(checkbox)
20638 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20639 this.groups[checkbox.groupId] = {};
20642 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20646 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20650 * fetch a CheckBox Group based on the group ID
20651 * @param {string} the group ID
20652 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20654 get: function(groupId) {
20655 if (typeof(this.groups[groupId]) == 'undefined') {
20659 return this.groups[groupId] ;
20672 * @class Roo.bootstrap.Radio
20673 * @extends Roo.bootstrap.Component
20674 * Bootstrap Radio class
20675 * @cfg {String} boxLabel - the label associated
20676 * @cfg {String} value - the value of radio
20679 * Create a new Radio
20680 * @param {Object} config The config object
20682 Roo.bootstrap.Radio = function(config){
20683 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20687 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20693 getAutoCreate : function()
20697 cls : 'form-group radio',
20702 html : this.boxLabel
20710 initEvents : function()
20712 this.parent().register(this);
20714 this.el.on('click', this.onClick, this);
20718 onClick : function()
20720 this.setChecked(true);
20723 setChecked : function(state, suppressEvent)
20725 this.parent().setValue(this.value, suppressEvent);
20740 * @class Roo.bootstrap.SecurePass
20741 * @extends Roo.bootstrap.Input
20742 * Bootstrap SecurePass class
20746 * Create a new SecurePass
20747 * @param {Object} config The config object
20750 Roo.bootstrap.SecurePass = function (config) {
20751 // these go here, so the translation tool can replace them..
20753 PwdEmpty: "Please type a password, and then retype it to confirm.",
20754 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20755 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20756 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20757 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20758 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20759 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20760 TooWeak: "Your password is Too Weak."
20762 this.meterLabel = "Password strength:";
20763 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20764 this.meterClass = [
20765 "roo-password-meter-tooweak",
20766 "roo-password-meter-weak",
20767 "roo-password-meter-medium",
20768 "roo-password-meter-strong",
20769 "roo-password-meter-grey"
20774 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20777 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20779 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20781 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20782 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20783 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20784 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20785 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20786 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20787 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20797 * @cfg {String/Object} Label for the strength meter (defaults to
20798 * 'Password strength:')
20803 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20804 * ['Weak', 'Medium', 'Strong'])
20807 pwdStrengths: false,
20820 initEvents: function ()
20822 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20824 if (this.el.is('input[type=password]') && Roo.isSafari) {
20825 this.el.on('keydown', this.SafariOnKeyDown, this);
20828 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20831 onRender: function (ct, position)
20833 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20834 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20835 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20837 this.trigger.createChild({
20842 cls: 'roo-password-meter-grey col-xs-12',
20845 //width: this.meterWidth + 'px'
20849 cls: 'roo-password-meter-text'
20855 if (this.hideTrigger) {
20856 this.trigger.setDisplayed(false);
20858 this.setSize(this.width || '', this.height || '');
20861 onDestroy: function ()
20863 if (this.trigger) {
20864 this.trigger.removeAllListeners();
20865 this.trigger.remove();
20868 this.wrap.remove();
20870 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20873 checkStrength: function ()
20875 var pwd = this.inputEl().getValue();
20876 if (pwd == this._lastPwd) {
20881 if (this.ClientSideStrongPassword(pwd)) {
20883 } else if (this.ClientSideMediumPassword(pwd)) {
20885 } else if (this.ClientSideWeakPassword(pwd)) {
20891 Roo.log('strength1: ' + strength);
20893 //var pm = this.trigger.child('div/div/div').dom;
20894 var pm = this.trigger.child('div/div');
20895 pm.removeClass(this.meterClass);
20896 pm.addClass(this.meterClass[strength]);
20899 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20901 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20903 this._lastPwd = pwd;
20907 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20909 this._lastPwd = '';
20911 var pm = this.trigger.child('div/div');
20912 pm.removeClass(this.meterClass);
20913 pm.addClass('roo-password-meter-grey');
20916 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20919 this.inputEl().dom.type='password';
20922 validateValue: function (value)
20925 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20928 if (value.length == 0) {
20929 if (this.allowBlank) {
20930 this.clearInvalid();
20934 this.markInvalid(this.errors.PwdEmpty);
20935 this.errorMsg = this.errors.PwdEmpty;
20943 if ('[\x21-\x7e]*'.match(value)) {
20944 this.markInvalid(this.errors.PwdBadChar);
20945 this.errorMsg = this.errors.PwdBadChar;
20948 if (value.length < 6) {
20949 this.markInvalid(this.errors.PwdShort);
20950 this.errorMsg = this.errors.PwdShort;
20953 if (value.length > 16) {
20954 this.markInvalid(this.errors.PwdLong);
20955 this.errorMsg = this.errors.PwdLong;
20959 if (this.ClientSideStrongPassword(value)) {
20961 } else if (this.ClientSideMediumPassword(value)) {
20963 } else if (this.ClientSideWeakPassword(value)) {
20970 if (strength < 2) {
20971 //this.markInvalid(this.errors.TooWeak);
20972 this.errorMsg = this.errors.TooWeak;
20977 console.log('strength2: ' + strength);
20979 //var pm = this.trigger.child('div/div/div').dom;
20981 var pm = this.trigger.child('div/div');
20982 pm.removeClass(this.meterClass);
20983 pm.addClass(this.meterClass[strength]);
20985 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20987 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20989 this.errorMsg = '';
20993 CharacterSetChecks: function (type)
20996 this.fResult = false;
20999 isctype: function (character, type)
21002 case this.kCapitalLetter:
21003 if (character >= 'A' && character <= 'Z') {
21008 case this.kSmallLetter:
21009 if (character >= 'a' && character <= 'z') {
21015 if (character >= '0' && character <= '9') {
21020 case this.kPunctuation:
21021 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21032 IsLongEnough: function (pwd, size)
21034 return !(pwd == null || isNaN(size) || pwd.length < size);
21037 SpansEnoughCharacterSets: function (word, nb)
21039 if (!this.IsLongEnough(word, nb))
21044 var characterSetChecks = new Array(
21045 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21046 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21049 for (var index = 0; index < word.length; ++index) {
21050 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21051 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21052 characterSetChecks[nCharSet].fResult = true;
21059 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21060 if (characterSetChecks[nCharSet].fResult) {
21065 if (nCharSets < nb) {
21071 ClientSideStrongPassword: function (pwd)
21073 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21076 ClientSideMediumPassword: function (pwd)
21078 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21081 ClientSideWeakPassword: function (pwd)
21083 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21086 })//<script type="text/javascript">
21089 * Based Ext JS Library 1.1.1
21090 * Copyright(c) 2006-2007, Ext JS, LLC.
21096 * @class Roo.HtmlEditorCore
21097 * @extends Roo.Component
21098 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21100 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21103 Roo.HtmlEditorCore = function(config){
21106 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21111 * @event initialize
21112 * Fires when the editor is fully initialized (including the iframe)
21113 * @param {Roo.HtmlEditorCore} this
21118 * Fires when the editor is first receives the focus. Any insertion must wait
21119 * until after this event.
21120 * @param {Roo.HtmlEditorCore} this
21124 * @event beforesync
21125 * Fires before the textarea is updated with content from the editor iframe. Return false
21126 * to cancel the sync.
21127 * @param {Roo.HtmlEditorCore} this
21128 * @param {String} html
21132 * @event beforepush
21133 * Fires before the iframe editor is updated with content from the textarea. Return false
21134 * to cancel the push.
21135 * @param {Roo.HtmlEditorCore} this
21136 * @param {String} html
21141 * Fires when the textarea is updated with content from the editor iframe.
21142 * @param {Roo.HtmlEditorCore} this
21143 * @param {String} html
21148 * Fires when the iframe editor is updated with content from the textarea.
21149 * @param {Roo.HtmlEditorCore} this
21150 * @param {String} html
21155 * @event editorevent
21156 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21157 * @param {Roo.HtmlEditorCore} this
21163 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21165 // defaults : white / black...
21166 this.applyBlacklists();
21173 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21177 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21183 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21188 * @cfg {Number} height (in pixels)
21192 * @cfg {Number} width (in pixels)
21197 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21200 stylesheets: false,
21205 // private properties
21206 validationEvent : false,
21208 initialized : false,
21210 sourceEditMode : false,
21211 onFocus : Roo.emptyFn,
21213 hideMode:'offsets',
21217 // blacklist + whitelisted elements..
21224 * Protected method that will not generally be called directly. It
21225 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21226 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21228 getDocMarkup : function(){
21232 // inherit styels from page...??
21233 if (this.stylesheets === false) {
21235 Roo.get(document.head).select('style').each(function(node) {
21236 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21239 Roo.get(document.head).select('link').each(function(node) {
21240 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21243 } else if (!this.stylesheets.length) {
21245 st = '<style type="text/css">' +
21246 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21252 st += '<style type="text/css">' +
21253 'IMG { cursor: pointer } ' +
21257 return '<html><head>' + st +
21258 //<style type="text/css">' +
21259 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21261 ' </head><body class="roo-htmleditor-body"></body></html>';
21265 onRender : function(ct, position)
21268 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21269 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21272 this.el.dom.style.border = '0 none';
21273 this.el.dom.setAttribute('tabIndex', -1);
21274 this.el.addClass('x-hidden hide');
21278 if(Roo.isIE){ // fix IE 1px bogus margin
21279 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21283 this.frameId = Roo.id();
21287 var iframe = this.owner.wrap.createChild({
21289 cls: 'form-control', // bootstrap..
21291 name: this.frameId,
21292 frameBorder : 'no',
21293 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21298 this.iframe = iframe.dom;
21300 this.assignDocWin();
21302 this.doc.designMode = 'on';
21305 this.doc.write(this.getDocMarkup());
21309 var task = { // must defer to wait for browser to be ready
21311 //console.log("run task?" + this.doc.readyState);
21312 this.assignDocWin();
21313 if(this.doc.body || this.doc.readyState == 'complete'){
21315 this.doc.designMode="on";
21319 Roo.TaskMgr.stop(task);
21320 this.initEditor.defer(10, this);
21327 Roo.TaskMgr.start(task);
21332 onResize : function(w, h)
21334 Roo.log('resize: ' +w + ',' + h );
21335 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21339 if(typeof w == 'number'){
21341 this.iframe.style.width = w + 'px';
21343 if(typeof h == 'number'){
21345 this.iframe.style.height = h + 'px';
21347 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21354 * Toggles the editor between standard and source edit mode.
21355 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21357 toggleSourceEdit : function(sourceEditMode){
21359 this.sourceEditMode = sourceEditMode === true;
21361 if(this.sourceEditMode){
21363 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21366 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21367 //this.iframe.className = '';
21370 //this.setSize(this.owner.wrap.getSize());
21371 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21378 * Protected method that will not generally be called directly. If you need/want
21379 * custom HTML cleanup, this is the method you should override.
21380 * @param {String} html The HTML to be cleaned
21381 * return {String} The cleaned HTML
21383 cleanHtml : function(html){
21384 html = String(html);
21385 if(html.length > 5){
21386 if(Roo.isSafari){ // strip safari nonsense
21387 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21390 if(html == ' '){
21397 * HTML Editor -> Textarea
21398 * Protected method that will not generally be called directly. Syncs the contents
21399 * of the editor iframe with the textarea.
21401 syncValue : function(){
21402 if(this.initialized){
21403 var bd = (this.doc.body || this.doc.documentElement);
21404 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21405 var html = bd.innerHTML;
21407 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21408 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21410 html = '<div style="'+m[0]+'">' + html + '</div>';
21413 html = this.cleanHtml(html);
21414 // fix up the special chars.. normaly like back quotes in word...
21415 // however we do not want to do this with chinese..
21416 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21417 var cc = b.charCodeAt();
21419 (cc >= 0x4E00 && cc < 0xA000 ) ||
21420 (cc >= 0x3400 && cc < 0x4E00 ) ||
21421 (cc >= 0xf900 && cc < 0xfb00 )
21427 if(this.owner.fireEvent('beforesync', this, html) !== false){
21428 this.el.dom.value = html;
21429 this.owner.fireEvent('sync', this, html);
21435 * Protected method that will not generally be called directly. Pushes the value of the textarea
21436 * into the iframe editor.
21438 pushValue : function(){
21439 if(this.initialized){
21440 var v = this.el.dom.value.trim();
21442 // if(v.length < 1){
21446 if(this.owner.fireEvent('beforepush', this, v) !== false){
21447 var d = (this.doc.body || this.doc.documentElement);
21449 this.cleanUpPaste();
21450 this.el.dom.value = d.innerHTML;
21451 this.owner.fireEvent('push', this, v);
21457 deferFocus : function(){
21458 this.focus.defer(10, this);
21462 focus : function(){
21463 if(this.win && !this.sourceEditMode){
21470 assignDocWin: function()
21472 var iframe = this.iframe;
21475 this.doc = iframe.contentWindow.document;
21476 this.win = iframe.contentWindow;
21478 // if (!Roo.get(this.frameId)) {
21481 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21482 // this.win = Roo.get(this.frameId).dom.contentWindow;
21484 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21488 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21489 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21494 initEditor : function(){
21495 //console.log("INIT EDITOR");
21496 this.assignDocWin();
21500 this.doc.designMode="on";
21502 this.doc.write(this.getDocMarkup());
21505 var dbody = (this.doc.body || this.doc.documentElement);
21506 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21507 // this copies styles from the containing element into thsi one..
21508 // not sure why we need all of this..
21509 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21511 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21512 //ss['background-attachment'] = 'fixed'; // w3c
21513 dbody.bgProperties = 'fixed'; // ie
21514 //Roo.DomHelper.applyStyles(dbody, ss);
21515 Roo.EventManager.on(this.doc, {
21516 //'mousedown': this.onEditorEvent,
21517 'mouseup': this.onEditorEvent,
21518 'dblclick': this.onEditorEvent,
21519 'click': this.onEditorEvent,
21520 'keyup': this.onEditorEvent,
21525 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21527 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21528 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21530 this.initialized = true;
21532 this.owner.fireEvent('initialize', this);
21537 onDestroy : function(){
21543 //for (var i =0; i < this.toolbars.length;i++) {
21544 // // fixme - ask toolbars for heights?
21545 // this.toolbars[i].onDestroy();
21548 //this.wrap.dom.innerHTML = '';
21549 //this.wrap.remove();
21554 onFirstFocus : function(){
21556 this.assignDocWin();
21559 this.activated = true;
21562 if(Roo.isGecko){ // prevent silly gecko errors
21564 var s = this.win.getSelection();
21565 if(!s.focusNode || s.focusNode.nodeType != 3){
21566 var r = s.getRangeAt(0);
21567 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21572 this.execCmd('useCSS', true);
21573 this.execCmd('styleWithCSS', false);
21576 this.owner.fireEvent('activate', this);
21580 adjustFont: function(btn){
21581 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21582 //if(Roo.isSafari){ // safari
21585 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21586 if(Roo.isSafari){ // safari
21587 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21588 v = (v < 10) ? 10 : v;
21589 v = (v > 48) ? 48 : v;
21590 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21595 v = Math.max(1, v+adjust);
21597 this.execCmd('FontSize', v );
21600 onEditorEvent : function(e)
21602 this.owner.fireEvent('editorevent', this, e);
21603 // this.updateToolbar();
21604 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21607 insertTag : function(tg)
21609 // could be a bit smarter... -> wrap the current selected tRoo..
21610 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21612 range = this.createRange(this.getSelection());
21613 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21614 wrappingNode.appendChild(range.extractContents());
21615 range.insertNode(wrappingNode);
21622 this.execCmd("formatblock", tg);
21626 insertText : function(txt)
21630 var range = this.createRange();
21631 range.deleteContents();
21632 //alert(Sender.getAttribute('label'));
21634 range.insertNode(this.doc.createTextNode(txt));
21640 * Executes a Midas editor command on the editor document and performs necessary focus and
21641 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21642 * @param {String} cmd The Midas command
21643 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21645 relayCmd : function(cmd, value){
21647 this.execCmd(cmd, value);
21648 this.owner.fireEvent('editorevent', this);
21649 //this.updateToolbar();
21650 this.owner.deferFocus();
21654 * Executes a Midas editor command directly on the editor document.
21655 * For visual commands, you should use {@link #relayCmd} instead.
21656 * <b>This should only be called after the editor is initialized.</b>
21657 * @param {String} cmd The Midas command
21658 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21660 execCmd : function(cmd, value){
21661 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21668 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21670 * @param {String} text | dom node..
21672 insertAtCursor : function(text)
21675 if(!this.activated){
21681 var r = this.doc.selection.createRange();
21692 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21696 // from jquery ui (MIT licenced)
21698 var win = this.win;
21700 if (win.getSelection && win.getSelection().getRangeAt) {
21701 range = win.getSelection().getRangeAt(0);
21702 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21703 range.insertNode(node);
21704 } else if (win.document.selection && win.document.selection.createRange) {
21705 // no firefox support
21706 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21707 win.document.selection.createRange().pasteHTML(txt);
21709 // no firefox support
21710 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21711 this.execCmd('InsertHTML', txt);
21720 mozKeyPress : function(e){
21722 var c = e.getCharCode(), cmd;
21725 c = String.fromCharCode(c).toLowerCase();
21739 this.cleanUpPaste.defer(100, this);
21747 e.preventDefault();
21755 fixKeys : function(){ // load time branching for fastest keydown performance
21757 return function(e){
21758 var k = e.getKey(), r;
21761 r = this.doc.selection.createRange();
21764 r.pasteHTML('    ');
21771 r = this.doc.selection.createRange();
21773 var target = r.parentElement();
21774 if(!target || target.tagName.toLowerCase() != 'li'){
21776 r.pasteHTML('<br />');
21782 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21783 this.cleanUpPaste.defer(100, this);
21789 }else if(Roo.isOpera){
21790 return function(e){
21791 var k = e.getKey();
21795 this.execCmd('InsertHTML','    ');
21798 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21799 this.cleanUpPaste.defer(100, this);
21804 }else if(Roo.isSafari){
21805 return function(e){
21806 var k = e.getKey();
21810 this.execCmd('InsertText','\t');
21814 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21815 this.cleanUpPaste.defer(100, this);
21823 getAllAncestors: function()
21825 var p = this.getSelectedNode();
21828 a.push(p); // push blank onto stack..
21829 p = this.getParentElement();
21833 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21837 a.push(this.doc.body);
21841 lastSelNode : false,
21844 getSelection : function()
21846 this.assignDocWin();
21847 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21850 getSelectedNode: function()
21852 // this may only work on Gecko!!!
21854 // should we cache this!!!!
21859 var range = this.createRange(this.getSelection()).cloneRange();
21862 var parent = range.parentElement();
21864 var testRange = range.duplicate();
21865 testRange.moveToElementText(parent);
21866 if (testRange.inRange(range)) {
21869 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21872 parent = parent.parentElement;
21877 // is ancestor a text element.
21878 var ac = range.commonAncestorContainer;
21879 if (ac.nodeType == 3) {
21880 ac = ac.parentNode;
21883 var ar = ac.childNodes;
21886 var other_nodes = [];
21887 var has_other_nodes = false;
21888 for (var i=0;i<ar.length;i++) {
21889 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21892 // fullly contained node.
21894 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21899 // probably selected..
21900 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21901 other_nodes.push(ar[i]);
21905 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21910 has_other_nodes = true;
21912 if (!nodes.length && other_nodes.length) {
21913 nodes= other_nodes;
21915 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21921 createRange: function(sel)
21923 // this has strange effects when using with
21924 // top toolbar - not sure if it's a great idea.
21925 //this.editor.contentWindow.focus();
21926 if (typeof sel != "undefined") {
21928 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21930 return this.doc.createRange();
21933 return this.doc.createRange();
21936 getParentElement: function()
21939 this.assignDocWin();
21940 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21942 var range = this.createRange(sel);
21945 var p = range.commonAncestorContainer;
21946 while (p.nodeType == 3) { // text node
21957 * Range intersection.. the hard stuff...
21961 * [ -- selected range --- ]
21965 * if end is before start or hits it. fail.
21966 * if start is after end or hits it fail.
21968 * if either hits (but other is outside. - then it's not
21974 // @see http://www.thismuchiknow.co.uk/?p=64.
21975 rangeIntersectsNode : function(range, node)
21977 var nodeRange = node.ownerDocument.createRange();
21979 nodeRange.selectNode(node);
21981 nodeRange.selectNodeContents(node);
21984 var rangeStartRange = range.cloneRange();
21985 rangeStartRange.collapse(true);
21987 var rangeEndRange = range.cloneRange();
21988 rangeEndRange.collapse(false);
21990 var nodeStartRange = nodeRange.cloneRange();
21991 nodeStartRange.collapse(true);
21993 var nodeEndRange = nodeRange.cloneRange();
21994 nodeEndRange.collapse(false);
21996 return rangeStartRange.compareBoundaryPoints(
21997 Range.START_TO_START, nodeEndRange) == -1 &&
21998 rangeEndRange.compareBoundaryPoints(
21999 Range.START_TO_START, nodeStartRange) == 1;
22003 rangeCompareNode : function(range, node)
22005 var nodeRange = node.ownerDocument.createRange();
22007 nodeRange.selectNode(node);
22009 nodeRange.selectNodeContents(node);
22013 range.collapse(true);
22015 nodeRange.collapse(true);
22017 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22018 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22020 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22022 var nodeIsBefore = ss == 1;
22023 var nodeIsAfter = ee == -1;
22025 if (nodeIsBefore && nodeIsAfter) {
22028 if (!nodeIsBefore && nodeIsAfter) {
22029 return 1; //right trailed.
22032 if (nodeIsBefore && !nodeIsAfter) {
22033 return 2; // left trailed.
22039 // private? - in a new class?
22040 cleanUpPaste : function()
22042 // cleans up the whole document..
22043 Roo.log('cleanuppaste');
22045 this.cleanUpChildren(this.doc.body);
22046 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22047 if (clean != this.doc.body.innerHTML) {
22048 this.doc.body.innerHTML = clean;
22053 cleanWordChars : function(input) {// change the chars to hex code
22054 var he = Roo.HtmlEditorCore;
22056 var output = input;
22057 Roo.each(he.swapCodes, function(sw) {
22058 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22060 output = output.replace(swapper, sw[1]);
22067 cleanUpChildren : function (n)
22069 if (!n.childNodes.length) {
22072 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22073 this.cleanUpChild(n.childNodes[i]);
22080 cleanUpChild : function (node)
22083 //console.log(node);
22084 if (node.nodeName == "#text") {
22085 // clean up silly Windows -- stuff?
22088 if (node.nodeName == "#comment") {
22089 node.parentNode.removeChild(node);
22090 // clean up silly Windows -- stuff?
22093 var lcname = node.tagName.toLowerCase();
22094 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22095 // whitelist of tags..
22097 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22099 node.parentNode.removeChild(node);
22104 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22106 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22107 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22109 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22110 // remove_keep_children = true;
22113 if (remove_keep_children) {
22114 this.cleanUpChildren(node);
22115 // inserts everything just before this node...
22116 while (node.childNodes.length) {
22117 var cn = node.childNodes[0];
22118 node.removeChild(cn);
22119 node.parentNode.insertBefore(cn, node);
22121 node.parentNode.removeChild(node);
22125 if (!node.attributes || !node.attributes.length) {
22126 this.cleanUpChildren(node);
22130 function cleanAttr(n,v)
22133 if (v.match(/^\./) || v.match(/^\//)) {
22136 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22139 if (v.match(/^#/)) {
22142 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22143 node.removeAttribute(n);
22147 var cwhite = this.cwhite;
22148 var cblack = this.cblack;
22150 function cleanStyle(n,v)
22152 if (v.match(/expression/)) { //XSS?? should we even bother..
22153 node.removeAttribute(n);
22157 var parts = v.split(/;/);
22160 Roo.each(parts, function(p) {
22161 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22165 var l = p.split(':').shift().replace(/\s+/g,'');
22166 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22168 if ( cwhite.length && cblack.indexOf(l) > -1) {
22169 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22170 //node.removeAttribute(n);
22174 // only allow 'c whitelisted system attributes'
22175 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22176 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22177 //node.removeAttribute(n);
22187 if (clean.length) {
22188 node.setAttribute(n, clean.join(';'));
22190 node.removeAttribute(n);
22196 for (var i = node.attributes.length-1; i > -1 ; i--) {
22197 var a = node.attributes[i];
22200 if (a.name.toLowerCase().substr(0,2)=='on') {
22201 node.removeAttribute(a.name);
22204 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22205 node.removeAttribute(a.name);
22208 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22209 cleanAttr(a.name,a.value); // fixme..
22212 if (a.name == 'style') {
22213 cleanStyle(a.name,a.value);
22216 /// clean up MS crap..
22217 // tecnically this should be a list of valid class'es..
22220 if (a.name == 'class') {
22221 if (a.value.match(/^Mso/)) {
22222 node.className = '';
22225 if (a.value.match(/^body$/)) {
22226 node.className = '';
22237 this.cleanUpChildren(node);
22243 * Clean up MS wordisms...
22245 cleanWord : function(node)
22250 this.cleanWord(this.doc.body);
22253 if (node.nodeName == "#text") {
22254 // clean up silly Windows -- stuff?
22257 if (node.nodeName == "#comment") {
22258 node.parentNode.removeChild(node);
22259 // clean up silly Windows -- stuff?
22263 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22264 node.parentNode.removeChild(node);
22268 // remove - but keep children..
22269 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22270 while (node.childNodes.length) {
22271 var cn = node.childNodes[0];
22272 node.removeChild(cn);
22273 node.parentNode.insertBefore(cn, node);
22275 node.parentNode.removeChild(node);
22276 this.iterateChildren(node, this.cleanWord);
22280 if (node.className.length) {
22282 var cn = node.className.split(/\W+/);
22284 Roo.each(cn, function(cls) {
22285 if (cls.match(/Mso[a-zA-Z]+/)) {
22290 node.className = cna.length ? cna.join(' ') : '';
22292 node.removeAttribute("class");
22296 if (node.hasAttribute("lang")) {
22297 node.removeAttribute("lang");
22300 if (node.hasAttribute("style")) {
22302 var styles = node.getAttribute("style").split(";");
22304 Roo.each(styles, function(s) {
22305 if (!s.match(/:/)) {
22308 var kv = s.split(":");
22309 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22312 // what ever is left... we allow.
22315 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22316 if (!nstyle.length) {
22317 node.removeAttribute('style');
22320 this.iterateChildren(node, this.cleanWord);
22326 * iterateChildren of a Node, calling fn each time, using this as the scole..
22327 * @param {DomNode} node node to iterate children of.
22328 * @param {Function} fn method of this class to call on each item.
22330 iterateChildren : function(node, fn)
22332 if (!node.childNodes.length) {
22335 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22336 fn.call(this, node.childNodes[i])
22342 * cleanTableWidths.
22344 * Quite often pasting from word etc.. results in tables with column and widths.
22345 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22348 cleanTableWidths : function(node)
22353 this.cleanTableWidths(this.doc.body);
22358 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22361 Roo.log(node.tagName);
22362 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22363 this.iterateChildren(node, this.cleanTableWidths);
22366 if (node.hasAttribute('width')) {
22367 node.removeAttribute('width');
22371 if (node.hasAttribute("style")) {
22374 var styles = node.getAttribute("style").split(";");
22376 Roo.each(styles, function(s) {
22377 if (!s.match(/:/)) {
22380 var kv = s.split(":");
22381 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22384 // what ever is left... we allow.
22387 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22388 if (!nstyle.length) {
22389 node.removeAttribute('style');
22393 this.iterateChildren(node, this.cleanTableWidths);
22401 domToHTML : function(currentElement, depth, nopadtext) {
22403 depth = depth || 0;
22404 nopadtext = nopadtext || false;
22406 if (!currentElement) {
22407 return this.domToHTML(this.doc.body);
22410 //Roo.log(currentElement);
22412 var allText = false;
22413 var nodeName = currentElement.nodeName;
22414 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22416 if (nodeName == '#text') {
22418 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22423 if (nodeName != 'BODY') {
22426 // Prints the node tagName, such as <A>, <IMG>, etc
22429 for(i = 0; i < currentElement.attributes.length;i++) {
22431 var aname = currentElement.attributes.item(i).name;
22432 if (!currentElement.attributes.item(i).value.length) {
22435 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22438 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22447 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22450 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22455 // Traverse the tree
22457 var currentElementChild = currentElement.childNodes.item(i);
22458 var allText = true;
22459 var innerHTML = '';
22461 while (currentElementChild) {
22462 // Formatting code (indent the tree so it looks nice on the screen)
22463 var nopad = nopadtext;
22464 if (lastnode == 'SPAN') {
22468 if (currentElementChild.nodeName == '#text') {
22469 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22470 toadd = nopadtext ? toadd : toadd.trim();
22471 if (!nopad && toadd.length > 80) {
22472 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22474 innerHTML += toadd;
22477 currentElementChild = currentElement.childNodes.item(i);
22483 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22485 // Recursively traverse the tree structure of the child node
22486 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22487 lastnode = currentElementChild.nodeName;
22489 currentElementChild=currentElement.childNodes.item(i);
22495 // The remaining code is mostly for formatting the tree
22496 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22501 ret+= "</"+tagName+">";
22507 applyBlacklists : function()
22509 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22510 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22514 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22515 if (b.indexOf(tag) > -1) {
22518 this.white.push(tag);
22522 Roo.each(w, function(tag) {
22523 if (b.indexOf(tag) > -1) {
22526 if (this.white.indexOf(tag) > -1) {
22529 this.white.push(tag);
22534 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22535 if (w.indexOf(tag) > -1) {
22538 this.black.push(tag);
22542 Roo.each(b, function(tag) {
22543 if (w.indexOf(tag) > -1) {
22546 if (this.black.indexOf(tag) > -1) {
22549 this.black.push(tag);
22554 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22555 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22559 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22560 if (b.indexOf(tag) > -1) {
22563 this.cwhite.push(tag);
22567 Roo.each(w, function(tag) {
22568 if (b.indexOf(tag) > -1) {
22571 if (this.cwhite.indexOf(tag) > -1) {
22574 this.cwhite.push(tag);
22579 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22580 if (w.indexOf(tag) > -1) {
22583 this.cblack.push(tag);
22587 Roo.each(b, function(tag) {
22588 if (w.indexOf(tag) > -1) {
22591 if (this.cblack.indexOf(tag) > -1) {
22594 this.cblack.push(tag);
22599 setStylesheets : function(stylesheets)
22601 if(typeof(stylesheets) == 'string'){
22602 Roo.get(this.iframe.contentDocument.head).createChild({
22604 rel : 'stylesheet',
22613 Roo.each(stylesheets, function(s) {
22618 Roo.get(_this.iframe.contentDocument.head).createChild({
22620 rel : 'stylesheet',
22629 removeStylesheets : function()
22633 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22638 // hide stuff that is not compatible
22652 * @event specialkey
22656 * @cfg {String} fieldClass @hide
22659 * @cfg {String} focusClass @hide
22662 * @cfg {String} autoCreate @hide
22665 * @cfg {String} inputType @hide
22668 * @cfg {String} invalidClass @hide
22671 * @cfg {String} invalidText @hide
22674 * @cfg {String} msgFx @hide
22677 * @cfg {String} validateOnBlur @hide
22681 Roo.HtmlEditorCore.white = [
22682 'area', 'br', 'img', 'input', 'hr', 'wbr',
22684 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22685 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22686 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22687 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22688 'table', 'ul', 'xmp',
22690 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22693 'dir', 'menu', 'ol', 'ul', 'dl',
22699 Roo.HtmlEditorCore.black = [
22700 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22702 'base', 'basefont', 'bgsound', 'blink', 'body',
22703 'frame', 'frameset', 'head', 'html', 'ilayer',
22704 'iframe', 'layer', 'link', 'meta', 'object',
22705 'script', 'style' ,'title', 'xml' // clean later..
22707 Roo.HtmlEditorCore.clean = [
22708 'script', 'style', 'title', 'xml'
22710 Roo.HtmlEditorCore.remove = [
22715 Roo.HtmlEditorCore.ablack = [
22719 Roo.HtmlEditorCore.aclean = [
22720 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22724 Roo.HtmlEditorCore.pwhite= [
22725 'http', 'https', 'mailto'
22728 // white listed style attributes.
22729 Roo.HtmlEditorCore.cwhite= [
22730 // 'text-align', /// default is to allow most things..
22736 // black listed style attributes.
22737 Roo.HtmlEditorCore.cblack= [
22738 // 'font-size' -- this can be set by the project
22742 Roo.HtmlEditorCore.swapCodes =[
22761 * @class Roo.bootstrap.HtmlEditor
22762 * @extends Roo.bootstrap.TextArea
22763 * Bootstrap HtmlEditor class
22766 * Create a new HtmlEditor
22767 * @param {Object} config The config object
22770 Roo.bootstrap.HtmlEditor = function(config){
22771 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22772 if (!this.toolbars) {
22773 this.toolbars = [];
22776 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22779 * @event initialize
22780 * Fires when the editor is fully initialized (including the iframe)
22781 * @param {HtmlEditor} this
22786 * Fires when the editor is first receives the focus. Any insertion must wait
22787 * until after this event.
22788 * @param {HtmlEditor} this
22792 * @event beforesync
22793 * Fires before the textarea is updated with content from the editor iframe. Return false
22794 * to cancel the sync.
22795 * @param {HtmlEditor} this
22796 * @param {String} html
22800 * @event beforepush
22801 * Fires before the iframe editor is updated with content from the textarea. Return false
22802 * to cancel the push.
22803 * @param {HtmlEditor} this
22804 * @param {String} html
22809 * Fires when the textarea is updated with content from the editor iframe.
22810 * @param {HtmlEditor} this
22811 * @param {String} html
22816 * Fires when the iframe editor is updated with content from the textarea.
22817 * @param {HtmlEditor} this
22818 * @param {String} html
22822 * @event editmodechange
22823 * Fires when the editor switches edit modes
22824 * @param {HtmlEditor} this
22825 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22827 editmodechange: true,
22829 * @event editorevent
22830 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22831 * @param {HtmlEditor} this
22835 * @event firstfocus
22836 * Fires when on first focus - needed by toolbars..
22837 * @param {HtmlEditor} this
22842 * Auto save the htmlEditor value as a file into Events
22843 * @param {HtmlEditor} this
22847 * @event savedpreview
22848 * preview the saved version of htmlEditor
22849 * @param {HtmlEditor} this
22856 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22860 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22865 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22870 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22875 * @cfg {Number} height (in pixels)
22879 * @cfg {Number} width (in pixels)
22884 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22887 stylesheets: false,
22892 // private properties
22893 validationEvent : false,
22895 initialized : false,
22898 onFocus : Roo.emptyFn,
22900 hideMode:'offsets',
22902 tbContainer : false,
22904 toolbarContainer :function() {
22905 return this.wrap.select('.x-html-editor-tb',true).first();
22909 * Protected method that will not generally be called directly. It
22910 * is called when the editor creates its toolbar. Override this method if you need to
22911 * add custom toolbar buttons.
22912 * @param {HtmlEditor} editor
22914 createToolbar : function(){
22915 Roo.log('renewing');
22916 Roo.log("create toolbars");
22918 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22919 this.toolbars[0].render(this.toolbarContainer());
22923 // if (!editor.toolbars || !editor.toolbars.length) {
22924 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22927 // for (var i =0 ; i < editor.toolbars.length;i++) {
22928 // editor.toolbars[i] = Roo.factory(
22929 // typeof(editor.toolbars[i]) == 'string' ?
22930 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22931 // Roo.bootstrap.HtmlEditor);
22932 // editor.toolbars[i].init(editor);
22938 onRender : function(ct, position)
22940 // Roo.log("Call onRender: " + this.xtype);
22942 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22944 this.wrap = this.inputEl().wrap({
22945 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22948 this.editorcore.onRender(ct, position);
22950 if (this.resizable) {
22951 this.resizeEl = new Roo.Resizable(this.wrap, {
22955 minHeight : this.height,
22956 height: this.height,
22957 handles : this.resizable,
22960 resize : function(r, w, h) {
22961 _t.onResize(w,h); // -something
22967 this.createToolbar(this);
22970 if(!this.width && this.resizable){
22971 this.setSize(this.wrap.getSize());
22973 if (this.resizeEl) {
22974 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22975 // should trigger onReize..
22981 onResize : function(w, h)
22983 Roo.log('resize: ' +w + ',' + h );
22984 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22988 if(this.inputEl() ){
22989 if(typeof w == 'number'){
22990 var aw = w - this.wrap.getFrameWidth('lr');
22991 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22994 if(typeof h == 'number'){
22995 var tbh = -11; // fixme it needs to tool bar size!
22996 for (var i =0; i < this.toolbars.length;i++) {
22997 // fixme - ask toolbars for heights?
22998 tbh += this.toolbars[i].el.getHeight();
22999 //if (this.toolbars[i].footer) {
23000 // tbh += this.toolbars[i].footer.el.getHeight();
23008 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23009 ah -= 5; // knock a few pixes off for look..
23010 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23014 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23015 this.editorcore.onResize(ew,eh);
23020 * Toggles the editor between standard and source edit mode.
23021 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23023 toggleSourceEdit : function(sourceEditMode)
23025 this.editorcore.toggleSourceEdit(sourceEditMode);
23027 if(this.editorcore.sourceEditMode){
23028 Roo.log('editor - showing textarea');
23031 // Roo.log(this.syncValue());
23033 this.inputEl().removeClass(['hide', 'x-hidden']);
23034 this.inputEl().dom.removeAttribute('tabIndex');
23035 this.inputEl().focus();
23037 Roo.log('editor - hiding textarea');
23039 // Roo.log(this.pushValue());
23042 this.inputEl().addClass(['hide', 'x-hidden']);
23043 this.inputEl().dom.setAttribute('tabIndex', -1);
23044 //this.deferFocus();
23047 if(this.resizable){
23048 this.setSize(this.wrap.getSize());
23051 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23054 // private (for BoxComponent)
23055 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23057 // private (for BoxComponent)
23058 getResizeEl : function(){
23062 // private (for BoxComponent)
23063 getPositionEl : function(){
23068 initEvents : function(){
23069 this.originalValue = this.getValue();
23073 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23076 // markInvalid : Roo.emptyFn,
23078 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23081 // clearInvalid : Roo.emptyFn,
23083 setValue : function(v){
23084 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23085 this.editorcore.pushValue();
23090 deferFocus : function(){
23091 this.focus.defer(10, this);
23095 focus : function(){
23096 this.editorcore.focus();
23102 onDestroy : function(){
23108 for (var i =0; i < this.toolbars.length;i++) {
23109 // fixme - ask toolbars for heights?
23110 this.toolbars[i].onDestroy();
23113 this.wrap.dom.innerHTML = '';
23114 this.wrap.remove();
23119 onFirstFocus : function(){
23120 //Roo.log("onFirstFocus");
23121 this.editorcore.onFirstFocus();
23122 for (var i =0; i < this.toolbars.length;i++) {
23123 this.toolbars[i].onFirstFocus();
23129 syncValue : function()
23131 this.editorcore.syncValue();
23134 pushValue : function()
23136 this.editorcore.pushValue();
23140 // hide stuff that is not compatible
23154 * @event specialkey
23158 * @cfg {String} fieldClass @hide
23161 * @cfg {String} focusClass @hide
23164 * @cfg {String} autoCreate @hide
23167 * @cfg {String} inputType @hide
23170 * @cfg {String} invalidClass @hide
23173 * @cfg {String} invalidText @hide
23176 * @cfg {String} msgFx @hide
23179 * @cfg {String} validateOnBlur @hide
23188 Roo.namespace('Roo.bootstrap.htmleditor');
23190 * @class Roo.bootstrap.HtmlEditorToolbar1
23195 new Roo.bootstrap.HtmlEditor({
23198 new Roo.bootstrap.HtmlEditorToolbar1({
23199 disable : { fonts: 1 , format: 1, ..., ... , ...],
23205 * @cfg {Object} disable List of elements to disable..
23206 * @cfg {Array} btns List of additional buttons.
23210 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23213 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23216 Roo.apply(this, config);
23218 // default disabled, based on 'good practice'..
23219 this.disable = this.disable || {};
23220 Roo.applyIf(this.disable, {
23223 specialElements : true
23225 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23227 this.editor = config.editor;
23228 this.editorcore = config.editor.editorcore;
23230 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23232 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23233 // dont call parent... till later.
23235 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23240 editorcore : false,
23245 "h1","h2","h3","h4","h5","h6",
23247 "abbr", "acronym", "address", "cite", "samp", "var",
23251 onRender : function(ct, position)
23253 // Roo.log("Call onRender: " + this.xtype);
23255 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23257 this.el.dom.style.marginBottom = '0';
23259 var editorcore = this.editorcore;
23260 var editor= this.editor;
23263 var btn = function(id,cmd , toggle, handler, html){
23265 var event = toggle ? 'toggle' : 'click';
23270 xns: Roo.bootstrap,
23273 enableToggle:toggle !== false,
23275 pressed : toggle ? false : null,
23278 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23279 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23285 // var cb_box = function...
23290 xns: Roo.bootstrap,
23291 glyphicon : 'font',
23295 xns: Roo.bootstrap,
23299 Roo.each(this.formats, function(f) {
23300 style.menu.items.push({
23302 xns: Roo.bootstrap,
23303 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23308 editorcore.insertTag(this.tagname);
23315 children.push(style);
23317 btn('bold',false,true);
23318 btn('italic',false,true);
23319 btn('align-left', 'justifyleft',true);
23320 btn('align-center', 'justifycenter',true);
23321 btn('align-right' , 'justifyright',true);
23322 btn('link', false, false, function(btn) {
23323 //Roo.log("create link?");
23324 var url = prompt(this.createLinkText, this.defaultLinkValue);
23325 if(url && url != 'http:/'+'/'){
23326 this.editorcore.relayCmd('createlink', url);
23329 btn('list','insertunorderedlist',true);
23330 btn('pencil', false,true, function(btn){
23332 this.toggleSourceEdit(btn.pressed);
23335 if (this.editor.btns.length > 0) {
23336 for (var i = 0; i<this.editor.btns.length; i++) {
23337 children.push(this.editor.btns[i]);
23345 xns: Roo.bootstrap,
23350 xns: Roo.bootstrap,
23355 cog.menu.items.push({
23357 xns: Roo.bootstrap,
23358 html : Clean styles,
23363 editorcore.insertTag(this.tagname);
23372 this.xtype = 'NavSimplebar';
23374 for(var i=0;i< children.length;i++) {
23376 this.buttons.add(this.addxtypeChild(children[i]));
23380 editor.on('editorevent', this.updateToolbar, this);
23382 onBtnClick : function(id)
23384 this.editorcore.relayCmd(id);
23385 this.editorcore.focus();
23389 * Protected method that will not generally be called directly. It triggers
23390 * a toolbar update by reading the markup state of the current selection in the editor.
23392 updateToolbar: function(){
23394 if(!this.editorcore.activated){
23395 this.editor.onFirstFocus(); // is this neeed?
23399 var btns = this.buttons;
23400 var doc = this.editorcore.doc;
23401 btns.get('bold').setActive(doc.queryCommandState('bold'));
23402 btns.get('italic').setActive(doc.queryCommandState('italic'));
23403 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23405 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23406 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23407 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23409 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23410 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23413 var ans = this.editorcore.getAllAncestors();
23414 if (this.formatCombo) {
23417 var store = this.formatCombo.store;
23418 this.formatCombo.setValue("");
23419 for (var i =0; i < ans.length;i++) {
23420 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23422 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23430 // hides menus... - so this cant be on a menu...
23431 Roo.bootstrap.MenuMgr.hideAll();
23433 Roo.bootstrap.MenuMgr.hideAll();
23434 //this.editorsyncValue();
23436 onFirstFocus: function() {
23437 this.buttons.each(function(item){
23441 toggleSourceEdit : function(sourceEditMode){
23444 if(sourceEditMode){
23445 Roo.log("disabling buttons");
23446 this.buttons.each( function(item){
23447 if(item.cmd != 'pencil'){
23453 Roo.log("enabling buttons");
23454 if(this.editorcore.initialized){
23455 this.buttons.each( function(item){
23461 Roo.log("calling toggole on editor");
23462 // tell the editor that it's been pressed..
23463 this.editor.toggleSourceEdit(sourceEditMode);
23473 * @class Roo.bootstrap.Table.AbstractSelectionModel
23474 * @extends Roo.util.Observable
23475 * Abstract base class for grid SelectionModels. It provides the interface that should be
23476 * implemented by descendant classes. This class should not be directly instantiated.
23479 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23480 this.locked = false;
23481 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23485 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23486 /** @ignore Called by the grid automatically. Do not call directly. */
23487 init : function(grid){
23493 * Locks the selections.
23496 this.locked = true;
23500 * Unlocks the selections.
23502 unlock : function(){
23503 this.locked = false;
23507 * Returns true if the selections are locked.
23508 * @return {Boolean}
23510 isLocked : function(){
23511 return this.locked;
23515 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23516 * @class Roo.bootstrap.Table.RowSelectionModel
23517 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23518 * It supports multiple selections and keyboard selection/navigation.
23520 * @param {Object} config
23523 Roo.bootstrap.Table.RowSelectionModel = function(config){
23524 Roo.apply(this, config);
23525 this.selections = new Roo.util.MixedCollection(false, function(o){
23530 this.lastActive = false;
23534 * @event selectionchange
23535 * Fires when the selection changes
23536 * @param {SelectionModel} this
23538 "selectionchange" : true,
23540 * @event afterselectionchange
23541 * Fires after the selection changes (eg. by key press or clicking)
23542 * @param {SelectionModel} this
23544 "afterselectionchange" : true,
23546 * @event beforerowselect
23547 * Fires when a row is selected being selected, return false to cancel.
23548 * @param {SelectionModel} this
23549 * @param {Number} rowIndex The selected index
23550 * @param {Boolean} keepExisting False if other selections will be cleared
23552 "beforerowselect" : true,
23555 * Fires when a row is selected.
23556 * @param {SelectionModel} this
23557 * @param {Number} rowIndex The selected index
23558 * @param {Roo.data.Record} r The record
23560 "rowselect" : true,
23562 * @event rowdeselect
23563 * Fires when a row is deselected.
23564 * @param {SelectionModel} this
23565 * @param {Number} rowIndex The selected index
23567 "rowdeselect" : true
23569 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23570 this.locked = false;
23573 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23575 * @cfg {Boolean} singleSelect
23576 * True to allow selection of only one row at a time (defaults to false)
23578 singleSelect : false,
23581 initEvents : function()
23584 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23585 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23586 //}else{ // allow click to work like normal
23587 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23589 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23590 this.grid.on("rowclick", this.handleMouseDown, this);
23592 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23593 "up" : function(e){
23595 this.selectPrevious(e.shiftKey);
23596 }else if(this.last !== false && this.lastActive !== false){
23597 var last = this.last;
23598 this.selectRange(this.last, this.lastActive-1);
23599 this.grid.getView().focusRow(this.lastActive);
23600 if(last !== false){
23604 this.selectFirstRow();
23606 this.fireEvent("afterselectionchange", this);
23608 "down" : function(e){
23610 this.selectNext(e.shiftKey);
23611 }else if(this.last !== false && this.lastActive !== false){
23612 var last = this.last;
23613 this.selectRange(this.last, this.lastActive+1);
23614 this.grid.getView().focusRow(this.lastActive);
23615 if(last !== false){
23619 this.selectFirstRow();
23621 this.fireEvent("afterselectionchange", this);
23625 this.grid.store.on('load', function(){
23626 this.selections.clear();
23629 var view = this.grid.view;
23630 view.on("refresh", this.onRefresh, this);
23631 view.on("rowupdated", this.onRowUpdated, this);
23632 view.on("rowremoved", this.onRemove, this);
23637 onRefresh : function()
23639 var ds = this.grid.store, i, v = this.grid.view;
23640 var s = this.selections;
23641 s.each(function(r){
23642 if((i = ds.indexOfId(r.id)) != -1){
23651 onRemove : function(v, index, r){
23652 this.selections.remove(r);
23656 onRowUpdated : function(v, index, r){
23657 if(this.isSelected(r)){
23658 v.onRowSelect(index);
23664 * @param {Array} records The records to select
23665 * @param {Boolean} keepExisting (optional) True to keep existing selections
23667 selectRecords : function(records, keepExisting)
23670 this.clearSelections();
23672 var ds = this.grid.store;
23673 for(var i = 0, len = records.length; i < len; i++){
23674 this.selectRow(ds.indexOf(records[i]), true);
23679 * Gets the number of selected rows.
23682 getCount : function(){
23683 return this.selections.length;
23687 * Selects the first row in the grid.
23689 selectFirstRow : function(){
23694 * Select the last row.
23695 * @param {Boolean} keepExisting (optional) True to keep existing selections
23697 selectLastRow : function(keepExisting){
23698 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23699 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23703 * Selects the row immediately following the last selected row.
23704 * @param {Boolean} keepExisting (optional) True to keep existing selections
23706 selectNext : function(keepExisting)
23708 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23709 this.selectRow(this.last+1, keepExisting);
23710 this.grid.getView().focusRow(this.last);
23715 * Selects the row that precedes the last selected row.
23716 * @param {Boolean} keepExisting (optional) True to keep existing selections
23718 selectPrevious : function(keepExisting){
23720 this.selectRow(this.last-1, keepExisting);
23721 this.grid.getView().focusRow(this.last);
23726 * Returns the selected records
23727 * @return {Array} Array of selected records
23729 getSelections : function(){
23730 return [].concat(this.selections.items);
23734 * Returns the first selected record.
23737 getSelected : function(){
23738 return this.selections.itemAt(0);
23743 * Clears all selections.
23745 clearSelections : function(fast)
23751 var ds = this.grid.store;
23752 var s = this.selections;
23753 s.each(function(r){
23754 this.deselectRow(ds.indexOfId(r.id));
23758 this.selections.clear();
23765 * Selects all rows.
23767 selectAll : function(){
23771 this.selections.clear();
23772 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23773 this.selectRow(i, true);
23778 * Returns True if there is a selection.
23779 * @return {Boolean}
23781 hasSelection : function(){
23782 return this.selections.length > 0;
23786 * Returns True if the specified row is selected.
23787 * @param {Number/Record} record The record or index of the record to check
23788 * @return {Boolean}
23790 isSelected : function(index){
23791 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23792 return (r && this.selections.key(r.id) ? true : false);
23796 * Returns True if the specified record id is selected.
23797 * @param {String} id The id of record to check
23798 * @return {Boolean}
23800 isIdSelected : function(id){
23801 return (this.selections.key(id) ? true : false);
23806 handleMouseDBClick : function(e, t){
23810 handleMouseDown : function(e, t)
23812 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23813 if(this.isLocked() || rowIndex < 0 ){
23816 if(e.shiftKey && this.last !== false){
23817 var last = this.last;
23818 this.selectRange(last, rowIndex, e.ctrlKey);
23819 this.last = last; // reset the last
23823 var isSelected = this.isSelected(rowIndex);
23824 //Roo.log("select row:" + rowIndex);
23826 this.deselectRow(rowIndex);
23828 this.selectRow(rowIndex, true);
23832 if(e.button !== 0 && isSelected){
23833 alert('rowIndex 2: ' + rowIndex);
23834 view.focusRow(rowIndex);
23835 }else if(e.ctrlKey && isSelected){
23836 this.deselectRow(rowIndex);
23837 }else if(!isSelected){
23838 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23839 view.focusRow(rowIndex);
23843 this.fireEvent("afterselectionchange", this);
23846 handleDragableRowClick : function(grid, rowIndex, e)
23848 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23849 this.selectRow(rowIndex, false);
23850 grid.view.focusRow(rowIndex);
23851 this.fireEvent("afterselectionchange", this);
23856 * Selects multiple rows.
23857 * @param {Array} rows Array of the indexes of the row to select
23858 * @param {Boolean} keepExisting (optional) True to keep existing selections
23860 selectRows : function(rows, keepExisting){
23862 this.clearSelections();
23864 for(var i = 0, len = rows.length; i < len; i++){
23865 this.selectRow(rows[i], true);
23870 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23871 * @param {Number} startRow The index of the first row in the range
23872 * @param {Number} endRow The index of the last row in the range
23873 * @param {Boolean} keepExisting (optional) True to retain existing selections
23875 selectRange : function(startRow, endRow, keepExisting){
23880 this.clearSelections();
23882 if(startRow <= endRow){
23883 for(var i = startRow; i <= endRow; i++){
23884 this.selectRow(i, true);
23887 for(var i = startRow; i >= endRow; i--){
23888 this.selectRow(i, true);
23894 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23895 * @param {Number} startRow The index of the first row in the range
23896 * @param {Number} endRow The index of the last row in the range
23898 deselectRange : function(startRow, endRow, preventViewNotify){
23902 for(var i = startRow; i <= endRow; i++){
23903 this.deselectRow(i, preventViewNotify);
23909 * @param {Number} row The index of the row to select
23910 * @param {Boolean} keepExisting (optional) True to keep existing selections
23912 selectRow : function(index, keepExisting, preventViewNotify)
23914 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23917 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23918 if(!keepExisting || this.singleSelect){
23919 this.clearSelections();
23922 var r = this.grid.store.getAt(index);
23923 //console.log('selectRow - record id :' + r.id);
23925 this.selections.add(r);
23926 this.last = this.lastActive = index;
23927 if(!preventViewNotify){
23928 var proxy = new Roo.Element(
23929 this.grid.getRowDom(index)
23931 proxy.addClass('bg-info info');
23933 this.fireEvent("rowselect", this, index, r);
23934 this.fireEvent("selectionchange", this);
23940 * @param {Number} row The index of the row to deselect
23942 deselectRow : function(index, preventViewNotify)
23947 if(this.last == index){
23950 if(this.lastActive == index){
23951 this.lastActive = false;
23954 var r = this.grid.store.getAt(index);
23959 this.selections.remove(r);
23960 //.console.log('deselectRow - record id :' + r.id);
23961 if(!preventViewNotify){
23963 var proxy = new Roo.Element(
23964 this.grid.getRowDom(index)
23966 proxy.removeClass('bg-info info');
23968 this.fireEvent("rowdeselect", this, index);
23969 this.fireEvent("selectionchange", this);
23973 restoreLast : function(){
23975 this.last = this._last;
23980 acceptsNav : function(row, col, cm){
23981 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23985 onEditorKey : function(field, e){
23986 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23991 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23993 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23995 }else if(k == e.ENTER && !e.ctrlKey){
23999 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24001 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24003 }else if(k == e.ESC){
24007 g.startEditing(newCell[0], newCell[1]);
24013 * Ext JS Library 1.1.1
24014 * Copyright(c) 2006-2007, Ext JS, LLC.
24016 * Originally Released Under LGPL - original licence link has changed is not relivant.
24019 * <script type="text/javascript">
24023 * @class Roo.bootstrap.PagingToolbar
24024 * @extends Roo.bootstrap.NavSimplebar
24025 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24027 * Create a new PagingToolbar
24028 * @param {Object} config The config object
24029 * @param {Roo.data.Store} store
24031 Roo.bootstrap.PagingToolbar = function(config)
24033 // old args format still supported... - xtype is prefered..
24034 // created from xtype...
24036 this.ds = config.dataSource;
24038 if (config.store && !this.ds) {
24039 this.store= Roo.factory(config.store, Roo.data);
24040 this.ds = this.store;
24041 this.ds.xmodule = this.xmodule || false;
24044 this.toolbarItems = [];
24045 if (config.items) {
24046 this.toolbarItems = config.items;
24049 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24054 this.bind(this.ds);
24057 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24061 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24063 * @cfg {Roo.data.Store} dataSource
24064 * The underlying data store providing the paged data
24067 * @cfg {String/HTMLElement/Element} container
24068 * container The id or element that will contain the toolbar
24071 * @cfg {Boolean} displayInfo
24072 * True to display the displayMsg (defaults to false)
24075 * @cfg {Number} pageSize
24076 * The number of records to display per page (defaults to 20)
24080 * @cfg {String} displayMsg
24081 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24083 displayMsg : 'Displaying {0} - {1} of {2}',
24085 * @cfg {String} emptyMsg
24086 * The message to display when no records are found (defaults to "No data to display")
24088 emptyMsg : 'No data to display',
24090 * Customizable piece of the default paging text (defaults to "Page")
24093 beforePageText : "Page",
24095 * Customizable piece of the default paging text (defaults to "of %0")
24098 afterPageText : "of {0}",
24100 * Customizable piece of the default paging text (defaults to "First Page")
24103 firstText : "First Page",
24105 * Customizable piece of the default paging text (defaults to "Previous Page")
24108 prevText : "Previous Page",
24110 * Customizable piece of the default paging text (defaults to "Next Page")
24113 nextText : "Next Page",
24115 * Customizable piece of the default paging text (defaults to "Last Page")
24118 lastText : "Last Page",
24120 * Customizable piece of the default paging text (defaults to "Refresh")
24123 refreshText : "Refresh",
24127 onRender : function(ct, position)
24129 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24130 this.navgroup.parentId = this.id;
24131 this.navgroup.onRender(this.el, null);
24132 // add the buttons to the navgroup
24134 if(this.displayInfo){
24135 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24136 this.displayEl = this.el.select('.x-paging-info', true).first();
24137 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24138 // this.displayEl = navel.el.select('span',true).first();
24144 Roo.each(_this.buttons, function(e){ // this might need to use render????
24145 Roo.factory(e).onRender(_this.el, null);
24149 Roo.each(_this.toolbarItems, function(e) {
24150 _this.navgroup.addItem(e);
24154 this.first = this.navgroup.addItem({
24155 tooltip: this.firstText,
24157 icon : 'fa fa-backward',
24159 preventDefault: true,
24160 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24163 this.prev = this.navgroup.addItem({
24164 tooltip: this.prevText,
24166 icon : 'fa fa-step-backward',
24168 preventDefault: true,
24169 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24171 //this.addSeparator();
24174 var field = this.navgroup.addItem( {
24176 cls : 'x-paging-position',
24178 html : this.beforePageText +
24179 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24180 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24183 this.field = field.el.select('input', true).first();
24184 this.field.on("keydown", this.onPagingKeydown, this);
24185 this.field.on("focus", function(){this.dom.select();});
24188 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24189 //this.field.setHeight(18);
24190 //this.addSeparator();
24191 this.next = this.navgroup.addItem({
24192 tooltip: this.nextText,
24194 html : ' <i class="fa fa-step-forward">',
24196 preventDefault: true,
24197 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24199 this.last = this.navgroup.addItem({
24200 tooltip: this.lastText,
24201 icon : 'fa fa-forward',
24204 preventDefault: true,
24205 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24207 //this.addSeparator();
24208 this.loading = this.navgroup.addItem({
24209 tooltip: this.refreshText,
24210 icon: 'fa fa-refresh',
24211 preventDefault: true,
24212 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24218 updateInfo : function(){
24219 if(this.displayEl){
24220 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24221 var msg = count == 0 ?
24225 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24227 this.displayEl.update(msg);
24232 onLoad : function(ds, r, o)
24234 this.cursor = o.params ? o.params.start : 0;
24235 var d = this.getPageData(),
24240 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24241 this.field.dom.value = ap;
24242 this.first.setDisabled(ap == 1);
24243 this.prev.setDisabled(ap == 1);
24244 this.next.setDisabled(ap == ps);
24245 this.last.setDisabled(ap == ps);
24246 this.loading.enable();
24251 getPageData : function(){
24252 var total = this.ds.getTotalCount();
24255 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24256 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24261 onLoadError : function(){
24262 this.loading.enable();
24266 onPagingKeydown : function(e){
24267 var k = e.getKey();
24268 var d = this.getPageData();
24270 var v = this.field.dom.value, pageNum;
24271 if(!v || isNaN(pageNum = parseInt(v, 10))){
24272 this.field.dom.value = d.activePage;
24275 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24276 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24279 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))
24281 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24282 this.field.dom.value = pageNum;
24283 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24286 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24288 var v = this.field.dom.value, pageNum;
24289 var increment = (e.shiftKey) ? 10 : 1;
24290 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24293 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24294 this.field.dom.value = d.activePage;
24297 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24299 this.field.dom.value = parseInt(v, 10) + increment;
24300 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24301 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24308 beforeLoad : function(){
24310 this.loading.disable();
24315 onClick : function(which){
24324 ds.load({params:{start: 0, limit: this.pageSize}});
24327 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24330 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24333 var total = ds.getTotalCount();
24334 var extra = total % this.pageSize;
24335 var lastStart = extra ? (total - extra) : total-this.pageSize;
24336 ds.load({params:{start: lastStart, limit: this.pageSize}});
24339 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24345 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24346 * @param {Roo.data.Store} store The data store to unbind
24348 unbind : function(ds){
24349 ds.un("beforeload", this.beforeLoad, this);
24350 ds.un("load", this.onLoad, this);
24351 ds.un("loadexception", this.onLoadError, this);
24352 ds.un("remove", this.updateInfo, this);
24353 ds.un("add", this.updateInfo, this);
24354 this.ds = undefined;
24358 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24359 * @param {Roo.data.Store} store The data store to bind
24361 bind : function(ds){
24362 ds.on("beforeload", this.beforeLoad, this);
24363 ds.on("load", this.onLoad, this);
24364 ds.on("loadexception", this.onLoadError, this);
24365 ds.on("remove", this.updateInfo, this);
24366 ds.on("add", this.updateInfo, this);
24377 * @class Roo.bootstrap.MessageBar
24378 * @extends Roo.bootstrap.Component
24379 * Bootstrap MessageBar class
24380 * @cfg {String} html contents of the MessageBar
24381 * @cfg {String} weight (info | success | warning | danger) default info
24382 * @cfg {String} beforeClass insert the bar before the given class
24383 * @cfg {Boolean} closable (true | false) default false
24384 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24387 * Create a new Element
24388 * @param {Object} config The config object
24391 Roo.bootstrap.MessageBar = function(config){
24392 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24395 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24401 beforeClass: 'bootstrap-sticky-wrap',
24403 getAutoCreate : function(){
24407 cls: 'alert alert-dismissable alert-' + this.weight,
24412 html: this.html || ''
24418 cfg.cls += ' alert-messages-fixed';
24432 onRender : function(ct, position)
24434 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24437 var cfg = Roo.apply({}, this.getAutoCreate());
24441 cfg.cls += ' ' + this.cls;
24444 cfg.style = this.style;
24446 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24448 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24451 this.el.select('>button.close').on('click', this.hide, this);
24457 if (!this.rendered) {
24463 this.fireEvent('show', this);
24469 if (!this.rendered) {
24475 this.fireEvent('hide', this);
24478 update : function()
24480 // var e = this.el.dom.firstChild;
24482 // if(this.closable){
24483 // e = e.nextSibling;
24486 // e.data = this.html || '';
24488 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24504 * @class Roo.bootstrap.Graph
24505 * @extends Roo.bootstrap.Component
24506 * Bootstrap Graph class
24510 @cfg {String} graphtype bar | vbar | pie
24511 @cfg {number} g_x coodinator | centre x (pie)
24512 @cfg {number} g_y coodinator | centre y (pie)
24513 @cfg {number} g_r radius (pie)
24514 @cfg {number} g_height height of the chart (respected by all elements in the set)
24515 @cfg {number} g_width width of the chart (respected by all elements in the set)
24516 @cfg {Object} title The title of the chart
24519 -opts (object) options for the chart
24521 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24522 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24524 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.
24525 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24527 o stretch (boolean)
24529 -opts (object) options for the pie
24532 o startAngle (number)
24533 o endAngle (number)
24537 * Create a new Input
24538 * @param {Object} config The config object
24541 Roo.bootstrap.Graph = function(config){
24542 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24548 * The img click event for the img.
24549 * @param {Roo.EventObject} e
24555 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24566 //g_colors: this.colors,
24573 getAutoCreate : function(){
24584 onRender : function(ct,position){
24587 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24589 if (typeof(Raphael) == 'undefined') {
24590 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24594 this.raphael = Raphael(this.el.dom);
24596 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24597 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24598 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24599 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24601 r.text(160, 10, "Single Series Chart").attr(txtattr);
24602 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24603 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24604 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24606 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24607 r.barchart(330, 10, 300, 220, data1);
24608 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24609 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24612 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24613 // r.barchart(30, 30, 560, 250, xdata, {
24614 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24615 // axis : "0 0 1 1",
24616 // axisxlabels : xdata
24617 // //yvalues : cols,
24620 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24622 // this.load(null,xdata,{
24623 // axis : "0 0 1 1",
24624 // axisxlabels : xdata
24629 load : function(graphtype,xdata,opts)
24631 this.raphael.clear();
24633 graphtype = this.graphtype;
24638 var r = this.raphael,
24639 fin = function () {
24640 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24642 fout = function () {
24643 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24645 pfin = function() {
24646 this.sector.stop();
24647 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24650 this.label[0].stop();
24651 this.label[0].attr({ r: 7.5 });
24652 this.label[1].attr({ "font-weight": 800 });
24655 pfout = function() {
24656 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24659 this.label[0].animate({ r: 5 }, 500, "bounce");
24660 this.label[1].attr({ "font-weight": 400 });
24666 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24669 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24672 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24673 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24675 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24682 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24687 setTitle: function(o)
24692 initEvents: function() {
24695 this.el.on('click', this.onClick, this);
24699 onClick : function(e)
24701 Roo.log('img onclick');
24702 this.fireEvent('click', this, e);
24714 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24717 * @class Roo.bootstrap.dash.NumberBox
24718 * @extends Roo.bootstrap.Component
24719 * Bootstrap NumberBox class
24720 * @cfg {String} headline Box headline
24721 * @cfg {String} content Box content
24722 * @cfg {String} icon Box icon
24723 * @cfg {String} footer Footer text
24724 * @cfg {String} fhref Footer href
24727 * Create a new NumberBox
24728 * @param {Object} config The config object
24732 Roo.bootstrap.dash.NumberBox = function(config){
24733 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24737 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24746 getAutoCreate : function(){
24750 cls : 'small-box ',
24758 cls : 'roo-headline',
24759 html : this.headline
24763 cls : 'roo-content',
24764 html : this.content
24778 cls : 'ion ' + this.icon
24787 cls : 'small-box-footer',
24788 href : this.fhref || '#',
24792 cfg.cn.push(footer);
24799 onRender : function(ct,position){
24800 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24807 setHeadline: function (value)
24809 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24812 setFooter: function (value, href)
24814 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24817 this.el.select('a.small-box-footer',true).first().attr('href', href);
24822 setContent: function (value)
24824 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24827 initEvents: function()
24841 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24844 * @class Roo.bootstrap.dash.TabBox
24845 * @extends Roo.bootstrap.Component
24846 * Bootstrap TabBox class
24847 * @cfg {String} title Title of the TabBox
24848 * @cfg {String} icon Icon of the TabBox
24849 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24850 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24853 * Create a new TabBox
24854 * @param {Object} config The config object
24858 Roo.bootstrap.dash.TabBox = function(config){
24859 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24864 * When a pane is added
24865 * @param {Roo.bootstrap.dash.TabPane} pane
24869 * @event activatepane
24870 * When a pane is activated
24871 * @param {Roo.bootstrap.dash.TabPane} pane
24873 "activatepane" : true
24881 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24886 tabScrollable : false,
24888 getChildContainer : function()
24890 return this.el.select('.tab-content', true).first();
24893 getAutoCreate : function(){
24897 cls: 'pull-left header',
24905 cls: 'fa ' + this.icon
24911 cls: 'nav nav-tabs pull-right',
24917 if(this.tabScrollable){
24924 cls: 'nav nav-tabs pull-right',
24935 cls: 'nav-tabs-custom',
24940 cls: 'tab-content no-padding',
24948 initEvents : function()
24950 //Roo.log('add add pane handler');
24951 this.on('addpane', this.onAddPane, this);
24954 * Updates the box title
24955 * @param {String} html to set the title to.
24957 setTitle : function(value)
24959 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24961 onAddPane : function(pane)
24963 this.panes.push(pane);
24964 //Roo.log('addpane');
24966 // tabs are rendere left to right..
24967 if(!this.showtabs){
24971 var ctr = this.el.select('.nav-tabs', true).first();
24974 var existing = ctr.select('.nav-tab',true);
24975 var qty = existing.getCount();;
24978 var tab = ctr.createChild({
24980 cls : 'nav-tab' + (qty ? '' : ' active'),
24988 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24991 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24993 pane.el.addClass('active');
24998 onTabClick : function(ev,un,ob,pane)
25000 //Roo.log('tab - prev default');
25001 ev.preventDefault();
25004 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25005 pane.tab.addClass('active');
25006 //Roo.log(pane.title);
25007 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25008 // technically we should have a deactivate event.. but maybe add later.
25009 // and it should not de-activate the selected tab...
25010 this.fireEvent('activatepane', pane);
25011 pane.el.addClass('active');
25012 pane.fireEvent('activate');
25017 getActivePane : function()
25020 Roo.each(this.panes, function(p) {
25021 if(p.el.hasClass('active')){
25042 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25044 * @class Roo.bootstrap.TabPane
25045 * @extends Roo.bootstrap.Component
25046 * Bootstrap TabPane class
25047 * @cfg {Boolean} active (false | true) Default false
25048 * @cfg {String} title title of panel
25052 * Create a new TabPane
25053 * @param {Object} config The config object
25056 Roo.bootstrap.dash.TabPane = function(config){
25057 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25063 * When a pane is activated
25064 * @param {Roo.bootstrap.dash.TabPane} pane
25071 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25076 // the tabBox that this is attached to.
25079 getAutoCreate : function()
25087 cfg.cls += ' active';
25092 initEvents : function()
25094 //Roo.log('trigger add pane handler');
25095 this.parent().fireEvent('addpane', this)
25099 * Updates the tab title
25100 * @param {String} html to set the title to.
25102 setTitle: function(str)
25108 this.tab.select('a', true).first().dom.innerHTML = str;
25125 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25128 * @class Roo.bootstrap.menu.Menu
25129 * @extends Roo.bootstrap.Component
25130 * Bootstrap Menu class - container for Menu
25131 * @cfg {String} html Text of the menu
25132 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25133 * @cfg {String} icon Font awesome icon
25134 * @cfg {String} pos Menu align to (top | bottom) default bottom
25138 * Create a new Menu
25139 * @param {Object} config The config object
25143 Roo.bootstrap.menu.Menu = function(config){
25144 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25148 * @event beforeshow
25149 * Fires before this menu is displayed
25150 * @param {Roo.bootstrap.menu.Menu} this
25154 * @event beforehide
25155 * Fires before this menu is hidden
25156 * @param {Roo.bootstrap.menu.Menu} this
25161 * Fires after this menu is displayed
25162 * @param {Roo.bootstrap.menu.Menu} this
25167 * Fires after this menu is hidden
25168 * @param {Roo.bootstrap.menu.Menu} this
25173 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25174 * @param {Roo.bootstrap.menu.Menu} this
25175 * @param {Roo.EventObject} e
25182 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25186 weight : 'default',
25191 getChildContainer : function() {
25192 if(this.isSubMenu){
25196 return this.el.select('ul.dropdown-menu', true).first();
25199 getAutoCreate : function()
25204 cls : 'roo-menu-text',
25212 cls : 'fa ' + this.icon
25223 cls : 'dropdown-button btn btn-' + this.weight,
25228 cls : 'dropdown-toggle btn btn-' + this.weight,
25238 cls : 'dropdown-menu'
25244 if(this.pos == 'top'){
25245 cfg.cls += ' dropup';
25248 if(this.isSubMenu){
25251 cls : 'dropdown-menu'
25258 onRender : function(ct, position)
25260 this.isSubMenu = ct.hasClass('dropdown-submenu');
25262 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25265 initEvents : function()
25267 if(this.isSubMenu){
25271 this.hidden = true;
25273 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25274 this.triggerEl.on('click', this.onTriggerPress, this);
25276 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25277 this.buttonEl.on('click', this.onClick, this);
25283 if(this.isSubMenu){
25287 return this.el.select('ul.dropdown-menu', true).first();
25290 onClick : function(e)
25292 this.fireEvent("click", this, e);
25295 onTriggerPress : function(e)
25297 if (this.isVisible()) {
25304 isVisible : function(){
25305 return !this.hidden;
25310 this.fireEvent("beforeshow", this);
25312 this.hidden = false;
25313 this.el.addClass('open');
25315 Roo.get(document).on("mouseup", this.onMouseUp, this);
25317 this.fireEvent("show", this);
25324 this.fireEvent("beforehide", this);
25326 this.hidden = true;
25327 this.el.removeClass('open');
25329 Roo.get(document).un("mouseup", this.onMouseUp);
25331 this.fireEvent("hide", this);
25334 onMouseUp : function()
25348 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25351 * @class Roo.bootstrap.menu.Item
25352 * @extends Roo.bootstrap.Component
25353 * Bootstrap MenuItem class
25354 * @cfg {Boolean} submenu (true | false) default false
25355 * @cfg {String} html text of the item
25356 * @cfg {String} href the link
25357 * @cfg {Boolean} disable (true | false) default false
25358 * @cfg {Boolean} preventDefault (true | false) default true
25359 * @cfg {String} icon Font awesome icon
25360 * @cfg {String} pos Submenu align to (left | right) default right
25364 * Create a new Item
25365 * @param {Object} config The config object
25369 Roo.bootstrap.menu.Item = function(config){
25370 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25374 * Fires when the mouse is hovering over this menu
25375 * @param {Roo.bootstrap.menu.Item} this
25376 * @param {Roo.EventObject} e
25381 * Fires when the mouse exits this menu
25382 * @param {Roo.bootstrap.menu.Item} this
25383 * @param {Roo.EventObject} e
25389 * The raw click event for the entire grid.
25390 * @param {Roo.EventObject} e
25396 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25401 preventDefault: true,
25406 getAutoCreate : function()
25411 cls : 'roo-menu-item-text',
25419 cls : 'fa ' + this.icon
25428 href : this.href || '#',
25435 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25439 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25441 if(this.pos == 'left'){
25442 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25449 initEvents : function()
25451 this.el.on('mouseover', this.onMouseOver, this);
25452 this.el.on('mouseout', this.onMouseOut, this);
25454 this.el.select('a', true).first().on('click', this.onClick, this);
25458 onClick : function(e)
25460 if(this.preventDefault){
25461 e.preventDefault();
25464 this.fireEvent("click", this, e);
25467 onMouseOver : function(e)
25469 if(this.submenu && this.pos == 'left'){
25470 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25473 this.fireEvent("mouseover", this, e);
25476 onMouseOut : function(e)
25478 this.fireEvent("mouseout", this, e);
25490 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25493 * @class Roo.bootstrap.menu.Separator
25494 * @extends Roo.bootstrap.Component
25495 * Bootstrap Separator class
25498 * Create a new Separator
25499 * @param {Object} config The config object
25503 Roo.bootstrap.menu.Separator = function(config){
25504 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25507 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25509 getAutoCreate : function(){
25530 * @class Roo.bootstrap.Tooltip
25531 * Bootstrap Tooltip class
25532 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25533 * to determine which dom element triggers the tooltip.
25535 * It needs to add support for additional attributes like tooltip-position
25538 * Create a new Toolti
25539 * @param {Object} config The config object
25542 Roo.bootstrap.Tooltip = function(config){
25543 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25545 this.alignment = Roo.bootstrap.Tooltip.alignment;
25547 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25548 this.alignment = config.alignment;
25553 Roo.apply(Roo.bootstrap.Tooltip, {
25555 * @function init initialize tooltip monitoring.
25559 currentTip : false,
25560 currentRegion : false,
25566 Roo.get(document).on('mouseover', this.enter ,this);
25567 Roo.get(document).on('mouseout', this.leave, this);
25570 this.currentTip = new Roo.bootstrap.Tooltip();
25573 enter : function(ev)
25575 var dom = ev.getTarget();
25577 //Roo.log(['enter',dom]);
25578 var el = Roo.fly(dom);
25579 if (this.currentEl) {
25581 //Roo.log(this.currentEl);
25582 //Roo.log(this.currentEl.contains(dom));
25583 if (this.currentEl == el) {
25586 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25592 if (this.currentTip.el) {
25593 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25597 if(!el || el.dom == document){
25603 // you can not look for children, as if el is the body.. then everythign is the child..
25604 if (!el.attr('tooltip')) { //
25605 if (!el.select("[tooltip]").elements.length) {
25608 // is the mouse over this child...?
25609 bindEl = el.select("[tooltip]").first();
25610 var xy = ev.getXY();
25611 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25612 //Roo.log("not in region.");
25615 //Roo.log("child element over..");
25618 this.currentEl = bindEl;
25619 this.currentTip.bind(bindEl);
25620 this.currentRegion = Roo.lib.Region.getRegion(dom);
25621 this.currentTip.enter();
25624 leave : function(ev)
25626 var dom = ev.getTarget();
25627 //Roo.log(['leave',dom]);
25628 if (!this.currentEl) {
25633 if (dom != this.currentEl.dom) {
25636 var xy = ev.getXY();
25637 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25640 // only activate leave if mouse cursor is outside... bounding box..
25645 if (this.currentTip) {
25646 this.currentTip.leave();
25648 //Roo.log('clear currentEl');
25649 this.currentEl = false;
25654 'left' : ['r-l', [-2,0], 'right'],
25655 'right' : ['l-r', [2,0], 'left'],
25656 'bottom' : ['t-b', [0,2], 'top'],
25657 'top' : [ 'b-t', [0,-2], 'bottom']
25663 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25668 delay : null, // can be { show : 300 , hide: 500}
25672 hoverState : null, //???
25674 placement : 'bottom',
25678 getAutoCreate : function(){
25685 cls : 'tooltip-arrow'
25688 cls : 'tooltip-inner'
25695 bind : function(el)
25701 enter : function () {
25703 if (this.timeout != null) {
25704 clearTimeout(this.timeout);
25707 this.hoverState = 'in';
25708 //Roo.log("enter - show");
25709 if (!this.delay || !this.delay.show) {
25714 this.timeout = setTimeout(function () {
25715 if (_t.hoverState == 'in') {
25718 }, this.delay.show);
25722 clearTimeout(this.timeout);
25724 this.hoverState = 'out';
25725 if (!this.delay || !this.delay.hide) {
25731 this.timeout = setTimeout(function () {
25732 //Roo.log("leave - timeout");
25734 if (_t.hoverState == 'out') {
25736 Roo.bootstrap.Tooltip.currentEl = false;
25741 show : function (msg)
25744 this.render(document.body);
25747 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25749 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25751 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25753 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25755 var placement = typeof this.placement == 'function' ?
25756 this.placement.call(this, this.el, on_el) :
25759 var autoToken = /\s?auto?\s?/i;
25760 var autoPlace = autoToken.test(placement);
25762 placement = placement.replace(autoToken, '') || 'top';
25766 //this.el.setXY([0,0]);
25768 //this.el.dom.style.display='block';
25770 //this.el.appendTo(on_el);
25772 var p = this.getPosition();
25773 var box = this.el.getBox();
25779 var align = this.alignment[placement];
25781 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25783 if(placement == 'top' || placement == 'bottom'){
25785 placement = 'right';
25788 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25789 placement = 'left';
25792 var scroll = Roo.select('body', true).first().getScroll();
25794 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25800 this.el.alignTo(this.bindEl, align[0],align[1]);
25801 //var arrow = this.el.select('.arrow',true).first();
25802 //arrow.set(align[2],
25804 this.el.addClass(placement);
25806 this.el.addClass('in fade');
25808 this.hoverState = null;
25810 if (this.el.hasClass('fade')) {
25821 //this.el.setXY([0,0]);
25822 this.el.removeClass('in');
25838 * @class Roo.bootstrap.LocationPicker
25839 * @extends Roo.bootstrap.Component
25840 * Bootstrap LocationPicker class
25841 * @cfg {Number} latitude Position when init default 0
25842 * @cfg {Number} longitude Position when init default 0
25843 * @cfg {Number} zoom default 15
25844 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25845 * @cfg {Boolean} mapTypeControl default false
25846 * @cfg {Boolean} disableDoubleClickZoom default false
25847 * @cfg {Boolean} scrollwheel default true
25848 * @cfg {Boolean} streetViewControl default false
25849 * @cfg {Number} radius default 0
25850 * @cfg {String} locationName
25851 * @cfg {Boolean} draggable default true
25852 * @cfg {Boolean} enableAutocomplete default false
25853 * @cfg {Boolean} enableReverseGeocode default true
25854 * @cfg {String} markerTitle
25857 * Create a new LocationPicker
25858 * @param {Object} config The config object
25862 Roo.bootstrap.LocationPicker = function(config){
25864 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25869 * Fires when the picker initialized.
25870 * @param {Roo.bootstrap.LocationPicker} this
25871 * @param {Google Location} location
25875 * @event positionchanged
25876 * Fires when the picker position changed.
25877 * @param {Roo.bootstrap.LocationPicker} this
25878 * @param {Google Location} location
25880 positionchanged : true,
25883 * Fires when the map resize.
25884 * @param {Roo.bootstrap.LocationPicker} this
25889 * Fires when the map show.
25890 * @param {Roo.bootstrap.LocationPicker} this
25895 * Fires when the map hide.
25896 * @param {Roo.bootstrap.LocationPicker} this
25901 * Fires when click the map.
25902 * @param {Roo.bootstrap.LocationPicker} this
25903 * @param {Map event} e
25907 * @event mapRightClick
25908 * Fires when right click the map.
25909 * @param {Roo.bootstrap.LocationPicker} this
25910 * @param {Map event} e
25912 mapRightClick : true,
25914 * @event markerClick
25915 * Fires when click the marker.
25916 * @param {Roo.bootstrap.LocationPicker} this
25917 * @param {Map event} e
25919 markerClick : true,
25921 * @event markerRightClick
25922 * Fires when right click the marker.
25923 * @param {Roo.bootstrap.LocationPicker} this
25924 * @param {Map event} e
25926 markerRightClick : true,
25928 * @event OverlayViewDraw
25929 * Fires when OverlayView Draw
25930 * @param {Roo.bootstrap.LocationPicker} this
25932 OverlayViewDraw : true,
25934 * @event OverlayViewOnAdd
25935 * Fires when OverlayView Draw
25936 * @param {Roo.bootstrap.LocationPicker} this
25938 OverlayViewOnAdd : true,
25940 * @event OverlayViewOnRemove
25941 * Fires when OverlayView Draw
25942 * @param {Roo.bootstrap.LocationPicker} this
25944 OverlayViewOnRemove : true,
25946 * @event OverlayViewShow
25947 * Fires when OverlayView Draw
25948 * @param {Roo.bootstrap.LocationPicker} this
25949 * @param {Pixel} cpx
25951 OverlayViewShow : true,
25953 * @event OverlayViewHide
25954 * Fires when OverlayView Draw
25955 * @param {Roo.bootstrap.LocationPicker} this
25957 OverlayViewHide : true,
25959 * @event loadexception
25960 * Fires when load google lib failed.
25961 * @param {Roo.bootstrap.LocationPicker} this
25963 loadexception : true
25968 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25970 gMapContext: false,
25976 mapTypeControl: false,
25977 disableDoubleClickZoom: false,
25979 streetViewControl: false,
25983 enableAutocomplete: false,
25984 enableReverseGeocode: true,
25987 getAutoCreate: function()
25992 cls: 'roo-location-picker'
25998 initEvents: function(ct, position)
26000 if(!this.el.getWidth() || this.isApplied()){
26004 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26009 initial: function()
26011 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26012 this.fireEvent('loadexception', this);
26016 if(!this.mapTypeId){
26017 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26020 this.gMapContext = this.GMapContext();
26022 this.initOverlayView();
26024 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26028 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26029 _this.setPosition(_this.gMapContext.marker.position);
26032 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26033 _this.fireEvent('mapClick', this, event);
26037 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26038 _this.fireEvent('mapRightClick', this, event);
26042 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26043 _this.fireEvent('markerClick', this, event);
26047 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26048 _this.fireEvent('markerRightClick', this, event);
26052 this.setPosition(this.gMapContext.location);
26054 this.fireEvent('initial', this, this.gMapContext.location);
26057 initOverlayView: function()
26061 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26065 _this.fireEvent('OverlayViewDraw', _this);
26070 _this.fireEvent('OverlayViewOnAdd', _this);
26073 onRemove: function()
26075 _this.fireEvent('OverlayViewOnRemove', _this);
26078 show: function(cpx)
26080 _this.fireEvent('OverlayViewShow', _this, cpx);
26085 _this.fireEvent('OverlayViewHide', _this);
26091 fromLatLngToContainerPixel: function(event)
26093 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26096 isApplied: function()
26098 return this.getGmapContext() == false ? false : true;
26101 getGmapContext: function()
26103 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26106 GMapContext: function()
26108 var position = new google.maps.LatLng(this.latitude, this.longitude);
26110 var _map = new google.maps.Map(this.el.dom, {
26113 mapTypeId: this.mapTypeId,
26114 mapTypeControl: this.mapTypeControl,
26115 disableDoubleClickZoom: this.disableDoubleClickZoom,
26116 scrollwheel: this.scrollwheel,
26117 streetViewControl: this.streetViewControl,
26118 locationName: this.locationName,
26119 draggable: this.draggable,
26120 enableAutocomplete: this.enableAutocomplete,
26121 enableReverseGeocode: this.enableReverseGeocode
26124 var _marker = new google.maps.Marker({
26125 position: position,
26127 title: this.markerTitle,
26128 draggable: this.draggable
26135 location: position,
26136 radius: this.radius,
26137 locationName: this.locationName,
26138 addressComponents: {
26139 formatted_address: null,
26140 addressLine1: null,
26141 addressLine2: null,
26143 streetNumber: null,
26147 stateOrProvince: null
26150 domContainer: this.el.dom,
26151 geodecoder: new google.maps.Geocoder()
26155 drawCircle: function(center, radius, options)
26157 if (this.gMapContext.circle != null) {
26158 this.gMapContext.circle.setMap(null);
26162 options = Roo.apply({}, options, {
26163 strokeColor: "#0000FF",
26164 strokeOpacity: .35,
26166 fillColor: "#0000FF",
26170 options.map = this.gMapContext.map;
26171 options.radius = radius;
26172 options.center = center;
26173 this.gMapContext.circle = new google.maps.Circle(options);
26174 return this.gMapContext.circle;
26180 setPosition: function(location)
26182 this.gMapContext.location = location;
26183 this.gMapContext.marker.setPosition(location);
26184 this.gMapContext.map.panTo(location);
26185 this.drawCircle(location, this.gMapContext.radius, {});
26189 if (this.gMapContext.settings.enableReverseGeocode) {
26190 this.gMapContext.geodecoder.geocode({
26191 latLng: this.gMapContext.location
26192 }, function(results, status) {
26194 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26195 _this.gMapContext.locationName = results[0].formatted_address;
26196 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26198 _this.fireEvent('positionchanged', this, location);
26205 this.fireEvent('positionchanged', this, location);
26210 google.maps.event.trigger(this.gMapContext.map, "resize");
26212 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26214 this.fireEvent('resize', this);
26217 setPositionByLatLng: function(latitude, longitude)
26219 this.setPosition(new google.maps.LatLng(latitude, longitude));
26222 getCurrentPosition: function()
26225 latitude: this.gMapContext.location.lat(),
26226 longitude: this.gMapContext.location.lng()
26230 getAddressName: function()
26232 return this.gMapContext.locationName;
26235 getAddressComponents: function()
26237 return this.gMapContext.addressComponents;
26240 address_component_from_google_geocode: function(address_components)
26244 for (var i = 0; i < address_components.length; i++) {
26245 var component = address_components[i];
26246 if (component.types.indexOf("postal_code") >= 0) {
26247 result.postalCode = component.short_name;
26248 } else if (component.types.indexOf("street_number") >= 0) {
26249 result.streetNumber = component.short_name;
26250 } else if (component.types.indexOf("route") >= 0) {
26251 result.streetName = component.short_name;
26252 } else if (component.types.indexOf("neighborhood") >= 0) {
26253 result.city = component.short_name;
26254 } else if (component.types.indexOf("locality") >= 0) {
26255 result.city = component.short_name;
26256 } else if (component.types.indexOf("sublocality") >= 0) {
26257 result.district = component.short_name;
26258 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26259 result.stateOrProvince = component.short_name;
26260 } else if (component.types.indexOf("country") >= 0) {
26261 result.country = component.short_name;
26265 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26266 result.addressLine2 = "";
26270 setZoomLevel: function(zoom)
26272 this.gMapContext.map.setZoom(zoom);
26285 this.fireEvent('show', this);
26296 this.fireEvent('hide', this);
26301 Roo.apply(Roo.bootstrap.LocationPicker, {
26303 OverlayView : function(map, options)
26305 options = options || {};
26319 * @class Roo.bootstrap.Alert
26320 * @extends Roo.bootstrap.Component
26321 * Bootstrap Alert class
26322 * @cfg {String} title The title of alert
26323 * @cfg {String} html The content of alert
26324 * @cfg {String} weight ( success | info | warning | danger )
26325 * @cfg {String} faicon font-awesomeicon
26328 * Create a new alert
26329 * @param {Object} config The config object
26333 Roo.bootstrap.Alert = function(config){
26334 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26338 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26345 getAutoCreate : function()
26354 cls : 'roo-alert-icon'
26359 cls : 'roo-alert-title',
26364 cls : 'roo-alert-text',
26371 cfg.cn[0].cls += ' fa ' + this.faicon;
26375 cfg.cls += ' alert-' + this.weight;
26381 initEvents: function()
26383 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26386 setTitle : function(str)
26388 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26391 setText : function(str)
26393 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26396 setWeight : function(weight)
26399 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26402 this.weight = weight;
26404 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26407 setIcon : function(icon)
26410 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26413 this.faicon = icon;
26415 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26436 * @class Roo.bootstrap.UploadCropbox
26437 * @extends Roo.bootstrap.Component
26438 * Bootstrap UploadCropbox class
26439 * @cfg {String} emptyText show when image has been loaded
26440 * @cfg {String} rotateNotify show when image too small to rotate
26441 * @cfg {Number} errorTimeout default 3000
26442 * @cfg {Number} minWidth default 300
26443 * @cfg {Number} minHeight default 300
26444 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26445 * @cfg {Boolean} isDocument (true|false) default false
26446 * @cfg {String} url action url
26447 * @cfg {String} paramName default 'imageUpload'
26448 * @cfg {String} method default POST
26449 * @cfg {Boolean} loadMask (true|false) default true
26450 * @cfg {Boolean} loadingText default 'Loading...'
26453 * Create a new UploadCropbox
26454 * @param {Object} config The config object
26457 Roo.bootstrap.UploadCropbox = function(config){
26458 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26462 * @event beforeselectfile
26463 * Fire before select file
26464 * @param {Roo.bootstrap.UploadCropbox} this
26466 "beforeselectfile" : true,
26469 * Fire after initEvent
26470 * @param {Roo.bootstrap.UploadCropbox} this
26475 * Fire after initEvent
26476 * @param {Roo.bootstrap.UploadCropbox} this
26477 * @param {String} data
26482 * Fire when preparing the file data
26483 * @param {Roo.bootstrap.UploadCropbox} this
26484 * @param {Object} file
26489 * Fire when get exception
26490 * @param {Roo.bootstrap.UploadCropbox} this
26491 * @param {XMLHttpRequest} xhr
26493 "exception" : true,
26495 * @event beforeloadcanvas
26496 * Fire before load the canvas
26497 * @param {Roo.bootstrap.UploadCropbox} this
26498 * @param {String} src
26500 "beforeloadcanvas" : true,
26503 * Fire when trash image
26504 * @param {Roo.bootstrap.UploadCropbox} this
26509 * Fire when download the image
26510 * @param {Roo.bootstrap.UploadCropbox} this
26514 * @event footerbuttonclick
26515 * Fire when footerbuttonclick
26516 * @param {Roo.bootstrap.UploadCropbox} this
26517 * @param {String} type
26519 "footerbuttonclick" : true,
26523 * @param {Roo.bootstrap.UploadCropbox} this
26528 * Fire when rotate the image
26529 * @param {Roo.bootstrap.UploadCropbox} this
26530 * @param {String} pos
26535 * Fire when inspect the file
26536 * @param {Roo.bootstrap.UploadCropbox} this
26537 * @param {Object} file
26542 * Fire when xhr upload the file
26543 * @param {Roo.bootstrap.UploadCropbox} this
26544 * @param {Object} data
26549 * Fire when arrange the file data
26550 * @param {Roo.bootstrap.UploadCropbox} this
26551 * @param {Object} formData
26556 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26559 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26561 emptyText : 'Click to upload image',
26562 rotateNotify : 'Image is too small to rotate',
26563 errorTimeout : 3000,
26577 cropType : 'image/jpeg',
26579 canvasLoaded : false,
26580 isDocument : false,
26582 paramName : 'imageUpload',
26584 loadingText : 'Loading...',
26587 getAutoCreate : function()
26591 cls : 'roo-upload-cropbox',
26595 cls : 'roo-upload-cropbox-selector',
26600 cls : 'roo-upload-cropbox-body',
26601 style : 'cursor:pointer',
26605 cls : 'roo-upload-cropbox-preview'
26609 cls : 'roo-upload-cropbox-thumb'
26613 cls : 'roo-upload-cropbox-empty-notify',
26614 html : this.emptyText
26618 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26619 html : this.rotateNotify
26625 cls : 'roo-upload-cropbox-footer',
26628 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26638 onRender : function(ct, position)
26640 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26642 if (this.buttons.length) {
26644 Roo.each(this.buttons, function(bb) {
26646 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26648 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26654 this.maskEl = this.el;
26658 initEvents : function()
26660 this.urlAPI = (window.createObjectURL && window) ||
26661 (window.URL && URL.revokeObjectURL && URL) ||
26662 (window.webkitURL && webkitURL);
26664 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26665 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26667 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26668 this.selectorEl.hide();
26670 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26671 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26673 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26674 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26675 this.thumbEl.hide();
26677 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26678 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26680 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26681 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26682 this.errorEl.hide();
26684 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26685 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26686 this.footerEl.hide();
26688 this.setThumbBoxSize();
26694 this.fireEvent('initial', this);
26701 window.addEventListener("resize", function() { _this.resize(); } );
26703 this.bodyEl.on('click', this.beforeSelectFile, this);
26706 this.bodyEl.on('touchstart', this.onTouchStart, this);
26707 this.bodyEl.on('touchmove', this.onTouchMove, this);
26708 this.bodyEl.on('touchend', this.onTouchEnd, this);
26712 this.bodyEl.on('mousedown', this.onMouseDown, this);
26713 this.bodyEl.on('mousemove', this.onMouseMove, this);
26714 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26715 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26716 Roo.get(document).on('mouseup', this.onMouseUp, this);
26719 this.selectorEl.on('change', this.onFileSelected, this);
26725 this.baseScale = 1;
26727 this.baseRotate = 1;
26728 this.dragable = false;
26729 this.pinching = false;
26732 this.cropData = false;
26733 this.notifyEl.dom.innerHTML = this.emptyText;
26735 this.selectorEl.dom.value = '';
26739 resize : function()
26741 if(this.fireEvent('resize', this) != false){
26742 this.setThumbBoxPosition();
26743 this.setCanvasPosition();
26747 onFooterButtonClick : function(e, el, o, type)
26750 case 'rotate-left' :
26751 this.onRotateLeft(e);
26753 case 'rotate-right' :
26754 this.onRotateRight(e);
26757 this.beforeSelectFile(e);
26772 this.fireEvent('footerbuttonclick', this, type);
26775 beforeSelectFile : function(e)
26777 e.preventDefault();
26779 if(this.fireEvent('beforeselectfile', this) != false){
26780 this.selectorEl.dom.click();
26784 onFileSelected : function(e)
26786 e.preventDefault();
26788 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26792 var file = this.selectorEl.dom.files[0];
26794 if(this.fireEvent('inspect', this, file) != false){
26795 this.prepare(file);
26800 trash : function(e)
26802 this.fireEvent('trash', this);
26805 download : function(e)
26807 this.fireEvent('download', this);
26810 loadCanvas : function(src)
26812 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26816 this.imageEl = document.createElement('img');
26820 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26822 this.imageEl.src = src;
26826 onLoadCanvas : function()
26828 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26829 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26831 this.bodyEl.un('click', this.beforeSelectFile, this);
26833 this.notifyEl.hide();
26834 this.thumbEl.show();
26835 this.footerEl.show();
26837 this.baseRotateLevel();
26839 if(this.isDocument){
26840 this.setThumbBoxSize();
26843 this.setThumbBoxPosition();
26845 this.baseScaleLevel();
26851 this.canvasLoaded = true;
26854 this.maskEl.unmask();
26859 setCanvasPosition : function()
26861 if(!this.canvasEl){
26865 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26866 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26868 this.previewEl.setLeft(pw);
26869 this.previewEl.setTop(ph);
26873 onMouseDown : function(e)
26877 this.dragable = true;
26878 this.pinching = false;
26880 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26881 this.dragable = false;
26885 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26886 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26890 onMouseMove : function(e)
26894 if(!this.canvasLoaded){
26898 if (!this.dragable){
26902 var minX = Math.ceil(this.thumbEl.getLeft(true));
26903 var minY = Math.ceil(this.thumbEl.getTop(true));
26905 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26906 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26908 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26909 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26911 x = x - this.mouseX;
26912 y = y - this.mouseY;
26914 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26915 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26917 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26918 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26920 this.previewEl.setLeft(bgX);
26921 this.previewEl.setTop(bgY);
26923 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26924 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26927 onMouseUp : function(e)
26931 this.dragable = false;
26934 onMouseWheel : function(e)
26938 this.startScale = this.scale;
26940 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26942 if(!this.zoomable()){
26943 this.scale = this.startScale;
26952 zoomable : function()
26954 var minScale = this.thumbEl.getWidth() / this.minWidth;
26956 if(this.minWidth < this.minHeight){
26957 minScale = this.thumbEl.getHeight() / this.minHeight;
26960 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26961 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26965 (this.rotate == 0 || this.rotate == 180) &&
26967 width > this.imageEl.OriginWidth ||
26968 height > this.imageEl.OriginHeight ||
26969 (width < this.minWidth && height < this.minHeight)
26977 (this.rotate == 90 || this.rotate == 270) &&
26979 width > this.imageEl.OriginWidth ||
26980 height > this.imageEl.OriginHeight ||
26981 (width < this.minHeight && height < this.minWidth)
26988 !this.isDocument &&
26989 (this.rotate == 0 || this.rotate == 180) &&
26991 width < this.minWidth ||
26992 width > this.imageEl.OriginWidth ||
26993 height < this.minHeight ||
26994 height > this.imageEl.OriginHeight
27001 !this.isDocument &&
27002 (this.rotate == 90 || this.rotate == 270) &&
27004 width < this.minHeight ||
27005 width > this.imageEl.OriginWidth ||
27006 height < this.minWidth ||
27007 height > this.imageEl.OriginHeight
27017 onRotateLeft : function(e)
27019 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27021 var minScale = this.thumbEl.getWidth() / this.minWidth;
27023 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27024 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27026 this.startScale = this.scale;
27028 while (this.getScaleLevel() < minScale){
27030 this.scale = this.scale + 1;
27032 if(!this.zoomable()){
27037 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27038 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27043 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27050 this.scale = this.startScale;
27052 this.onRotateFail();
27057 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27059 if(this.isDocument){
27060 this.setThumbBoxSize();
27061 this.setThumbBoxPosition();
27062 this.setCanvasPosition();
27067 this.fireEvent('rotate', this, 'left');
27071 onRotateRight : function(e)
27073 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27075 var minScale = this.thumbEl.getWidth() / this.minWidth;
27077 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27078 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27080 this.startScale = this.scale;
27082 while (this.getScaleLevel() < minScale){
27084 this.scale = this.scale + 1;
27086 if(!this.zoomable()){
27091 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27092 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27097 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27104 this.scale = this.startScale;
27106 this.onRotateFail();
27111 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27113 if(this.isDocument){
27114 this.setThumbBoxSize();
27115 this.setThumbBoxPosition();
27116 this.setCanvasPosition();
27121 this.fireEvent('rotate', this, 'right');
27124 onRotateFail : function()
27126 this.errorEl.show(true);
27130 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27135 this.previewEl.dom.innerHTML = '';
27137 var canvasEl = document.createElement("canvas");
27139 var contextEl = canvasEl.getContext("2d");
27141 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27142 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27143 var center = this.imageEl.OriginWidth / 2;
27145 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27146 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27147 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27148 center = this.imageEl.OriginHeight / 2;
27151 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27153 contextEl.translate(center, center);
27154 contextEl.rotate(this.rotate * Math.PI / 180);
27156 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27158 this.canvasEl = document.createElement("canvas");
27160 this.contextEl = this.canvasEl.getContext("2d");
27162 switch (this.rotate) {
27165 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27166 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27168 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27173 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27174 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27176 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27177 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);
27181 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27186 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27187 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27189 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27190 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);
27194 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);
27199 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27200 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27202 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27203 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27207 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);
27214 this.previewEl.appendChild(this.canvasEl);
27216 this.setCanvasPosition();
27221 if(!this.canvasLoaded){
27225 var imageCanvas = document.createElement("canvas");
27227 var imageContext = imageCanvas.getContext("2d");
27229 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27230 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27232 var center = imageCanvas.width / 2;
27234 imageContext.translate(center, center);
27236 imageContext.rotate(this.rotate * Math.PI / 180);
27238 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27240 var canvas = document.createElement("canvas");
27242 var context = canvas.getContext("2d");
27244 canvas.width = this.minWidth;
27245 canvas.height = this.minHeight;
27247 switch (this.rotate) {
27250 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27251 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27253 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27254 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27256 var targetWidth = this.minWidth - 2 * x;
27257 var targetHeight = this.minHeight - 2 * y;
27261 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27262 scale = targetWidth / width;
27265 if(x > 0 && y == 0){
27266 scale = targetHeight / height;
27269 if(x > 0 && y > 0){
27270 scale = targetWidth / width;
27272 if(width < height){
27273 scale = targetHeight / height;
27277 context.scale(scale, scale);
27279 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27280 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27282 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27283 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27285 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27290 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27291 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27293 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27294 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27296 var targetWidth = this.minWidth - 2 * x;
27297 var targetHeight = this.minHeight - 2 * y;
27301 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27302 scale = targetWidth / width;
27305 if(x > 0 && y == 0){
27306 scale = targetHeight / height;
27309 if(x > 0 && y > 0){
27310 scale = targetWidth / width;
27312 if(width < height){
27313 scale = targetHeight / height;
27317 context.scale(scale, scale);
27319 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27320 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27322 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27323 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27325 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27327 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27332 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27333 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27335 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27336 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27338 var targetWidth = this.minWidth - 2 * x;
27339 var targetHeight = this.minHeight - 2 * y;
27343 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27344 scale = targetWidth / width;
27347 if(x > 0 && y == 0){
27348 scale = targetHeight / height;
27351 if(x > 0 && y > 0){
27352 scale = targetWidth / width;
27354 if(width < height){
27355 scale = targetHeight / height;
27359 context.scale(scale, scale);
27361 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27362 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27364 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27365 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27367 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27368 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27370 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27375 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27376 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27378 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27379 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27381 var targetWidth = this.minWidth - 2 * x;
27382 var targetHeight = this.minHeight - 2 * y;
27386 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27387 scale = targetWidth / width;
27390 if(x > 0 && y == 0){
27391 scale = targetHeight / height;
27394 if(x > 0 && y > 0){
27395 scale = targetWidth / width;
27397 if(width < height){
27398 scale = targetHeight / height;
27402 context.scale(scale, scale);
27404 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27405 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27407 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27408 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27410 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27412 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27419 this.cropData = canvas.toDataURL(this.cropType);
27421 if(this.fireEvent('crop', this, this.cropData) !== false){
27422 this.process(this.file, this.cropData);
27429 setThumbBoxSize : function()
27433 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27434 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27435 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27437 this.minWidth = width;
27438 this.minHeight = height;
27440 if(this.rotate == 90 || this.rotate == 270){
27441 this.minWidth = height;
27442 this.minHeight = width;
27447 width = Math.ceil(this.minWidth * height / this.minHeight);
27449 if(this.minWidth > this.minHeight){
27451 height = Math.ceil(this.minHeight * width / this.minWidth);
27454 this.thumbEl.setStyle({
27455 width : width + 'px',
27456 height : height + 'px'
27463 setThumbBoxPosition : function()
27465 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27466 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27468 this.thumbEl.setLeft(x);
27469 this.thumbEl.setTop(y);
27473 baseRotateLevel : function()
27475 this.baseRotate = 1;
27478 typeof(this.exif) != 'undefined' &&
27479 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27480 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27482 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27485 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27489 baseScaleLevel : function()
27493 if(this.isDocument){
27495 if(this.baseRotate == 6 || this.baseRotate == 8){
27497 height = this.thumbEl.getHeight();
27498 this.baseScale = height / this.imageEl.OriginWidth;
27500 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27501 width = this.thumbEl.getWidth();
27502 this.baseScale = width / this.imageEl.OriginHeight;
27508 height = this.thumbEl.getHeight();
27509 this.baseScale = height / this.imageEl.OriginHeight;
27511 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27512 width = this.thumbEl.getWidth();
27513 this.baseScale = width / this.imageEl.OriginWidth;
27519 if(this.baseRotate == 6 || this.baseRotate == 8){
27521 width = this.thumbEl.getHeight();
27522 this.baseScale = width / this.imageEl.OriginHeight;
27524 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27525 height = this.thumbEl.getWidth();
27526 this.baseScale = height / this.imageEl.OriginHeight;
27529 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27530 height = this.thumbEl.getWidth();
27531 this.baseScale = height / this.imageEl.OriginHeight;
27533 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27534 width = this.thumbEl.getHeight();
27535 this.baseScale = width / this.imageEl.OriginWidth;
27542 width = this.thumbEl.getWidth();
27543 this.baseScale = width / this.imageEl.OriginWidth;
27545 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27546 height = this.thumbEl.getHeight();
27547 this.baseScale = height / this.imageEl.OriginHeight;
27550 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27552 height = this.thumbEl.getHeight();
27553 this.baseScale = height / this.imageEl.OriginHeight;
27555 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27556 width = this.thumbEl.getWidth();
27557 this.baseScale = width / this.imageEl.OriginWidth;
27565 getScaleLevel : function()
27567 return this.baseScale * Math.pow(1.1, this.scale);
27570 onTouchStart : function(e)
27572 if(!this.canvasLoaded){
27573 this.beforeSelectFile(e);
27577 var touches = e.browserEvent.touches;
27583 if(touches.length == 1){
27584 this.onMouseDown(e);
27588 if(touches.length != 2){
27594 for(var i = 0, finger; finger = touches[i]; i++){
27595 coords.push(finger.pageX, finger.pageY);
27598 var x = Math.pow(coords[0] - coords[2], 2);
27599 var y = Math.pow(coords[1] - coords[3], 2);
27601 this.startDistance = Math.sqrt(x + y);
27603 this.startScale = this.scale;
27605 this.pinching = true;
27606 this.dragable = false;
27610 onTouchMove : function(e)
27612 if(!this.pinching && !this.dragable){
27616 var touches = e.browserEvent.touches;
27623 this.onMouseMove(e);
27629 for(var i = 0, finger; finger = touches[i]; i++){
27630 coords.push(finger.pageX, finger.pageY);
27633 var x = Math.pow(coords[0] - coords[2], 2);
27634 var y = Math.pow(coords[1] - coords[3], 2);
27636 this.endDistance = Math.sqrt(x + y);
27638 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27640 if(!this.zoomable()){
27641 this.scale = this.startScale;
27649 onTouchEnd : function(e)
27651 this.pinching = false;
27652 this.dragable = false;
27656 process : function(file, crop)
27659 this.maskEl.mask(this.loadingText);
27662 this.xhr = new XMLHttpRequest();
27664 file.xhr = this.xhr;
27666 this.xhr.open(this.method, this.url, true);
27669 "Accept": "application/json",
27670 "Cache-Control": "no-cache",
27671 "X-Requested-With": "XMLHttpRequest"
27674 for (var headerName in headers) {
27675 var headerValue = headers[headerName];
27677 this.xhr.setRequestHeader(headerName, headerValue);
27683 this.xhr.onload = function()
27685 _this.xhrOnLoad(_this.xhr);
27688 this.xhr.onerror = function()
27690 _this.xhrOnError(_this.xhr);
27693 var formData = new FormData();
27695 formData.append('returnHTML', 'NO');
27698 formData.append('crop', crop);
27701 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27702 formData.append(this.paramName, file, file.name);
27705 if(typeof(file.filename) != 'undefined'){
27706 formData.append('filename', file.filename);
27709 if(typeof(file.mimetype) != 'undefined'){
27710 formData.append('mimetype', file.mimetype);
27713 if(this.fireEvent('arrange', this, formData) != false){
27714 this.xhr.send(formData);
27718 xhrOnLoad : function(xhr)
27721 this.maskEl.unmask();
27724 if (xhr.readyState !== 4) {
27725 this.fireEvent('exception', this, xhr);
27729 var response = Roo.decode(xhr.responseText);
27731 if(!response.success){
27732 this.fireEvent('exception', this, xhr);
27736 var response = Roo.decode(xhr.responseText);
27738 this.fireEvent('upload', this, response);
27742 xhrOnError : function()
27745 this.maskEl.unmask();
27748 Roo.log('xhr on error');
27750 var response = Roo.decode(xhr.responseText);
27756 prepare : function(file)
27759 this.maskEl.mask(this.loadingText);
27765 if(typeof(file) === 'string'){
27766 this.loadCanvas(file);
27770 if(!file || !this.urlAPI){
27775 this.cropType = file.type;
27779 if(this.fireEvent('prepare', this, this.file) != false){
27781 var reader = new FileReader();
27783 reader.onload = function (e) {
27784 if (e.target.error) {
27785 Roo.log(e.target.error);
27789 var buffer = e.target.result,
27790 dataView = new DataView(buffer),
27792 maxOffset = dataView.byteLength - 4,
27796 if (dataView.getUint16(0) === 0xffd8) {
27797 while (offset < maxOffset) {
27798 markerBytes = dataView.getUint16(offset);
27800 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27801 markerLength = dataView.getUint16(offset + 2) + 2;
27802 if (offset + markerLength > dataView.byteLength) {
27803 Roo.log('Invalid meta data: Invalid segment size.');
27807 if(markerBytes == 0xffe1){
27808 _this.parseExifData(
27815 offset += markerLength;
27825 var url = _this.urlAPI.createObjectURL(_this.file);
27827 _this.loadCanvas(url);
27832 reader.readAsArrayBuffer(this.file);
27838 parseExifData : function(dataView, offset, length)
27840 var tiffOffset = offset + 10,
27844 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27845 // No Exif data, might be XMP data instead
27849 // Check for the ASCII code for "Exif" (0x45786966):
27850 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27851 // No Exif data, might be XMP data instead
27854 if (tiffOffset + 8 > dataView.byteLength) {
27855 Roo.log('Invalid Exif data: Invalid segment size.');
27858 // Check for the two null bytes:
27859 if (dataView.getUint16(offset + 8) !== 0x0000) {
27860 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27863 // Check the byte alignment:
27864 switch (dataView.getUint16(tiffOffset)) {
27866 littleEndian = true;
27869 littleEndian = false;
27872 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27875 // Check for the TIFF tag marker (0x002A):
27876 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27877 Roo.log('Invalid Exif data: Missing TIFF marker.');
27880 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27881 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27883 this.parseExifTags(
27886 tiffOffset + dirOffset,
27891 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27896 if (dirOffset + 6 > dataView.byteLength) {
27897 Roo.log('Invalid Exif data: Invalid directory offset.');
27900 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27901 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27902 if (dirEndOffset + 4 > dataView.byteLength) {
27903 Roo.log('Invalid Exif data: Invalid directory size.');
27906 for (i = 0; i < tagsNumber; i += 1) {
27910 dirOffset + 2 + 12 * i, // tag offset
27914 // Return the offset to the next directory:
27915 return dataView.getUint32(dirEndOffset, littleEndian);
27918 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27920 var tag = dataView.getUint16(offset, littleEndian);
27922 this.exif[tag] = this.getExifValue(
27926 dataView.getUint16(offset + 2, littleEndian), // tag type
27927 dataView.getUint32(offset + 4, littleEndian), // tag length
27932 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27934 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27943 Roo.log('Invalid Exif data: Invalid tag type.');
27947 tagSize = tagType.size * length;
27948 // Determine if the value is contained in the dataOffset bytes,
27949 // or if the value at the dataOffset is a pointer to the actual data:
27950 dataOffset = tagSize > 4 ?
27951 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27952 if (dataOffset + tagSize > dataView.byteLength) {
27953 Roo.log('Invalid Exif data: Invalid data offset.');
27956 if (length === 1) {
27957 return tagType.getValue(dataView, dataOffset, littleEndian);
27960 for (i = 0; i < length; i += 1) {
27961 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27964 if (tagType.ascii) {
27966 // Concatenate the chars:
27967 for (i = 0; i < values.length; i += 1) {
27969 // Ignore the terminating NULL byte(s):
27970 if (c === '\u0000') {
27982 Roo.apply(Roo.bootstrap.UploadCropbox, {
27984 'Orientation': 0x0112
27988 1: 0, //'top-left',
27990 3: 180, //'bottom-right',
27991 // 4: 'bottom-left',
27993 6: 90, //'right-top',
27994 // 7: 'right-bottom',
27995 8: 270 //'left-bottom'
27999 // byte, 8-bit unsigned int:
28001 getValue: function (dataView, dataOffset) {
28002 return dataView.getUint8(dataOffset);
28006 // ascii, 8-bit byte:
28008 getValue: function (dataView, dataOffset) {
28009 return String.fromCharCode(dataView.getUint8(dataOffset));
28014 // short, 16 bit int:
28016 getValue: function (dataView, dataOffset, littleEndian) {
28017 return dataView.getUint16(dataOffset, littleEndian);
28021 // long, 32 bit int:
28023 getValue: function (dataView, dataOffset, littleEndian) {
28024 return dataView.getUint32(dataOffset, littleEndian);
28028 // rational = two long values, first is numerator, second is denominator:
28030 getValue: function (dataView, dataOffset, littleEndian) {
28031 return dataView.getUint32(dataOffset, littleEndian) /
28032 dataView.getUint32(dataOffset + 4, littleEndian);
28036 // slong, 32 bit signed int:
28038 getValue: function (dataView, dataOffset, littleEndian) {
28039 return dataView.getInt32(dataOffset, littleEndian);
28043 // srational, two slongs, first is numerator, second is denominator:
28045 getValue: function (dataView, dataOffset, littleEndian) {
28046 return dataView.getInt32(dataOffset, littleEndian) /
28047 dataView.getInt32(dataOffset + 4, littleEndian);
28057 cls : 'btn-group roo-upload-cropbox-rotate-left',
28058 action : 'rotate-left',
28062 cls : 'btn btn-default',
28063 html : '<i class="fa fa-undo"></i>'
28069 cls : 'btn-group roo-upload-cropbox-picture',
28070 action : 'picture',
28074 cls : 'btn btn-default',
28075 html : '<i class="fa fa-picture-o"></i>'
28081 cls : 'btn-group roo-upload-cropbox-rotate-right',
28082 action : 'rotate-right',
28086 cls : 'btn btn-default',
28087 html : '<i class="fa fa-repeat"></i>'
28095 cls : 'btn-group roo-upload-cropbox-rotate-left',
28096 action : 'rotate-left',
28100 cls : 'btn btn-default',
28101 html : '<i class="fa fa-undo"></i>'
28107 cls : 'btn-group roo-upload-cropbox-download',
28108 action : 'download',
28112 cls : 'btn btn-default',
28113 html : '<i class="fa fa-download"></i>'
28119 cls : 'btn-group roo-upload-cropbox-crop',
28124 cls : 'btn btn-default',
28125 html : '<i class="fa fa-crop"></i>'
28131 cls : 'btn-group roo-upload-cropbox-trash',
28136 cls : 'btn btn-default',
28137 html : '<i class="fa fa-trash"></i>'
28143 cls : 'btn-group roo-upload-cropbox-rotate-right',
28144 action : 'rotate-right',
28148 cls : 'btn btn-default',
28149 html : '<i class="fa fa-repeat"></i>'
28157 cls : 'btn-group roo-upload-cropbox-rotate-left',
28158 action : 'rotate-left',
28162 cls : 'btn btn-default',
28163 html : '<i class="fa fa-undo"></i>'
28169 cls : 'btn-group roo-upload-cropbox-rotate-right',
28170 action : 'rotate-right',
28174 cls : 'btn btn-default',
28175 html : '<i class="fa fa-repeat"></i>'
28188 * @class Roo.bootstrap.DocumentManager
28189 * @extends Roo.bootstrap.Component
28190 * Bootstrap DocumentManager class
28191 * @cfg {String} paramName default 'imageUpload'
28192 * @cfg {String} toolTipName default 'filename'
28193 * @cfg {String} method default POST
28194 * @cfg {String} url action url
28195 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28196 * @cfg {Boolean} multiple multiple upload default true
28197 * @cfg {Number} thumbSize default 300
28198 * @cfg {String} fieldLabel
28199 * @cfg {Number} labelWidth default 4
28200 * @cfg {String} labelAlign (left|top) default left
28201 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28202 * @cfg {Number} labellg set the width of label (1-12)
28203 * @cfg {Number} labelmd set the width of label (1-12)
28204 * @cfg {Number} labelsm set the width of label (1-12)
28205 * @cfg {Number} labelxs set the width of label (1-12)
28208 * Create a new DocumentManager
28209 * @param {Object} config The config object
28212 Roo.bootstrap.DocumentManager = function(config){
28213 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28216 this.delegates = [];
28221 * Fire when initial the DocumentManager
28222 * @param {Roo.bootstrap.DocumentManager} this
28227 * inspect selected file
28228 * @param {Roo.bootstrap.DocumentManager} this
28229 * @param {File} file
28234 * Fire when xhr load exception
28235 * @param {Roo.bootstrap.DocumentManager} this
28236 * @param {XMLHttpRequest} xhr
28238 "exception" : true,
28240 * @event afterupload
28241 * Fire when xhr load exception
28242 * @param {Roo.bootstrap.DocumentManager} this
28243 * @param {XMLHttpRequest} xhr
28245 "afterupload" : true,
28248 * prepare the form data
28249 * @param {Roo.bootstrap.DocumentManager} this
28250 * @param {Object} formData
28255 * Fire when remove the file
28256 * @param {Roo.bootstrap.DocumentManager} this
28257 * @param {Object} file
28262 * Fire after refresh the file
28263 * @param {Roo.bootstrap.DocumentManager} this
28268 * Fire after click the image
28269 * @param {Roo.bootstrap.DocumentManager} this
28270 * @param {Object} file
28275 * Fire when upload a image and editable set to true
28276 * @param {Roo.bootstrap.DocumentManager} this
28277 * @param {Object} file
28281 * @event beforeselectfile
28282 * Fire before select file
28283 * @param {Roo.bootstrap.DocumentManager} this
28285 "beforeselectfile" : true,
28288 * Fire before process file
28289 * @param {Roo.bootstrap.DocumentManager} this
28290 * @param {Object} file
28297 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28306 paramName : 'imageUpload',
28307 toolTipName : 'filename',
28310 labelAlign : 'left',
28320 getAutoCreate : function()
28322 var managerWidget = {
28324 cls : 'roo-document-manager',
28328 cls : 'roo-document-manager-selector',
28333 cls : 'roo-document-manager-uploader',
28337 cls : 'roo-document-manager-upload-btn',
28338 html : '<i class="fa fa-plus"></i>'
28349 cls : 'column col-md-12',
28354 if(this.fieldLabel.length){
28359 cls : 'column col-md-12',
28360 html : this.fieldLabel
28364 cls : 'column col-md-12',
28369 if(this.labelAlign == 'left'){
28374 html : this.fieldLabel
28383 if(this.labelWidth > 12){
28384 content[0].style = "width: " + this.labelWidth + 'px';
28387 if(this.labelWidth < 13 && this.labelmd == 0){
28388 this.labelmd = this.labelWidth;
28391 if(this.labellg > 0){
28392 content[0].cls += ' col-lg-' + this.labellg;
28393 content[1].cls += ' col-lg-' + (12 - this.labellg);
28396 if(this.labelmd > 0){
28397 content[0].cls += ' col-md-' + this.labelmd;
28398 content[1].cls += ' col-md-' + (12 - this.labelmd);
28401 if(this.labelsm > 0){
28402 content[0].cls += ' col-sm-' + this.labelsm;
28403 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28406 if(this.labelxs > 0){
28407 content[0].cls += ' col-xs-' + this.labelxs;
28408 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28416 cls : 'row clearfix',
28424 initEvents : function()
28426 this.managerEl = this.el.select('.roo-document-manager', true).first();
28427 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28429 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28430 this.selectorEl.hide();
28433 this.selectorEl.attr('multiple', 'multiple');
28436 this.selectorEl.on('change', this.onFileSelected, this);
28438 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28439 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28441 this.uploader.on('click', this.onUploaderClick, this);
28443 this.renderProgressDialog();
28447 window.addEventListener("resize", function() { _this.refresh(); } );
28449 this.fireEvent('initial', this);
28452 renderProgressDialog : function()
28456 this.progressDialog = new Roo.bootstrap.Modal({
28457 cls : 'roo-document-manager-progress-dialog',
28458 allow_close : false,
28468 btnclick : function() {
28469 _this.uploadCancel();
28475 this.progressDialog.render(Roo.get(document.body));
28477 this.progress = new Roo.bootstrap.Progress({
28478 cls : 'roo-document-manager-progress',
28483 this.progress.render(this.progressDialog.getChildContainer());
28485 this.progressBar = new Roo.bootstrap.ProgressBar({
28486 cls : 'roo-document-manager-progress-bar',
28489 aria_valuemax : 12,
28493 this.progressBar.render(this.progress.getChildContainer());
28496 onUploaderClick : function(e)
28498 e.preventDefault();
28500 if(this.fireEvent('beforeselectfile', this) != false){
28501 this.selectorEl.dom.click();
28506 onFileSelected : function(e)
28508 e.preventDefault();
28510 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28514 Roo.each(this.selectorEl.dom.files, function(file){
28515 if(this.fireEvent('inspect', this, file) != false){
28516 this.files.push(file);
28526 this.selectorEl.dom.value = '';
28528 if(!this.files.length){
28532 if(this.boxes > 0 && this.files.length > this.boxes){
28533 this.files = this.files.slice(0, this.boxes);
28536 this.uploader.show();
28538 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28539 this.uploader.hide();
28548 Roo.each(this.files, function(file){
28550 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28551 var f = this.renderPreview(file);
28556 if(file.type.indexOf('image') != -1){
28557 this.delegates.push(
28559 _this.process(file);
28560 }).createDelegate(this)
28568 _this.process(file);
28569 }).createDelegate(this)
28574 this.files = files;
28576 this.delegates = this.delegates.concat(docs);
28578 if(!this.delegates.length){
28583 this.progressBar.aria_valuemax = this.delegates.length;
28590 arrange : function()
28592 if(!this.delegates.length){
28593 this.progressDialog.hide();
28598 var delegate = this.delegates.shift();
28600 this.progressDialog.show();
28602 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28604 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28609 refresh : function()
28611 this.uploader.show();
28613 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28614 this.uploader.hide();
28617 Roo.isTouch ? this.closable(false) : this.closable(true);
28619 this.fireEvent('refresh', this);
28622 onRemove : function(e, el, o)
28624 e.preventDefault();
28626 this.fireEvent('remove', this, o);
28630 remove : function(o)
28634 Roo.each(this.files, function(file){
28635 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28644 this.files = files;
28651 Roo.each(this.files, function(file){
28656 file.target.remove();
28665 onClick : function(e, el, o)
28667 e.preventDefault();
28669 this.fireEvent('click', this, o);
28673 closable : function(closable)
28675 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28677 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28689 xhrOnLoad : function(xhr)
28691 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28695 if (xhr.readyState !== 4) {
28697 this.fireEvent('exception', this, xhr);
28701 var response = Roo.decode(xhr.responseText);
28703 if(!response.success){
28705 this.fireEvent('exception', this, xhr);
28709 var file = this.renderPreview(response.data);
28711 this.files.push(file);
28715 this.fireEvent('afterupload', this, xhr);
28719 xhrOnError : function(xhr)
28721 Roo.log('xhr on error');
28723 var response = Roo.decode(xhr.responseText);
28730 process : function(file)
28732 if(this.fireEvent('process', this, file) !== false){
28733 if(this.editable && file.type.indexOf('image') != -1){
28734 this.fireEvent('edit', this, file);
28738 this.uploadStart(file, false);
28745 uploadStart : function(file, crop)
28747 this.xhr = new XMLHttpRequest();
28749 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28754 file.xhr = this.xhr;
28756 this.managerEl.createChild({
28758 cls : 'roo-document-manager-loading',
28762 tooltip : file.name,
28763 cls : 'roo-document-manager-thumb',
28764 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28770 this.xhr.open(this.method, this.url, true);
28773 "Accept": "application/json",
28774 "Cache-Control": "no-cache",
28775 "X-Requested-With": "XMLHttpRequest"
28778 for (var headerName in headers) {
28779 var headerValue = headers[headerName];
28781 this.xhr.setRequestHeader(headerName, headerValue);
28787 this.xhr.onload = function()
28789 _this.xhrOnLoad(_this.xhr);
28792 this.xhr.onerror = function()
28794 _this.xhrOnError(_this.xhr);
28797 var formData = new FormData();
28799 formData.append('returnHTML', 'NO');
28802 formData.append('crop', crop);
28805 formData.append(this.paramName, file, file.name);
28812 if(this.fireEvent('prepare', this, formData, options) != false){
28814 if(options.manually){
28818 this.xhr.send(formData);
28822 this.uploadCancel();
28825 uploadCancel : function()
28831 this.delegates = [];
28833 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28840 renderPreview : function(file)
28842 if(typeof(file.target) != 'undefined' && file.target){
28846 var previewEl = this.managerEl.createChild({
28848 cls : 'roo-document-manager-preview',
28852 tooltip : file[this.toolTipName],
28853 cls : 'roo-document-manager-thumb',
28854 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28859 html : '<i class="fa fa-times-circle"></i>'
28864 var close = previewEl.select('button.close', true).first();
28866 close.on('click', this.onRemove, this, file);
28868 file.target = previewEl;
28870 var image = previewEl.select('img', true).first();
28874 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28876 image.on('click', this.onClick, this, file);
28882 onPreviewLoad : function(file, image)
28884 if(typeof(file.target) == 'undefined' || !file.target){
28888 var width = image.dom.naturalWidth || image.dom.width;
28889 var height = image.dom.naturalHeight || image.dom.height;
28891 if(width > height){
28892 file.target.addClass('wide');
28896 file.target.addClass('tall');
28901 uploadFromSource : function(file, crop)
28903 this.xhr = new XMLHttpRequest();
28905 this.managerEl.createChild({
28907 cls : 'roo-document-manager-loading',
28911 tooltip : file.name,
28912 cls : 'roo-document-manager-thumb',
28913 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28919 this.xhr.open(this.method, this.url, true);
28922 "Accept": "application/json",
28923 "Cache-Control": "no-cache",
28924 "X-Requested-With": "XMLHttpRequest"
28927 for (var headerName in headers) {
28928 var headerValue = headers[headerName];
28930 this.xhr.setRequestHeader(headerName, headerValue);
28936 this.xhr.onload = function()
28938 _this.xhrOnLoad(_this.xhr);
28941 this.xhr.onerror = function()
28943 _this.xhrOnError(_this.xhr);
28946 var formData = new FormData();
28948 formData.append('returnHTML', 'NO');
28950 formData.append('crop', crop);
28952 if(typeof(file.filename) != 'undefined'){
28953 formData.append('filename', file.filename);
28956 if(typeof(file.mimetype) != 'undefined'){
28957 formData.append('mimetype', file.mimetype);
28962 if(this.fireEvent('prepare', this, formData) != false){
28963 this.xhr.send(formData);
28973 * @class Roo.bootstrap.DocumentViewer
28974 * @extends Roo.bootstrap.Component
28975 * Bootstrap DocumentViewer class
28976 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28977 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28980 * Create a new DocumentViewer
28981 * @param {Object} config The config object
28984 Roo.bootstrap.DocumentViewer = function(config){
28985 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28990 * Fire after initEvent
28991 * @param {Roo.bootstrap.DocumentViewer} this
28997 * @param {Roo.bootstrap.DocumentViewer} this
29002 * Fire after download button
29003 * @param {Roo.bootstrap.DocumentViewer} this
29008 * Fire after trash button
29009 * @param {Roo.bootstrap.DocumentViewer} this
29016 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29018 showDownload : true,
29022 getAutoCreate : function()
29026 cls : 'roo-document-viewer',
29030 cls : 'roo-document-viewer-body',
29034 cls : 'roo-document-viewer-thumb',
29038 cls : 'roo-document-viewer-image'
29046 cls : 'roo-document-viewer-footer',
29049 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29053 cls : 'btn-group roo-document-viewer-download',
29057 cls : 'btn btn-default',
29058 html : '<i class="fa fa-download"></i>'
29064 cls : 'btn-group roo-document-viewer-trash',
29068 cls : 'btn btn-default',
29069 html : '<i class="fa fa-trash"></i>'
29082 initEvents : function()
29084 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29085 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29087 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29088 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29090 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29091 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29093 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29094 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29096 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29097 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29099 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29100 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29102 this.bodyEl.on('click', this.onClick, this);
29103 this.downloadBtn.on('click', this.onDownload, this);
29104 this.trashBtn.on('click', this.onTrash, this);
29106 this.downloadBtn.hide();
29107 this.trashBtn.hide();
29109 if(this.showDownload){
29110 this.downloadBtn.show();
29113 if(this.showTrash){
29114 this.trashBtn.show();
29117 if(!this.showDownload && !this.showTrash) {
29118 this.footerEl.hide();
29123 initial : function()
29125 this.fireEvent('initial', this);
29129 onClick : function(e)
29131 e.preventDefault();
29133 this.fireEvent('click', this);
29136 onDownload : function(e)
29138 e.preventDefault();
29140 this.fireEvent('download', this);
29143 onTrash : function(e)
29145 e.preventDefault();
29147 this.fireEvent('trash', this);
29159 * @class Roo.bootstrap.NavProgressBar
29160 * @extends Roo.bootstrap.Component
29161 * Bootstrap NavProgressBar class
29164 * Create a new nav progress bar
29165 * @param {Object} config The config object
29168 Roo.bootstrap.NavProgressBar = function(config){
29169 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29171 this.bullets = this.bullets || [];
29173 // Roo.bootstrap.NavProgressBar.register(this);
29177 * Fires when the active item changes
29178 * @param {Roo.bootstrap.NavProgressBar} this
29179 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29180 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29187 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29192 getAutoCreate : function()
29194 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29198 cls : 'roo-navigation-bar-group',
29202 cls : 'roo-navigation-top-bar'
29206 cls : 'roo-navigation-bullets-bar',
29210 cls : 'roo-navigation-bar'
29217 cls : 'roo-navigation-bottom-bar'
29227 initEvents: function()
29232 onRender : function(ct, position)
29234 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29236 if(this.bullets.length){
29237 Roo.each(this.bullets, function(b){
29246 addItem : function(cfg)
29248 var item = new Roo.bootstrap.NavProgressItem(cfg);
29250 item.parentId = this.id;
29251 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29254 var top = new Roo.bootstrap.Element({
29256 cls : 'roo-navigation-bar-text'
29259 var bottom = new Roo.bootstrap.Element({
29261 cls : 'roo-navigation-bar-text'
29264 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29265 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29267 var topText = new Roo.bootstrap.Element({
29269 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29272 var bottomText = new Roo.bootstrap.Element({
29274 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29277 topText.onRender(top.el, null);
29278 bottomText.onRender(bottom.el, null);
29281 item.bottomEl = bottom;
29284 this.barItems.push(item);
29289 getActive : function()
29291 var active = false;
29293 Roo.each(this.barItems, function(v){
29295 if (!v.isActive()) {
29307 setActiveItem : function(item)
29311 Roo.each(this.barItems, function(v){
29312 if (v.rid == item.rid) {
29316 if (v.isActive()) {
29317 v.setActive(false);
29322 item.setActive(true);
29324 this.fireEvent('changed', this, item, prev);
29327 getBarItem: function(rid)
29331 Roo.each(this.barItems, function(e) {
29332 if (e.rid != rid) {
29343 indexOfItem : function(item)
29347 Roo.each(this.barItems, function(v, i){
29349 if (v.rid != item.rid) {
29360 setActiveNext : function()
29362 var i = this.indexOfItem(this.getActive());
29364 if (i > this.barItems.length) {
29368 this.setActiveItem(this.barItems[i+1]);
29371 setActivePrev : function()
29373 var i = this.indexOfItem(this.getActive());
29379 this.setActiveItem(this.barItems[i-1]);
29382 format : function()
29384 if(!this.barItems.length){
29388 var width = 100 / this.barItems.length;
29390 Roo.each(this.barItems, function(i){
29391 i.el.setStyle('width', width + '%');
29392 i.topEl.el.setStyle('width', width + '%');
29393 i.bottomEl.el.setStyle('width', width + '%');
29402 * Nav Progress Item
29407 * @class Roo.bootstrap.NavProgressItem
29408 * @extends Roo.bootstrap.Component
29409 * Bootstrap NavProgressItem class
29410 * @cfg {String} rid the reference id
29411 * @cfg {Boolean} active (true|false) Is item active default false
29412 * @cfg {Boolean} disabled (true|false) Is item active default false
29413 * @cfg {String} html
29414 * @cfg {String} position (top|bottom) text position default bottom
29415 * @cfg {String} icon show icon instead of number
29418 * Create a new NavProgressItem
29419 * @param {Object} config The config object
29421 Roo.bootstrap.NavProgressItem = function(config){
29422 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29427 * The raw click event for the entire grid.
29428 * @param {Roo.bootstrap.NavProgressItem} this
29429 * @param {Roo.EventObject} e
29436 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29442 position : 'bottom',
29445 getAutoCreate : function()
29447 var iconCls = 'roo-navigation-bar-item-icon';
29449 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29453 cls: 'roo-navigation-bar-item',
29463 cfg.cls += ' active';
29466 cfg.cls += ' disabled';
29472 disable : function()
29474 this.setDisabled(true);
29477 enable : function()
29479 this.setDisabled(false);
29482 initEvents: function()
29484 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29486 this.iconEl.on('click', this.onClick, this);
29489 onClick : function(e)
29491 e.preventDefault();
29497 if(this.fireEvent('click', this, e) === false){
29501 this.parent().setActiveItem(this);
29504 isActive: function ()
29506 return this.active;
29509 setActive : function(state)
29511 if(this.active == state){
29515 this.active = state;
29518 this.el.addClass('active');
29522 this.el.removeClass('active');
29527 setDisabled : function(state)
29529 if(this.disabled == state){
29533 this.disabled = state;
29536 this.el.addClass('disabled');
29540 this.el.removeClass('disabled');
29543 tooltipEl : function()
29545 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29558 * @class Roo.bootstrap.FieldLabel
29559 * @extends Roo.bootstrap.Component
29560 * Bootstrap FieldLabel class
29561 * @cfg {String} html contents of the element
29562 * @cfg {String} tag tag of the element default label
29563 * @cfg {String} cls class of the element
29564 * @cfg {String} target label target
29565 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29566 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29567 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29568 * @cfg {String} iconTooltip default "This field is required"
29571 * Create a new FieldLabel
29572 * @param {Object} config The config object
29575 Roo.bootstrap.FieldLabel = function(config){
29576 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29581 * Fires after the field has been marked as invalid.
29582 * @param {Roo.form.FieldLabel} this
29583 * @param {String} msg The validation message
29588 * Fires after the field has been validated with no errors.
29589 * @param {Roo.form.FieldLabel} this
29595 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29602 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29603 validClass : 'text-success fa fa-lg fa-check',
29604 iconTooltip : 'This field is required',
29606 getAutoCreate : function(){
29610 cls : 'roo-bootstrap-field-label ' + this.cls,
29616 tooltip : this.iconTooltip
29628 initEvents: function()
29630 Roo.bootstrap.Element.superclass.initEvents.call(this);
29632 this.iconEl = this.el.select('i', true).first();
29634 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29636 Roo.bootstrap.FieldLabel.register(this);
29640 * Mark this field as valid
29642 markValid : function()
29644 this.iconEl.show();
29646 this.iconEl.removeClass(this.invalidClass);
29648 this.iconEl.addClass(this.validClass);
29650 this.fireEvent('valid', this);
29654 * Mark this field as invalid
29655 * @param {String} msg The validation message
29657 markInvalid : function(msg)
29659 this.iconEl.show();
29661 this.iconEl.removeClass(this.validClass);
29663 this.iconEl.addClass(this.invalidClass);
29665 this.fireEvent('invalid', this, msg);
29671 Roo.apply(Roo.bootstrap.FieldLabel, {
29676 * register a FieldLabel Group
29677 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29679 register : function(label)
29681 if(this.groups.hasOwnProperty(label.target)){
29685 this.groups[label.target] = label;
29689 * fetch a FieldLabel Group based on the target
29690 * @param {string} target
29691 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29693 get: function(target) {
29694 if (typeof(this.groups[target]) == 'undefined') {
29698 return this.groups[target] ;
29707 * page DateSplitField.
29713 * @class Roo.bootstrap.DateSplitField
29714 * @extends Roo.bootstrap.Component
29715 * Bootstrap DateSplitField class
29716 * @cfg {string} fieldLabel - the label associated
29717 * @cfg {Number} labelWidth set the width of label (0-12)
29718 * @cfg {String} labelAlign (top|left)
29719 * @cfg {Boolean} dayAllowBlank (true|false) default false
29720 * @cfg {Boolean} monthAllowBlank (true|false) default false
29721 * @cfg {Boolean} yearAllowBlank (true|false) default false
29722 * @cfg {string} dayPlaceholder
29723 * @cfg {string} monthPlaceholder
29724 * @cfg {string} yearPlaceholder
29725 * @cfg {string} dayFormat default 'd'
29726 * @cfg {string} monthFormat default 'm'
29727 * @cfg {string} yearFormat default 'Y'
29728 * @cfg {Number} labellg set the width of label (1-12)
29729 * @cfg {Number} labelmd set the width of label (1-12)
29730 * @cfg {Number} labelsm set the width of label (1-12)
29731 * @cfg {Number} labelxs set the width of label (1-12)
29735 * Create a new DateSplitField
29736 * @param {Object} config The config object
29739 Roo.bootstrap.DateSplitField = function(config){
29740 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29746 * getting the data of years
29747 * @param {Roo.bootstrap.DateSplitField} this
29748 * @param {Object} years
29753 * getting the data of days
29754 * @param {Roo.bootstrap.DateSplitField} this
29755 * @param {Object} days
29760 * Fires after the field has been marked as invalid.
29761 * @param {Roo.form.Field} this
29762 * @param {String} msg The validation message
29767 * Fires after the field has been validated with no errors.
29768 * @param {Roo.form.Field} this
29774 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29777 labelAlign : 'top',
29779 dayAllowBlank : false,
29780 monthAllowBlank : false,
29781 yearAllowBlank : false,
29782 dayPlaceholder : '',
29783 monthPlaceholder : '',
29784 yearPlaceholder : '',
29788 isFormField : true,
29794 getAutoCreate : function()
29798 cls : 'row roo-date-split-field-group',
29803 cls : 'form-hidden-field roo-date-split-field-group-value',
29809 var labelCls = 'col-md-12';
29810 var contentCls = 'col-md-4';
29812 if(this.fieldLabel){
29816 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29820 html : this.fieldLabel
29825 if(this.labelAlign == 'left'){
29827 if(this.labelWidth > 12){
29828 label.style = "width: " + this.labelWidth + 'px';
29831 if(this.labelWidth < 13 && this.labelmd == 0){
29832 this.labelmd = this.labelWidth;
29835 if(this.labellg > 0){
29836 labelCls = ' col-lg-' + this.labellg;
29837 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29840 if(this.labelmd > 0){
29841 labelCls = ' col-md-' + this.labelmd;
29842 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29845 if(this.labelsm > 0){
29846 labelCls = ' col-sm-' + this.labelsm;
29847 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29850 if(this.labelxs > 0){
29851 labelCls = ' col-xs-' + this.labelxs;
29852 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29856 label.cls += ' ' + labelCls;
29858 cfg.cn.push(label);
29861 Roo.each(['day', 'month', 'year'], function(t){
29864 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29871 inputEl: function ()
29873 return this.el.select('.roo-date-split-field-group-value', true).first();
29876 onRender : function(ct, position)
29880 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29882 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29884 this.dayField = new Roo.bootstrap.ComboBox({
29885 allowBlank : this.dayAllowBlank,
29886 alwaysQuery : true,
29887 displayField : 'value',
29890 forceSelection : true,
29892 placeholder : this.dayPlaceholder,
29893 selectOnFocus : true,
29894 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29895 triggerAction : 'all',
29897 valueField : 'value',
29898 store : new Roo.data.SimpleStore({
29899 data : (function() {
29901 _this.fireEvent('days', _this, days);
29904 fields : [ 'value' ]
29907 select : function (_self, record, index)
29909 _this.setValue(_this.getValue());
29914 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29916 this.monthField = new Roo.bootstrap.MonthField({
29917 after : '<i class=\"fa fa-calendar\"></i>',
29918 allowBlank : this.monthAllowBlank,
29919 placeholder : this.monthPlaceholder,
29922 render : function (_self)
29924 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29925 e.preventDefault();
29929 select : function (_self, oldvalue, newvalue)
29931 _this.setValue(_this.getValue());
29936 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29938 this.yearField = new Roo.bootstrap.ComboBox({
29939 allowBlank : this.yearAllowBlank,
29940 alwaysQuery : true,
29941 displayField : 'value',
29944 forceSelection : true,
29946 placeholder : this.yearPlaceholder,
29947 selectOnFocus : true,
29948 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29949 triggerAction : 'all',
29951 valueField : 'value',
29952 store : new Roo.data.SimpleStore({
29953 data : (function() {
29955 _this.fireEvent('years', _this, years);
29958 fields : [ 'value' ]
29961 select : function (_self, record, index)
29963 _this.setValue(_this.getValue());
29968 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29971 setValue : function(v, format)
29973 this.inputEl.dom.value = v;
29975 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29977 var d = Date.parseDate(v, f);
29984 this.setDay(d.format(this.dayFormat));
29985 this.setMonth(d.format(this.monthFormat));
29986 this.setYear(d.format(this.yearFormat));
29993 setDay : function(v)
29995 this.dayField.setValue(v);
29996 this.inputEl.dom.value = this.getValue();
30001 setMonth : function(v)
30003 this.monthField.setValue(v, true);
30004 this.inputEl.dom.value = this.getValue();
30009 setYear : function(v)
30011 this.yearField.setValue(v);
30012 this.inputEl.dom.value = this.getValue();
30017 getDay : function()
30019 return this.dayField.getValue();
30022 getMonth : function()
30024 return this.monthField.getValue();
30027 getYear : function()
30029 return this.yearField.getValue();
30032 getValue : function()
30034 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30036 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30046 this.inputEl.dom.value = '';
30051 validate : function()
30053 var d = this.dayField.validate();
30054 var m = this.monthField.validate();
30055 var y = this.yearField.validate();
30060 (!this.dayAllowBlank && !d) ||
30061 (!this.monthAllowBlank && !m) ||
30062 (!this.yearAllowBlank && !y)
30067 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30076 this.markInvalid();
30081 markValid : function()
30084 var label = this.el.select('label', true).first();
30085 var icon = this.el.select('i.fa-star', true).first();
30091 this.fireEvent('valid', this);
30095 * Mark this field as invalid
30096 * @param {String} msg The validation message
30098 markInvalid : function(msg)
30101 var label = this.el.select('label', true).first();
30102 var icon = this.el.select('i.fa-star', true).first();
30104 if(label && !icon){
30105 this.el.select('.roo-date-split-field-label', true).createChild({
30107 cls : 'text-danger fa fa-lg fa-star',
30108 tooltip : 'This field is required',
30109 style : 'margin-right:5px;'
30113 this.fireEvent('invalid', this, msg);
30116 clearInvalid : function()
30118 var label = this.el.select('label', true).first();
30119 var icon = this.el.select('i.fa-star', true).first();
30125 this.fireEvent('valid', this);
30128 getName: function()
30138 * http://masonry.desandro.com
30140 * The idea is to render all the bricks based on vertical width...
30142 * The original code extends 'outlayer' - we might need to use that....
30148 * @class Roo.bootstrap.LayoutMasonry
30149 * @extends Roo.bootstrap.Component
30150 * Bootstrap Layout Masonry class
30153 * Create a new Element
30154 * @param {Object} config The config object
30157 Roo.bootstrap.LayoutMasonry = function(config){
30159 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30163 Roo.bootstrap.LayoutMasonry.register(this);
30169 * Fire after layout the items
30170 * @param {Roo.bootstrap.LayoutMasonry} this
30171 * @param {Roo.EventObject} e
30178 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30181 * @cfg {Boolean} isLayoutInstant = no animation?
30183 isLayoutInstant : false, // needed?
30186 * @cfg {Number} boxWidth width of the columns
30191 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30196 * @cfg {Number} padWidth padding below box..
30201 * @cfg {Number} gutter gutter width..
30206 * @cfg {Number} maxCols maximum number of columns
30212 * @cfg {Boolean} isAutoInitial defalut true
30214 isAutoInitial : true,
30219 * @cfg {Boolean} isHorizontal defalut false
30221 isHorizontal : false,
30223 currentSize : null,
30229 bricks: null, //CompositeElement
30233 _isLayoutInited : false,
30235 // isAlternative : false, // only use for vertical layout...
30238 * @cfg {Number} alternativePadWidth padding below box..
30240 alternativePadWidth : 50,
30242 selectedBrick : [],
30244 getAutoCreate : function(){
30246 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30250 cls: 'blog-masonary-wrapper ' + this.cls,
30252 cls : 'mas-boxes masonary'
30259 getChildContainer: function( )
30261 if (this.boxesEl) {
30262 return this.boxesEl;
30265 this.boxesEl = this.el.select('.mas-boxes').first();
30267 return this.boxesEl;
30271 initEvents : function()
30275 if(this.isAutoInitial){
30276 Roo.log('hook children rendered');
30277 this.on('childrenrendered', function() {
30278 Roo.log('children rendered');
30284 initial : function()
30286 this.selectedBrick = [];
30288 this.currentSize = this.el.getBox(true);
30290 Roo.EventManager.onWindowResize(this.resize, this);
30292 if(!this.isAutoInitial){
30300 //this.layout.defer(500,this);
30304 resize : function()
30306 var cs = this.el.getBox(true);
30309 this.currentSize.width == cs.width &&
30310 this.currentSize.x == cs.x &&
30311 this.currentSize.height == cs.height &&
30312 this.currentSize.y == cs.y
30314 Roo.log("no change in with or X or Y");
30318 this.currentSize = cs;
30324 layout : function()
30326 this._resetLayout();
30328 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30330 this.layoutItems( isInstant );
30332 this._isLayoutInited = true;
30334 this.fireEvent('layout', this);
30338 _resetLayout : function()
30340 if(this.isHorizontal){
30341 this.horizontalMeasureColumns();
30345 this.verticalMeasureColumns();
30349 verticalMeasureColumns : function()
30351 this.getContainerWidth();
30353 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30354 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30358 var boxWidth = this.boxWidth + this.padWidth;
30360 if(this.containerWidth < this.boxWidth){
30361 boxWidth = this.containerWidth
30364 var containerWidth = this.containerWidth;
30366 var cols = Math.floor(containerWidth / boxWidth);
30368 this.cols = Math.max( cols, 1 );
30370 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30372 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30374 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30376 this.colWidth = boxWidth + avail - this.padWidth;
30378 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30379 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30382 horizontalMeasureColumns : function()
30384 this.getContainerWidth();
30386 var boxWidth = this.boxWidth;
30388 if(this.containerWidth < boxWidth){
30389 boxWidth = this.containerWidth;
30392 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30394 this.el.setHeight(boxWidth);
30398 getContainerWidth : function()
30400 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30403 layoutItems : function( isInstant )
30405 Roo.log(this.bricks);
30407 var items = Roo.apply([], this.bricks);
30409 if(this.isHorizontal){
30410 this._horizontalLayoutItems( items , isInstant );
30414 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30415 // this._verticalAlternativeLayoutItems( items , isInstant );
30419 this._verticalLayoutItems( items , isInstant );
30423 _verticalLayoutItems : function ( items , isInstant)
30425 if ( !items || !items.length ) {
30430 ['xs', 'xs', 'xs', 'tall'],
30431 ['xs', 'xs', 'tall'],
30432 ['xs', 'xs', 'sm'],
30433 ['xs', 'xs', 'xs'],
30439 ['sm', 'xs', 'xs'],
30443 ['tall', 'xs', 'xs', 'xs'],
30444 ['tall', 'xs', 'xs'],
30456 Roo.each(items, function(item, k){
30458 switch (item.size) {
30459 // these layouts take up a full box,
30470 boxes.push([item]);
30493 var filterPattern = function(box, length)
30501 var pattern = box.slice(0, length);
30505 Roo.each(pattern, function(i){
30506 format.push(i.size);
30509 Roo.each(standard, function(s){
30511 if(String(s) != String(format)){
30520 if(!match && length == 1){
30525 filterPattern(box, length - 1);
30529 queue.push(pattern);
30531 box = box.slice(length, box.length);
30533 filterPattern(box, 4);
30539 Roo.each(boxes, function(box, k){
30545 if(box.length == 1){
30550 filterPattern(box, 4);
30554 this._processVerticalLayoutQueue( queue, isInstant );
30558 // _verticalAlternativeLayoutItems : function( items , isInstant )
30560 // if ( !items || !items.length ) {
30564 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30568 _horizontalLayoutItems : function ( items , isInstant)
30570 if ( !items || !items.length || items.length < 3) {
30576 var eItems = items.slice(0, 3);
30578 items = items.slice(3, items.length);
30581 ['xs', 'xs', 'xs', 'wide'],
30582 ['xs', 'xs', 'wide'],
30583 ['xs', 'xs', 'sm'],
30584 ['xs', 'xs', 'xs'],
30590 ['sm', 'xs', 'xs'],
30594 ['wide', 'xs', 'xs', 'xs'],
30595 ['wide', 'xs', 'xs'],
30608 Roo.each(items, function(item, k){
30610 switch (item.size) {
30621 boxes.push([item]);
30645 var filterPattern = function(box, length)
30653 var pattern = box.slice(0, length);
30657 Roo.each(pattern, function(i){
30658 format.push(i.size);
30661 Roo.each(standard, function(s){
30663 if(String(s) != String(format)){
30672 if(!match && length == 1){
30677 filterPattern(box, length - 1);
30681 queue.push(pattern);
30683 box = box.slice(length, box.length);
30685 filterPattern(box, 4);
30691 Roo.each(boxes, function(box, k){
30697 if(box.length == 1){
30702 filterPattern(box, 4);
30709 var pos = this.el.getBox(true);
30713 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30715 var hit_end = false;
30717 Roo.each(queue, function(box){
30721 Roo.each(box, function(b){
30723 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30733 Roo.each(box, function(b){
30735 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30738 mx = Math.max(mx, b.x);
30742 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30746 Roo.each(box, function(b){
30748 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30762 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30765 /** Sets position of item in DOM
30766 * @param {Element} item
30767 * @param {Number} x - horizontal position
30768 * @param {Number} y - vertical position
30769 * @param {Boolean} isInstant - disables transitions
30771 _processVerticalLayoutQueue : function( queue, isInstant )
30773 var pos = this.el.getBox(true);
30778 for (var i = 0; i < this.cols; i++){
30782 Roo.each(queue, function(box, k){
30784 var col = k % this.cols;
30786 Roo.each(box, function(b,kk){
30788 b.el.position('absolute');
30790 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30791 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30793 if(b.size == 'md-left' || b.size == 'md-right'){
30794 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30795 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30798 b.el.setWidth(width);
30799 b.el.setHeight(height);
30801 b.el.select('iframe',true).setSize(width,height);
30805 for (var i = 0; i < this.cols; i++){
30807 if(maxY[i] < maxY[col]){
30812 col = Math.min(col, i);
30816 x = pos.x + col * (this.colWidth + this.padWidth);
30820 var positions = [];
30822 switch (box.length){
30824 positions = this.getVerticalOneBoxColPositions(x, y, box);
30827 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30830 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30833 positions = this.getVerticalFourBoxColPositions(x, y, box);
30839 Roo.each(box, function(b,kk){
30841 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30843 var sz = b.el.getSize();
30845 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30853 for (var i = 0; i < this.cols; i++){
30854 mY = Math.max(mY, maxY[i]);
30857 this.el.setHeight(mY - pos.y);
30861 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30863 // var pos = this.el.getBox(true);
30866 // var maxX = pos.right;
30868 // var maxHeight = 0;
30870 // Roo.each(items, function(item, k){
30874 // item.el.position('absolute');
30876 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30878 // item.el.setWidth(width);
30880 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30882 // item.el.setHeight(height);
30885 // item.el.setXY([x, y], isInstant ? false : true);
30887 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30890 // y = y + height + this.alternativePadWidth;
30892 // maxHeight = maxHeight + height + this.alternativePadWidth;
30896 // this.el.setHeight(maxHeight);
30900 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30902 var pos = this.el.getBox(true);
30907 var maxX = pos.right;
30909 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30911 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30913 Roo.each(queue, function(box, k){
30915 Roo.each(box, function(b, kk){
30917 b.el.position('absolute');
30919 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30920 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30922 if(b.size == 'md-left' || b.size == 'md-right'){
30923 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30924 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30927 b.el.setWidth(width);
30928 b.el.setHeight(height);
30936 var positions = [];
30938 switch (box.length){
30940 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30943 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30946 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30949 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30955 Roo.each(box, function(b,kk){
30957 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30959 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30967 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30969 Roo.each(eItems, function(b,k){
30971 b.size = (k == 0) ? 'sm' : 'xs';
30972 b.x = (k == 0) ? 2 : 1;
30973 b.y = (k == 0) ? 2 : 1;
30975 b.el.position('absolute');
30977 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30979 b.el.setWidth(width);
30981 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30983 b.el.setHeight(height);
30987 var positions = [];
30990 x : maxX - this.unitWidth * 2 - this.gutter,
30995 x : maxX - this.unitWidth,
30996 y : minY + (this.unitWidth + this.gutter) * 2
31000 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31004 Roo.each(eItems, function(b,k){
31006 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31012 getVerticalOneBoxColPositions : function(x, y, box)
31016 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31018 if(box[0].size == 'md-left'){
31022 if(box[0].size == 'md-right'){
31027 x : x + (this.unitWidth + this.gutter) * rand,
31034 getVerticalTwoBoxColPositions : function(x, y, box)
31038 if(box[0].size == 'xs'){
31042 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31046 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31060 x : x + (this.unitWidth + this.gutter) * 2,
31061 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31068 getVerticalThreeBoxColPositions : function(x, y, box)
31072 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31080 x : x + (this.unitWidth + this.gutter) * 1,
31085 x : x + (this.unitWidth + this.gutter) * 2,
31093 if(box[0].size == 'xs' && box[1].size == 'xs'){
31102 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31106 x : x + (this.unitWidth + this.gutter) * 1,
31120 x : x + (this.unitWidth + this.gutter) * 2,
31125 x : x + (this.unitWidth + this.gutter) * 2,
31126 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31133 getVerticalFourBoxColPositions : function(x, y, box)
31137 if(box[0].size == 'xs'){
31146 y : y + (this.unitHeight + this.gutter) * 1
31151 y : y + (this.unitHeight + this.gutter) * 2
31155 x : x + (this.unitWidth + this.gutter) * 1,
31169 x : x + (this.unitWidth + this.gutter) * 2,
31174 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31175 y : y + (this.unitHeight + this.gutter) * 1
31179 x : x + (this.unitWidth + this.gutter) * 2,
31180 y : y + (this.unitWidth + this.gutter) * 2
31187 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31191 if(box[0].size == 'md-left'){
31193 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31200 if(box[0].size == 'md-right'){
31202 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31203 y : minY + (this.unitWidth + this.gutter) * 1
31209 var rand = Math.floor(Math.random() * (4 - box[0].y));
31212 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31213 y : minY + (this.unitWidth + this.gutter) * rand
31220 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31224 if(box[0].size == 'xs'){
31227 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31232 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31233 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31241 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31246 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31247 y : minY + (this.unitWidth + this.gutter) * 2
31254 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31258 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31261 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31266 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31267 y : minY + (this.unitWidth + this.gutter) * 1
31271 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31272 y : minY + (this.unitWidth + this.gutter) * 2
31279 if(box[0].size == 'xs' && box[1].size == 'xs'){
31282 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31287 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31292 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31293 y : minY + (this.unitWidth + this.gutter) * 1
31301 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31306 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31307 y : minY + (this.unitWidth + this.gutter) * 2
31311 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31312 y : minY + (this.unitWidth + this.gutter) * 2
31319 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31323 if(box[0].size == 'xs'){
31326 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31331 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31336 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),
31341 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31342 y : minY + (this.unitWidth + this.gutter) * 1
31350 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31355 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31356 y : minY + (this.unitWidth + this.gutter) * 2
31360 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31361 y : minY + (this.unitWidth + this.gutter) * 2
31365 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),
31366 y : minY + (this.unitWidth + this.gutter) * 2
31374 * remove a Masonry Brick
31375 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31377 removeBrick : function(brick_id)
31383 for (var i = 0; i<this.bricks.length; i++) {
31384 if (this.bricks[i].id == brick_id) {
31385 this.bricks.splice(i,1);
31386 this.el.dom.removeChild(Roo.get(brick_id).dom);
31393 * adds a Masonry Brick
31394 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31396 addBrick : function(cfg)
31398 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31399 //this.register(cn);
31400 cn.parentId = this.id;
31401 cn.onRender(this.el, null);
31406 * register a Masonry Brick
31407 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31410 register : function(brick)
31412 this.bricks.push(brick);
31413 brick.masonryId = this.id;
31417 * clear all the Masonry Brick
31419 clearAll : function()
31422 //this.getChildContainer().dom.innerHTML = "";
31423 this.el.dom.innerHTML = '';
31426 getSelected : function()
31428 if (!this.selectedBrick) {
31432 return this.selectedBrick;
31436 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31440 * register a Masonry Layout
31441 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31444 register : function(layout)
31446 this.groups[layout.id] = layout;
31449 * fetch a Masonry Layout based on the masonry layout ID
31450 * @param {string} the masonry layout to add
31451 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31454 get: function(layout_id) {
31455 if (typeof(this.groups[layout_id]) == 'undefined') {
31458 return this.groups[layout_id] ;
31470 * http://masonry.desandro.com
31472 * The idea is to render all the bricks based on vertical width...
31474 * The original code extends 'outlayer' - we might need to use that....
31480 * @class Roo.bootstrap.LayoutMasonryAuto
31481 * @extends Roo.bootstrap.Component
31482 * Bootstrap Layout Masonry class
31485 * Create a new Element
31486 * @param {Object} config The config object
31489 Roo.bootstrap.LayoutMasonryAuto = function(config){
31490 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31493 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31496 * @cfg {Boolean} isFitWidth - resize the width..
31498 isFitWidth : false, // options..
31500 * @cfg {Boolean} isOriginLeft = left align?
31502 isOriginLeft : true,
31504 * @cfg {Boolean} isOriginTop = top align?
31506 isOriginTop : false,
31508 * @cfg {Boolean} isLayoutInstant = no animation?
31510 isLayoutInstant : false, // needed?
31512 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31514 isResizingContainer : true,
31516 * @cfg {Number} columnWidth width of the columns
31522 * @cfg {Number} maxCols maximum number of columns
31527 * @cfg {Number} padHeight padding below box..
31533 * @cfg {Boolean} isAutoInitial defalut true
31536 isAutoInitial : true,
31542 initialColumnWidth : 0,
31543 currentSize : null,
31545 colYs : null, // array.
31552 bricks: null, //CompositeElement
31553 cols : 0, // array?
31554 // element : null, // wrapped now this.el
31555 _isLayoutInited : null,
31558 getAutoCreate : function(){
31562 cls: 'blog-masonary-wrapper ' + this.cls,
31564 cls : 'mas-boxes masonary'
31571 getChildContainer: function( )
31573 if (this.boxesEl) {
31574 return this.boxesEl;
31577 this.boxesEl = this.el.select('.mas-boxes').first();
31579 return this.boxesEl;
31583 initEvents : function()
31587 if(this.isAutoInitial){
31588 Roo.log('hook children rendered');
31589 this.on('childrenrendered', function() {
31590 Roo.log('children rendered');
31597 initial : function()
31599 this.reloadItems();
31601 this.currentSize = this.el.getBox(true);
31603 /// was window resize... - let's see if this works..
31604 Roo.EventManager.onWindowResize(this.resize, this);
31606 if(!this.isAutoInitial){
31611 this.layout.defer(500,this);
31614 reloadItems: function()
31616 this.bricks = this.el.select('.masonry-brick', true);
31618 this.bricks.each(function(b) {
31619 //Roo.log(b.getSize());
31620 if (!b.attr('originalwidth')) {
31621 b.attr('originalwidth', b.getSize().width);
31626 Roo.log(this.bricks.elements.length);
31629 resize : function()
31632 var cs = this.el.getBox(true);
31634 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31635 Roo.log("no change in with or X");
31638 this.currentSize = cs;
31642 layout : function()
31645 this._resetLayout();
31646 //this._manageStamps();
31648 // don't animate first layout
31649 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31650 this.layoutItems( isInstant );
31652 // flag for initalized
31653 this._isLayoutInited = true;
31656 layoutItems : function( isInstant )
31658 //var items = this._getItemsForLayout( this.items );
31659 // original code supports filtering layout items.. we just ignore it..
31661 this._layoutItems( this.bricks , isInstant );
31663 this._postLayout();
31665 _layoutItems : function ( items , isInstant)
31667 //this.fireEvent( 'layout', this, items );
31670 if ( !items || !items.elements.length ) {
31671 // no items, emit event with empty array
31676 items.each(function(item) {
31677 Roo.log("layout item");
31679 // get x/y object from method
31680 var position = this._getItemLayoutPosition( item );
31682 position.item = item;
31683 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31684 queue.push( position );
31687 this._processLayoutQueue( queue );
31689 /** Sets position of item in DOM
31690 * @param {Element} item
31691 * @param {Number} x - horizontal position
31692 * @param {Number} y - vertical position
31693 * @param {Boolean} isInstant - disables transitions
31695 _processLayoutQueue : function( queue )
31697 for ( var i=0, len = queue.length; i < len; i++ ) {
31698 var obj = queue[i];
31699 obj.item.position('absolute');
31700 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31706 * Any logic you want to do after each layout,
31707 * i.e. size the container
31709 _postLayout : function()
31711 this.resizeContainer();
31714 resizeContainer : function()
31716 if ( !this.isResizingContainer ) {
31719 var size = this._getContainerSize();
31721 this.el.setSize(size.width,size.height);
31722 this.boxesEl.setSize(size.width,size.height);
31728 _resetLayout : function()
31730 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31731 this.colWidth = this.el.getWidth();
31732 //this.gutter = this.el.getWidth();
31734 this.measureColumns();
31740 this.colYs.push( 0 );
31746 measureColumns : function()
31748 this.getContainerWidth();
31749 // if columnWidth is 0, default to outerWidth of first item
31750 if ( !this.columnWidth ) {
31751 var firstItem = this.bricks.first();
31752 Roo.log(firstItem);
31753 this.columnWidth = this.containerWidth;
31754 if (firstItem && firstItem.attr('originalwidth') ) {
31755 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31757 // columnWidth fall back to item of first element
31758 Roo.log("set column width?");
31759 this.initialColumnWidth = this.columnWidth ;
31761 // if first elem has no width, default to size of container
31766 if (this.initialColumnWidth) {
31767 this.columnWidth = this.initialColumnWidth;
31772 // column width is fixed at the top - however if container width get's smaller we should
31775 // this bit calcs how man columns..
31777 var columnWidth = this.columnWidth += this.gutter;
31779 // calculate columns
31780 var containerWidth = this.containerWidth + this.gutter;
31782 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31783 // fix rounding errors, typically with gutters
31784 var excess = columnWidth - containerWidth % columnWidth;
31787 // if overshoot is less than a pixel, round up, otherwise floor it
31788 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31789 cols = Math[ mathMethod ]( cols );
31790 this.cols = Math.max( cols, 1 );
31791 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31793 // padding positioning..
31794 var totalColWidth = this.cols * this.columnWidth;
31795 var padavail = this.containerWidth - totalColWidth;
31796 // so for 2 columns - we need 3 'pads'
31798 var padNeeded = (1+this.cols) * this.padWidth;
31800 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31802 this.columnWidth += padExtra
31803 //this.padWidth = Math.floor(padavail / ( this.cols));
31805 // adjust colum width so that padding is fixed??
31807 // we have 3 columns ... total = width * 3
31808 // we have X left over... that should be used by
31810 //if (this.expandC) {
31818 getContainerWidth : function()
31820 /* // container is parent if fit width
31821 var container = this.isFitWidth ? this.element.parentNode : this.element;
31822 // check that this.size and size are there
31823 // IE8 triggers resize on body size change, so they might not be
31825 var size = getSize( container ); //FIXME
31826 this.containerWidth = size && size.innerWidth; //FIXME
31829 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31833 _getItemLayoutPosition : function( item ) // what is item?
31835 // we resize the item to our columnWidth..
31837 item.setWidth(this.columnWidth);
31838 item.autoBoxAdjust = false;
31840 var sz = item.getSize();
31842 // how many columns does this brick span
31843 var remainder = this.containerWidth % this.columnWidth;
31845 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31846 // round if off by 1 pixel, otherwise use ceil
31847 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31848 colSpan = Math.min( colSpan, this.cols );
31850 // normally this should be '1' as we dont' currently allow multi width columns..
31852 var colGroup = this._getColGroup( colSpan );
31853 // get the minimum Y value from the columns
31854 var minimumY = Math.min.apply( Math, colGroup );
31855 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31857 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31859 // position the brick
31861 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31862 y: this.currentSize.y + minimumY + this.padHeight
31866 // apply setHeight to necessary columns
31867 var setHeight = minimumY + sz.height + this.padHeight;
31868 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31870 var setSpan = this.cols + 1 - colGroup.length;
31871 for ( var i = 0; i < setSpan; i++ ) {
31872 this.colYs[ shortColIndex + i ] = setHeight ;
31879 * @param {Number} colSpan - number of columns the element spans
31880 * @returns {Array} colGroup
31882 _getColGroup : function( colSpan )
31884 if ( colSpan < 2 ) {
31885 // if brick spans only one column, use all the column Ys
31890 // how many different places could this brick fit horizontally
31891 var groupCount = this.cols + 1 - colSpan;
31892 // for each group potential horizontal position
31893 for ( var i = 0; i < groupCount; i++ ) {
31894 // make an array of colY values for that one group
31895 var groupColYs = this.colYs.slice( i, i + colSpan );
31896 // and get the max value of the array
31897 colGroup[i] = Math.max.apply( Math, groupColYs );
31902 _manageStamp : function( stamp )
31904 var stampSize = stamp.getSize();
31905 var offset = stamp.getBox();
31906 // get the columns that this stamp affects
31907 var firstX = this.isOriginLeft ? offset.x : offset.right;
31908 var lastX = firstX + stampSize.width;
31909 var firstCol = Math.floor( firstX / this.columnWidth );
31910 firstCol = Math.max( 0, firstCol );
31912 var lastCol = Math.floor( lastX / this.columnWidth );
31913 // lastCol should not go over if multiple of columnWidth #425
31914 lastCol -= lastX % this.columnWidth ? 0 : 1;
31915 lastCol = Math.min( this.cols - 1, lastCol );
31917 // set colYs to bottom of the stamp
31918 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31921 for ( var i = firstCol; i <= lastCol; i++ ) {
31922 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31927 _getContainerSize : function()
31929 this.maxY = Math.max.apply( Math, this.colYs );
31934 if ( this.isFitWidth ) {
31935 size.width = this._getContainerFitWidth();
31941 _getContainerFitWidth : function()
31943 var unusedCols = 0;
31944 // count unused columns
31947 if ( this.colYs[i] !== 0 ) {
31952 // fit container to columns that have been used
31953 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31956 needsResizeLayout : function()
31958 var previousWidth = this.containerWidth;
31959 this.getContainerWidth();
31960 return previousWidth !== this.containerWidth;
31975 * @class Roo.bootstrap.MasonryBrick
31976 * @extends Roo.bootstrap.Component
31977 * Bootstrap MasonryBrick class
31980 * Create a new MasonryBrick
31981 * @param {Object} config The config object
31984 Roo.bootstrap.MasonryBrick = function(config){
31986 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31988 Roo.bootstrap.MasonryBrick.register(this);
31994 * When a MasonryBrick is clcik
31995 * @param {Roo.bootstrap.MasonryBrick} this
31996 * @param {Roo.EventObject} e
32002 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32005 * @cfg {String} title
32009 * @cfg {String} html
32013 * @cfg {String} bgimage
32017 * @cfg {String} videourl
32021 * @cfg {String} cls
32025 * @cfg {String} href
32029 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32034 * @cfg {String} placetitle (center|bottom)
32039 * @cfg {Boolean} isFitContainer defalut true
32041 isFitContainer : true,
32044 * @cfg {Boolean} preventDefault defalut false
32046 preventDefault : false,
32049 * @cfg {Boolean} inverse defalut false
32051 maskInverse : false,
32053 getAutoCreate : function()
32055 if(!this.isFitContainer){
32056 return this.getSplitAutoCreate();
32059 var cls = 'masonry-brick masonry-brick-full';
32061 if(this.href.length){
32062 cls += ' masonry-brick-link';
32065 if(this.bgimage.length){
32066 cls += ' masonry-brick-image';
32069 if(this.maskInverse){
32070 cls += ' mask-inverse';
32073 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32074 cls += ' enable-mask';
32078 cls += ' masonry-' + this.size + '-brick';
32081 if(this.placetitle.length){
32083 switch (this.placetitle) {
32085 cls += ' masonry-center-title';
32088 cls += ' masonry-bottom-title';
32095 if(!this.html.length && !this.bgimage.length){
32096 cls += ' masonry-center-title';
32099 if(!this.html.length && this.bgimage.length){
32100 cls += ' masonry-bottom-title';
32105 cls += ' ' + this.cls;
32109 tag: (this.href.length) ? 'a' : 'div',
32114 cls: 'masonry-brick-mask'
32118 cls: 'masonry-brick-paragraph',
32124 if(this.href.length){
32125 cfg.href = this.href;
32128 var cn = cfg.cn[1].cn;
32130 if(this.title.length){
32133 cls: 'masonry-brick-title',
32138 if(this.html.length){
32141 cls: 'masonry-brick-text',
32146 if (!this.title.length && !this.html.length) {
32147 cfg.cn[1].cls += ' hide';
32150 if(this.bgimage.length){
32153 cls: 'masonry-brick-image-view',
32158 if(this.videourl.length){
32159 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32160 // youtube support only?
32163 cls: 'masonry-brick-image-view',
32166 allowfullscreen : true
32174 getSplitAutoCreate : function()
32176 var cls = 'masonry-brick masonry-brick-split';
32178 if(this.href.length){
32179 cls += ' masonry-brick-link';
32182 if(this.bgimage.length){
32183 cls += ' masonry-brick-image';
32187 cls += ' masonry-' + this.size + '-brick';
32190 switch (this.placetitle) {
32192 cls += ' masonry-center-title';
32195 cls += ' masonry-bottom-title';
32198 if(!this.bgimage.length){
32199 cls += ' masonry-center-title';
32202 if(this.bgimage.length){
32203 cls += ' masonry-bottom-title';
32209 cls += ' ' + this.cls;
32213 tag: (this.href.length) ? 'a' : 'div',
32218 cls: 'masonry-brick-split-head',
32222 cls: 'masonry-brick-paragraph',
32229 cls: 'masonry-brick-split-body',
32235 if(this.href.length){
32236 cfg.href = this.href;
32239 if(this.title.length){
32240 cfg.cn[0].cn[0].cn.push({
32242 cls: 'masonry-brick-title',
32247 if(this.html.length){
32248 cfg.cn[1].cn.push({
32250 cls: 'masonry-brick-text',
32255 if(this.bgimage.length){
32256 cfg.cn[0].cn.push({
32258 cls: 'masonry-brick-image-view',
32263 if(this.videourl.length){
32264 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32265 // youtube support only?
32266 cfg.cn[0].cn.cn.push({
32268 cls: 'masonry-brick-image-view',
32271 allowfullscreen : true
32278 initEvents: function()
32280 switch (this.size) {
32313 this.el.on('touchstart', this.onTouchStart, this);
32314 this.el.on('touchmove', this.onTouchMove, this);
32315 this.el.on('touchend', this.onTouchEnd, this);
32316 this.el.on('contextmenu', this.onContextMenu, this);
32318 this.el.on('mouseenter' ,this.enter, this);
32319 this.el.on('mouseleave', this.leave, this);
32320 this.el.on('click', this.onClick, this);
32323 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32324 this.parent().bricks.push(this);
32329 onClick: function(e, el)
32331 var time = this.endTimer - this.startTimer;
32332 // Roo.log(e.preventDefault());
32335 e.preventDefault();
32340 if(!this.preventDefault){
32344 e.preventDefault();
32346 if (this.activcClass != '') {
32347 this.selectBrick();
32350 this.fireEvent('click', this);
32353 enter: function(e, el)
32355 e.preventDefault();
32357 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32361 if(this.bgimage.length && this.html.length){
32362 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32366 leave: function(e, el)
32368 e.preventDefault();
32370 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32374 if(this.bgimage.length && this.html.length){
32375 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32379 onTouchStart: function(e, el)
32381 // e.preventDefault();
32383 this.touchmoved = false;
32385 if(!this.isFitContainer){
32389 if(!this.bgimage.length || !this.html.length){
32393 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32395 this.timer = new Date().getTime();
32399 onTouchMove: function(e, el)
32401 this.touchmoved = true;
32404 onContextMenu : function(e,el)
32406 e.preventDefault();
32407 e.stopPropagation();
32411 onTouchEnd: function(e, el)
32413 // e.preventDefault();
32415 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32422 if(!this.bgimage.length || !this.html.length){
32424 if(this.href.length){
32425 window.location.href = this.href;
32431 if(!this.isFitContainer){
32435 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32437 window.location.href = this.href;
32440 //selection on single brick only
32441 selectBrick : function() {
32443 if (!this.parentId) {
32447 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32448 var index = m.selectedBrick.indexOf(this.id);
32451 m.selectedBrick.splice(index,1);
32452 this.el.removeClass(this.activeClass);
32456 for(var i = 0; i < m.selectedBrick.length; i++) {
32457 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32458 b.el.removeClass(b.activeClass);
32461 m.selectedBrick = [];
32463 m.selectedBrick.push(this.id);
32464 this.el.addClass(this.activeClass);
32470 Roo.apply(Roo.bootstrap.MasonryBrick, {
32473 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32475 * register a Masonry Brick
32476 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32479 register : function(brick)
32481 //this.groups[brick.id] = brick;
32482 this.groups.add(brick.id, brick);
32485 * fetch a masonry brick based on the masonry brick ID
32486 * @param {string} the masonry brick to add
32487 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32490 get: function(brick_id)
32492 // if (typeof(this.groups[brick_id]) == 'undefined') {
32495 // return this.groups[brick_id] ;
32497 if(this.groups.key(brick_id)) {
32498 return this.groups.key(brick_id);
32516 * @class Roo.bootstrap.Brick
32517 * @extends Roo.bootstrap.Component
32518 * Bootstrap Brick class
32521 * Create a new Brick
32522 * @param {Object} config The config object
32525 Roo.bootstrap.Brick = function(config){
32526 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32532 * When a Brick is click
32533 * @param {Roo.bootstrap.Brick} this
32534 * @param {Roo.EventObject} e
32540 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32543 * @cfg {String} title
32547 * @cfg {String} html
32551 * @cfg {String} bgimage
32555 * @cfg {String} cls
32559 * @cfg {String} href
32563 * @cfg {String} video
32567 * @cfg {Boolean} square
32571 getAutoCreate : function()
32573 var cls = 'roo-brick';
32575 if(this.href.length){
32576 cls += ' roo-brick-link';
32579 if(this.bgimage.length){
32580 cls += ' roo-brick-image';
32583 if(!this.html.length && !this.bgimage.length){
32584 cls += ' roo-brick-center-title';
32587 if(!this.html.length && this.bgimage.length){
32588 cls += ' roo-brick-bottom-title';
32592 cls += ' ' + this.cls;
32596 tag: (this.href.length) ? 'a' : 'div',
32601 cls: 'roo-brick-paragraph',
32607 if(this.href.length){
32608 cfg.href = this.href;
32611 var cn = cfg.cn[0].cn;
32613 if(this.title.length){
32616 cls: 'roo-brick-title',
32621 if(this.html.length){
32624 cls: 'roo-brick-text',
32631 if(this.bgimage.length){
32634 cls: 'roo-brick-image-view',
32642 initEvents: function()
32644 if(this.title.length || this.html.length){
32645 this.el.on('mouseenter' ,this.enter, this);
32646 this.el.on('mouseleave', this.leave, this);
32649 Roo.EventManager.onWindowResize(this.resize, this);
32651 if(this.bgimage.length){
32652 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32653 this.imageEl.on('load', this.onImageLoad, this);
32660 onImageLoad : function()
32665 resize : function()
32667 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32669 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32671 if(this.bgimage.length){
32672 var image = this.el.select('.roo-brick-image-view', true).first();
32674 image.setWidth(paragraph.getWidth());
32677 image.setHeight(paragraph.getWidth());
32680 this.el.setHeight(image.getHeight());
32681 paragraph.setHeight(image.getHeight());
32687 enter: function(e, el)
32689 e.preventDefault();
32691 if(this.bgimage.length){
32692 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32693 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32697 leave: function(e, el)
32699 e.preventDefault();
32701 if(this.bgimage.length){
32702 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32703 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32719 * @class Roo.bootstrap.NumberField
32720 * @extends Roo.bootstrap.Input
32721 * Bootstrap NumberField class
32727 * Create a new NumberField
32728 * @param {Object} config The config object
32731 Roo.bootstrap.NumberField = function(config){
32732 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32735 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32738 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32740 allowDecimals : true,
32742 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32744 decimalSeparator : ".",
32746 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32748 decimalPrecision : 2,
32750 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32752 allowNegative : true,
32754 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32756 minValue : Number.NEGATIVE_INFINITY,
32758 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32760 maxValue : Number.MAX_VALUE,
32762 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32764 minText : "The minimum value for this field is {0}",
32766 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32768 maxText : "The maximum value for this field is {0}",
32770 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32771 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32773 nanText : "{0} is not a valid number",
32775 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32780 initEvents : function()
32782 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32784 var allowed = "0123456789";
32786 if(this.allowDecimals){
32787 allowed += this.decimalSeparator;
32790 if(this.allowNegative){
32794 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32796 var keyPress = function(e){
32798 var k = e.getKey();
32800 var c = e.getCharCode();
32803 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32804 allowed.indexOf(String.fromCharCode(c)) === -1
32810 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32814 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32819 this.el.on("keypress", keyPress, this);
32822 validateValue : function(value)
32825 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32829 var num = this.parseValue(value);
32832 this.markInvalid(String.format(this.nanText, value));
32836 if(num < this.minValue){
32837 this.markInvalid(String.format(this.minText, this.minValue));
32841 if(num > this.maxValue){
32842 this.markInvalid(String.format(this.maxText, this.maxValue));
32849 getValue : function()
32851 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32854 parseValue : function(value)
32856 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32857 return isNaN(value) ? '' : value;
32860 fixPrecision : function(value)
32862 var nan = isNaN(value);
32864 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32865 return nan ? '' : value;
32867 return parseFloat(value).toFixed(this.decimalPrecision);
32870 setValue : function(v)
32872 v = this.fixPrecision(v);
32873 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32876 decimalPrecisionFcn : function(v)
32878 return Math.floor(v);
32881 beforeBlur : function()
32887 var v = this.parseValue(this.getRawValue());
32902 * @class Roo.bootstrap.DocumentSlider
32903 * @extends Roo.bootstrap.Component
32904 * Bootstrap DocumentSlider class
32907 * Create a new DocumentViewer
32908 * @param {Object} config The config object
32911 Roo.bootstrap.DocumentSlider = function(config){
32912 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32919 * Fire after initEvent
32920 * @param {Roo.bootstrap.DocumentSlider} this
32925 * Fire after update
32926 * @param {Roo.bootstrap.DocumentSlider} this
32932 * @param {Roo.bootstrap.DocumentSlider} this
32938 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32944 getAutoCreate : function()
32948 cls : 'roo-document-slider',
32952 cls : 'roo-document-slider-header',
32956 cls : 'roo-document-slider-header-title'
32962 cls : 'roo-document-slider-body',
32966 cls : 'roo-document-slider-prev',
32970 cls : 'fa fa-chevron-left'
32976 cls : 'roo-document-slider-thumb',
32980 cls : 'roo-document-slider-image'
32986 cls : 'roo-document-slider-next',
32990 cls : 'fa fa-chevron-right'
33002 initEvents : function()
33004 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33005 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33007 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33008 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33010 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33011 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33013 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33014 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33016 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33017 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33019 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33020 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33022 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33023 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33025 this.thumbEl.on('click', this.onClick, this);
33027 this.prevIndicator.on('click', this.prev, this);
33029 this.nextIndicator.on('click', this.next, this);
33033 initial : function()
33035 if(this.files.length){
33036 this.indicator = 1;
33040 this.fireEvent('initial', this);
33043 update : function()
33045 this.imageEl.attr('src', this.files[this.indicator - 1]);
33047 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33049 this.prevIndicator.show();
33051 if(this.indicator == 1){
33052 this.prevIndicator.hide();
33055 this.nextIndicator.show();
33057 if(this.indicator == this.files.length){
33058 this.nextIndicator.hide();
33061 this.thumbEl.scrollTo('top');
33063 this.fireEvent('update', this);
33066 onClick : function(e)
33068 e.preventDefault();
33070 this.fireEvent('click', this);
33075 e.preventDefault();
33077 this.indicator = Math.max(1, this.indicator - 1);
33084 e.preventDefault();
33086 this.indicator = Math.min(this.files.length, this.indicator + 1);
33100 * @class Roo.bootstrap.RadioSet
33101 * @extends Roo.bootstrap.Input
33102 * Bootstrap RadioSet class
33103 * @cfg {String} indicatorpos (left|right) default left
33104 * @cfg {Boolean} inline (true|false) inline the element (default true)
33105 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33107 * Create a new RadioSet
33108 * @param {Object} config The config object
33111 Roo.bootstrap.RadioSet = function(config){
33113 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33117 Roo.bootstrap.RadioSet.register(this);
33122 * Fires when the element is checked or unchecked.
33123 * @param {Roo.bootstrap.RadioSet} this This radio
33124 * @param {Roo.bootstrap.Radio} item The checked item
33131 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33139 indicatorpos : 'left',
33141 getAutoCreate : function()
33145 cls : 'roo-radio-set-label',
33149 html : this.fieldLabel
33154 if(this.indicatorpos == 'left'){
33157 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33158 tooltip : 'This field is required'
33163 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33164 tooltip : 'This field is required'
33170 cls : 'roo-radio-set-items'
33173 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33175 if (align === 'left' && this.fieldLabel.length) {
33178 cls : "roo-radio-set-right",
33184 if(this.labelWidth > 12){
33185 label.style = "width: " + this.labelWidth + 'px';
33188 if(this.labelWidth < 13 && this.labelmd == 0){
33189 this.labelmd = this.labelWidth;
33192 if(this.labellg > 0){
33193 label.cls += ' col-lg-' + this.labellg;
33194 items.cls += ' col-lg-' + (12 - this.labellg);
33197 if(this.labelmd > 0){
33198 label.cls += ' col-md-' + this.labelmd;
33199 items.cls += ' col-md-' + (12 - this.labelmd);
33202 if(this.labelsm > 0){
33203 label.cls += ' col-sm-' + this.labelsm;
33204 items.cls += ' col-sm-' + (12 - this.labelsm);
33207 if(this.labelxs > 0){
33208 label.cls += ' col-xs-' + this.labelxs;
33209 items.cls += ' col-xs-' + (12 - this.labelxs);
33215 cls : 'roo-radio-set',
33219 cls : 'roo-radio-set-input',
33222 value : this.value ? this.value : ''
33229 if(this.weight.length){
33230 cfg.cls += ' roo-radio-' + this.weight;
33234 cfg.cls += ' roo-radio-set-inline';
33241 initEvents : function()
33243 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33244 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33246 if(!this.fieldLabel.length){
33247 this.labelEl.hide();
33250 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33251 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33253 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33254 this.indicatorEl().hide();
33256 this.originalValue = this.getValue();
33260 inputEl: function ()
33262 return this.el.select('.roo-radio-set-input', true).first();
33265 getChildContainer : function()
33267 return this.itemsEl;
33270 register : function(item)
33272 this.radioes.push(item);
33276 validate : function()
33280 Roo.each(this.radioes, function(i){
33289 if(this.allowBlank) {
33293 if(this.disabled || valid){
33298 this.markInvalid();
33303 markValid : function()
33305 if(this.labelEl.isVisible(true)){
33306 this.indicatorEl().hide();
33309 this.el.removeClass([this.invalidClass, this.validClass]);
33310 this.el.addClass(this.validClass);
33312 this.fireEvent('valid', this);
33315 markInvalid : function(msg)
33317 if(this.allowBlank || this.disabled){
33321 if(this.labelEl.isVisible(true)){
33322 this.indicatorEl().show();
33325 this.el.removeClass([this.invalidClass, this.validClass]);
33326 this.el.addClass(this.invalidClass);
33328 this.fireEvent('invalid', this, msg);
33332 setValue : function(v, suppressEvent)
33336 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33339 Roo.each(this.radioes, function(i){
33342 i.el.removeClass('checked');
33344 if(i.value === v || i.value.toString() === v.toString()){
33346 i.el.addClass('checked');
33348 if(suppressEvent !== true){
33349 this.fireEvent('check', this, i);
33358 clearInvalid : function(){
33360 if(!this.el || this.preventMark){
33364 this.el.removeClass([this.invalidClass]);
33366 this.fireEvent('valid', this);
33371 Roo.apply(Roo.bootstrap.RadioSet, {
33375 register : function(set)
33377 this.groups[set.name] = set;
33380 get: function(name)
33382 if (typeof(this.groups[name]) == 'undefined') {
33386 return this.groups[name] ;
33392 * Ext JS Library 1.1.1
33393 * Copyright(c) 2006-2007, Ext JS, LLC.
33395 * Originally Released Under LGPL - original licence link has changed is not relivant.
33398 * <script type="text/javascript">
33403 * @class Roo.bootstrap.SplitBar
33404 * @extends Roo.util.Observable
33405 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33409 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33410 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33411 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33412 split.minSize = 100;
33413 split.maxSize = 600;
33414 split.animate = true;
33415 split.on('moved', splitterMoved);
33418 * Create a new SplitBar
33419 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33420 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33421 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33422 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33423 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33424 position of the SplitBar).
33426 Roo.bootstrap.SplitBar = function(cfg){
33431 // dragElement : elm
33432 // resizingElement: el,
33434 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33435 // placement : Roo.bootstrap.SplitBar.LEFT ,
33436 // existingProxy ???
33439 this.el = Roo.get(cfg.dragElement, true);
33440 this.el.dom.unselectable = "on";
33442 this.resizingEl = Roo.get(cfg.resizingElement, true);
33446 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33447 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33450 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33453 * The minimum size of the resizing element. (Defaults to 0)
33459 * The maximum size of the resizing element. (Defaults to 2000)
33462 this.maxSize = 2000;
33465 * Whether to animate the transition to the new size
33468 this.animate = false;
33471 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33474 this.useShim = false;
33479 if(!cfg.existingProxy){
33481 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33483 this.proxy = Roo.get(cfg.existingProxy).dom;
33486 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33489 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33492 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33495 this.dragSpecs = {};
33498 * @private The adapter to use to positon and resize elements
33500 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33501 this.adapter.init(this);
33503 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33505 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33506 this.el.addClass("roo-splitbar-h");
33509 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33510 this.el.addClass("roo-splitbar-v");
33516 * Fires when the splitter is moved (alias for {@link #event-moved})
33517 * @param {Roo.bootstrap.SplitBar} this
33518 * @param {Number} newSize the new width or height
33523 * Fires when the splitter is moved
33524 * @param {Roo.bootstrap.SplitBar} this
33525 * @param {Number} newSize the new width or height
33529 * @event beforeresize
33530 * Fires before the splitter is dragged
33531 * @param {Roo.bootstrap.SplitBar} this
33533 "beforeresize" : true,
33535 "beforeapply" : true
33538 Roo.util.Observable.call(this);
33541 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33542 onStartProxyDrag : function(x, y){
33543 this.fireEvent("beforeresize", this);
33545 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33547 o.enableDisplayMode("block");
33548 // all splitbars share the same overlay
33549 Roo.bootstrap.SplitBar.prototype.overlay = o;
33551 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33552 this.overlay.show();
33553 Roo.get(this.proxy).setDisplayed("block");
33554 var size = this.adapter.getElementSize(this);
33555 this.activeMinSize = this.getMinimumSize();;
33556 this.activeMaxSize = this.getMaximumSize();;
33557 var c1 = size - this.activeMinSize;
33558 var c2 = Math.max(this.activeMaxSize - size, 0);
33559 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33560 this.dd.resetConstraints();
33561 this.dd.setXConstraint(
33562 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33563 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33565 this.dd.setYConstraint(0, 0);
33567 this.dd.resetConstraints();
33568 this.dd.setXConstraint(0, 0);
33569 this.dd.setYConstraint(
33570 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33571 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33574 this.dragSpecs.startSize = size;
33575 this.dragSpecs.startPoint = [x, y];
33576 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33580 * @private Called after the drag operation by the DDProxy
33582 onEndProxyDrag : function(e){
33583 Roo.get(this.proxy).setDisplayed(false);
33584 var endPoint = Roo.lib.Event.getXY(e);
33586 this.overlay.hide();
33589 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33590 newSize = this.dragSpecs.startSize +
33591 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33592 endPoint[0] - this.dragSpecs.startPoint[0] :
33593 this.dragSpecs.startPoint[0] - endPoint[0]
33596 newSize = this.dragSpecs.startSize +
33597 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33598 endPoint[1] - this.dragSpecs.startPoint[1] :
33599 this.dragSpecs.startPoint[1] - endPoint[1]
33602 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33603 if(newSize != this.dragSpecs.startSize){
33604 if(this.fireEvent('beforeapply', this, newSize) !== false){
33605 this.adapter.setElementSize(this, newSize);
33606 this.fireEvent("moved", this, newSize);
33607 this.fireEvent("resize", this, newSize);
33613 * Get the adapter this SplitBar uses
33614 * @return The adapter object
33616 getAdapter : function(){
33617 return this.adapter;
33621 * Set the adapter this SplitBar uses
33622 * @param {Object} adapter A SplitBar adapter object
33624 setAdapter : function(adapter){
33625 this.adapter = adapter;
33626 this.adapter.init(this);
33630 * Gets the minimum size for the resizing element
33631 * @return {Number} The minimum size
33633 getMinimumSize : function(){
33634 return this.minSize;
33638 * Sets the minimum size for the resizing element
33639 * @param {Number} minSize The minimum size
33641 setMinimumSize : function(minSize){
33642 this.minSize = minSize;
33646 * Gets the maximum size for the resizing element
33647 * @return {Number} The maximum size
33649 getMaximumSize : function(){
33650 return this.maxSize;
33654 * Sets the maximum size for the resizing element
33655 * @param {Number} maxSize The maximum size
33657 setMaximumSize : function(maxSize){
33658 this.maxSize = maxSize;
33662 * Sets the initialize size for the resizing element
33663 * @param {Number} size The initial size
33665 setCurrentSize : function(size){
33666 var oldAnimate = this.animate;
33667 this.animate = false;
33668 this.adapter.setElementSize(this, size);
33669 this.animate = oldAnimate;
33673 * Destroy this splitbar.
33674 * @param {Boolean} removeEl True to remove the element
33676 destroy : function(removeEl){
33678 this.shim.remove();
33681 this.proxy.parentNode.removeChild(this.proxy);
33689 * @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.
33691 Roo.bootstrap.SplitBar.createProxy = function(dir){
33692 var proxy = new Roo.Element(document.createElement("div"));
33693 proxy.unselectable();
33694 var cls = 'roo-splitbar-proxy';
33695 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33696 document.body.appendChild(proxy.dom);
33701 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33702 * Default Adapter. It assumes the splitter and resizing element are not positioned
33703 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33705 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33708 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33709 // do nothing for now
33710 init : function(s){
33714 * Called before drag operations to get the current size of the resizing element.
33715 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33717 getElementSize : function(s){
33718 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33719 return s.resizingEl.getWidth();
33721 return s.resizingEl.getHeight();
33726 * Called after drag operations to set the size of the resizing element.
33727 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33728 * @param {Number} newSize The new size to set
33729 * @param {Function} onComplete A function to be invoked when resizing is complete
33731 setElementSize : function(s, newSize, onComplete){
33732 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33734 s.resizingEl.setWidth(newSize);
33736 onComplete(s, newSize);
33739 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33744 s.resizingEl.setHeight(newSize);
33746 onComplete(s, newSize);
33749 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33756 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33757 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33758 * Adapter that moves the splitter element to align with the resized sizing element.
33759 * Used with an absolute positioned SplitBar.
33760 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33761 * document.body, make sure you assign an id to the body element.
33763 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33764 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33765 this.container = Roo.get(container);
33768 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33769 init : function(s){
33770 this.basic.init(s);
33773 getElementSize : function(s){
33774 return this.basic.getElementSize(s);
33777 setElementSize : function(s, newSize, onComplete){
33778 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33781 moveSplitter : function(s){
33782 var yes = Roo.bootstrap.SplitBar;
33783 switch(s.placement){
33785 s.el.setX(s.resizingEl.getRight());
33788 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33791 s.el.setY(s.resizingEl.getBottom());
33794 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33801 * Orientation constant - Create a vertical SplitBar
33805 Roo.bootstrap.SplitBar.VERTICAL = 1;
33808 * Orientation constant - Create a horizontal SplitBar
33812 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33815 * Placement constant - The resizing element is to the left of the splitter element
33819 Roo.bootstrap.SplitBar.LEFT = 1;
33822 * Placement constant - The resizing element is to the right of the splitter element
33826 Roo.bootstrap.SplitBar.RIGHT = 2;
33829 * Placement constant - The resizing element is positioned above the splitter element
33833 Roo.bootstrap.SplitBar.TOP = 3;
33836 * Placement constant - The resizing element is positioned under splitter element
33840 Roo.bootstrap.SplitBar.BOTTOM = 4;
33841 Roo.namespace("Roo.bootstrap.layout");/*
33843 * Ext JS Library 1.1.1
33844 * Copyright(c) 2006-2007, Ext JS, LLC.
33846 * Originally Released Under LGPL - original licence link has changed is not relivant.
33849 * <script type="text/javascript">
33853 * @class Roo.bootstrap.layout.Manager
33854 * @extends Roo.bootstrap.Component
33855 * Base class for layout managers.
33857 Roo.bootstrap.layout.Manager = function(config)
33859 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33865 /** false to disable window resize monitoring @type Boolean */
33866 this.monitorWindowResize = true;
33871 * Fires when a layout is performed.
33872 * @param {Roo.LayoutManager} this
33876 * @event regionresized
33877 * Fires when the user resizes a region.
33878 * @param {Roo.LayoutRegion} region The resized region
33879 * @param {Number} newSize The new size (width for east/west, height for north/south)
33881 "regionresized" : true,
33883 * @event regioncollapsed
33884 * Fires when a region is collapsed.
33885 * @param {Roo.LayoutRegion} region The collapsed region
33887 "regioncollapsed" : true,
33889 * @event regionexpanded
33890 * Fires when a region is expanded.
33891 * @param {Roo.LayoutRegion} region The expanded region
33893 "regionexpanded" : true
33895 this.updating = false;
33898 this.el = Roo.get(config.el);
33904 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33909 monitorWindowResize : true,
33915 onRender : function(ct, position)
33918 this.el = Roo.get(ct);
33921 //this.fireEvent('render',this);
33925 initEvents: function()
33929 // ie scrollbar fix
33930 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33931 document.body.scroll = "no";
33932 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33933 this.el.position('relative');
33935 this.id = this.el.id;
33936 this.el.addClass("roo-layout-container");
33937 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33938 if(this.el.dom != document.body ) {
33939 this.el.on('resize', this.layout,this);
33940 this.el.on('show', this.layout,this);
33946 * Returns true if this layout is currently being updated
33947 * @return {Boolean}
33949 isUpdating : function(){
33950 return this.updating;
33954 * Suspend the LayoutManager from doing auto-layouts while
33955 * making multiple add or remove calls
33957 beginUpdate : function(){
33958 this.updating = true;
33962 * Restore auto-layouts and optionally disable the manager from performing a layout
33963 * @param {Boolean} noLayout true to disable a layout update
33965 endUpdate : function(noLayout){
33966 this.updating = false;
33972 layout: function(){
33976 onRegionResized : function(region, newSize){
33977 this.fireEvent("regionresized", region, newSize);
33981 onRegionCollapsed : function(region){
33982 this.fireEvent("regioncollapsed", region);
33985 onRegionExpanded : function(region){
33986 this.fireEvent("regionexpanded", region);
33990 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33991 * performs box-model adjustments.
33992 * @return {Object} The size as an object {width: (the width), height: (the height)}
33994 getViewSize : function()
33997 if(this.el.dom != document.body){
33998 size = this.el.getSize();
34000 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34002 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34003 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34008 * Returns the Element this layout is bound to.
34009 * @return {Roo.Element}
34011 getEl : function(){
34016 * Returns the specified region.
34017 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34018 * @return {Roo.LayoutRegion}
34020 getRegion : function(target){
34021 return this.regions[target.toLowerCase()];
34024 onWindowResize : function(){
34025 if(this.monitorWindowResize){
34032 * Ext JS Library 1.1.1
34033 * Copyright(c) 2006-2007, Ext JS, LLC.
34035 * Originally Released Under LGPL - original licence link has changed is not relivant.
34038 * <script type="text/javascript">
34041 * @class Roo.bootstrap.layout.Border
34042 * @extends Roo.bootstrap.layout.Manager
34043 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34044 * please see: examples/bootstrap/nested.html<br><br>
34046 <b>The container the layout is rendered into can be either the body element or any other element.
34047 If it is not the body element, the container needs to either be an absolute positioned element,
34048 or you will need to add "position:relative" to the css of the container. You will also need to specify
34049 the container size if it is not the body element.</b>
34052 * Create a new Border
34053 * @param {Object} config Configuration options
34055 Roo.bootstrap.layout.Border = function(config){
34056 config = config || {};
34057 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34061 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34062 if(config[region]){
34063 config[region].region = region;
34064 this.addRegion(config[region]);
34070 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34072 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34074 * Creates and adds a new region if it doesn't already exist.
34075 * @param {String} target The target region key (north, south, east, west or center).
34076 * @param {Object} config The regions config object
34077 * @return {BorderLayoutRegion} The new region
34079 addRegion : function(config)
34081 if(!this.regions[config.region]){
34082 var r = this.factory(config);
34083 this.bindRegion(r);
34085 return this.regions[config.region];
34089 bindRegion : function(r){
34090 this.regions[r.config.region] = r;
34092 r.on("visibilitychange", this.layout, this);
34093 r.on("paneladded", this.layout, this);
34094 r.on("panelremoved", this.layout, this);
34095 r.on("invalidated", this.layout, this);
34096 r.on("resized", this.onRegionResized, this);
34097 r.on("collapsed", this.onRegionCollapsed, this);
34098 r.on("expanded", this.onRegionExpanded, this);
34102 * Performs a layout update.
34104 layout : function()
34106 if(this.updating) {
34110 // render all the rebions if they have not been done alreayd?
34111 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34112 if(this.regions[region] && !this.regions[region].bodyEl){
34113 this.regions[region].onRender(this.el)
34117 var size = this.getViewSize();
34118 var w = size.width;
34119 var h = size.height;
34124 //var x = 0, y = 0;
34126 var rs = this.regions;
34127 var north = rs["north"];
34128 var south = rs["south"];
34129 var west = rs["west"];
34130 var east = rs["east"];
34131 var center = rs["center"];
34132 //if(this.hideOnLayout){ // not supported anymore
34133 //c.el.setStyle("display", "none");
34135 if(north && north.isVisible()){
34136 var b = north.getBox();
34137 var m = north.getMargins();
34138 b.width = w - (m.left+m.right);
34141 centerY = b.height + b.y + m.bottom;
34142 centerH -= centerY;
34143 north.updateBox(this.safeBox(b));
34145 if(south && south.isVisible()){
34146 var b = south.getBox();
34147 var m = south.getMargins();
34148 b.width = w - (m.left+m.right);
34150 var totalHeight = (b.height + m.top + m.bottom);
34151 b.y = h - totalHeight + m.top;
34152 centerH -= totalHeight;
34153 south.updateBox(this.safeBox(b));
34155 if(west && west.isVisible()){
34156 var b = west.getBox();
34157 var m = west.getMargins();
34158 b.height = centerH - (m.top+m.bottom);
34160 b.y = centerY + m.top;
34161 var totalWidth = (b.width + m.left + m.right);
34162 centerX += totalWidth;
34163 centerW -= totalWidth;
34164 west.updateBox(this.safeBox(b));
34166 if(east && east.isVisible()){
34167 var b = east.getBox();
34168 var m = east.getMargins();
34169 b.height = centerH - (m.top+m.bottom);
34170 var totalWidth = (b.width + m.left + m.right);
34171 b.x = w - totalWidth + m.left;
34172 b.y = centerY + m.top;
34173 centerW -= totalWidth;
34174 east.updateBox(this.safeBox(b));
34177 var m = center.getMargins();
34179 x: centerX + m.left,
34180 y: centerY + m.top,
34181 width: centerW - (m.left+m.right),
34182 height: centerH - (m.top+m.bottom)
34184 //if(this.hideOnLayout){
34185 //center.el.setStyle("display", "block");
34187 center.updateBox(this.safeBox(centerBox));
34190 this.fireEvent("layout", this);
34194 safeBox : function(box){
34195 box.width = Math.max(0, box.width);
34196 box.height = Math.max(0, box.height);
34201 * Adds a ContentPanel (or subclass) to this layout.
34202 * @param {String} target The target region key (north, south, east, west or center).
34203 * @param {Roo.ContentPanel} panel The panel to add
34204 * @return {Roo.ContentPanel} The added panel
34206 add : function(target, panel){
34208 target = target.toLowerCase();
34209 return this.regions[target].add(panel);
34213 * Remove a ContentPanel (or subclass) to this layout.
34214 * @param {String} target The target region key (north, south, east, west or center).
34215 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34216 * @return {Roo.ContentPanel} The removed panel
34218 remove : function(target, panel){
34219 target = target.toLowerCase();
34220 return this.regions[target].remove(panel);
34224 * Searches all regions for a panel with the specified id
34225 * @param {String} panelId
34226 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34228 findPanel : function(panelId){
34229 var rs = this.regions;
34230 for(var target in rs){
34231 if(typeof rs[target] != "function"){
34232 var p = rs[target].getPanel(panelId);
34242 * Searches all regions for a panel with the specified id and activates (shows) it.
34243 * @param {String/ContentPanel} panelId The panels id or the panel itself
34244 * @return {Roo.ContentPanel} The shown panel or null
34246 showPanel : function(panelId) {
34247 var rs = this.regions;
34248 for(var target in rs){
34249 var r = rs[target];
34250 if(typeof r != "function"){
34251 if(r.hasPanel(panelId)){
34252 return r.showPanel(panelId);
34260 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34261 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34264 restoreState : function(provider){
34266 provider = Roo.state.Manager;
34268 var sm = new Roo.LayoutStateManager();
34269 sm.init(this, provider);
34275 * Adds a xtype elements to the layout.
34279 xtype : 'ContentPanel',
34286 xtype : 'NestedLayoutPanel',
34292 items : [ ... list of content panels or nested layout panels.. ]
34296 * @param {Object} cfg Xtype definition of item to add.
34298 addxtype : function(cfg)
34300 // basically accepts a pannel...
34301 // can accept a layout region..!?!?
34302 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34305 // theory? children can only be panels??
34307 //if (!cfg.xtype.match(/Panel$/)) {
34312 if (typeof(cfg.region) == 'undefined') {
34313 Roo.log("Failed to add Panel, region was not set");
34317 var region = cfg.region;
34323 xitems = cfg.items;
34330 case 'Content': // ContentPanel (el, cfg)
34331 case 'Scroll': // ContentPanel (el, cfg)
34333 cfg.autoCreate = true;
34334 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34336 // var el = this.el.createChild();
34337 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34340 this.add(region, ret);
34344 case 'TreePanel': // our new panel!
34345 cfg.el = this.el.createChild();
34346 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34347 this.add(region, ret);
34352 // create a new Layout (which is a Border Layout...
34354 var clayout = cfg.layout;
34355 clayout.el = this.el.createChild();
34356 clayout.items = clayout.items || [];
34360 // replace this exitems with the clayout ones..
34361 xitems = clayout.items;
34363 // force background off if it's in center...
34364 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34365 cfg.background = false;
34367 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34370 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34371 //console.log('adding nested layout panel ' + cfg.toSource());
34372 this.add(region, ret);
34373 nb = {}; /// find first...
34378 // needs grid and region
34380 //var el = this.getRegion(region).el.createChild();
34382 *var el = this.el.createChild();
34383 // create the grid first...
34384 cfg.grid.container = el;
34385 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34388 if (region == 'center' && this.active ) {
34389 cfg.background = false;
34392 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34394 this.add(region, ret);
34396 if (cfg.background) {
34397 // render grid on panel activation (if panel background)
34398 ret.on('activate', function(gp) {
34399 if (!gp.grid.rendered) {
34400 // gp.grid.render(el);
34404 // cfg.grid.render(el);
34410 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34411 // it was the old xcomponent building that caused this before.
34412 // espeically if border is the top element in the tree.
34422 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34424 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34425 this.add(region, ret);
34429 throw "Can not add '" + cfg.xtype + "' to Border";
34435 this.beginUpdate();
34439 Roo.each(xitems, function(i) {
34440 region = nb && i.region ? i.region : false;
34442 var add = ret.addxtype(i);
34445 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34446 if (!i.background) {
34447 abn[region] = nb[region] ;
34454 // make the last non-background panel active..
34455 //if (nb) { Roo.log(abn); }
34458 for(var r in abn) {
34459 region = this.getRegion(r);
34461 // tried using nb[r], but it does not work..
34463 region.showPanel(abn[r]);
34474 factory : function(cfg)
34477 var validRegions = Roo.bootstrap.layout.Border.regions;
34479 var target = cfg.region;
34482 var r = Roo.bootstrap.layout;
34486 return new r.North(cfg);
34488 return new r.South(cfg);
34490 return new r.East(cfg);
34492 return new r.West(cfg);
34494 return new r.Center(cfg);
34496 throw 'Layout region "'+target+'" not supported.';
34503 * Ext JS Library 1.1.1
34504 * Copyright(c) 2006-2007, Ext JS, LLC.
34506 * Originally Released Under LGPL - original licence link has changed is not relivant.
34509 * <script type="text/javascript">
34513 * @class Roo.bootstrap.layout.Basic
34514 * @extends Roo.util.Observable
34515 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34516 * and does not have a titlebar, tabs or any other features. All it does is size and position
34517 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34518 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34519 * @cfg {string} region the region that it inhabits..
34520 * @cfg {bool} skipConfig skip config?
34524 Roo.bootstrap.layout.Basic = function(config){
34526 this.mgr = config.mgr;
34528 this.position = config.region;
34530 var skipConfig = config.skipConfig;
34534 * @scope Roo.BasicLayoutRegion
34538 * @event beforeremove
34539 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34540 * @param {Roo.LayoutRegion} this
34541 * @param {Roo.ContentPanel} panel The panel
34542 * @param {Object} e The cancel event object
34544 "beforeremove" : true,
34546 * @event invalidated
34547 * Fires when the layout for this region is changed.
34548 * @param {Roo.LayoutRegion} this
34550 "invalidated" : true,
34552 * @event visibilitychange
34553 * Fires when this region is shown or hidden
34554 * @param {Roo.LayoutRegion} this
34555 * @param {Boolean} visibility true or false
34557 "visibilitychange" : true,
34559 * @event paneladded
34560 * Fires when a panel is added.
34561 * @param {Roo.LayoutRegion} this
34562 * @param {Roo.ContentPanel} panel The panel
34564 "paneladded" : true,
34566 * @event panelremoved
34567 * Fires when a panel is removed.
34568 * @param {Roo.LayoutRegion} this
34569 * @param {Roo.ContentPanel} panel The panel
34571 "panelremoved" : true,
34573 * @event beforecollapse
34574 * Fires when this region before collapse.
34575 * @param {Roo.LayoutRegion} this
34577 "beforecollapse" : true,
34580 * Fires when this region is collapsed.
34581 * @param {Roo.LayoutRegion} this
34583 "collapsed" : true,
34586 * Fires when this region is expanded.
34587 * @param {Roo.LayoutRegion} this
34592 * Fires when this region is slid into view.
34593 * @param {Roo.LayoutRegion} this
34595 "slideshow" : true,
34598 * Fires when this region slides out of view.
34599 * @param {Roo.LayoutRegion} this
34601 "slidehide" : true,
34603 * @event panelactivated
34604 * Fires when a panel is activated.
34605 * @param {Roo.LayoutRegion} this
34606 * @param {Roo.ContentPanel} panel The activated panel
34608 "panelactivated" : true,
34611 * Fires when the user resizes this region.
34612 * @param {Roo.LayoutRegion} this
34613 * @param {Number} newSize The new size (width for east/west, height for north/south)
34617 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34618 this.panels = new Roo.util.MixedCollection();
34619 this.panels.getKey = this.getPanelId.createDelegate(this);
34621 this.activePanel = null;
34622 // ensure listeners are added...
34624 if (config.listeners || config.events) {
34625 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34626 listeners : config.listeners || {},
34627 events : config.events || {}
34631 if(skipConfig !== true){
34632 this.applyConfig(config);
34636 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34638 getPanelId : function(p){
34642 applyConfig : function(config){
34643 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34644 this.config = config;
34649 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34650 * the width, for horizontal (north, south) the height.
34651 * @param {Number} newSize The new width or height
34653 resizeTo : function(newSize){
34654 var el = this.el ? this.el :
34655 (this.activePanel ? this.activePanel.getEl() : null);
34657 switch(this.position){
34660 el.setWidth(newSize);
34661 this.fireEvent("resized", this, newSize);
34665 el.setHeight(newSize);
34666 this.fireEvent("resized", this, newSize);
34672 getBox : function(){
34673 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34676 getMargins : function(){
34677 return this.margins;
34680 updateBox : function(box){
34682 var el = this.activePanel.getEl();
34683 el.dom.style.left = box.x + "px";
34684 el.dom.style.top = box.y + "px";
34685 this.activePanel.setSize(box.width, box.height);
34689 * Returns the container element for this region.
34690 * @return {Roo.Element}
34692 getEl : function(){
34693 return this.activePanel;
34697 * Returns true if this region is currently visible.
34698 * @return {Boolean}
34700 isVisible : function(){
34701 return this.activePanel ? true : false;
34704 setActivePanel : function(panel){
34705 panel = this.getPanel(panel);
34706 if(this.activePanel && this.activePanel != panel){
34707 this.activePanel.setActiveState(false);
34708 this.activePanel.getEl().setLeftTop(-10000,-10000);
34710 this.activePanel = panel;
34711 panel.setActiveState(true);
34713 panel.setSize(this.box.width, this.box.height);
34715 this.fireEvent("panelactivated", this, panel);
34716 this.fireEvent("invalidated");
34720 * Show the specified panel.
34721 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34722 * @return {Roo.ContentPanel} The shown panel or null
34724 showPanel : function(panel){
34725 panel = this.getPanel(panel);
34727 this.setActivePanel(panel);
34733 * Get the active panel for this region.
34734 * @return {Roo.ContentPanel} The active panel or null
34736 getActivePanel : function(){
34737 return this.activePanel;
34741 * Add the passed ContentPanel(s)
34742 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34743 * @return {Roo.ContentPanel} The panel added (if only one was added)
34745 add : function(panel){
34746 if(arguments.length > 1){
34747 for(var i = 0, len = arguments.length; i < len; i++) {
34748 this.add(arguments[i]);
34752 if(this.hasPanel(panel)){
34753 this.showPanel(panel);
34756 var el = panel.getEl();
34757 if(el.dom.parentNode != this.mgr.el.dom){
34758 this.mgr.el.dom.appendChild(el.dom);
34760 if(panel.setRegion){
34761 panel.setRegion(this);
34763 this.panels.add(panel);
34764 el.setStyle("position", "absolute");
34765 if(!panel.background){
34766 this.setActivePanel(panel);
34767 if(this.config.initialSize && this.panels.getCount()==1){
34768 this.resizeTo(this.config.initialSize);
34771 this.fireEvent("paneladded", this, panel);
34776 * Returns true if the panel is in this region.
34777 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34778 * @return {Boolean}
34780 hasPanel : function(panel){
34781 if(typeof panel == "object"){ // must be panel obj
34782 panel = panel.getId();
34784 return this.getPanel(panel) ? true : false;
34788 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34789 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34790 * @param {Boolean} preservePanel Overrides the config preservePanel option
34791 * @return {Roo.ContentPanel} The panel that was removed
34793 remove : function(panel, preservePanel){
34794 panel = this.getPanel(panel);
34799 this.fireEvent("beforeremove", this, panel, e);
34800 if(e.cancel === true){
34803 var panelId = panel.getId();
34804 this.panels.removeKey(panelId);
34809 * Returns the panel specified or null if it's not in this region.
34810 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34811 * @return {Roo.ContentPanel}
34813 getPanel : function(id){
34814 if(typeof id == "object"){ // must be panel obj
34817 return this.panels.get(id);
34821 * Returns this regions position (north/south/east/west/center).
34824 getPosition: function(){
34825 return this.position;
34829 * Ext JS Library 1.1.1
34830 * Copyright(c) 2006-2007, Ext JS, LLC.
34832 * Originally Released Under LGPL - original licence link has changed is not relivant.
34835 * <script type="text/javascript">
34839 * @class Roo.bootstrap.layout.Region
34840 * @extends Roo.bootstrap.layout.Basic
34841 * This class represents a region in a layout manager.
34843 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34844 * @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})
34845 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34846 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34847 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34848 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34849 * @cfg {String} title The title for the region (overrides panel titles)
34850 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34851 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34852 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34853 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34854 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34855 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34856 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34857 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34858 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34859 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34861 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34862 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34863 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34864 * @cfg {Number} width For East/West panels
34865 * @cfg {Number} height For North/South panels
34866 * @cfg {Boolean} split To show the splitter
34867 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34869 * @cfg {string} cls Extra CSS classes to add to region
34871 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34872 * @cfg {string} region the region that it inhabits..
34875 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34876 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34878 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34879 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34880 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34882 Roo.bootstrap.layout.Region = function(config)
34884 this.applyConfig(config);
34886 var mgr = config.mgr;
34887 var pos = config.region;
34888 config.skipConfig = true;
34889 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34892 this.onRender(mgr.el);
34895 this.visible = true;
34896 this.collapsed = false;
34897 this.unrendered_panels = [];
34900 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34902 position: '', // set by wrapper (eg. north/south etc..)
34903 unrendered_panels : null, // unrendered panels.
34904 createBody : function(){
34905 /** This region's body element
34906 * @type Roo.Element */
34907 this.bodyEl = this.el.createChild({
34909 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34913 onRender: function(ctr, pos)
34915 var dh = Roo.DomHelper;
34916 /** This region's container element
34917 * @type Roo.Element */
34918 this.el = dh.append(ctr.dom, {
34920 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34922 /** This region's title element
34923 * @type Roo.Element */
34925 this.titleEl = dh.append(this.el.dom,
34928 unselectable: "on",
34929 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34931 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34932 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34935 this.titleEl.enableDisplayMode();
34936 /** This region's title text element
34937 * @type HTMLElement */
34938 this.titleTextEl = this.titleEl.dom.firstChild;
34939 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34941 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34942 this.closeBtn.enableDisplayMode();
34943 this.closeBtn.on("click", this.closeClicked, this);
34944 this.closeBtn.hide();
34946 this.createBody(this.config);
34947 if(this.config.hideWhenEmpty){
34949 this.on("paneladded", this.validateVisibility, this);
34950 this.on("panelremoved", this.validateVisibility, this);
34952 if(this.autoScroll){
34953 this.bodyEl.setStyle("overflow", "auto");
34955 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34957 //if(c.titlebar !== false){
34958 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34959 this.titleEl.hide();
34961 this.titleEl.show();
34962 if(this.config.title){
34963 this.titleTextEl.innerHTML = this.config.title;
34967 if(this.config.collapsed){
34968 this.collapse(true);
34970 if(this.config.hidden){
34974 if (this.unrendered_panels && this.unrendered_panels.length) {
34975 for (var i =0;i< this.unrendered_panels.length; i++) {
34976 this.add(this.unrendered_panels[i]);
34978 this.unrendered_panels = null;
34984 applyConfig : function(c)
34987 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34988 var dh = Roo.DomHelper;
34989 if(c.titlebar !== false){
34990 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34991 this.collapseBtn.on("click", this.collapse, this);
34992 this.collapseBtn.enableDisplayMode();
34994 if(c.showPin === true || this.showPin){
34995 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34996 this.stickBtn.enableDisplayMode();
34997 this.stickBtn.on("click", this.expand, this);
34998 this.stickBtn.hide();
35003 /** This region's collapsed element
35004 * @type Roo.Element */
35007 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35008 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35011 if(c.floatable !== false){
35012 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35013 this.collapsedEl.on("click", this.collapseClick, this);
35016 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35017 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35018 id: "message", unselectable: "on", style:{"float":"left"}});
35019 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35021 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35022 this.expandBtn.on("click", this.expand, this);
35026 if(this.collapseBtn){
35027 this.collapseBtn.setVisible(c.collapsible == true);
35030 this.cmargins = c.cmargins || this.cmargins ||
35031 (this.position == "west" || this.position == "east" ?
35032 {top: 0, left: 2, right:2, bottom: 0} :
35033 {top: 2, left: 0, right:0, bottom: 2});
35035 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35038 this.bottomTabs = c.tabPosition != "top";
35040 this.autoScroll = c.autoScroll || false;
35045 this.duration = c.duration || .30;
35046 this.slideDuration = c.slideDuration || .45;
35051 * Returns true if this region is currently visible.
35052 * @return {Boolean}
35054 isVisible : function(){
35055 return this.visible;
35059 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35060 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35062 //setCollapsedTitle : function(title){
35063 // title = title || " ";
35064 // if(this.collapsedTitleTextEl){
35065 // this.collapsedTitleTextEl.innerHTML = title;
35069 getBox : function(){
35071 // if(!this.collapsed){
35072 b = this.el.getBox(false, true);
35074 // b = this.collapsedEl.getBox(false, true);
35079 getMargins : function(){
35080 return this.margins;
35081 //return this.collapsed ? this.cmargins : this.margins;
35084 highlight : function(){
35085 this.el.addClass("x-layout-panel-dragover");
35088 unhighlight : function(){
35089 this.el.removeClass("x-layout-panel-dragover");
35092 updateBox : function(box)
35094 if (!this.bodyEl) {
35095 return; // not rendered yet..
35099 if(!this.collapsed){
35100 this.el.dom.style.left = box.x + "px";
35101 this.el.dom.style.top = box.y + "px";
35102 this.updateBody(box.width, box.height);
35104 this.collapsedEl.dom.style.left = box.x + "px";
35105 this.collapsedEl.dom.style.top = box.y + "px";
35106 this.collapsedEl.setSize(box.width, box.height);
35109 this.tabs.autoSizeTabs();
35113 updateBody : function(w, h)
35116 this.el.setWidth(w);
35117 w -= this.el.getBorderWidth("rl");
35118 if(this.config.adjustments){
35119 w += this.config.adjustments[0];
35122 if(h !== null && h > 0){
35123 this.el.setHeight(h);
35124 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35125 h -= this.el.getBorderWidth("tb");
35126 if(this.config.adjustments){
35127 h += this.config.adjustments[1];
35129 this.bodyEl.setHeight(h);
35131 h = this.tabs.syncHeight(h);
35134 if(this.panelSize){
35135 w = w !== null ? w : this.panelSize.width;
35136 h = h !== null ? h : this.panelSize.height;
35138 if(this.activePanel){
35139 var el = this.activePanel.getEl();
35140 w = w !== null ? w : el.getWidth();
35141 h = h !== null ? h : el.getHeight();
35142 this.panelSize = {width: w, height: h};
35143 this.activePanel.setSize(w, h);
35145 if(Roo.isIE && this.tabs){
35146 this.tabs.el.repaint();
35151 * Returns the container element for this region.
35152 * @return {Roo.Element}
35154 getEl : function(){
35159 * Hides this region.
35162 //if(!this.collapsed){
35163 this.el.dom.style.left = "-2000px";
35166 // this.collapsedEl.dom.style.left = "-2000px";
35167 // this.collapsedEl.hide();
35169 this.visible = false;
35170 this.fireEvent("visibilitychange", this, false);
35174 * Shows this region if it was previously hidden.
35177 //if(!this.collapsed){
35180 // this.collapsedEl.show();
35182 this.visible = true;
35183 this.fireEvent("visibilitychange", this, true);
35186 closeClicked : function(){
35187 if(this.activePanel){
35188 this.remove(this.activePanel);
35192 collapseClick : function(e){
35194 e.stopPropagation();
35197 e.stopPropagation();
35203 * Collapses this region.
35204 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35207 collapse : function(skipAnim, skipCheck = false){
35208 if(this.collapsed) {
35212 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35214 this.collapsed = true;
35216 this.split.el.hide();
35218 if(this.config.animate && skipAnim !== true){
35219 this.fireEvent("invalidated", this);
35220 this.animateCollapse();
35222 this.el.setLocation(-20000,-20000);
35224 this.collapsedEl.show();
35225 this.fireEvent("collapsed", this);
35226 this.fireEvent("invalidated", this);
35232 animateCollapse : function(){
35237 * Expands this region if it was previously collapsed.
35238 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35239 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35242 expand : function(e, skipAnim){
35244 e.stopPropagation();
35246 if(!this.collapsed || this.el.hasActiveFx()) {
35250 this.afterSlideIn();
35253 this.collapsed = false;
35254 if(this.config.animate && skipAnim !== true){
35255 this.animateExpand();
35259 this.split.el.show();
35261 this.collapsedEl.setLocation(-2000,-2000);
35262 this.collapsedEl.hide();
35263 this.fireEvent("invalidated", this);
35264 this.fireEvent("expanded", this);
35268 animateExpand : function(){
35272 initTabs : function()
35274 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35276 var ts = new Roo.bootstrap.panel.Tabs({
35277 el: this.bodyEl.dom,
35278 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35279 disableTooltips: this.config.disableTabTips,
35280 toolbar : this.config.toolbar
35283 if(this.config.hideTabs){
35284 ts.stripWrap.setDisplayed(false);
35287 ts.resizeTabs = this.config.resizeTabs === true;
35288 ts.minTabWidth = this.config.minTabWidth || 40;
35289 ts.maxTabWidth = this.config.maxTabWidth || 250;
35290 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35291 ts.monitorResize = false;
35292 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35293 ts.bodyEl.addClass('roo-layout-tabs-body');
35294 this.panels.each(this.initPanelAsTab, this);
35297 initPanelAsTab : function(panel){
35298 var ti = this.tabs.addTab(
35302 this.config.closeOnTab && panel.isClosable(),
35305 if(panel.tabTip !== undefined){
35306 ti.setTooltip(panel.tabTip);
35308 ti.on("activate", function(){
35309 this.setActivePanel(panel);
35312 if(this.config.closeOnTab){
35313 ti.on("beforeclose", function(t, e){
35315 this.remove(panel);
35319 panel.tabItem = ti;
35324 updatePanelTitle : function(panel, title)
35326 if(this.activePanel == panel){
35327 this.updateTitle(title);
35330 var ti = this.tabs.getTab(panel.getEl().id);
35332 if(panel.tabTip !== undefined){
35333 ti.setTooltip(panel.tabTip);
35338 updateTitle : function(title){
35339 if(this.titleTextEl && !this.config.title){
35340 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35344 setActivePanel : function(panel)
35346 panel = this.getPanel(panel);
35347 if(this.activePanel && this.activePanel != panel){
35348 this.activePanel.setActiveState(false);
35350 this.activePanel = panel;
35351 panel.setActiveState(true);
35352 if(this.panelSize){
35353 panel.setSize(this.panelSize.width, this.panelSize.height);
35356 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35358 this.updateTitle(panel.getTitle());
35360 this.fireEvent("invalidated", this);
35362 this.fireEvent("panelactivated", this, panel);
35366 * Shows the specified panel.
35367 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35368 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35370 showPanel : function(panel)
35372 panel = this.getPanel(panel);
35375 var tab = this.tabs.getTab(panel.getEl().id);
35376 if(tab.isHidden()){
35377 this.tabs.unhideTab(tab.id);
35381 this.setActivePanel(panel);
35388 * Get the active panel for this region.
35389 * @return {Roo.ContentPanel} The active panel or null
35391 getActivePanel : function(){
35392 return this.activePanel;
35395 validateVisibility : function(){
35396 if(this.panels.getCount() < 1){
35397 this.updateTitle(" ");
35398 this.closeBtn.hide();
35401 if(!this.isVisible()){
35408 * Adds the passed ContentPanel(s) to this region.
35409 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35410 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35412 add : function(panel)
35414 if(arguments.length > 1){
35415 for(var i = 0, len = arguments.length; i < len; i++) {
35416 this.add(arguments[i]);
35421 // if we have not been rendered yet, then we can not really do much of this..
35422 if (!this.bodyEl) {
35423 this.unrendered_panels.push(panel);
35430 if(this.hasPanel(panel)){
35431 this.showPanel(panel);
35434 panel.setRegion(this);
35435 this.panels.add(panel);
35436 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35437 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35438 // and hide them... ???
35439 this.bodyEl.dom.appendChild(panel.getEl().dom);
35440 if(panel.background !== true){
35441 this.setActivePanel(panel);
35443 this.fireEvent("paneladded", this, panel);
35450 this.initPanelAsTab(panel);
35454 if(panel.background !== true){
35455 this.tabs.activate(panel.getEl().id);
35457 this.fireEvent("paneladded", this, panel);
35462 * Hides the tab for the specified panel.
35463 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35465 hidePanel : function(panel){
35466 if(this.tabs && (panel = this.getPanel(panel))){
35467 this.tabs.hideTab(panel.getEl().id);
35472 * Unhides the tab for a previously hidden panel.
35473 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35475 unhidePanel : function(panel){
35476 if(this.tabs && (panel = this.getPanel(panel))){
35477 this.tabs.unhideTab(panel.getEl().id);
35481 clearPanels : function(){
35482 while(this.panels.getCount() > 0){
35483 this.remove(this.panels.first());
35488 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35489 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35490 * @param {Boolean} preservePanel Overrides the config preservePanel option
35491 * @return {Roo.ContentPanel} The panel that was removed
35493 remove : function(panel, preservePanel)
35495 panel = this.getPanel(panel);
35500 this.fireEvent("beforeremove", this, panel, e);
35501 if(e.cancel === true){
35504 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35505 var panelId = panel.getId();
35506 this.panels.removeKey(panelId);
35508 document.body.appendChild(panel.getEl().dom);
35511 this.tabs.removeTab(panel.getEl().id);
35512 }else if (!preservePanel){
35513 this.bodyEl.dom.removeChild(panel.getEl().dom);
35515 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35516 var p = this.panels.first();
35517 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35518 tempEl.appendChild(p.getEl().dom);
35519 this.bodyEl.update("");
35520 this.bodyEl.dom.appendChild(p.getEl().dom);
35522 this.updateTitle(p.getTitle());
35524 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35525 this.setActivePanel(p);
35527 panel.setRegion(null);
35528 if(this.activePanel == panel){
35529 this.activePanel = null;
35531 if(this.config.autoDestroy !== false && preservePanel !== true){
35532 try{panel.destroy();}catch(e){}
35534 this.fireEvent("panelremoved", this, panel);
35539 * Returns the TabPanel component used by this region
35540 * @return {Roo.TabPanel}
35542 getTabs : function(){
35546 createTool : function(parentEl, className){
35547 var btn = Roo.DomHelper.append(parentEl, {
35549 cls: "x-layout-tools-button",
35552 cls: "roo-layout-tools-button-inner " + className,
35556 btn.addClassOnOver("roo-layout-tools-button-over");
35561 * Ext JS Library 1.1.1
35562 * Copyright(c) 2006-2007, Ext JS, LLC.
35564 * Originally Released Under LGPL - original licence link has changed is not relivant.
35567 * <script type="text/javascript">
35573 * @class Roo.SplitLayoutRegion
35574 * @extends Roo.LayoutRegion
35575 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35577 Roo.bootstrap.layout.Split = function(config){
35578 this.cursor = config.cursor;
35579 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35582 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35584 splitTip : "Drag to resize.",
35585 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35586 useSplitTips : false,
35588 applyConfig : function(config){
35589 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35592 onRender : function(ctr,pos) {
35594 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35595 if(!this.config.split){
35600 var splitEl = Roo.DomHelper.append(ctr.dom, {
35602 id: this.el.id + "-split",
35603 cls: "roo-layout-split roo-layout-split-"+this.position,
35606 /** The SplitBar for this region
35607 * @type Roo.SplitBar */
35608 // does not exist yet...
35609 Roo.log([this.position, this.orientation]);
35611 this.split = new Roo.bootstrap.SplitBar({
35612 dragElement : splitEl,
35613 resizingElement: this.el,
35614 orientation : this.orientation
35617 this.split.on("moved", this.onSplitMove, this);
35618 this.split.useShim = this.config.useShim === true;
35619 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35620 if(this.useSplitTips){
35621 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35623 //if(config.collapsible){
35624 // this.split.el.on("dblclick", this.collapse, this);
35627 if(typeof this.config.minSize != "undefined"){
35628 this.split.minSize = this.config.minSize;
35630 if(typeof this.config.maxSize != "undefined"){
35631 this.split.maxSize = this.config.maxSize;
35633 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35634 this.hideSplitter();
35639 getHMaxSize : function(){
35640 var cmax = this.config.maxSize || 10000;
35641 var center = this.mgr.getRegion("center");
35642 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35645 getVMaxSize : function(){
35646 var cmax = this.config.maxSize || 10000;
35647 var center = this.mgr.getRegion("center");
35648 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35651 onSplitMove : function(split, newSize){
35652 this.fireEvent("resized", this, newSize);
35656 * Returns the {@link Roo.SplitBar} for this region.
35657 * @return {Roo.SplitBar}
35659 getSplitBar : function(){
35664 this.hideSplitter();
35665 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35668 hideSplitter : function(){
35670 this.split.el.setLocation(-2000,-2000);
35671 this.split.el.hide();
35677 this.split.el.show();
35679 Roo.bootstrap.layout.Split.superclass.show.call(this);
35682 beforeSlide: function(){
35683 if(Roo.isGecko){// firefox overflow auto bug workaround
35684 this.bodyEl.clip();
35686 this.tabs.bodyEl.clip();
35688 if(this.activePanel){
35689 this.activePanel.getEl().clip();
35691 if(this.activePanel.beforeSlide){
35692 this.activePanel.beforeSlide();
35698 afterSlide : function(){
35699 if(Roo.isGecko){// firefox overflow auto bug workaround
35700 this.bodyEl.unclip();
35702 this.tabs.bodyEl.unclip();
35704 if(this.activePanel){
35705 this.activePanel.getEl().unclip();
35706 if(this.activePanel.afterSlide){
35707 this.activePanel.afterSlide();
35713 initAutoHide : function(){
35714 if(this.autoHide !== false){
35715 if(!this.autoHideHd){
35716 var st = new Roo.util.DelayedTask(this.slideIn, this);
35717 this.autoHideHd = {
35718 "mouseout": function(e){
35719 if(!e.within(this.el, true)){
35723 "mouseover" : function(e){
35729 this.el.on(this.autoHideHd);
35733 clearAutoHide : function(){
35734 if(this.autoHide !== false){
35735 this.el.un("mouseout", this.autoHideHd.mouseout);
35736 this.el.un("mouseover", this.autoHideHd.mouseover);
35740 clearMonitor : function(){
35741 Roo.get(document).un("click", this.slideInIf, this);
35744 // these names are backwards but not changed for compat
35745 slideOut : function(){
35746 if(this.isSlid || this.el.hasActiveFx()){
35749 this.isSlid = true;
35750 if(this.collapseBtn){
35751 this.collapseBtn.hide();
35753 this.closeBtnState = this.closeBtn.getStyle('display');
35754 this.closeBtn.hide();
35756 this.stickBtn.show();
35759 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35760 this.beforeSlide();
35761 this.el.setStyle("z-index", 10001);
35762 this.el.slideIn(this.getSlideAnchor(), {
35763 callback: function(){
35765 this.initAutoHide();
35766 Roo.get(document).on("click", this.slideInIf, this);
35767 this.fireEvent("slideshow", this);
35774 afterSlideIn : function(){
35775 this.clearAutoHide();
35776 this.isSlid = false;
35777 this.clearMonitor();
35778 this.el.setStyle("z-index", "");
35779 if(this.collapseBtn){
35780 this.collapseBtn.show();
35782 this.closeBtn.setStyle('display', this.closeBtnState);
35784 this.stickBtn.hide();
35786 this.fireEvent("slidehide", this);
35789 slideIn : function(cb){
35790 if(!this.isSlid || this.el.hasActiveFx()){
35794 this.isSlid = false;
35795 this.beforeSlide();
35796 this.el.slideOut(this.getSlideAnchor(), {
35797 callback: function(){
35798 this.el.setLeftTop(-10000, -10000);
35800 this.afterSlideIn();
35808 slideInIf : function(e){
35809 if(!e.within(this.el)){
35814 animateCollapse : function(){
35815 this.beforeSlide();
35816 this.el.setStyle("z-index", 20000);
35817 var anchor = this.getSlideAnchor();
35818 this.el.slideOut(anchor, {
35819 callback : function(){
35820 this.el.setStyle("z-index", "");
35821 this.collapsedEl.slideIn(anchor, {duration:.3});
35823 this.el.setLocation(-10000,-10000);
35825 this.fireEvent("collapsed", this);
35832 animateExpand : function(){
35833 this.beforeSlide();
35834 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35835 this.el.setStyle("z-index", 20000);
35836 this.collapsedEl.hide({
35839 this.el.slideIn(this.getSlideAnchor(), {
35840 callback : function(){
35841 this.el.setStyle("z-index", "");
35844 this.split.el.show();
35846 this.fireEvent("invalidated", this);
35847 this.fireEvent("expanded", this);
35875 getAnchor : function(){
35876 return this.anchors[this.position];
35879 getCollapseAnchor : function(){
35880 return this.canchors[this.position];
35883 getSlideAnchor : function(){
35884 return this.sanchors[this.position];
35887 getAlignAdj : function(){
35888 var cm = this.cmargins;
35889 switch(this.position){
35905 getExpandAdj : function(){
35906 var c = this.collapsedEl, cm = this.cmargins;
35907 switch(this.position){
35909 return [-(cm.right+c.getWidth()+cm.left), 0];
35912 return [cm.right+c.getWidth()+cm.left, 0];
35915 return [0, -(cm.top+cm.bottom+c.getHeight())];
35918 return [0, cm.top+cm.bottom+c.getHeight()];
35924 * Ext JS Library 1.1.1
35925 * Copyright(c) 2006-2007, Ext JS, LLC.
35927 * Originally Released Under LGPL - original licence link has changed is not relivant.
35930 * <script type="text/javascript">
35933 * These classes are private internal classes
35935 Roo.bootstrap.layout.Center = function(config){
35936 config.region = "center";
35937 Roo.bootstrap.layout.Region.call(this, config);
35938 this.visible = true;
35939 this.minWidth = config.minWidth || 20;
35940 this.minHeight = config.minHeight || 20;
35943 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35945 // center panel can't be hidden
35949 // center panel can't be hidden
35952 getMinWidth: function(){
35953 return this.minWidth;
35956 getMinHeight: function(){
35957 return this.minHeight;
35970 Roo.bootstrap.layout.North = function(config)
35972 config.region = 'north';
35973 config.cursor = 'n-resize';
35975 Roo.bootstrap.layout.Split.call(this, config);
35979 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35980 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35981 this.split.el.addClass("roo-layout-split-v");
35983 var size = config.initialSize || config.height;
35984 if(typeof size != "undefined"){
35985 this.el.setHeight(size);
35988 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35990 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35994 getBox : function(){
35995 if(this.collapsed){
35996 return this.collapsedEl.getBox();
35998 var box = this.el.getBox();
36000 box.height += this.split.el.getHeight();
36005 updateBox : function(box){
36006 if(this.split && !this.collapsed){
36007 box.height -= this.split.el.getHeight();
36008 this.split.el.setLeft(box.x);
36009 this.split.el.setTop(box.y+box.height);
36010 this.split.el.setWidth(box.width);
36012 if(this.collapsed){
36013 this.updateBody(box.width, null);
36015 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36023 Roo.bootstrap.layout.South = function(config){
36024 config.region = 'south';
36025 config.cursor = 's-resize';
36026 Roo.bootstrap.layout.Split.call(this, config);
36028 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36029 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36030 this.split.el.addClass("roo-layout-split-v");
36032 var size = config.initialSize || config.height;
36033 if(typeof size != "undefined"){
36034 this.el.setHeight(size);
36038 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36039 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36040 getBox : function(){
36041 if(this.collapsed){
36042 return this.collapsedEl.getBox();
36044 var box = this.el.getBox();
36046 var sh = this.split.el.getHeight();
36053 updateBox : function(box){
36054 if(this.split && !this.collapsed){
36055 var sh = this.split.el.getHeight();
36058 this.split.el.setLeft(box.x);
36059 this.split.el.setTop(box.y-sh);
36060 this.split.el.setWidth(box.width);
36062 if(this.collapsed){
36063 this.updateBody(box.width, null);
36065 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36069 Roo.bootstrap.layout.East = function(config){
36070 config.region = "east";
36071 config.cursor = "e-resize";
36072 Roo.bootstrap.layout.Split.call(this, config);
36074 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36075 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36076 this.split.el.addClass("roo-layout-split-h");
36078 var size = config.initialSize || config.width;
36079 if(typeof size != "undefined"){
36080 this.el.setWidth(size);
36083 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36084 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36085 getBox : function(){
36086 if(this.collapsed){
36087 return this.collapsedEl.getBox();
36089 var box = this.el.getBox();
36091 var sw = this.split.el.getWidth();
36098 updateBox : function(box){
36099 if(this.split && !this.collapsed){
36100 var sw = this.split.el.getWidth();
36102 this.split.el.setLeft(box.x);
36103 this.split.el.setTop(box.y);
36104 this.split.el.setHeight(box.height);
36107 if(this.collapsed){
36108 this.updateBody(null, box.height);
36110 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36114 Roo.bootstrap.layout.West = function(config){
36115 config.region = "west";
36116 config.cursor = "w-resize";
36118 Roo.bootstrap.layout.Split.call(this, config);
36120 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36121 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36122 this.split.el.addClass("roo-layout-split-h");
36126 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36127 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36129 onRender: function(ctr, pos)
36131 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36132 var size = this.config.initialSize || this.config.width;
36133 if(typeof size != "undefined"){
36134 this.el.setWidth(size);
36138 getBox : function(){
36139 if(this.collapsed){
36140 return this.collapsedEl.getBox();
36142 var box = this.el.getBox();
36144 box.width += this.split.el.getWidth();
36149 updateBox : function(box){
36150 if(this.split && !this.collapsed){
36151 var sw = this.split.el.getWidth();
36153 this.split.el.setLeft(box.x+box.width);
36154 this.split.el.setTop(box.y);
36155 this.split.el.setHeight(box.height);
36157 if(this.collapsed){
36158 this.updateBody(null, box.height);
36160 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36163 Roo.namespace("Roo.bootstrap.panel");/*
36165 * Ext JS Library 1.1.1
36166 * Copyright(c) 2006-2007, Ext JS, LLC.
36168 * Originally Released Under LGPL - original licence link has changed is not relivant.
36171 * <script type="text/javascript">
36174 * @class Roo.ContentPanel
36175 * @extends Roo.util.Observable
36176 * A basic ContentPanel element.
36177 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36178 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36179 * @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
36180 * @cfg {Boolean} closable True if the panel can be closed/removed
36181 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36182 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36183 * @cfg {Toolbar} toolbar A toolbar for this panel
36184 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36185 * @cfg {String} title The title for this panel
36186 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36187 * @cfg {String} url Calls {@link #setUrl} with this value
36188 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36189 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36190 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36191 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36192 * @cfg {Boolean} badges render the badges
36195 * Create a new ContentPanel.
36196 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36197 * @param {String/Object} config A string to set only the title or a config object
36198 * @param {String} content (optional) Set the HTML content for this panel
36199 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36201 Roo.bootstrap.panel.Content = function( config){
36203 this.tpl = config.tpl || false;
36205 var el = config.el;
36206 var content = config.content;
36208 if(config.autoCreate){ // xtype is available if this is called from factory
36211 this.el = Roo.get(el);
36212 if(!this.el && config && config.autoCreate){
36213 if(typeof config.autoCreate == "object"){
36214 if(!config.autoCreate.id){
36215 config.autoCreate.id = config.id||el;
36217 this.el = Roo.DomHelper.append(document.body,
36218 config.autoCreate, true);
36220 var elcfg = { tag: "div",
36221 cls: "roo-layout-inactive-content",
36225 elcfg.html = config.html;
36229 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36232 this.closable = false;
36233 this.loaded = false;
36234 this.active = false;
36237 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36239 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36241 this.wrapEl = this.el; //this.el.wrap();
36243 if (config.toolbar.items) {
36244 ti = config.toolbar.items ;
36245 delete config.toolbar.items ;
36249 this.toolbar.render(this.wrapEl, 'before');
36250 for(var i =0;i < ti.length;i++) {
36251 // Roo.log(['add child', items[i]]);
36252 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36254 this.toolbar.items = nitems;
36255 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36256 delete config.toolbar;
36260 // xtype created footer. - not sure if will work as we normally have to render first..
36261 if (this.footer && !this.footer.el && this.footer.xtype) {
36262 if (!this.wrapEl) {
36263 this.wrapEl = this.el.wrap();
36266 this.footer.container = this.wrapEl.createChild();
36268 this.footer = Roo.factory(this.footer, Roo);
36273 if(typeof config == "string"){
36274 this.title = config;
36276 Roo.apply(this, config);
36280 this.resizeEl = Roo.get(this.resizeEl, true);
36282 this.resizeEl = this.el;
36284 // handle view.xtype
36292 * Fires when this panel is activated.
36293 * @param {Roo.ContentPanel} this
36297 * @event deactivate
36298 * Fires when this panel is activated.
36299 * @param {Roo.ContentPanel} this
36301 "deactivate" : true,
36305 * Fires when this panel is resized if fitToFrame is true.
36306 * @param {Roo.ContentPanel} this
36307 * @param {Number} width The width after any component adjustments
36308 * @param {Number} height The height after any component adjustments
36314 * Fires when this tab is created
36315 * @param {Roo.ContentPanel} this
36326 if(this.autoScroll){
36327 this.resizeEl.setStyle("overflow", "auto");
36329 // fix randome scrolling
36330 //this.el.on('scroll', function() {
36331 // Roo.log('fix random scolling');
36332 // this.scrollTo('top',0);
36335 content = content || this.content;
36337 this.setContent(content);
36339 if(config && config.url){
36340 this.setUrl(this.url, this.params, this.loadOnce);
36345 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36347 if (this.view && typeof(this.view.xtype) != 'undefined') {
36348 this.view.el = this.el.appendChild(document.createElement("div"));
36349 this.view = Roo.factory(this.view);
36350 this.view.render && this.view.render(false, '');
36354 this.fireEvent('render', this);
36357 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36361 setRegion : function(region){
36362 this.region = region;
36363 this.setActiveClass(region && !this.background);
36367 setActiveClass: function(state)
36370 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36371 this.el.setStyle('position','relative');
36373 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36374 this.el.setStyle('position', 'absolute');
36379 * Returns the toolbar for this Panel if one was configured.
36380 * @return {Roo.Toolbar}
36382 getToolbar : function(){
36383 return this.toolbar;
36386 setActiveState : function(active)
36388 this.active = active;
36389 this.setActiveClass(active);
36391 this.fireEvent("deactivate", this);
36393 this.fireEvent("activate", this);
36397 * Updates this panel's element
36398 * @param {String} content The new content
36399 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36401 setContent : function(content, loadScripts){
36402 this.el.update(content, loadScripts);
36405 ignoreResize : function(w, h){
36406 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36409 this.lastSize = {width: w, height: h};
36414 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36415 * @return {Roo.UpdateManager} The UpdateManager
36417 getUpdateManager : function(){
36418 return this.el.getUpdateManager();
36421 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36422 * @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:
36425 url: "your-url.php",
36426 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36427 callback: yourFunction,
36428 scope: yourObject, //(optional scope)
36431 text: "Loading...",
36436 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36437 * 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.
36438 * @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}
36439 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36440 * @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.
36441 * @return {Roo.ContentPanel} this
36444 var um = this.el.getUpdateManager();
36445 um.update.apply(um, arguments);
36451 * 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.
36452 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36453 * @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)
36454 * @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)
36455 * @return {Roo.UpdateManager} The UpdateManager
36457 setUrl : function(url, params, loadOnce){
36458 if(this.refreshDelegate){
36459 this.removeListener("activate", this.refreshDelegate);
36461 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36462 this.on("activate", this.refreshDelegate);
36463 return this.el.getUpdateManager();
36466 _handleRefresh : function(url, params, loadOnce){
36467 if(!loadOnce || !this.loaded){
36468 var updater = this.el.getUpdateManager();
36469 updater.update(url, params, this._setLoaded.createDelegate(this));
36473 _setLoaded : function(){
36474 this.loaded = true;
36478 * Returns this panel's id
36481 getId : function(){
36486 * Returns this panel's element - used by regiosn to add.
36487 * @return {Roo.Element}
36489 getEl : function(){
36490 return this.wrapEl || this.el;
36495 adjustForComponents : function(width, height)
36497 //Roo.log('adjustForComponents ');
36498 if(this.resizeEl != this.el){
36499 width -= this.el.getFrameWidth('lr');
36500 height -= this.el.getFrameWidth('tb');
36503 var te = this.toolbar.getEl();
36504 te.setWidth(width);
36505 height -= te.getHeight();
36508 var te = this.footer.getEl();
36509 te.setWidth(width);
36510 height -= te.getHeight();
36514 if(this.adjustments){
36515 width += this.adjustments[0];
36516 height += this.adjustments[1];
36518 return {"width": width, "height": height};
36521 setSize : function(width, height){
36522 if(this.fitToFrame && !this.ignoreResize(width, height)){
36523 if(this.fitContainer && this.resizeEl != this.el){
36524 this.el.setSize(width, height);
36526 var size = this.adjustForComponents(width, height);
36527 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36528 this.fireEvent('resize', this, size.width, size.height);
36533 * Returns this panel's title
36536 getTitle : function(){
36538 if (typeof(this.title) != 'object') {
36543 for (var k in this.title) {
36544 if (!this.title.hasOwnProperty(k)) {
36548 if (k.indexOf('-') >= 0) {
36549 var s = k.split('-');
36550 for (var i = 0; i<s.length; i++) {
36551 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36554 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36561 * Set this panel's title
36562 * @param {String} title
36564 setTitle : function(title){
36565 this.title = title;
36567 this.region.updatePanelTitle(this, title);
36572 * Returns true is this panel was configured to be closable
36573 * @return {Boolean}
36575 isClosable : function(){
36576 return this.closable;
36579 beforeSlide : function(){
36581 this.resizeEl.clip();
36584 afterSlide : function(){
36586 this.resizeEl.unclip();
36590 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36591 * Will fail silently if the {@link #setUrl} method has not been called.
36592 * This does not activate the panel, just updates its content.
36594 refresh : function(){
36595 if(this.refreshDelegate){
36596 this.loaded = false;
36597 this.refreshDelegate();
36602 * Destroys this panel
36604 destroy : function(){
36605 this.el.removeAllListeners();
36606 var tempEl = document.createElement("span");
36607 tempEl.appendChild(this.el.dom);
36608 tempEl.innerHTML = "";
36614 * form - if the content panel contains a form - this is a reference to it.
36615 * @type {Roo.form.Form}
36619 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36620 * This contains a reference to it.
36626 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36636 * @param {Object} cfg Xtype definition of item to add.
36640 getChildContainer: function () {
36641 return this.getEl();
36646 var ret = new Roo.factory(cfg);
36651 if (cfg.xtype.match(/^Form$/)) {
36654 //if (this.footer) {
36655 // el = this.footer.container.insertSibling(false, 'before');
36657 el = this.el.createChild();
36660 this.form = new Roo.form.Form(cfg);
36663 if ( this.form.allItems.length) {
36664 this.form.render(el.dom);
36668 // should only have one of theses..
36669 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36670 // views.. should not be just added - used named prop 'view''
36672 cfg.el = this.el.appendChild(document.createElement("div"));
36675 var ret = new Roo.factory(cfg);
36677 ret.render && ret.render(false, ''); // render blank..
36687 * @class Roo.bootstrap.panel.Grid
36688 * @extends Roo.bootstrap.panel.Content
36690 * Create a new GridPanel.
36691 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36692 * @param {Object} config A the config object
36698 Roo.bootstrap.panel.Grid = function(config)
36702 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36703 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36705 config.el = this.wrapper;
36706 //this.el = this.wrapper;
36708 if (config.container) {
36709 // ctor'ed from a Border/panel.grid
36712 this.wrapper.setStyle("overflow", "hidden");
36713 this.wrapper.addClass('roo-grid-container');
36718 if(config.toolbar){
36719 var tool_el = this.wrapper.createChild();
36720 this.toolbar = Roo.factory(config.toolbar);
36722 if (config.toolbar.items) {
36723 ti = config.toolbar.items ;
36724 delete config.toolbar.items ;
36728 this.toolbar.render(tool_el);
36729 for(var i =0;i < ti.length;i++) {
36730 // Roo.log(['add child', items[i]]);
36731 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36733 this.toolbar.items = nitems;
36735 delete config.toolbar;
36738 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36739 config.grid.scrollBody = true;;
36740 config.grid.monitorWindowResize = false; // turn off autosizing
36741 config.grid.autoHeight = false;
36742 config.grid.autoWidth = false;
36744 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36746 if (config.background) {
36747 // render grid on panel activation (if panel background)
36748 this.on('activate', function(gp) {
36749 if (!gp.grid.rendered) {
36750 gp.grid.render(this.wrapper);
36751 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36756 this.grid.render(this.wrapper);
36757 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36760 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36761 // ??? needed ??? config.el = this.wrapper;
36766 // xtype created footer. - not sure if will work as we normally have to render first..
36767 if (this.footer && !this.footer.el && this.footer.xtype) {
36769 var ctr = this.grid.getView().getFooterPanel(true);
36770 this.footer.dataSource = this.grid.dataSource;
36771 this.footer = Roo.factory(this.footer, Roo);
36772 this.footer.render(ctr);
36782 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36783 getId : function(){
36784 return this.grid.id;
36788 * Returns the grid for this panel
36789 * @return {Roo.bootstrap.Table}
36791 getGrid : function(){
36795 setSize : function(width, height){
36796 if(!this.ignoreResize(width, height)){
36797 var grid = this.grid;
36798 var size = this.adjustForComponents(width, height);
36799 var gridel = grid.getGridEl();
36800 gridel.setSize(size.width, size.height);
36802 var thd = grid.getGridEl().select('thead',true).first();
36803 var tbd = grid.getGridEl().select('tbody', true).first();
36805 tbd.setSize(width, height - thd.getHeight());
36814 beforeSlide : function(){
36815 this.grid.getView().scroller.clip();
36818 afterSlide : function(){
36819 this.grid.getView().scroller.unclip();
36822 destroy : function(){
36823 this.grid.destroy();
36825 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36830 * @class Roo.bootstrap.panel.Nest
36831 * @extends Roo.bootstrap.panel.Content
36833 * Create a new Panel, that can contain a layout.Border.
36836 * @param {Roo.BorderLayout} layout The layout for this panel
36837 * @param {String/Object} config A string to set only the title or a config object
36839 Roo.bootstrap.panel.Nest = function(config)
36841 // construct with only one argument..
36842 /* FIXME - implement nicer consturctors
36843 if (layout.layout) {
36845 layout = config.layout;
36846 delete config.layout;
36848 if (layout.xtype && !layout.getEl) {
36849 // then layout needs constructing..
36850 layout = Roo.factory(layout, Roo);
36854 config.el = config.layout.getEl();
36856 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36858 config.layout.monitorWindowResize = false; // turn off autosizing
36859 this.layout = config.layout;
36860 this.layout.getEl().addClass("roo-layout-nested-layout");
36867 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36869 setSize : function(width, height){
36870 if(!this.ignoreResize(width, height)){
36871 var size = this.adjustForComponents(width, height);
36872 var el = this.layout.getEl();
36873 if (size.height < 1) {
36874 el.setWidth(size.width);
36876 el.setSize(size.width, size.height);
36878 var touch = el.dom.offsetWidth;
36879 this.layout.layout();
36880 // ie requires a double layout on the first pass
36881 if(Roo.isIE && !this.initialized){
36882 this.initialized = true;
36883 this.layout.layout();
36888 // activate all subpanels if not currently active..
36890 setActiveState : function(active){
36891 this.active = active;
36892 this.setActiveClass(active);
36895 this.fireEvent("deactivate", this);
36899 this.fireEvent("activate", this);
36900 // not sure if this should happen before or after..
36901 if (!this.layout) {
36902 return; // should not happen..
36905 for (var r in this.layout.regions) {
36906 reg = this.layout.getRegion(r);
36907 if (reg.getActivePanel()) {
36908 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36909 reg.setActivePanel(reg.getActivePanel());
36912 if (!reg.panels.length) {
36915 reg.showPanel(reg.getPanel(0));
36924 * Returns the nested BorderLayout for this panel
36925 * @return {Roo.BorderLayout}
36927 getLayout : function(){
36928 return this.layout;
36932 * Adds a xtype elements to the layout of the nested panel
36936 xtype : 'ContentPanel',
36943 xtype : 'NestedLayoutPanel',
36949 items : [ ... list of content panels or nested layout panels.. ]
36953 * @param {Object} cfg Xtype definition of item to add.
36955 addxtype : function(cfg) {
36956 return this.layout.addxtype(cfg);
36961 * Ext JS Library 1.1.1
36962 * Copyright(c) 2006-2007, Ext JS, LLC.
36964 * Originally Released Under LGPL - original licence link has changed is not relivant.
36967 * <script type="text/javascript">
36970 * @class Roo.TabPanel
36971 * @extends Roo.util.Observable
36972 * A lightweight tab container.
36976 // basic tabs 1, built from existing content
36977 var tabs = new Roo.TabPanel("tabs1");
36978 tabs.addTab("script", "View Script");
36979 tabs.addTab("markup", "View Markup");
36980 tabs.activate("script");
36982 // more advanced tabs, built from javascript
36983 var jtabs = new Roo.TabPanel("jtabs");
36984 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36986 // set up the UpdateManager
36987 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36988 var updater = tab2.getUpdateManager();
36989 updater.setDefaultUrl("ajax1.htm");
36990 tab2.on('activate', updater.refresh, updater, true);
36992 // Use setUrl for Ajax loading
36993 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36994 tab3.setUrl("ajax2.htm", null, true);
36997 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37000 jtabs.activate("jtabs-1");
37003 * Create a new TabPanel.
37004 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37005 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37007 Roo.bootstrap.panel.Tabs = function(config){
37009 * The container element for this TabPanel.
37010 * @type Roo.Element
37012 this.el = Roo.get(config.el);
37015 if(typeof config == "boolean"){
37016 this.tabPosition = config ? "bottom" : "top";
37018 Roo.apply(this, config);
37022 if(this.tabPosition == "bottom"){
37023 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37024 this.el.addClass("roo-tabs-bottom");
37026 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37027 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37028 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37030 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37032 if(this.tabPosition != "bottom"){
37033 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37034 * @type Roo.Element
37036 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37037 this.el.addClass("roo-tabs-top");
37041 this.bodyEl.setStyle("position", "relative");
37043 this.active = null;
37044 this.activateDelegate = this.activate.createDelegate(this);
37049 * Fires when the active tab changes
37050 * @param {Roo.TabPanel} this
37051 * @param {Roo.TabPanelItem} activePanel The new active tab
37055 * @event beforetabchange
37056 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37057 * @param {Roo.TabPanel} this
37058 * @param {Object} e Set cancel to true on this object to cancel the tab change
37059 * @param {Roo.TabPanelItem} tab The tab being changed to
37061 "beforetabchange" : true
37064 Roo.EventManager.onWindowResize(this.onResize, this);
37065 this.cpad = this.el.getPadding("lr");
37066 this.hiddenCount = 0;
37069 // toolbar on the tabbar support...
37070 if (this.toolbar) {
37071 alert("no toolbar support yet");
37072 this.toolbar = false;
37074 var tcfg = this.toolbar;
37075 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37076 this.toolbar = new Roo.Toolbar(tcfg);
37077 if (Roo.isSafari) {
37078 var tbl = tcfg.container.child('table', true);
37079 tbl.setAttribute('width', '100%');
37087 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37090 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37092 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37094 tabPosition : "top",
37096 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37098 currentTabWidth : 0,
37100 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37104 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37108 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37110 preferredTabWidth : 175,
37112 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37114 resizeTabs : false,
37116 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37118 monitorResize : true,
37120 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37125 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37126 * @param {String} id The id of the div to use <b>or create</b>
37127 * @param {String} text The text for the tab
37128 * @param {String} content (optional) Content to put in the TabPanelItem body
37129 * @param {Boolean} closable (optional) True to create a close icon on the tab
37130 * @return {Roo.TabPanelItem} The created TabPanelItem
37132 addTab : function(id, text, content, closable, tpl)
37134 var item = new Roo.bootstrap.panel.TabItem({
37138 closable : closable,
37141 this.addTabItem(item);
37143 item.setContent(content);
37149 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37150 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37151 * @return {Roo.TabPanelItem}
37153 getTab : function(id){
37154 return this.items[id];
37158 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37159 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37161 hideTab : function(id){
37162 var t = this.items[id];
37165 this.hiddenCount++;
37166 this.autoSizeTabs();
37171 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37172 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37174 unhideTab : function(id){
37175 var t = this.items[id];
37177 t.setHidden(false);
37178 this.hiddenCount--;
37179 this.autoSizeTabs();
37184 * Adds an existing {@link Roo.TabPanelItem}.
37185 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37187 addTabItem : function(item){
37188 this.items[item.id] = item;
37189 this.items.push(item);
37190 // if(this.resizeTabs){
37191 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37192 // this.autoSizeTabs();
37194 // item.autoSize();
37199 * Removes a {@link Roo.TabPanelItem}.
37200 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37202 removeTab : function(id){
37203 var items = this.items;
37204 var tab = items[id];
37205 if(!tab) { return; }
37206 var index = items.indexOf(tab);
37207 if(this.active == tab && items.length > 1){
37208 var newTab = this.getNextAvailable(index);
37213 this.stripEl.dom.removeChild(tab.pnode.dom);
37214 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37215 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37217 items.splice(index, 1);
37218 delete this.items[tab.id];
37219 tab.fireEvent("close", tab);
37220 tab.purgeListeners();
37221 this.autoSizeTabs();
37224 getNextAvailable : function(start){
37225 var items = this.items;
37227 // look for a next tab that will slide over to
37228 // replace the one being removed
37229 while(index < items.length){
37230 var item = items[++index];
37231 if(item && !item.isHidden()){
37235 // if one isn't found select the previous tab (on the left)
37238 var item = items[--index];
37239 if(item && !item.isHidden()){
37247 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37248 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37250 disableTab : function(id){
37251 var tab = this.items[id];
37252 if(tab && this.active != tab){
37258 * Enables a {@link Roo.TabPanelItem} that is disabled.
37259 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37261 enableTab : function(id){
37262 var tab = this.items[id];
37267 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37268 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37269 * @return {Roo.TabPanelItem} The TabPanelItem.
37271 activate : function(id){
37272 var tab = this.items[id];
37276 if(tab == this.active || tab.disabled){
37280 this.fireEvent("beforetabchange", this, e, tab);
37281 if(e.cancel !== true && !tab.disabled){
37283 this.active.hide();
37285 this.active = this.items[id];
37286 this.active.show();
37287 this.fireEvent("tabchange", this, this.active);
37293 * Gets the active {@link Roo.TabPanelItem}.
37294 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37296 getActiveTab : function(){
37297 return this.active;
37301 * Updates the tab body element to fit the height of the container element
37302 * for overflow scrolling
37303 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37305 syncHeight : function(targetHeight){
37306 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37307 var bm = this.bodyEl.getMargins();
37308 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37309 this.bodyEl.setHeight(newHeight);
37313 onResize : function(){
37314 if(this.monitorResize){
37315 this.autoSizeTabs();
37320 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37322 beginUpdate : function(){
37323 this.updating = true;
37327 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37329 endUpdate : function(){
37330 this.updating = false;
37331 this.autoSizeTabs();
37335 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37337 autoSizeTabs : function(){
37338 var count = this.items.length;
37339 var vcount = count - this.hiddenCount;
37340 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37343 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37344 var availWidth = Math.floor(w / vcount);
37345 var b = this.stripBody;
37346 if(b.getWidth() > w){
37347 var tabs = this.items;
37348 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37349 if(availWidth < this.minTabWidth){
37350 /*if(!this.sleft){ // incomplete scrolling code
37351 this.createScrollButtons();
37354 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37357 if(this.currentTabWidth < this.preferredTabWidth){
37358 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37364 * Returns the number of tabs in this TabPanel.
37367 getCount : function(){
37368 return this.items.length;
37372 * Resizes all the tabs to the passed width
37373 * @param {Number} The new width
37375 setTabWidth : function(width){
37376 this.currentTabWidth = width;
37377 for(var i = 0, len = this.items.length; i < len; i++) {
37378 if(!this.items[i].isHidden()) {
37379 this.items[i].setWidth(width);
37385 * Destroys this TabPanel
37386 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37388 destroy : function(removeEl){
37389 Roo.EventManager.removeResizeListener(this.onResize, this);
37390 for(var i = 0, len = this.items.length; i < len; i++){
37391 this.items[i].purgeListeners();
37393 if(removeEl === true){
37394 this.el.update("");
37399 createStrip : function(container)
37401 var strip = document.createElement("nav");
37402 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37403 container.appendChild(strip);
37407 createStripList : function(strip)
37409 // div wrapper for retard IE
37410 // returns the "tr" element.
37411 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37412 //'<div class="x-tabs-strip-wrap">'+
37413 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37414 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37415 return strip.firstChild; //.firstChild.firstChild.firstChild;
37417 createBody : function(container)
37419 var body = document.createElement("div");
37420 Roo.id(body, "tab-body");
37421 //Roo.fly(body).addClass("x-tabs-body");
37422 Roo.fly(body).addClass("tab-content");
37423 container.appendChild(body);
37426 createItemBody :function(bodyEl, id){
37427 var body = Roo.getDom(id);
37429 body = document.createElement("div");
37432 //Roo.fly(body).addClass("x-tabs-item-body");
37433 Roo.fly(body).addClass("tab-pane");
37434 bodyEl.insertBefore(body, bodyEl.firstChild);
37438 createStripElements : function(stripEl, text, closable, tpl)
37440 var td = document.createElement("li"); // was td..
37443 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37446 stripEl.appendChild(td);
37448 td.className = "x-tabs-closable";
37449 if(!this.closeTpl){
37450 this.closeTpl = new Roo.Template(
37451 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37452 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37453 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37456 var el = this.closeTpl.overwrite(td, {"text": text});
37457 var close = el.getElementsByTagName("div")[0];
37458 var inner = el.getElementsByTagName("em")[0];
37459 return {"el": el, "close": close, "inner": inner};
37462 // not sure what this is..
37463 // if(!this.tabTpl){
37464 //this.tabTpl = new Roo.Template(
37465 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37466 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37468 // this.tabTpl = new Roo.Template(
37469 // '<a href="#">' +
37470 // '<span unselectable="on"' +
37471 // (this.disableTooltips ? '' : ' title="{text}"') +
37472 // ' >{text}</span></a>'
37478 var template = tpl || this.tabTpl || false;
37482 template = new Roo.Template(
37484 '<span unselectable="on"' +
37485 (this.disableTooltips ? '' : ' title="{text}"') +
37486 ' >{text}</span></a>'
37490 switch (typeof(template)) {
37494 template = new Roo.Template(template);
37500 var el = template.overwrite(td, {"text": text});
37502 var inner = el.getElementsByTagName("span")[0];
37504 return {"el": el, "inner": inner};
37512 * @class Roo.TabPanelItem
37513 * @extends Roo.util.Observable
37514 * Represents an individual item (tab plus body) in a TabPanel.
37515 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37516 * @param {String} id The id of this TabPanelItem
37517 * @param {String} text The text for the tab of this TabPanelItem
37518 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37520 Roo.bootstrap.panel.TabItem = function(config){
37522 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37523 * @type Roo.TabPanel
37525 this.tabPanel = config.panel;
37527 * The id for this TabPanelItem
37530 this.id = config.id;
37532 this.disabled = false;
37534 this.text = config.text;
37536 this.loaded = false;
37537 this.closable = config.closable;
37540 * The body element for this TabPanelItem.
37541 * @type Roo.Element
37543 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37544 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37545 this.bodyEl.setStyle("display", "block");
37546 this.bodyEl.setStyle("zoom", "1");
37547 //this.hideAction();
37549 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37551 this.el = Roo.get(els.el);
37552 this.inner = Roo.get(els.inner, true);
37553 this.textEl = Roo.get(this.el.dom.firstChild, true);
37554 this.pnode = Roo.get(els.el.parentNode, true);
37555 this.el.on("mousedown", this.onTabMouseDown, this);
37556 this.el.on("click", this.onTabClick, this);
37558 if(config.closable){
37559 var c = Roo.get(els.close, true);
37560 c.dom.title = this.closeText;
37561 c.addClassOnOver("close-over");
37562 c.on("click", this.closeClick, this);
37568 * Fires when this tab becomes the active tab.
37569 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37570 * @param {Roo.TabPanelItem} this
37574 * @event beforeclose
37575 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37576 * @param {Roo.TabPanelItem} this
37577 * @param {Object} e Set cancel to true on this object to cancel the close.
37579 "beforeclose": true,
37582 * Fires when this tab is closed.
37583 * @param {Roo.TabPanelItem} this
37587 * @event deactivate
37588 * Fires when this tab is no longer the active tab.
37589 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37590 * @param {Roo.TabPanelItem} this
37592 "deactivate" : true
37594 this.hidden = false;
37596 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37599 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37601 purgeListeners : function(){
37602 Roo.util.Observable.prototype.purgeListeners.call(this);
37603 this.el.removeAllListeners();
37606 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37609 this.pnode.addClass("active");
37612 this.tabPanel.stripWrap.repaint();
37614 this.fireEvent("activate", this.tabPanel, this);
37618 * Returns true if this tab is the active tab.
37619 * @return {Boolean}
37621 isActive : function(){
37622 return this.tabPanel.getActiveTab() == this;
37626 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37629 this.pnode.removeClass("active");
37631 this.fireEvent("deactivate", this.tabPanel, this);
37634 hideAction : function(){
37635 this.bodyEl.hide();
37636 this.bodyEl.setStyle("position", "absolute");
37637 this.bodyEl.setLeft("-20000px");
37638 this.bodyEl.setTop("-20000px");
37641 showAction : function(){
37642 this.bodyEl.setStyle("position", "relative");
37643 this.bodyEl.setTop("");
37644 this.bodyEl.setLeft("");
37645 this.bodyEl.show();
37649 * Set the tooltip for the tab.
37650 * @param {String} tooltip The tab's tooltip
37652 setTooltip : function(text){
37653 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37654 this.textEl.dom.qtip = text;
37655 this.textEl.dom.removeAttribute('title');
37657 this.textEl.dom.title = text;
37661 onTabClick : function(e){
37662 e.preventDefault();
37663 this.tabPanel.activate(this.id);
37666 onTabMouseDown : function(e){
37667 e.preventDefault();
37668 this.tabPanel.activate(this.id);
37671 getWidth : function(){
37672 return this.inner.getWidth();
37675 setWidth : function(width){
37676 var iwidth = width - this.pnode.getPadding("lr");
37677 this.inner.setWidth(iwidth);
37678 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37679 this.pnode.setWidth(width);
37683 * Show or hide the tab
37684 * @param {Boolean} hidden True to hide or false to show.
37686 setHidden : function(hidden){
37687 this.hidden = hidden;
37688 this.pnode.setStyle("display", hidden ? "none" : "");
37692 * Returns true if this tab is "hidden"
37693 * @return {Boolean}
37695 isHidden : function(){
37696 return this.hidden;
37700 * Returns the text for this tab
37703 getText : function(){
37707 autoSize : function(){
37708 //this.el.beginMeasure();
37709 this.textEl.setWidth(1);
37711 * #2804 [new] Tabs in Roojs
37712 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37714 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37715 //this.el.endMeasure();
37719 * Sets the text for the tab (Note: this also sets the tooltip text)
37720 * @param {String} text The tab's text and tooltip
37722 setText : function(text){
37724 this.textEl.update(text);
37725 this.setTooltip(text);
37726 //if(!this.tabPanel.resizeTabs){
37727 // this.autoSize();
37731 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37733 activate : function(){
37734 this.tabPanel.activate(this.id);
37738 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37740 disable : function(){
37741 if(this.tabPanel.active != this){
37742 this.disabled = true;
37743 this.pnode.addClass("disabled");
37748 * Enables this TabPanelItem if it was previously disabled.
37750 enable : function(){
37751 this.disabled = false;
37752 this.pnode.removeClass("disabled");
37756 * Sets the content for this TabPanelItem.
37757 * @param {String} content The content
37758 * @param {Boolean} loadScripts true to look for and load scripts
37760 setContent : function(content, loadScripts){
37761 this.bodyEl.update(content, loadScripts);
37765 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37766 * @return {Roo.UpdateManager} The UpdateManager
37768 getUpdateManager : function(){
37769 return this.bodyEl.getUpdateManager();
37773 * Set a URL to be used to load the content for this TabPanelItem.
37774 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37775 * @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)
37776 * @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)
37777 * @return {Roo.UpdateManager} The UpdateManager
37779 setUrl : function(url, params, loadOnce){
37780 if(this.refreshDelegate){
37781 this.un('activate', this.refreshDelegate);
37783 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37784 this.on("activate", this.refreshDelegate);
37785 return this.bodyEl.getUpdateManager();
37789 _handleRefresh : function(url, params, loadOnce){
37790 if(!loadOnce || !this.loaded){
37791 var updater = this.bodyEl.getUpdateManager();
37792 updater.update(url, params, this._setLoaded.createDelegate(this));
37797 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37798 * Will fail silently if the setUrl method has not been called.
37799 * This does not activate the panel, just updates its content.
37801 refresh : function(){
37802 if(this.refreshDelegate){
37803 this.loaded = false;
37804 this.refreshDelegate();
37809 _setLoaded : function(){
37810 this.loaded = true;
37814 closeClick : function(e){
37817 this.fireEvent("beforeclose", this, o);
37818 if(o.cancel !== true){
37819 this.tabPanel.removeTab(this.id);
37823 * The text displayed in the tooltip for the close icon.
37826 closeText : "Close this tab"