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
12930 if(this.indicatorpos == 'right'){
12931 Roo.log('hidden name:'+this.hiddenName);
12938 html : this.fieldLabel
12942 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12943 tooltip : 'This field is required'
12954 // Roo.log(" no label && no align");
12961 ['xs','sm','md','lg'].map(function(size){
12962 if (settings[size]) {
12963 cfg.cls += ' col-' + size + '-' + settings[size];
12971 _initEventsCalled : false,
12974 initEvents: function()
12976 if (this._initEventsCalled) { // as we call render... prevent looping...
12979 this._initEventsCalled = true;
12982 throw "can not find store for combo";
12985 this.store = Roo.factory(this.store, Roo.data);
12986 this.store.parent = this;
12988 // if we are building from html. then this element is so complex, that we can not really
12989 // use the rendered HTML.
12990 // so we have to trash and replace the previous code.
12991 if (Roo.XComponent.build_from_html) {
12993 // remove this element....
12994 var e = this.el.dom, k=0;
12995 while (e ) { e = e.previousSibling; ++k;}
13000 this.rendered = false;
13002 this.render(this.parent().getChildContainer(true), k);
13008 if(Roo.isIOS && this.useNativeIOS){
13009 this.initIOSView();
13017 if(Roo.isTouch && this.mobileTouchView){
13018 this.initTouchView();
13023 this.initTickableEvents();
13027 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13029 if(this.hiddenName){
13031 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13033 this.hiddenField.dom.value =
13034 this.hiddenValue !== undefined ? this.hiddenValue :
13035 this.value !== undefined ? this.value : '';
13037 // prevent input submission
13038 this.el.dom.removeAttribute('name');
13039 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13044 // this.el.dom.setAttribute('autocomplete', 'off');
13047 var cls = 'x-combo-list';
13049 //this.list = new Roo.Layer({
13050 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13056 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13057 _this.list.setWidth(lw);
13060 this.list.on('mouseover', this.onViewOver, this);
13061 this.list.on('mousemove', this.onViewMove, this);
13063 this.list.on('scroll', this.onViewScroll, this);
13066 this.list.swallowEvent('mousewheel');
13067 this.assetHeight = 0;
13070 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13071 this.assetHeight += this.header.getHeight();
13074 this.innerList = this.list.createChild({cls:cls+'-inner'});
13075 this.innerList.on('mouseover', this.onViewOver, this);
13076 this.innerList.on('mousemove', this.onViewMove, this);
13077 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13079 if(this.allowBlank && !this.pageSize && !this.disableClear){
13080 this.footer = this.list.createChild({cls:cls+'-ft'});
13081 this.pageTb = new Roo.Toolbar(this.footer);
13085 this.footer = this.list.createChild({cls:cls+'-ft'});
13086 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13087 {pageSize: this.pageSize});
13091 if (this.pageTb && this.allowBlank && !this.disableClear) {
13093 this.pageTb.add(new Roo.Toolbar.Fill(), {
13094 cls: 'x-btn-icon x-btn-clear',
13096 handler: function()
13099 _this.clearValue();
13100 _this.onSelect(false, -1);
13105 this.assetHeight += this.footer.getHeight();
13110 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13113 this.view = new Roo.View(this.list, this.tpl, {
13114 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13116 //this.view.wrapEl.setDisplayed(false);
13117 this.view.on('click', this.onViewClick, this);
13120 this.store.on('beforeload', this.onBeforeLoad, this);
13121 this.store.on('load', this.onLoad, this);
13122 this.store.on('loadexception', this.onLoadException, this);
13124 if(this.resizable){
13125 this.resizer = new Roo.Resizable(this.list, {
13126 pinned:true, handles:'se'
13128 this.resizer.on('resize', function(r, w, h){
13129 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13130 this.listWidth = w;
13131 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13132 this.restrictHeight();
13134 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13137 if(!this.editable){
13138 this.editable = true;
13139 this.setEditable(false);
13144 if (typeof(this.events.add.listeners) != 'undefined') {
13146 this.addicon = this.wrap.createChild(
13147 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13149 this.addicon.on('click', function(e) {
13150 this.fireEvent('add', this);
13153 if (typeof(this.events.edit.listeners) != 'undefined') {
13155 this.editicon = this.wrap.createChild(
13156 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13157 if (this.addicon) {
13158 this.editicon.setStyle('margin-left', '40px');
13160 this.editicon.on('click', function(e) {
13162 // we fire even if inothing is selected..
13163 this.fireEvent('edit', this, this.lastData );
13169 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13170 "up" : function(e){
13171 this.inKeyMode = true;
13175 "down" : function(e){
13176 if(!this.isExpanded()){
13177 this.onTriggerClick();
13179 this.inKeyMode = true;
13184 "enter" : function(e){
13185 // this.onViewClick();
13189 if(this.fireEvent("specialkey", this, e)){
13190 this.onViewClick(false);
13196 "esc" : function(e){
13200 "tab" : function(e){
13203 if(this.fireEvent("specialkey", this, e)){
13204 this.onViewClick(false);
13212 doRelay : function(foo, bar, hname){
13213 if(hname == 'down' || this.scope.isExpanded()){
13214 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13223 this.queryDelay = Math.max(this.queryDelay || 10,
13224 this.mode == 'local' ? 10 : 250);
13227 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13229 if(this.typeAhead){
13230 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13232 if(this.editable !== false){
13233 this.inputEl().on("keyup", this.onKeyUp, this);
13235 if(this.forceSelection){
13236 this.inputEl().on('blur', this.doForce, this);
13240 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13241 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13245 initTickableEvents: function()
13249 if(this.hiddenName){
13251 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13253 this.hiddenField.dom.value =
13254 this.hiddenValue !== undefined ? this.hiddenValue :
13255 this.value !== undefined ? this.value : '';
13257 // prevent input submission
13258 this.el.dom.removeAttribute('name');
13259 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13264 // this.list = this.el.select('ul.dropdown-menu',true).first();
13266 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13267 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13268 if(this.triggerList){
13269 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13272 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13273 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13275 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13276 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13278 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13279 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13281 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13282 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13283 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13286 this.cancelBtn.hide();
13291 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13292 _this.list.setWidth(lw);
13295 this.list.on('mouseover', this.onViewOver, this);
13296 this.list.on('mousemove', this.onViewMove, this);
13298 this.list.on('scroll', this.onViewScroll, this);
13301 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>';
13304 this.view = new Roo.View(this.list, this.tpl, {
13305 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13308 //this.view.wrapEl.setDisplayed(false);
13309 this.view.on('click', this.onViewClick, this);
13313 this.store.on('beforeload', this.onBeforeLoad, this);
13314 this.store.on('load', this.onLoad, this);
13315 this.store.on('loadexception', this.onLoadException, this);
13318 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13319 "up" : function(e){
13320 this.inKeyMode = true;
13324 "down" : function(e){
13325 this.inKeyMode = true;
13329 "enter" : function(e){
13330 if(this.fireEvent("specialkey", this, e)){
13331 this.onViewClick(false);
13337 "esc" : function(e){
13338 this.onTickableFooterButtonClick(e, false, false);
13341 "tab" : function(e){
13342 this.fireEvent("specialkey", this, e);
13344 this.onTickableFooterButtonClick(e, false, false);
13351 doRelay : function(e, fn, key){
13352 if(this.scope.isExpanded()){
13353 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13362 this.queryDelay = Math.max(this.queryDelay || 10,
13363 this.mode == 'local' ? 10 : 250);
13366 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13368 if(this.typeAhead){
13369 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13372 if(this.editable !== false){
13373 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13376 this.indicator = this.indicatorEl();
13378 if(this.indicator){
13379 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13380 this.indicator.hide();
13385 onDestroy : function(){
13387 this.view.setStore(null);
13388 this.view.el.removeAllListeners();
13389 this.view.el.remove();
13390 this.view.purgeListeners();
13393 this.list.dom.innerHTML = '';
13397 this.store.un('beforeload', this.onBeforeLoad, this);
13398 this.store.un('load', this.onLoad, this);
13399 this.store.un('loadexception', this.onLoadException, this);
13401 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13405 fireKey : function(e){
13406 if(e.isNavKeyPress() && !this.list.isVisible()){
13407 this.fireEvent("specialkey", this, e);
13412 onResize: function(w, h){
13413 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13415 // if(typeof w != 'number'){
13416 // // we do not handle it!?!?
13419 // var tw = this.trigger.getWidth();
13420 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13421 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13423 // this.inputEl().setWidth( this.adjustWidth('input', x));
13425 // //this.trigger.setStyle('left', x+'px');
13427 // if(this.list && this.listWidth === undefined){
13428 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13429 // this.list.setWidth(lw);
13430 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13438 * Allow or prevent the user from directly editing the field text. If false is passed,
13439 * the user will only be able to select from the items defined in the dropdown list. This method
13440 * is the runtime equivalent of setting the 'editable' config option at config time.
13441 * @param {Boolean} value True to allow the user to directly edit the field text
13443 setEditable : function(value){
13444 if(value == this.editable){
13447 this.editable = value;
13449 this.inputEl().dom.setAttribute('readOnly', true);
13450 this.inputEl().on('mousedown', this.onTriggerClick, this);
13451 this.inputEl().addClass('x-combo-noedit');
13453 this.inputEl().dom.setAttribute('readOnly', false);
13454 this.inputEl().un('mousedown', this.onTriggerClick, this);
13455 this.inputEl().removeClass('x-combo-noedit');
13461 onBeforeLoad : function(combo,opts){
13462 if(!this.hasFocus){
13466 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13468 this.restrictHeight();
13469 this.selectedIndex = -1;
13473 onLoad : function(){
13475 this.hasQuery = false;
13477 if(!this.hasFocus){
13481 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13482 this.loading.hide();
13485 if(this.store.getCount() > 0){
13488 this.restrictHeight();
13489 if(this.lastQuery == this.allQuery){
13490 if(this.editable && !this.tickable){
13491 this.inputEl().dom.select();
13495 !this.selectByValue(this.value, true) &&
13498 !this.store.lastOptions ||
13499 typeof(this.store.lastOptions.add) == 'undefined' ||
13500 this.store.lastOptions.add != true
13503 this.select(0, true);
13506 if(this.autoFocus){
13509 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13510 this.taTask.delay(this.typeAheadDelay);
13514 this.onEmptyResults();
13520 onLoadException : function()
13522 this.hasQuery = false;
13524 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13525 this.loading.hide();
13528 if(this.tickable && this.editable){
13533 // only causes errors at present
13534 //Roo.log(this.store.reader.jsonData);
13535 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13537 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13543 onTypeAhead : function(){
13544 if(this.store.getCount() > 0){
13545 var r = this.store.getAt(0);
13546 var newValue = r.data[this.displayField];
13547 var len = newValue.length;
13548 var selStart = this.getRawValue().length;
13550 if(selStart != len){
13551 this.setRawValue(newValue);
13552 this.selectText(selStart, newValue.length);
13558 onSelect : function(record, index){
13560 if(this.fireEvent('beforeselect', this, record, index) !== false){
13562 this.setFromData(index > -1 ? record.data : false);
13565 this.fireEvent('select', this, record, index);
13570 * Returns the currently selected field value or empty string if no value is set.
13571 * @return {String} value The selected value
13573 getValue : function()
13575 if(Roo.isIOS && this.useNativeIOS){
13576 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13580 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13583 if(this.valueField){
13584 return typeof this.value != 'undefined' ? this.value : '';
13586 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13590 getRawValue : function()
13592 if(Roo.isIOS && this.useNativeIOS){
13593 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13596 var v = this.inputEl().getValue();
13602 * Clears any text/value currently set in the field
13604 clearValue : function(){
13606 if(this.hiddenField){
13607 this.hiddenField.dom.value = '';
13610 this.setRawValue('');
13611 this.lastSelectionText = '';
13612 this.lastData = false;
13614 var close = this.closeTriggerEl();
13625 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13626 * will be displayed in the field. If the value does not match the data value of an existing item,
13627 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13628 * Otherwise the field will be blank (although the value will still be set).
13629 * @param {String} value The value to match
13631 setValue : function(v)
13633 if(Roo.isIOS && this.useNativeIOS){
13634 this.setIOSValue(v);
13644 if(this.valueField){
13645 var r = this.findRecord(this.valueField, v);
13647 text = r.data[this.displayField];
13648 }else if(this.valueNotFoundText !== undefined){
13649 text = this.valueNotFoundText;
13652 this.lastSelectionText = text;
13653 if(this.hiddenField){
13654 this.hiddenField.dom.value = v;
13656 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13659 var close = this.closeTriggerEl();
13662 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13668 * @property {Object} the last set data for the element
13673 * Sets the value of the field based on a object which is related to the record format for the store.
13674 * @param {Object} value the value to set as. or false on reset?
13676 setFromData : function(o){
13683 var dv = ''; // display value
13684 var vv = ''; // value value..
13686 if (this.displayField) {
13687 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13689 // this is an error condition!!!
13690 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13693 if(this.valueField){
13694 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13697 var close = this.closeTriggerEl();
13700 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13703 if(this.hiddenField){
13704 this.hiddenField.dom.value = vv;
13706 this.lastSelectionText = dv;
13707 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13711 // no hidden field.. - we store the value in 'value', but still display
13712 // display field!!!!
13713 this.lastSelectionText = dv;
13714 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13721 reset : function(){
13722 // overridden so that last data is reset..
13729 this.setValue(this.originalValue);
13730 //this.clearInvalid();
13731 this.lastData = false;
13733 this.view.clearSelections();
13739 findRecord : function(prop, value){
13741 if(this.store.getCount() > 0){
13742 this.store.each(function(r){
13743 if(r.data[prop] == value){
13753 getName: function()
13755 // returns hidden if it's set..
13756 if (!this.rendered) {return ''};
13757 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13761 onViewMove : function(e, t){
13762 this.inKeyMode = false;
13766 onViewOver : function(e, t){
13767 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13770 var item = this.view.findItemFromChild(t);
13773 var index = this.view.indexOf(item);
13774 this.select(index, false);
13779 onViewClick : function(view, doFocus, el, e)
13781 var index = this.view.getSelectedIndexes()[0];
13783 var r = this.store.getAt(index);
13787 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13794 Roo.each(this.tickItems, function(v,k){
13796 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13798 _this.tickItems.splice(k, 1);
13800 if(typeof(e) == 'undefined' && view == false){
13801 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13813 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13814 this.tickItems.push(r.data);
13817 if(typeof(e) == 'undefined' && view == false){
13818 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13825 this.onSelect(r, index);
13827 if(doFocus !== false && !this.blockFocus){
13828 this.inputEl().focus();
13833 restrictHeight : function(){
13834 //this.innerList.dom.style.height = '';
13835 //var inner = this.innerList.dom;
13836 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13837 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13838 //this.list.beginUpdate();
13839 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13840 this.list.alignTo(this.inputEl(), this.listAlign);
13841 this.list.alignTo(this.inputEl(), this.listAlign);
13842 //this.list.endUpdate();
13846 onEmptyResults : function(){
13848 if(this.tickable && this.editable){
13849 this.restrictHeight();
13857 * Returns true if the dropdown list is expanded, else false.
13859 isExpanded : function(){
13860 return this.list.isVisible();
13864 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13865 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13866 * @param {String} value The data value of the item to select
13867 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13868 * selected item if it is not currently in view (defaults to true)
13869 * @return {Boolean} True if the value matched an item in the list, else false
13871 selectByValue : function(v, scrollIntoView){
13872 if(v !== undefined && v !== null){
13873 var r = this.findRecord(this.valueField || this.displayField, v);
13875 this.select(this.store.indexOf(r), scrollIntoView);
13883 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13884 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13885 * @param {Number} index The zero-based index of the list item to select
13886 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13887 * selected item if it is not currently in view (defaults to true)
13889 select : function(index, scrollIntoView){
13890 this.selectedIndex = index;
13891 this.view.select(index);
13892 if(scrollIntoView !== false){
13893 var el = this.view.getNode(index);
13895 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13898 this.list.scrollChildIntoView(el, false);
13904 selectNext : function(){
13905 var ct = this.store.getCount();
13907 if(this.selectedIndex == -1){
13909 }else if(this.selectedIndex < ct-1){
13910 this.select(this.selectedIndex+1);
13916 selectPrev : function(){
13917 var ct = this.store.getCount();
13919 if(this.selectedIndex == -1){
13921 }else if(this.selectedIndex != 0){
13922 this.select(this.selectedIndex-1);
13928 onKeyUp : function(e){
13929 if(this.editable !== false && !e.isSpecialKey()){
13930 this.lastKey = e.getKey();
13931 this.dqTask.delay(this.queryDelay);
13936 validateBlur : function(){
13937 return !this.list || !this.list.isVisible();
13941 initQuery : function(){
13943 var v = this.getRawValue();
13945 if(this.tickable && this.editable){
13946 v = this.tickableInputEl().getValue();
13953 doForce : function(){
13954 if(this.inputEl().dom.value.length > 0){
13955 this.inputEl().dom.value =
13956 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13962 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13963 * query allowing the query action to be canceled if needed.
13964 * @param {String} query The SQL query to execute
13965 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13966 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13967 * saved in the current store (defaults to false)
13969 doQuery : function(q, forceAll){
13971 if(q === undefined || q === null){
13976 forceAll: forceAll,
13980 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13985 forceAll = qe.forceAll;
13986 if(forceAll === true || (q.length >= this.minChars)){
13988 this.hasQuery = true;
13990 if(this.lastQuery != q || this.alwaysQuery){
13991 this.lastQuery = q;
13992 if(this.mode == 'local'){
13993 this.selectedIndex = -1;
13995 this.store.clearFilter();
13998 if(this.specialFilter){
13999 this.fireEvent('specialfilter', this);
14004 this.store.filter(this.displayField, q);
14007 this.store.fireEvent("datachanged", this.store);
14014 this.store.baseParams[this.queryParam] = q;
14016 var options = {params : this.getParams(q)};
14019 options.add = true;
14020 options.params.start = this.page * this.pageSize;
14023 this.store.load(options);
14026 * this code will make the page width larger, at the beginning, the list not align correctly,
14027 * we should expand the list on onLoad
14028 * so command out it
14033 this.selectedIndex = -1;
14038 this.loadNext = false;
14042 getParams : function(q){
14044 //p[this.queryParam] = q;
14048 p.limit = this.pageSize;
14054 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14056 collapse : function(){
14057 if(!this.isExpanded()){
14063 this.hasFocus = false;
14067 this.cancelBtn.hide();
14068 this.trigger.show();
14071 this.tickableInputEl().dom.value = '';
14072 this.tickableInputEl().blur();
14077 Roo.get(document).un('mousedown', this.collapseIf, this);
14078 Roo.get(document).un('mousewheel', this.collapseIf, this);
14079 if (!this.editable) {
14080 Roo.get(document).un('keydown', this.listKeyPress, this);
14082 this.fireEvent('collapse', this);
14088 collapseIf : function(e){
14089 var in_combo = e.within(this.el);
14090 var in_list = e.within(this.list);
14091 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14093 if (in_combo || in_list || is_list) {
14094 //e.stopPropagation();
14099 this.onTickableFooterButtonClick(e, false, false);
14107 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14109 expand : function(){
14111 if(this.isExpanded() || !this.hasFocus){
14115 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14116 this.list.setWidth(lw);
14122 this.restrictHeight();
14126 this.tickItems = Roo.apply([], this.item);
14129 this.cancelBtn.show();
14130 this.trigger.hide();
14133 this.tickableInputEl().focus();
14138 Roo.get(document).on('mousedown', this.collapseIf, this);
14139 Roo.get(document).on('mousewheel', this.collapseIf, this);
14140 if (!this.editable) {
14141 Roo.get(document).on('keydown', this.listKeyPress, this);
14144 this.fireEvent('expand', this);
14148 // Implements the default empty TriggerField.onTriggerClick function
14149 onTriggerClick : function(e)
14151 Roo.log('trigger click');
14153 if(this.disabled || !this.triggerList){
14158 this.loadNext = false;
14160 if(this.isExpanded()){
14162 if (!this.blockFocus) {
14163 this.inputEl().focus();
14167 this.hasFocus = true;
14168 if(this.triggerAction == 'all') {
14169 this.doQuery(this.allQuery, true);
14171 this.doQuery(this.getRawValue());
14173 if (!this.blockFocus) {
14174 this.inputEl().focus();
14179 onTickableTriggerClick : function(e)
14186 this.loadNext = false;
14187 this.hasFocus = true;
14189 if(this.triggerAction == 'all') {
14190 this.doQuery(this.allQuery, true);
14192 this.doQuery(this.getRawValue());
14196 onSearchFieldClick : function(e)
14198 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14199 this.onTickableFooterButtonClick(e, false, false);
14203 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14208 this.loadNext = false;
14209 this.hasFocus = true;
14211 if(this.triggerAction == 'all') {
14212 this.doQuery(this.allQuery, true);
14214 this.doQuery(this.getRawValue());
14218 listKeyPress : function(e)
14220 //Roo.log('listkeypress');
14221 // scroll to first matching element based on key pres..
14222 if (e.isSpecialKey()) {
14225 var k = String.fromCharCode(e.getKey()).toUpperCase();
14228 var csel = this.view.getSelectedNodes();
14229 var cselitem = false;
14231 var ix = this.view.indexOf(csel[0]);
14232 cselitem = this.store.getAt(ix);
14233 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14239 this.store.each(function(v) {
14241 // start at existing selection.
14242 if (cselitem.id == v.id) {
14248 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14249 match = this.store.indexOf(v);
14255 if (match === false) {
14256 return true; // no more action?
14259 this.view.select(match);
14260 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14261 sn.scrollIntoView(sn.dom.parentNode, false);
14264 onViewScroll : function(e, t){
14266 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){
14270 this.hasQuery = true;
14272 this.loading = this.list.select('.loading', true).first();
14274 if(this.loading === null){
14275 this.list.createChild({
14277 cls: 'loading roo-select2-more-results roo-select2-active',
14278 html: 'Loading more results...'
14281 this.loading = this.list.select('.loading', true).first();
14283 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14285 this.loading.hide();
14288 this.loading.show();
14293 this.loadNext = true;
14295 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14300 addItem : function(o)
14302 var dv = ''; // display value
14304 if (this.displayField) {
14305 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14307 // this is an error condition!!!
14308 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14315 var choice = this.choices.createChild({
14317 cls: 'roo-select2-search-choice',
14326 cls: 'roo-select2-search-choice-close fa fa-times',
14331 }, this.searchField);
14333 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14335 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14343 this.inputEl().dom.value = '';
14348 onRemoveItem : function(e, _self, o)
14350 e.preventDefault();
14352 this.lastItem = Roo.apply([], this.item);
14354 var index = this.item.indexOf(o.data) * 1;
14357 Roo.log('not this item?!');
14361 this.item.splice(index, 1);
14366 this.fireEvent('remove', this, e);
14372 syncValue : function()
14374 if(!this.item.length){
14381 Roo.each(this.item, function(i){
14382 if(_this.valueField){
14383 value.push(i[_this.valueField]);
14390 this.value = value.join(',');
14392 if(this.hiddenField){
14393 this.hiddenField.dom.value = this.value;
14396 this.store.fireEvent("datachanged", this.store);
14401 clearItem : function()
14403 if(!this.multiple){
14409 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14417 if(this.tickable && !Roo.isTouch){
14418 this.view.refresh();
14422 inputEl: function ()
14424 if(Roo.isIOS && this.useNativeIOS){
14425 return this.el.select('select.roo-ios-select', true).first();
14428 if(Roo.isTouch && this.mobileTouchView){
14429 return this.el.select('input.form-control',true).first();
14433 return this.searchField;
14436 return this.el.select('input.form-control',true).first();
14439 onTickableFooterButtonClick : function(e, btn, el)
14441 e.preventDefault();
14443 this.lastItem = Roo.apply([], this.item);
14445 if(btn && btn.name == 'cancel'){
14446 this.tickItems = Roo.apply([], this.item);
14455 Roo.each(this.tickItems, function(o){
14463 validate : function()
14465 var v = this.getRawValue();
14468 v = this.getValue();
14471 if(this.disabled || this.allowBlank || v.length){
14476 this.markInvalid();
14480 tickableInputEl : function()
14482 if(!this.tickable || !this.editable){
14483 return this.inputEl();
14486 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14490 getAutoCreateTouchView : function()
14495 cls: 'form-group' //input-group
14501 type : this.inputType,
14502 cls : 'form-control x-combo-noedit',
14503 autocomplete: 'new-password',
14504 placeholder : this.placeholder || '',
14509 input.name = this.name;
14513 input.cls += ' input-' + this.size;
14516 if (this.disabled) {
14517 input.disabled = true;
14528 inputblock.cls += ' input-group';
14530 inputblock.cn.unshift({
14532 cls : 'input-group-addon',
14537 if(this.removable && !this.multiple){
14538 inputblock.cls += ' roo-removable';
14540 inputblock.cn.push({
14543 cls : 'roo-combo-removable-btn close'
14547 if(this.hasFeedback && !this.allowBlank){
14549 inputblock.cls += ' has-feedback';
14551 inputblock.cn.push({
14553 cls: 'glyphicon form-control-feedback'
14560 inputblock.cls += (this.before) ? '' : ' input-group';
14562 inputblock.cn.push({
14564 cls : 'input-group-addon',
14575 cls: 'form-hidden-field'
14589 cls: 'form-hidden-field'
14593 cls: 'roo-select2-choices',
14597 cls: 'roo-select2-search-field',
14610 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14616 if(!this.multiple && this.showToggleBtn){
14623 if (this.caret != false) {
14626 cls: 'fa fa-' + this.caret
14633 cls : 'input-group-addon btn dropdown-toggle',
14638 cls: 'combobox-clear',
14652 combobox.cls += ' roo-select2-container-multi';
14655 var align = this.labelAlign || this.parentLabelAlign();
14657 if (align ==='left' && this.fieldLabel.length) {
14662 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14663 tooltip : 'This field is required'
14667 cls : 'control-label',
14668 html : this.fieldLabel
14679 var labelCfg = cfg.cn[1];
14680 var contentCfg = cfg.cn[2];
14683 if(this.indicatorpos == 'right'){
14687 cls : 'control-label',
14688 html : this.fieldLabel,
14692 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14693 tooltip : 'This field is required'
14706 labelCfg = cfg.cn[0];
14707 contentCfg = cfg.cn[2];
14709 if(this.labelWidth > 12){
14710 labelCfg.style = "width: " + this.labelWidth + 'px';
14713 if(this.labelWidth < 13 && this.labelmd == 0){
14714 this.labelmd = this.labelWidth;
14717 if(this.labellg > 0){
14718 labelCfg.cls += ' col-lg-' + this.labellg;
14719 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14722 if(this.labelmd > 0){
14723 labelCfg.cls += ' col-md-' + this.labelmd;
14724 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14727 if(this.labelsm > 0){
14728 labelCfg.cls += ' col-sm-' + this.labelsm;
14729 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14732 if(this.labelxs > 0){
14733 labelCfg.cls += ' col-xs-' + this.labelxs;
14734 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14738 } else if ( this.fieldLabel.length) {
14742 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14743 tooltip : 'This field is required'
14747 cls : 'control-label',
14748 html : this.fieldLabel
14759 if(this.indicatorpos == 'right'){
14763 cls : 'control-label',
14764 html : this.fieldLabel,
14768 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14769 tooltip : 'This field is required'
14786 var settings = this;
14788 ['xs','sm','md','lg'].map(function(size){
14789 if (settings[size]) {
14790 cfg.cls += ' col-' + size + '-' + settings[size];
14797 initTouchView : function()
14799 this.renderTouchView();
14801 this.touchViewEl.on('scroll', function(){
14802 this.el.dom.scrollTop = 0;
14805 this.originalValue = this.getValue();
14807 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14809 this.inputEl().on("click", this.showTouchView, this);
14810 if (this.triggerEl) {
14811 this.triggerEl.on("click", this.showTouchView, this);
14815 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14816 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14818 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14820 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14821 this.store.on('load', this.onTouchViewLoad, this);
14822 this.store.on('loadexception', this.onTouchViewLoadException, this);
14824 if(this.hiddenName){
14826 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14828 this.hiddenField.dom.value =
14829 this.hiddenValue !== undefined ? this.hiddenValue :
14830 this.value !== undefined ? this.value : '';
14832 this.el.dom.removeAttribute('name');
14833 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14837 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14838 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14841 if(this.removable && !this.multiple){
14842 var close = this.closeTriggerEl();
14844 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14845 close.on('click', this.removeBtnClick, this, close);
14849 * fix the bug in Safari iOS8
14851 this.inputEl().on("focus", function(e){
14852 document.activeElement.blur();
14860 renderTouchView : function()
14862 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14863 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14865 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14866 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14868 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14869 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14870 this.touchViewBodyEl.setStyle('overflow', 'auto');
14872 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14873 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14875 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14876 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14880 showTouchView : function()
14886 this.touchViewHeaderEl.hide();
14888 if(this.modalTitle.length){
14889 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14890 this.touchViewHeaderEl.show();
14893 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14894 this.touchViewEl.show();
14896 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14897 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14898 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14900 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14902 if(this.modalTitle.length){
14903 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14906 this.touchViewBodyEl.setHeight(bodyHeight);
14910 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14912 this.touchViewEl.addClass('in');
14915 this.doTouchViewQuery();
14919 hideTouchView : function()
14921 this.touchViewEl.removeClass('in');
14925 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14927 this.touchViewEl.setStyle('display', 'none');
14932 setTouchViewValue : function()
14939 Roo.each(this.tickItems, function(o){
14944 this.hideTouchView();
14947 doTouchViewQuery : function()
14956 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14960 if(!this.alwaysQuery || this.mode == 'local'){
14961 this.onTouchViewLoad();
14968 onTouchViewBeforeLoad : function(combo,opts)
14974 onTouchViewLoad : function()
14976 if(this.store.getCount() < 1){
14977 this.onTouchViewEmptyResults();
14981 this.clearTouchView();
14983 var rawValue = this.getRawValue();
14985 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14987 this.tickItems = [];
14989 this.store.data.each(function(d, rowIndex){
14990 var row = this.touchViewListGroup.createChild(template);
14992 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14993 row.addClass(d.data.cls);
14996 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14999 html : d.data[this.displayField]
15002 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15003 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15006 row.removeClass('selected');
15007 if(!this.multiple && this.valueField &&
15008 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15011 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15012 row.addClass('selected');
15015 if(this.multiple && this.valueField &&
15016 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15020 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15021 this.tickItems.push(d.data);
15024 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15028 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15030 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15032 if(this.modalTitle.length){
15033 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15036 var listHeight = this.touchViewListGroup.getHeight();
15040 if(firstChecked && listHeight > bodyHeight){
15041 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15046 onTouchViewLoadException : function()
15048 this.hideTouchView();
15051 onTouchViewEmptyResults : function()
15053 this.clearTouchView();
15055 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15057 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15061 clearTouchView : function()
15063 this.touchViewListGroup.dom.innerHTML = '';
15066 onTouchViewClick : function(e, el, o)
15068 e.preventDefault();
15071 var rowIndex = o.rowIndex;
15073 var r = this.store.getAt(rowIndex);
15075 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15077 if(!this.multiple){
15078 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15079 c.dom.removeAttribute('checked');
15082 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15084 this.setFromData(r.data);
15086 var close = this.closeTriggerEl();
15092 this.hideTouchView();
15094 this.fireEvent('select', this, r, rowIndex);
15099 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15100 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15101 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15105 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15106 this.addItem(r.data);
15107 this.tickItems.push(r.data);
15111 getAutoCreateNativeIOS : function()
15114 cls: 'form-group' //input-group,
15119 cls : 'roo-ios-select'
15123 combobox.name = this.name;
15126 if (this.disabled) {
15127 combobox.disabled = true;
15130 var settings = this;
15132 ['xs','sm','md','lg'].map(function(size){
15133 if (settings[size]) {
15134 cfg.cls += ' col-' + size + '-' + settings[size];
15144 initIOSView : function()
15146 this.store.on('load', this.onIOSViewLoad, this);
15151 onIOSViewLoad : function()
15153 if(this.store.getCount() < 1){
15157 this.clearIOSView();
15159 if(this.allowBlank) {
15161 var default_text = '-- SELECT --';
15163 var opt = this.inputEl().createChild({
15166 html : default_text
15170 o[this.valueField] = 0;
15171 o[this.displayField] = default_text;
15173 this.ios_options.push({
15180 this.store.data.each(function(d, rowIndex){
15184 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15185 html = d.data[this.displayField];
15190 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15191 value = d.data[this.valueField];
15200 if(this.value == d.data[this.valueField]){
15201 option['selected'] = true;
15204 var opt = this.inputEl().createChild(option);
15206 this.ios_options.push({
15213 this.inputEl().on('change', function(){
15214 this.fireEvent('select', this);
15219 clearIOSView: function()
15221 this.inputEl().dom.innerHTML = '';
15223 this.ios_options = [];
15226 setIOSValue: function(v)
15230 if(!this.ios_options){
15234 Roo.each(this.ios_options, function(opts){
15236 opts.el.dom.removeAttribute('selected');
15238 if(opts.data[this.valueField] != v){
15242 opts.el.dom.setAttribute('selected', true);
15248 * @cfg {Boolean} grow
15252 * @cfg {Number} growMin
15256 * @cfg {Number} growMax
15265 Roo.apply(Roo.bootstrap.ComboBox, {
15269 cls: 'modal-header',
15291 cls: 'list-group-item',
15295 cls: 'roo-combobox-list-group-item-value'
15299 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15313 listItemCheckbox : {
15315 cls: 'list-group-item',
15319 cls: 'roo-combobox-list-group-item-value'
15323 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15339 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15344 cls: 'modal-footer',
15352 cls: 'col-xs-6 text-left',
15355 cls: 'btn btn-danger roo-touch-view-cancel',
15361 cls: 'col-xs-6 text-right',
15364 cls: 'btn btn-success roo-touch-view-ok',
15375 Roo.apply(Roo.bootstrap.ComboBox, {
15377 touchViewTemplate : {
15379 cls: 'modal fade roo-combobox-touch-view',
15383 cls: 'modal-dialog',
15384 style : 'position:fixed', // we have to fix position....
15388 cls: 'modal-content',
15390 Roo.bootstrap.ComboBox.header,
15391 Roo.bootstrap.ComboBox.body,
15392 Roo.bootstrap.ComboBox.footer
15401 * Ext JS Library 1.1.1
15402 * Copyright(c) 2006-2007, Ext JS, LLC.
15404 * Originally Released Under LGPL - original licence link has changed is not relivant.
15407 * <script type="text/javascript">
15412 * @extends Roo.util.Observable
15413 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15414 * This class also supports single and multi selection modes. <br>
15415 * Create a data model bound view:
15417 var store = new Roo.data.Store(...);
15419 var view = new Roo.View({
15421 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15423 singleSelect: true,
15424 selectedClass: "ydataview-selected",
15428 // listen for node click?
15429 view.on("click", function(vw, index, node, e){
15430 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15434 dataModel.load("foobar.xml");
15436 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15438 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15439 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15441 * Note: old style constructor is still suported (container, template, config)
15444 * Create a new View
15445 * @param {Object} config The config object
15448 Roo.View = function(config, depreciated_tpl, depreciated_config){
15450 this.parent = false;
15452 if (typeof(depreciated_tpl) == 'undefined') {
15453 // new way.. - universal constructor.
15454 Roo.apply(this, config);
15455 this.el = Roo.get(this.el);
15458 this.el = Roo.get(config);
15459 this.tpl = depreciated_tpl;
15460 Roo.apply(this, depreciated_config);
15462 this.wrapEl = this.el.wrap().wrap();
15463 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15466 if(typeof(this.tpl) == "string"){
15467 this.tpl = new Roo.Template(this.tpl);
15469 // support xtype ctors..
15470 this.tpl = new Roo.factory(this.tpl, Roo);
15474 this.tpl.compile();
15479 * @event beforeclick
15480 * Fires before a click is processed. Returns false to cancel the default action.
15481 * @param {Roo.View} this
15482 * @param {Number} index The index of the target node
15483 * @param {HTMLElement} node The target node
15484 * @param {Roo.EventObject} e The raw event object
15486 "beforeclick" : true,
15489 * Fires when a template node is clicked.
15490 * @param {Roo.View} this
15491 * @param {Number} index The index of the target node
15492 * @param {HTMLElement} node The target node
15493 * @param {Roo.EventObject} e The raw event object
15498 * Fires when a template node is double clicked.
15499 * @param {Roo.View} this
15500 * @param {Number} index The index of the target node
15501 * @param {HTMLElement} node The target node
15502 * @param {Roo.EventObject} e The raw event object
15506 * @event contextmenu
15507 * Fires when a template node is right clicked.
15508 * @param {Roo.View} this
15509 * @param {Number} index The index of the target node
15510 * @param {HTMLElement} node The target node
15511 * @param {Roo.EventObject} e The raw event object
15513 "contextmenu" : true,
15515 * @event selectionchange
15516 * Fires when the selected nodes change.
15517 * @param {Roo.View} this
15518 * @param {Array} selections Array of the selected nodes
15520 "selectionchange" : true,
15523 * @event beforeselect
15524 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15525 * @param {Roo.View} this
15526 * @param {HTMLElement} node The node to be selected
15527 * @param {Array} selections Array of currently selected nodes
15529 "beforeselect" : true,
15531 * @event preparedata
15532 * Fires on every row to render, to allow you to change the data.
15533 * @param {Roo.View} this
15534 * @param {Object} data to be rendered (change this)
15536 "preparedata" : true
15544 "click": this.onClick,
15545 "dblclick": this.onDblClick,
15546 "contextmenu": this.onContextMenu,
15550 this.selections = [];
15552 this.cmp = new Roo.CompositeElementLite([]);
15554 this.store = Roo.factory(this.store, Roo.data);
15555 this.setStore(this.store, true);
15558 if ( this.footer && this.footer.xtype) {
15560 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15562 this.footer.dataSource = this.store;
15563 this.footer.container = fctr;
15564 this.footer = Roo.factory(this.footer, Roo);
15565 fctr.insertFirst(this.el);
15567 // this is a bit insane - as the paging toolbar seems to detach the el..
15568 // dom.parentNode.parentNode.parentNode
15569 // they get detached?
15573 Roo.View.superclass.constructor.call(this);
15578 Roo.extend(Roo.View, Roo.util.Observable, {
15581 * @cfg {Roo.data.Store} store Data store to load data from.
15586 * @cfg {String|Roo.Element} el The container element.
15591 * @cfg {String|Roo.Template} tpl The template used by this View
15595 * @cfg {String} dataName the named area of the template to use as the data area
15596 * Works with domtemplates roo-name="name"
15600 * @cfg {String} selectedClass The css class to add to selected nodes
15602 selectedClass : "x-view-selected",
15604 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15609 * @cfg {String} text to display on mask (default Loading)
15613 * @cfg {Boolean} multiSelect Allow multiple selection
15615 multiSelect : false,
15617 * @cfg {Boolean} singleSelect Allow single selection
15619 singleSelect: false,
15622 * @cfg {Boolean} toggleSelect - selecting
15624 toggleSelect : false,
15627 * @cfg {Boolean} tickable - selecting
15632 * Returns the element this view is bound to.
15633 * @return {Roo.Element}
15635 getEl : function(){
15636 return this.wrapEl;
15642 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15644 refresh : function(){
15645 //Roo.log('refresh');
15648 // if we are using something like 'domtemplate', then
15649 // the what gets used is:
15650 // t.applySubtemplate(NAME, data, wrapping data..)
15651 // the outer template then get' applied with
15652 // the store 'extra data'
15653 // and the body get's added to the
15654 // roo-name="data" node?
15655 // <span class='roo-tpl-{name}'></span> ?????
15659 this.clearSelections();
15660 this.el.update("");
15662 var records = this.store.getRange();
15663 if(records.length < 1) {
15665 // is this valid?? = should it render a template??
15667 this.el.update(this.emptyText);
15671 if (this.dataName) {
15672 this.el.update(t.apply(this.store.meta)); //????
15673 el = this.el.child('.roo-tpl-' + this.dataName);
15676 for(var i = 0, len = records.length; i < len; i++){
15677 var data = this.prepareData(records[i].data, i, records[i]);
15678 this.fireEvent("preparedata", this, data, i, records[i]);
15680 var d = Roo.apply({}, data);
15683 Roo.apply(d, {'roo-id' : Roo.id()});
15687 Roo.each(this.parent.item, function(item){
15688 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15691 Roo.apply(d, {'roo-data-checked' : 'checked'});
15695 html[html.length] = Roo.util.Format.trim(
15697 t.applySubtemplate(this.dataName, d, this.store.meta) :
15704 el.update(html.join(""));
15705 this.nodes = el.dom.childNodes;
15706 this.updateIndexes(0);
15711 * Function to override to reformat the data that is sent to
15712 * the template for each node.
15713 * DEPRICATED - use the preparedata event handler.
15714 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15715 * a JSON object for an UpdateManager bound view).
15717 prepareData : function(data, index, record)
15719 this.fireEvent("preparedata", this, data, index, record);
15723 onUpdate : function(ds, record){
15724 // Roo.log('on update');
15725 this.clearSelections();
15726 var index = this.store.indexOf(record);
15727 var n = this.nodes[index];
15728 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15729 n.parentNode.removeChild(n);
15730 this.updateIndexes(index, index);
15736 onAdd : function(ds, records, index)
15738 //Roo.log(['on Add', ds, records, index] );
15739 this.clearSelections();
15740 if(this.nodes.length == 0){
15744 var n = this.nodes[index];
15745 for(var i = 0, len = records.length; i < len; i++){
15746 var d = this.prepareData(records[i].data, i, records[i]);
15748 this.tpl.insertBefore(n, d);
15751 this.tpl.append(this.el, d);
15754 this.updateIndexes(index);
15757 onRemove : function(ds, record, index){
15758 // Roo.log('onRemove');
15759 this.clearSelections();
15760 var el = this.dataName ?
15761 this.el.child('.roo-tpl-' + this.dataName) :
15764 el.dom.removeChild(this.nodes[index]);
15765 this.updateIndexes(index);
15769 * Refresh an individual node.
15770 * @param {Number} index
15772 refreshNode : function(index){
15773 this.onUpdate(this.store, this.store.getAt(index));
15776 updateIndexes : function(startIndex, endIndex){
15777 var ns = this.nodes;
15778 startIndex = startIndex || 0;
15779 endIndex = endIndex || ns.length - 1;
15780 for(var i = startIndex; i <= endIndex; i++){
15781 ns[i].nodeIndex = i;
15786 * Changes the data store this view uses and refresh the view.
15787 * @param {Store} store
15789 setStore : function(store, initial){
15790 if(!initial && this.store){
15791 this.store.un("datachanged", this.refresh);
15792 this.store.un("add", this.onAdd);
15793 this.store.un("remove", this.onRemove);
15794 this.store.un("update", this.onUpdate);
15795 this.store.un("clear", this.refresh);
15796 this.store.un("beforeload", this.onBeforeLoad);
15797 this.store.un("load", this.onLoad);
15798 this.store.un("loadexception", this.onLoad);
15802 store.on("datachanged", this.refresh, this);
15803 store.on("add", this.onAdd, this);
15804 store.on("remove", this.onRemove, this);
15805 store.on("update", this.onUpdate, this);
15806 store.on("clear", this.refresh, this);
15807 store.on("beforeload", this.onBeforeLoad, this);
15808 store.on("load", this.onLoad, this);
15809 store.on("loadexception", this.onLoad, this);
15817 * onbeforeLoad - masks the loading area.
15820 onBeforeLoad : function(store,opts)
15822 //Roo.log('onBeforeLoad');
15824 this.el.update("");
15826 this.el.mask(this.mask ? this.mask : "Loading" );
15828 onLoad : function ()
15835 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15836 * @param {HTMLElement} node
15837 * @return {HTMLElement} The template node
15839 findItemFromChild : function(node){
15840 var el = this.dataName ?
15841 this.el.child('.roo-tpl-' + this.dataName,true) :
15844 if(!node || node.parentNode == el){
15847 var p = node.parentNode;
15848 while(p && p != el){
15849 if(p.parentNode == el){
15858 onClick : function(e){
15859 var item = this.findItemFromChild(e.getTarget());
15861 var index = this.indexOf(item);
15862 if(this.onItemClick(item, index, e) !== false){
15863 this.fireEvent("click", this, index, item, e);
15866 this.clearSelections();
15871 onContextMenu : function(e){
15872 var item = this.findItemFromChild(e.getTarget());
15874 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15879 onDblClick : function(e){
15880 var item = this.findItemFromChild(e.getTarget());
15882 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15886 onItemClick : function(item, index, e)
15888 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15891 if (this.toggleSelect) {
15892 var m = this.isSelected(item) ? 'unselect' : 'select';
15895 _t[m](item, true, false);
15898 if(this.multiSelect || this.singleSelect){
15899 if(this.multiSelect && e.shiftKey && this.lastSelection){
15900 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15902 this.select(item, this.multiSelect && e.ctrlKey);
15903 this.lastSelection = item;
15906 if(!this.tickable){
15907 e.preventDefault();
15915 * Get the number of selected nodes.
15918 getSelectionCount : function(){
15919 return this.selections.length;
15923 * Get the currently selected nodes.
15924 * @return {Array} An array of HTMLElements
15926 getSelectedNodes : function(){
15927 return this.selections;
15931 * Get the indexes of the selected nodes.
15934 getSelectedIndexes : function(){
15935 var indexes = [], s = this.selections;
15936 for(var i = 0, len = s.length; i < len; i++){
15937 indexes.push(s[i].nodeIndex);
15943 * Clear all selections
15944 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15946 clearSelections : function(suppressEvent){
15947 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15948 this.cmp.elements = this.selections;
15949 this.cmp.removeClass(this.selectedClass);
15950 this.selections = [];
15951 if(!suppressEvent){
15952 this.fireEvent("selectionchange", this, this.selections);
15958 * Returns true if the passed node is selected
15959 * @param {HTMLElement/Number} node The node or node index
15960 * @return {Boolean}
15962 isSelected : function(node){
15963 var s = this.selections;
15967 node = this.getNode(node);
15968 return s.indexOf(node) !== -1;
15973 * @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
15974 * @param {Boolean} keepExisting (optional) true to keep existing selections
15975 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15977 select : function(nodeInfo, keepExisting, suppressEvent){
15978 if(nodeInfo instanceof Array){
15980 this.clearSelections(true);
15982 for(var i = 0, len = nodeInfo.length; i < len; i++){
15983 this.select(nodeInfo[i], true, true);
15987 var node = this.getNode(nodeInfo);
15988 if(!node || this.isSelected(node)){
15989 return; // already selected.
15992 this.clearSelections(true);
15995 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15996 Roo.fly(node).addClass(this.selectedClass);
15997 this.selections.push(node);
15998 if(!suppressEvent){
15999 this.fireEvent("selectionchange", this, this.selections);
16007 * @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
16008 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16009 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16011 unselect : function(nodeInfo, keepExisting, suppressEvent)
16013 if(nodeInfo instanceof Array){
16014 Roo.each(this.selections, function(s) {
16015 this.unselect(s, nodeInfo);
16019 var node = this.getNode(nodeInfo);
16020 if(!node || !this.isSelected(node)){
16021 //Roo.log("not selected");
16022 return; // not selected.
16026 Roo.each(this.selections, function(s) {
16028 Roo.fly(node).removeClass(this.selectedClass);
16035 this.selections= ns;
16036 this.fireEvent("selectionchange", this, this.selections);
16040 * Gets a template node.
16041 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16042 * @return {HTMLElement} The node or null if it wasn't found
16044 getNode : function(nodeInfo){
16045 if(typeof nodeInfo == "string"){
16046 return document.getElementById(nodeInfo);
16047 }else if(typeof nodeInfo == "number"){
16048 return this.nodes[nodeInfo];
16054 * Gets a range template nodes.
16055 * @param {Number} startIndex
16056 * @param {Number} endIndex
16057 * @return {Array} An array of nodes
16059 getNodes : function(start, end){
16060 var ns = this.nodes;
16061 start = start || 0;
16062 end = typeof end == "undefined" ? ns.length - 1 : end;
16065 for(var i = start; i <= end; i++){
16069 for(var i = start; i >= end; i--){
16077 * Finds the index of the passed node
16078 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16079 * @return {Number} The index of the node or -1
16081 indexOf : function(node){
16082 node = this.getNode(node);
16083 if(typeof node.nodeIndex == "number"){
16084 return node.nodeIndex;
16086 var ns = this.nodes;
16087 for(var i = 0, len = ns.length; i < len; i++){
16098 * based on jquery fullcalendar
16102 Roo.bootstrap = Roo.bootstrap || {};
16104 * @class Roo.bootstrap.Calendar
16105 * @extends Roo.bootstrap.Component
16106 * Bootstrap Calendar class
16107 * @cfg {Boolean} loadMask (true|false) default false
16108 * @cfg {Object} header generate the user specific header of the calendar, default false
16111 * Create a new Container
16112 * @param {Object} config The config object
16117 Roo.bootstrap.Calendar = function(config){
16118 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16122 * Fires when a date is selected
16123 * @param {DatePicker} this
16124 * @param {Date} date The selected date
16128 * @event monthchange
16129 * Fires when the displayed month changes
16130 * @param {DatePicker} this
16131 * @param {Date} date The selected month
16133 'monthchange': true,
16135 * @event evententer
16136 * Fires when mouse over an event
16137 * @param {Calendar} this
16138 * @param {event} Event
16140 'evententer': true,
16142 * @event eventleave
16143 * Fires when the mouse leaves an
16144 * @param {Calendar} this
16147 'eventleave': true,
16149 * @event eventclick
16150 * Fires when the mouse click an
16151 * @param {Calendar} this
16160 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16163 * @cfg {Number} startDay
16164 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16172 getAutoCreate : function(){
16175 var fc_button = function(name, corner, style, content ) {
16176 return Roo.apply({},{
16178 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16180 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16183 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16194 style : 'width:100%',
16201 cls : 'fc-header-left',
16203 fc_button('prev', 'left', 'arrow', '‹' ),
16204 fc_button('next', 'right', 'arrow', '›' ),
16205 { tag: 'span', cls: 'fc-header-space' },
16206 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16214 cls : 'fc-header-center',
16218 cls: 'fc-header-title',
16221 html : 'month / year'
16229 cls : 'fc-header-right',
16231 /* fc_button('month', 'left', '', 'month' ),
16232 fc_button('week', '', '', 'week' ),
16233 fc_button('day', 'right', '', 'day' )
16245 header = this.header;
16248 var cal_heads = function() {
16250 // fixme - handle this.
16252 for (var i =0; i < Date.dayNames.length; i++) {
16253 var d = Date.dayNames[i];
16256 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16257 html : d.substring(0,3)
16261 ret[0].cls += ' fc-first';
16262 ret[6].cls += ' fc-last';
16265 var cal_cell = function(n) {
16268 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16273 cls: 'fc-day-number',
16277 cls: 'fc-day-content',
16281 style: 'position: relative;' // height: 17px;
16293 var cal_rows = function() {
16296 for (var r = 0; r < 6; r++) {
16303 for (var i =0; i < Date.dayNames.length; i++) {
16304 var d = Date.dayNames[i];
16305 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16308 row.cn[0].cls+=' fc-first';
16309 row.cn[0].cn[0].style = 'min-height:90px';
16310 row.cn[6].cls+=' fc-last';
16314 ret[0].cls += ' fc-first';
16315 ret[4].cls += ' fc-prev-last';
16316 ret[5].cls += ' fc-last';
16323 cls: 'fc-border-separate',
16324 style : 'width:100%',
16332 cls : 'fc-first fc-last',
16350 cls : 'fc-content',
16351 style : "position: relative;",
16354 cls : 'fc-view fc-view-month fc-grid',
16355 style : 'position: relative',
16356 unselectable : 'on',
16359 cls : 'fc-event-container',
16360 style : 'position:absolute;z-index:8;top:0;left:0;'
16378 initEvents : function()
16381 throw "can not find store for calendar";
16387 style: "text-align:center",
16391 style: "background-color:white;width:50%;margin:250 auto",
16395 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16406 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16408 var size = this.el.select('.fc-content', true).first().getSize();
16409 this.maskEl.setSize(size.width, size.height);
16410 this.maskEl.enableDisplayMode("block");
16411 if(!this.loadMask){
16412 this.maskEl.hide();
16415 this.store = Roo.factory(this.store, Roo.data);
16416 this.store.on('load', this.onLoad, this);
16417 this.store.on('beforeload', this.onBeforeLoad, this);
16421 this.cells = this.el.select('.fc-day',true);
16422 //Roo.log(this.cells);
16423 this.textNodes = this.el.query('.fc-day-number');
16424 this.cells.addClassOnOver('fc-state-hover');
16426 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16427 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16428 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16429 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16431 this.on('monthchange', this.onMonthChange, this);
16433 this.update(new Date().clearTime());
16436 resize : function() {
16437 var sz = this.el.getSize();
16439 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16440 this.el.select('.fc-day-content div',true).setHeight(34);
16445 showPrevMonth : function(e){
16446 this.update(this.activeDate.add("mo", -1));
16448 showToday : function(e){
16449 this.update(new Date().clearTime());
16452 showNextMonth : function(e){
16453 this.update(this.activeDate.add("mo", 1));
16457 showPrevYear : function(){
16458 this.update(this.activeDate.add("y", -1));
16462 showNextYear : function(){
16463 this.update(this.activeDate.add("y", 1));
16468 update : function(date)
16470 var vd = this.activeDate;
16471 this.activeDate = date;
16472 // if(vd && this.el){
16473 // var t = date.getTime();
16474 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16475 // Roo.log('using add remove');
16477 // this.fireEvent('monthchange', this, date);
16479 // this.cells.removeClass("fc-state-highlight");
16480 // this.cells.each(function(c){
16481 // if(c.dateValue == t){
16482 // c.addClass("fc-state-highlight");
16483 // setTimeout(function(){
16484 // try{c.dom.firstChild.focus();}catch(e){}
16494 var days = date.getDaysInMonth();
16496 var firstOfMonth = date.getFirstDateOfMonth();
16497 var startingPos = firstOfMonth.getDay()-this.startDay;
16499 if(startingPos < this.startDay){
16503 var pm = date.add(Date.MONTH, -1);
16504 var prevStart = pm.getDaysInMonth()-startingPos;
16506 this.cells = this.el.select('.fc-day',true);
16507 this.textNodes = this.el.query('.fc-day-number');
16508 this.cells.addClassOnOver('fc-state-hover');
16510 var cells = this.cells.elements;
16511 var textEls = this.textNodes;
16513 Roo.each(cells, function(cell){
16514 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16517 days += startingPos;
16519 // convert everything to numbers so it's fast
16520 var day = 86400000;
16521 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16524 //Roo.log(prevStart);
16526 var today = new Date().clearTime().getTime();
16527 var sel = date.clearTime().getTime();
16528 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16529 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16530 var ddMatch = this.disabledDatesRE;
16531 var ddText = this.disabledDatesText;
16532 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16533 var ddaysText = this.disabledDaysText;
16534 var format = this.format;
16536 var setCellClass = function(cal, cell){
16540 //Roo.log('set Cell Class');
16542 var t = d.getTime();
16546 cell.dateValue = t;
16548 cell.className += " fc-today";
16549 cell.className += " fc-state-highlight";
16550 cell.title = cal.todayText;
16553 // disable highlight in other month..
16554 //cell.className += " fc-state-highlight";
16559 cell.className = " fc-state-disabled";
16560 cell.title = cal.minText;
16564 cell.className = " fc-state-disabled";
16565 cell.title = cal.maxText;
16569 if(ddays.indexOf(d.getDay()) != -1){
16570 cell.title = ddaysText;
16571 cell.className = " fc-state-disabled";
16574 if(ddMatch && format){
16575 var fvalue = d.dateFormat(format);
16576 if(ddMatch.test(fvalue)){
16577 cell.title = ddText.replace("%0", fvalue);
16578 cell.className = " fc-state-disabled";
16582 if (!cell.initialClassName) {
16583 cell.initialClassName = cell.dom.className;
16586 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16591 for(; i < startingPos; i++) {
16592 textEls[i].innerHTML = (++prevStart);
16593 d.setDate(d.getDate()+1);
16595 cells[i].className = "fc-past fc-other-month";
16596 setCellClass(this, cells[i]);
16601 for(; i < days; i++){
16602 intDay = i - startingPos + 1;
16603 textEls[i].innerHTML = (intDay);
16604 d.setDate(d.getDate()+1);
16606 cells[i].className = ''; // "x-date-active";
16607 setCellClass(this, cells[i]);
16611 for(; i < 42; i++) {
16612 textEls[i].innerHTML = (++extraDays);
16613 d.setDate(d.getDate()+1);
16615 cells[i].className = "fc-future fc-other-month";
16616 setCellClass(this, cells[i]);
16619 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16621 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16623 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16624 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16626 if(totalRows != 6){
16627 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16628 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16631 this.fireEvent('monthchange', this, date);
16635 if(!this.internalRender){
16636 var main = this.el.dom.firstChild;
16637 var w = main.offsetWidth;
16638 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16639 Roo.fly(main).setWidth(w);
16640 this.internalRender = true;
16641 // opera does not respect the auto grow header center column
16642 // then, after it gets a width opera refuses to recalculate
16643 // without a second pass
16644 if(Roo.isOpera && !this.secondPass){
16645 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16646 this.secondPass = true;
16647 this.update.defer(10, this, [date]);
16654 findCell : function(dt) {
16655 dt = dt.clearTime().getTime();
16657 this.cells.each(function(c){
16658 //Roo.log("check " +c.dateValue + '?=' + dt);
16659 if(c.dateValue == dt){
16669 findCells : function(ev) {
16670 var s = ev.start.clone().clearTime().getTime();
16672 var e= ev.end.clone().clearTime().getTime();
16675 this.cells.each(function(c){
16676 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16678 if(c.dateValue > e){
16681 if(c.dateValue < s){
16690 // findBestRow: function(cells)
16694 // for (var i =0 ; i < cells.length;i++) {
16695 // ret = Math.max(cells[i].rows || 0,ret);
16702 addItem : function(ev)
16704 // look for vertical location slot in
16705 var cells = this.findCells(ev);
16707 // ev.row = this.findBestRow(cells);
16709 // work out the location.
16713 for(var i =0; i < cells.length; i++) {
16715 cells[i].row = cells[0].row;
16718 cells[i].row = cells[i].row + 1;
16728 if (crow.start.getY() == cells[i].getY()) {
16730 crow.end = cells[i];
16747 cells[0].events.push(ev);
16749 this.calevents.push(ev);
16752 clearEvents: function() {
16754 if(!this.calevents){
16758 Roo.each(this.cells.elements, function(c){
16764 Roo.each(this.calevents, function(e) {
16765 Roo.each(e.els, function(el) {
16766 el.un('mouseenter' ,this.onEventEnter, this);
16767 el.un('mouseleave' ,this.onEventLeave, this);
16772 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16778 renderEvents: function()
16782 this.cells.each(function(c) {
16791 if(c.row != c.events.length){
16792 r = 4 - (4 - (c.row - c.events.length));
16795 c.events = ev.slice(0, r);
16796 c.more = ev.slice(r);
16798 if(c.more.length && c.more.length == 1){
16799 c.events.push(c.more.pop());
16802 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16806 this.cells.each(function(c) {
16808 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16811 for (var e = 0; e < c.events.length; e++){
16812 var ev = c.events[e];
16813 var rows = ev.rows;
16815 for(var i = 0; i < rows.length; i++) {
16817 // how many rows should it span..
16820 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16821 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16823 unselectable : "on",
16826 cls: 'fc-event-inner',
16830 // cls: 'fc-event-time',
16831 // html : cells.length > 1 ? '' : ev.time
16835 cls: 'fc-event-title',
16836 html : String.format('{0}', ev.title)
16843 cls: 'ui-resizable-handle ui-resizable-e',
16844 html : '  '
16851 cfg.cls += ' fc-event-start';
16853 if ((i+1) == rows.length) {
16854 cfg.cls += ' fc-event-end';
16857 var ctr = _this.el.select('.fc-event-container',true).first();
16858 var cg = ctr.createChild(cfg);
16860 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16861 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16863 var r = (c.more.length) ? 1 : 0;
16864 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16865 cg.setWidth(ebox.right - sbox.x -2);
16867 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16868 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16869 cg.on('click', _this.onEventClick, _this, ev);
16880 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16881 style : 'position: absolute',
16882 unselectable : "on",
16885 cls: 'fc-event-inner',
16889 cls: 'fc-event-title',
16897 cls: 'ui-resizable-handle ui-resizable-e',
16898 html : '  '
16904 var ctr = _this.el.select('.fc-event-container',true).first();
16905 var cg = ctr.createChild(cfg);
16907 var sbox = c.select('.fc-day-content',true).first().getBox();
16908 var ebox = c.select('.fc-day-content',true).first().getBox();
16910 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16911 cg.setWidth(ebox.right - sbox.x -2);
16913 cg.on('click', _this.onMoreEventClick, _this, c.more);
16923 onEventEnter: function (e, el,event,d) {
16924 this.fireEvent('evententer', this, el, event);
16927 onEventLeave: function (e, el,event,d) {
16928 this.fireEvent('eventleave', this, el, event);
16931 onEventClick: function (e, el,event,d) {
16932 this.fireEvent('eventclick', this, el, event);
16935 onMonthChange: function () {
16939 onMoreEventClick: function(e, el, more)
16943 this.calpopover.placement = 'right';
16944 this.calpopover.setTitle('More');
16946 this.calpopover.setContent('');
16948 var ctr = this.calpopover.el.select('.popover-content', true).first();
16950 Roo.each(more, function(m){
16952 cls : 'fc-event-hori fc-event-draggable',
16955 var cg = ctr.createChild(cfg);
16957 cg.on('click', _this.onEventClick, _this, m);
16960 this.calpopover.show(el);
16965 onLoad: function ()
16967 this.calevents = [];
16970 if(this.store.getCount() > 0){
16971 this.store.data.each(function(d){
16974 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16975 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16976 time : d.data.start_time,
16977 title : d.data.title,
16978 description : d.data.description,
16979 venue : d.data.venue
16984 this.renderEvents();
16986 if(this.calevents.length && this.loadMask){
16987 this.maskEl.hide();
16991 onBeforeLoad: function()
16993 this.clearEvents();
16995 this.maskEl.show();
17009 * @class Roo.bootstrap.Popover
17010 * @extends Roo.bootstrap.Component
17011 * Bootstrap Popover class
17012 * @cfg {String} html contents of the popover (or false to use children..)
17013 * @cfg {String} title of popover (or false to hide)
17014 * @cfg {String} placement how it is placed
17015 * @cfg {String} trigger click || hover (or false to trigger manually)
17016 * @cfg {String} over what (parent or false to trigger manually.)
17017 * @cfg {Number} delay - delay before showing
17020 * Create a new Popover
17021 * @param {Object} config The config object
17024 Roo.bootstrap.Popover = function(config){
17025 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17031 * After the popover show
17033 * @param {Roo.bootstrap.Popover} this
17038 * After the popover hide
17040 * @param {Roo.bootstrap.Popover} this
17046 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17048 title: 'Fill in a title',
17051 placement : 'right',
17052 trigger : 'hover', // hover
17058 can_build_overlaid : false,
17060 getChildContainer : function()
17062 return this.el.select('.popover-content',true).first();
17065 getAutoCreate : function(){
17068 cls : 'popover roo-dynamic',
17069 style: 'display:block',
17075 cls : 'popover-inner',
17079 cls: 'popover-title',
17083 cls : 'popover-content',
17094 setTitle: function(str)
17097 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17099 setContent: function(str)
17102 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17104 // as it get's added to the bottom of the page.
17105 onRender : function(ct, position)
17107 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17109 var cfg = Roo.apply({}, this.getAutoCreate());
17113 cfg.cls += ' ' + this.cls;
17116 cfg.style = this.style;
17118 //Roo.log("adding to ");
17119 this.el = Roo.get(document.body).createChild(cfg, position);
17120 // Roo.log(this.el);
17125 initEvents : function()
17127 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17128 this.el.enableDisplayMode('block');
17130 if (this.over === false) {
17133 if (this.triggers === false) {
17136 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17137 var triggers = this.trigger ? this.trigger.split(' ') : [];
17138 Roo.each(triggers, function(trigger) {
17140 if (trigger == 'click') {
17141 on_el.on('click', this.toggle, this);
17142 } else if (trigger != 'manual') {
17143 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17144 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17146 on_el.on(eventIn ,this.enter, this);
17147 on_el.on(eventOut, this.leave, this);
17158 toggle : function () {
17159 this.hoverState == 'in' ? this.leave() : this.enter();
17162 enter : function () {
17164 clearTimeout(this.timeout);
17166 this.hoverState = 'in';
17168 if (!this.delay || !this.delay.show) {
17173 this.timeout = setTimeout(function () {
17174 if (_t.hoverState == 'in') {
17177 }, this.delay.show)
17180 leave : function() {
17181 clearTimeout(this.timeout);
17183 this.hoverState = 'out';
17185 if (!this.delay || !this.delay.hide) {
17190 this.timeout = setTimeout(function () {
17191 if (_t.hoverState == 'out') {
17194 }, this.delay.hide)
17197 show : function (on_el)
17200 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17204 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17205 if (this.html !== false) {
17206 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17208 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17209 if (!this.title.length) {
17210 this.el.select('.popover-title',true).hide();
17213 var placement = typeof this.placement == 'function' ?
17214 this.placement.call(this, this.el, on_el) :
17217 var autoToken = /\s?auto?\s?/i;
17218 var autoPlace = autoToken.test(placement);
17220 placement = placement.replace(autoToken, '') || 'top';
17224 //this.el.setXY([0,0]);
17226 this.el.dom.style.display='block';
17227 this.el.addClass(placement);
17229 //this.el.appendTo(on_el);
17231 var p = this.getPosition();
17232 var box = this.el.getBox();
17237 var align = Roo.bootstrap.Popover.alignment[placement];
17238 this.el.alignTo(on_el, align[0],align[1]);
17239 //var arrow = this.el.select('.arrow',true).first();
17240 //arrow.set(align[2],
17242 this.el.addClass('in');
17245 if (this.el.hasClass('fade')) {
17249 this.hoverState = 'in';
17251 this.fireEvent('show', this);
17256 this.el.setXY([0,0]);
17257 this.el.removeClass('in');
17259 this.hoverState = null;
17261 this.fireEvent('hide', this);
17266 Roo.bootstrap.Popover.alignment = {
17267 'left' : ['r-l', [-10,0], 'right'],
17268 'right' : ['l-r', [10,0], 'left'],
17269 'bottom' : ['t-b', [0,10], 'top'],
17270 'top' : [ 'b-t', [0,-10], 'bottom']
17281 * @class Roo.bootstrap.Progress
17282 * @extends Roo.bootstrap.Component
17283 * Bootstrap Progress class
17284 * @cfg {Boolean} striped striped of the progress bar
17285 * @cfg {Boolean} active animated of the progress bar
17289 * Create a new Progress
17290 * @param {Object} config The config object
17293 Roo.bootstrap.Progress = function(config){
17294 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17297 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17302 getAutoCreate : function(){
17310 cfg.cls += ' progress-striped';
17314 cfg.cls += ' active';
17333 * @class Roo.bootstrap.ProgressBar
17334 * @extends Roo.bootstrap.Component
17335 * Bootstrap ProgressBar class
17336 * @cfg {Number} aria_valuenow aria-value now
17337 * @cfg {Number} aria_valuemin aria-value min
17338 * @cfg {Number} aria_valuemax aria-value max
17339 * @cfg {String} label label for the progress bar
17340 * @cfg {String} panel (success | info | warning | danger )
17341 * @cfg {String} role role of the progress bar
17342 * @cfg {String} sr_only text
17346 * Create a new ProgressBar
17347 * @param {Object} config The config object
17350 Roo.bootstrap.ProgressBar = function(config){
17351 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17354 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17358 aria_valuemax : 100,
17364 getAutoCreate : function()
17369 cls: 'progress-bar',
17370 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17382 cfg.role = this.role;
17385 if(this.aria_valuenow){
17386 cfg['aria-valuenow'] = this.aria_valuenow;
17389 if(this.aria_valuemin){
17390 cfg['aria-valuemin'] = this.aria_valuemin;
17393 if(this.aria_valuemax){
17394 cfg['aria-valuemax'] = this.aria_valuemax;
17397 if(this.label && !this.sr_only){
17398 cfg.html = this.label;
17402 cfg.cls += ' progress-bar-' + this.panel;
17408 update : function(aria_valuenow)
17410 this.aria_valuenow = aria_valuenow;
17412 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17427 * @class Roo.bootstrap.TabGroup
17428 * @extends Roo.bootstrap.Column
17429 * Bootstrap Column class
17430 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17431 * @cfg {Boolean} carousel true to make the group behave like a carousel
17432 * @cfg {Boolean} bullets show bullets for the panels
17433 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17434 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17435 * @cfg {Boolean} showarrow (true|false) show arrow default true
17438 * Create a new TabGroup
17439 * @param {Object} config The config object
17442 Roo.bootstrap.TabGroup = function(config){
17443 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17445 this.navId = Roo.id();
17448 Roo.bootstrap.TabGroup.register(this);
17452 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17455 transition : false,
17460 slideOnTouch : false,
17463 getAutoCreate : function()
17465 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17467 cfg.cls += ' tab-content';
17469 if (this.carousel) {
17470 cfg.cls += ' carousel slide';
17473 cls : 'carousel-inner',
17477 if(this.bullets && !Roo.isTouch){
17480 cls : 'carousel-bullets',
17484 if(this.bullets_cls){
17485 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17492 cfg.cn[0].cn.push(bullets);
17495 if(this.showarrow){
17496 cfg.cn[0].cn.push({
17498 class : 'carousel-arrow',
17502 class : 'carousel-prev',
17506 class : 'fa fa-chevron-left'
17512 class : 'carousel-next',
17516 class : 'fa fa-chevron-right'
17529 initEvents: function()
17531 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17532 // this.el.on("touchstart", this.onTouchStart, this);
17535 if(this.autoslide){
17538 this.slideFn = window.setInterval(function() {
17539 _this.showPanelNext();
17543 if(this.showarrow){
17544 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17545 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17551 // onTouchStart : function(e, el, o)
17553 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17557 // this.showPanelNext();
17561 getChildContainer : function()
17563 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17567 * register a Navigation item
17568 * @param {Roo.bootstrap.NavItem} the navitem to add
17570 register : function(item)
17572 this.tabs.push( item);
17573 item.navId = this.navId; // not really needed..
17578 getActivePanel : function()
17581 Roo.each(this.tabs, function(t) {
17591 getPanelByName : function(n)
17594 Roo.each(this.tabs, function(t) {
17595 if (t.tabId == n) {
17603 indexOfPanel : function(p)
17606 Roo.each(this.tabs, function(t,i) {
17607 if (t.tabId == p.tabId) {
17616 * show a specific panel
17617 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17618 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17620 showPanel : function (pan)
17622 if(this.transition || typeof(pan) == 'undefined'){
17623 Roo.log("waiting for the transitionend");
17627 if (typeof(pan) == 'number') {
17628 pan = this.tabs[pan];
17631 if (typeof(pan) == 'string') {
17632 pan = this.getPanelByName(pan);
17635 var cur = this.getActivePanel();
17638 Roo.log('pan or acitve pan is undefined');
17642 if (pan.tabId == this.getActivePanel().tabId) {
17646 if (false === cur.fireEvent('beforedeactivate')) {
17650 if(this.bullets > 0 && !Roo.isTouch){
17651 this.setActiveBullet(this.indexOfPanel(pan));
17654 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17656 this.transition = true;
17657 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17658 var lr = dir == 'next' ? 'left' : 'right';
17659 pan.el.addClass(dir); // or prev
17660 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17661 cur.el.addClass(lr); // or right
17662 pan.el.addClass(lr);
17665 cur.el.on('transitionend', function() {
17666 Roo.log("trans end?");
17668 pan.el.removeClass([lr,dir]);
17669 pan.setActive(true);
17671 cur.el.removeClass([lr]);
17672 cur.setActive(false);
17674 _this.transition = false;
17676 }, this, { single: true } );
17681 cur.setActive(false);
17682 pan.setActive(true);
17687 showPanelNext : function()
17689 var i = this.indexOfPanel(this.getActivePanel());
17691 if (i >= this.tabs.length - 1 && !this.autoslide) {
17695 if (i >= this.tabs.length - 1 && this.autoslide) {
17699 this.showPanel(this.tabs[i+1]);
17702 showPanelPrev : function()
17704 var i = this.indexOfPanel(this.getActivePanel());
17706 if (i < 1 && !this.autoslide) {
17710 if (i < 1 && this.autoslide) {
17711 i = this.tabs.length;
17714 this.showPanel(this.tabs[i-1]);
17718 addBullet: function()
17720 if(!this.bullets || Roo.isTouch){
17723 var ctr = this.el.select('.carousel-bullets',true).first();
17724 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17725 var bullet = ctr.createChild({
17726 cls : 'bullet bullet-' + i
17727 },ctr.dom.lastChild);
17732 bullet.on('click', (function(e, el, o, ii, t){
17734 e.preventDefault();
17736 this.showPanel(ii);
17738 if(this.autoslide && this.slideFn){
17739 clearInterval(this.slideFn);
17740 this.slideFn = window.setInterval(function() {
17741 _this.showPanelNext();
17745 }).createDelegate(this, [i, bullet], true));
17750 setActiveBullet : function(i)
17756 Roo.each(this.el.select('.bullet', true).elements, function(el){
17757 el.removeClass('selected');
17760 var bullet = this.el.select('.bullet-' + i, true).first();
17766 bullet.addClass('selected');
17777 Roo.apply(Roo.bootstrap.TabGroup, {
17781 * register a Navigation Group
17782 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17784 register : function(navgrp)
17786 this.groups[navgrp.navId] = navgrp;
17790 * fetch a Navigation Group based on the navigation ID
17791 * if one does not exist , it will get created.
17792 * @param {string} the navgroup to add
17793 * @returns {Roo.bootstrap.NavGroup} the navgroup
17795 get: function(navId) {
17796 if (typeof(this.groups[navId]) == 'undefined') {
17797 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17799 return this.groups[navId] ;
17814 * @class Roo.bootstrap.TabPanel
17815 * @extends Roo.bootstrap.Component
17816 * Bootstrap TabPanel class
17817 * @cfg {Boolean} active panel active
17818 * @cfg {String} html panel content
17819 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17820 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17821 * @cfg {String} href click to link..
17825 * Create a new TabPanel
17826 * @param {Object} config The config object
17829 Roo.bootstrap.TabPanel = function(config){
17830 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17834 * Fires when the active status changes
17835 * @param {Roo.bootstrap.TabPanel} this
17836 * @param {Boolean} state the new state
17841 * @event beforedeactivate
17842 * Fires before a tab is de-activated - can be used to do validation on a form.
17843 * @param {Roo.bootstrap.TabPanel} this
17844 * @return {Boolean} false if there is an error
17847 'beforedeactivate': true
17850 this.tabId = this.tabId || Roo.id();
17854 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17862 getAutoCreate : function(){
17865 // item is needed for carousel - not sure if it has any effect otherwise
17866 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17867 html: this.html || ''
17871 cfg.cls += ' active';
17875 cfg.tabId = this.tabId;
17882 initEvents: function()
17884 var p = this.parent();
17886 this.navId = this.navId || p.navId;
17888 if (typeof(this.navId) != 'undefined') {
17889 // not really needed.. but just in case.. parent should be a NavGroup.
17890 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17894 var i = tg.tabs.length - 1;
17896 if(this.active && tg.bullets > 0 && i < tg.bullets){
17897 tg.setActiveBullet(i);
17901 this.el.on('click', this.onClick, this);
17904 this.el.on("touchstart", this.onTouchStart, this);
17905 this.el.on("touchmove", this.onTouchMove, this);
17906 this.el.on("touchend", this.onTouchEnd, this);
17911 onRender : function(ct, position)
17913 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17916 setActive : function(state)
17918 Roo.log("panel - set active " + this.tabId + "=" + state);
17920 this.active = state;
17922 this.el.removeClass('active');
17924 } else if (!this.el.hasClass('active')) {
17925 this.el.addClass('active');
17928 this.fireEvent('changed', this, state);
17931 onClick : function(e)
17933 e.preventDefault();
17935 if(!this.href.length){
17939 window.location.href = this.href;
17948 onTouchStart : function(e)
17950 this.swiping = false;
17952 this.startX = e.browserEvent.touches[0].clientX;
17953 this.startY = e.browserEvent.touches[0].clientY;
17956 onTouchMove : function(e)
17958 this.swiping = true;
17960 this.endX = e.browserEvent.touches[0].clientX;
17961 this.endY = e.browserEvent.touches[0].clientY;
17964 onTouchEnd : function(e)
17971 var tabGroup = this.parent();
17973 if(this.endX > this.startX){ // swiping right
17974 tabGroup.showPanelPrev();
17978 if(this.startX > this.endX){ // swiping left
17979 tabGroup.showPanelNext();
17998 * @class Roo.bootstrap.DateField
17999 * @extends Roo.bootstrap.Input
18000 * Bootstrap DateField class
18001 * @cfg {Number} weekStart default 0
18002 * @cfg {String} viewMode default empty, (months|years)
18003 * @cfg {String} minViewMode default empty, (months|years)
18004 * @cfg {Number} startDate default -Infinity
18005 * @cfg {Number} endDate default Infinity
18006 * @cfg {Boolean} todayHighlight default false
18007 * @cfg {Boolean} todayBtn default false
18008 * @cfg {Boolean} calendarWeeks default false
18009 * @cfg {Object} daysOfWeekDisabled default empty
18010 * @cfg {Boolean} singleMode default false (true | false)
18012 * @cfg {Boolean} keyboardNavigation default true
18013 * @cfg {String} language default en
18016 * Create a new DateField
18017 * @param {Object} config The config object
18020 Roo.bootstrap.DateField = function(config){
18021 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18025 * Fires when this field show.
18026 * @param {Roo.bootstrap.DateField} this
18027 * @param {Mixed} date The date value
18032 * Fires when this field hide.
18033 * @param {Roo.bootstrap.DateField} this
18034 * @param {Mixed} date The date value
18039 * Fires when select a date.
18040 * @param {Roo.bootstrap.DateField} this
18041 * @param {Mixed} date The date value
18045 * @event beforeselect
18046 * Fires when before select a date.
18047 * @param {Roo.bootstrap.DateField} this
18048 * @param {Mixed} date The date value
18050 beforeselect : true
18054 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18057 * @cfg {String} format
18058 * The default date format string which can be overriden for localization support. The format must be
18059 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18063 * @cfg {String} altFormats
18064 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18065 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18067 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18075 todayHighlight : false,
18081 keyboardNavigation: true,
18083 calendarWeeks: false,
18085 startDate: -Infinity,
18089 daysOfWeekDisabled: [],
18093 singleMode : false,
18095 UTCDate: function()
18097 return new Date(Date.UTC.apply(Date, arguments));
18100 UTCToday: function()
18102 var today = new Date();
18103 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18106 getDate: function() {
18107 var d = this.getUTCDate();
18108 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18111 getUTCDate: function() {
18115 setDate: function(d) {
18116 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18119 setUTCDate: function(d) {
18121 this.setValue(this.formatDate(this.date));
18124 onRender: function(ct, position)
18127 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18129 this.language = this.language || 'en';
18130 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18131 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18133 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18134 this.format = this.format || 'm/d/y';
18135 this.isInline = false;
18136 this.isInput = true;
18137 this.component = this.el.select('.add-on', true).first() || false;
18138 this.component = (this.component && this.component.length === 0) ? false : this.component;
18139 this.hasInput = this.component && this.inputEl().length;
18141 if (typeof(this.minViewMode === 'string')) {
18142 switch (this.minViewMode) {
18144 this.minViewMode = 1;
18147 this.minViewMode = 2;
18150 this.minViewMode = 0;
18155 if (typeof(this.viewMode === 'string')) {
18156 switch (this.viewMode) {
18169 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18171 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18173 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18175 this.picker().on('mousedown', this.onMousedown, this);
18176 this.picker().on('click', this.onClick, this);
18178 this.picker().addClass('datepicker-dropdown');
18180 this.startViewMode = this.viewMode;
18182 if(this.singleMode){
18183 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18184 v.setVisibilityMode(Roo.Element.DISPLAY);
18188 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18189 v.setStyle('width', '189px');
18193 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18194 if(!this.calendarWeeks){
18199 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18200 v.attr('colspan', function(i, val){
18201 return parseInt(val) + 1;
18206 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18208 this.setStartDate(this.startDate);
18209 this.setEndDate(this.endDate);
18211 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18218 if(this.isInline) {
18223 picker : function()
18225 return this.pickerEl;
18226 // return this.el.select('.datepicker', true).first();
18229 fillDow: function()
18231 var dowCnt = this.weekStart;
18240 if(this.calendarWeeks){
18248 while (dowCnt < this.weekStart + 7) {
18252 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18256 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18259 fillMonths: function()
18262 var months = this.picker().select('>.datepicker-months td', true).first();
18264 months.dom.innerHTML = '';
18270 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18273 months.createChild(month);
18280 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;
18282 if (this.date < this.startDate) {
18283 this.viewDate = new Date(this.startDate);
18284 } else if (this.date > this.endDate) {
18285 this.viewDate = new Date(this.endDate);
18287 this.viewDate = new Date(this.date);
18295 var d = new Date(this.viewDate),
18296 year = d.getUTCFullYear(),
18297 month = d.getUTCMonth(),
18298 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18299 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18300 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18301 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18302 currentDate = this.date && this.date.valueOf(),
18303 today = this.UTCToday();
18305 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18307 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18309 // this.picker.select('>tfoot th.today').
18310 // .text(dates[this.language].today)
18311 // .toggle(this.todayBtn !== false);
18313 this.updateNavArrows();
18316 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18318 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18320 prevMonth.setUTCDate(day);
18322 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18324 var nextMonth = new Date(prevMonth);
18326 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18328 nextMonth = nextMonth.valueOf();
18330 var fillMonths = false;
18332 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18334 while(prevMonth.valueOf() < nextMonth) {
18337 if (prevMonth.getUTCDay() === this.weekStart) {
18339 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18347 if(this.calendarWeeks){
18348 // ISO 8601: First week contains first thursday.
18349 // ISO also states week starts on Monday, but we can be more abstract here.
18351 // Start of current week: based on weekstart/current date
18352 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18353 // Thursday of this week
18354 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18355 // First Thursday of year, year from thursday
18356 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18357 // Calendar week: ms between thursdays, div ms per day, div 7 days
18358 calWeek = (th - yth) / 864e5 / 7 + 1;
18360 fillMonths.cn.push({
18368 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18370 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18373 if (this.todayHighlight &&
18374 prevMonth.getUTCFullYear() == today.getFullYear() &&
18375 prevMonth.getUTCMonth() == today.getMonth() &&
18376 prevMonth.getUTCDate() == today.getDate()) {
18377 clsName += ' today';
18380 if (currentDate && prevMonth.valueOf() === currentDate) {
18381 clsName += ' active';
18384 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18385 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18386 clsName += ' disabled';
18389 fillMonths.cn.push({
18391 cls: 'day ' + clsName,
18392 html: prevMonth.getDate()
18395 prevMonth.setDate(prevMonth.getDate()+1);
18398 var currentYear = this.date && this.date.getUTCFullYear();
18399 var currentMonth = this.date && this.date.getUTCMonth();
18401 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18403 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18404 v.removeClass('active');
18406 if(currentYear === year && k === currentMonth){
18407 v.addClass('active');
18410 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18411 v.addClass('disabled');
18417 year = parseInt(year/10, 10) * 10;
18419 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18421 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18424 for (var i = -1; i < 11; i++) {
18425 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18427 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18435 showMode: function(dir)
18438 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18441 Roo.each(this.picker().select('>div',true).elements, function(v){
18442 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18445 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18450 if(this.isInline) {
18454 this.picker().removeClass(['bottom', 'top']);
18456 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18458 * place to the top of element!
18462 this.picker().addClass('top');
18463 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18468 this.picker().addClass('bottom');
18470 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18473 parseDate : function(value)
18475 if(!value || value instanceof Date){
18478 var v = Date.parseDate(value, this.format);
18479 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18480 v = Date.parseDate(value, 'Y-m-d');
18482 if(!v && this.altFormats){
18483 if(!this.altFormatsArray){
18484 this.altFormatsArray = this.altFormats.split("|");
18486 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18487 v = Date.parseDate(value, this.altFormatsArray[i]);
18493 formatDate : function(date, fmt)
18495 return (!date || !(date instanceof Date)) ?
18496 date : date.dateFormat(fmt || this.format);
18499 onFocus : function()
18501 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18505 onBlur : function()
18507 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18509 var d = this.inputEl().getValue();
18518 this.picker().show();
18522 this.fireEvent('show', this, this.date);
18527 if(this.isInline) {
18530 this.picker().hide();
18531 this.viewMode = this.startViewMode;
18534 this.fireEvent('hide', this, this.date);
18538 onMousedown: function(e)
18540 e.stopPropagation();
18541 e.preventDefault();
18546 Roo.bootstrap.DateField.superclass.keyup.call(this);
18550 setValue: function(v)
18552 if(this.fireEvent('beforeselect', this, v) !== false){
18553 var d = new Date(this.parseDate(v) ).clearTime();
18555 if(isNaN(d.getTime())){
18556 this.date = this.viewDate = '';
18557 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18561 v = this.formatDate(d);
18563 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18565 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18569 this.fireEvent('select', this, this.date);
18573 getValue: function()
18575 return this.formatDate(this.date);
18578 fireKey: function(e)
18580 if (!this.picker().isVisible()){
18581 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18587 var dateChanged = false,
18589 newDate, newViewDate;
18594 e.preventDefault();
18598 if (!this.keyboardNavigation) {
18601 dir = e.keyCode == 37 ? -1 : 1;
18604 newDate = this.moveYear(this.date, dir);
18605 newViewDate = this.moveYear(this.viewDate, dir);
18606 } else if (e.shiftKey){
18607 newDate = this.moveMonth(this.date, dir);
18608 newViewDate = this.moveMonth(this.viewDate, dir);
18610 newDate = new Date(this.date);
18611 newDate.setUTCDate(this.date.getUTCDate() + dir);
18612 newViewDate = new Date(this.viewDate);
18613 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18615 if (this.dateWithinRange(newDate)){
18616 this.date = newDate;
18617 this.viewDate = newViewDate;
18618 this.setValue(this.formatDate(this.date));
18620 e.preventDefault();
18621 dateChanged = true;
18626 if (!this.keyboardNavigation) {
18629 dir = e.keyCode == 38 ? -1 : 1;
18631 newDate = this.moveYear(this.date, dir);
18632 newViewDate = this.moveYear(this.viewDate, dir);
18633 } else if (e.shiftKey){
18634 newDate = this.moveMonth(this.date, dir);
18635 newViewDate = this.moveMonth(this.viewDate, dir);
18637 newDate = new Date(this.date);
18638 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18639 newViewDate = new Date(this.viewDate);
18640 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18642 if (this.dateWithinRange(newDate)){
18643 this.date = newDate;
18644 this.viewDate = newViewDate;
18645 this.setValue(this.formatDate(this.date));
18647 e.preventDefault();
18648 dateChanged = true;
18652 this.setValue(this.formatDate(this.date));
18654 e.preventDefault();
18657 this.setValue(this.formatDate(this.date));
18671 onClick: function(e)
18673 e.stopPropagation();
18674 e.preventDefault();
18676 var target = e.getTarget();
18678 if(target.nodeName.toLowerCase() === 'i'){
18679 target = Roo.get(target).dom.parentNode;
18682 var nodeName = target.nodeName;
18683 var className = target.className;
18684 var html = target.innerHTML;
18685 //Roo.log(nodeName);
18687 switch(nodeName.toLowerCase()) {
18689 switch(className) {
18695 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18696 switch(this.viewMode){
18698 this.viewDate = this.moveMonth(this.viewDate, dir);
18702 this.viewDate = this.moveYear(this.viewDate, dir);
18708 var date = new Date();
18709 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18711 this.setValue(this.formatDate(this.date));
18718 if (className.indexOf('disabled') < 0) {
18719 this.viewDate.setUTCDate(1);
18720 if (className.indexOf('month') > -1) {
18721 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18723 var year = parseInt(html, 10) || 0;
18724 this.viewDate.setUTCFullYear(year);
18728 if(this.singleMode){
18729 this.setValue(this.formatDate(this.viewDate));
18740 //Roo.log(className);
18741 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18742 var day = parseInt(html, 10) || 1;
18743 var year = this.viewDate.getUTCFullYear(),
18744 month = this.viewDate.getUTCMonth();
18746 if (className.indexOf('old') > -1) {
18753 } else if (className.indexOf('new') > -1) {
18761 //Roo.log([year,month,day]);
18762 this.date = this.UTCDate(year, month, day,0,0,0,0);
18763 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18765 //Roo.log(this.formatDate(this.date));
18766 this.setValue(this.formatDate(this.date));
18773 setStartDate: function(startDate)
18775 this.startDate = startDate || -Infinity;
18776 if (this.startDate !== -Infinity) {
18777 this.startDate = this.parseDate(this.startDate);
18780 this.updateNavArrows();
18783 setEndDate: function(endDate)
18785 this.endDate = endDate || Infinity;
18786 if (this.endDate !== Infinity) {
18787 this.endDate = this.parseDate(this.endDate);
18790 this.updateNavArrows();
18793 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18795 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18796 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18797 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18799 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18800 return parseInt(d, 10);
18803 this.updateNavArrows();
18806 updateNavArrows: function()
18808 if(this.singleMode){
18812 var d = new Date(this.viewDate),
18813 year = d.getUTCFullYear(),
18814 month = d.getUTCMonth();
18816 Roo.each(this.picker().select('.prev', true).elements, function(v){
18818 switch (this.viewMode) {
18821 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18827 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18834 Roo.each(this.picker().select('.next', true).elements, function(v){
18836 switch (this.viewMode) {
18839 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18845 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18853 moveMonth: function(date, dir)
18858 var new_date = new Date(date.valueOf()),
18859 day = new_date.getUTCDate(),
18860 month = new_date.getUTCMonth(),
18861 mag = Math.abs(dir),
18863 dir = dir > 0 ? 1 : -1;
18866 // If going back one month, make sure month is not current month
18867 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18869 return new_date.getUTCMonth() == month;
18871 // If going forward one month, make sure month is as expected
18872 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18874 return new_date.getUTCMonth() != new_month;
18876 new_month = month + dir;
18877 new_date.setUTCMonth(new_month);
18878 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18879 if (new_month < 0 || new_month > 11) {
18880 new_month = (new_month + 12) % 12;
18883 // For magnitudes >1, move one month at a time...
18884 for (var i=0; i<mag; i++) {
18885 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18886 new_date = this.moveMonth(new_date, dir);
18888 // ...then reset the day, keeping it in the new month
18889 new_month = new_date.getUTCMonth();
18890 new_date.setUTCDate(day);
18892 return new_month != new_date.getUTCMonth();
18895 // Common date-resetting loop -- if date is beyond end of month, make it
18898 new_date.setUTCDate(--day);
18899 new_date.setUTCMonth(new_month);
18904 moveYear: function(date, dir)
18906 return this.moveMonth(date, dir*12);
18909 dateWithinRange: function(date)
18911 return date >= this.startDate && date <= this.endDate;
18917 this.picker().remove();
18920 validateValue : function(value)
18922 if(value.length < 1) {
18923 if(this.allowBlank){
18929 if(value.length < this.minLength){
18932 if(value.length > this.maxLength){
18936 var vt = Roo.form.VTypes;
18937 if(!vt[this.vtype](value, this)){
18941 if(typeof this.validator == "function"){
18942 var msg = this.validator(value);
18948 if(this.regex && !this.regex.test(value)){
18952 if(typeof(this.parseDate(value)) == 'undefined'){
18956 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18960 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18970 Roo.apply(Roo.bootstrap.DateField, {
18981 html: '<i class="fa fa-arrow-left"/>'
18991 html: '<i class="fa fa-arrow-right"/>'
19033 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19034 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19035 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19036 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19037 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19050 navFnc: 'FullYear',
19055 navFnc: 'FullYear',
19060 Roo.apply(Roo.bootstrap.DateField, {
19064 cls: 'datepicker dropdown-menu roo-dynamic',
19068 cls: 'datepicker-days',
19072 cls: 'table-condensed',
19074 Roo.bootstrap.DateField.head,
19078 Roo.bootstrap.DateField.footer
19085 cls: 'datepicker-months',
19089 cls: 'table-condensed',
19091 Roo.bootstrap.DateField.head,
19092 Roo.bootstrap.DateField.content,
19093 Roo.bootstrap.DateField.footer
19100 cls: 'datepicker-years',
19104 cls: 'table-condensed',
19106 Roo.bootstrap.DateField.head,
19107 Roo.bootstrap.DateField.content,
19108 Roo.bootstrap.DateField.footer
19127 * @class Roo.bootstrap.TimeField
19128 * @extends Roo.bootstrap.Input
19129 * Bootstrap DateField class
19133 * Create a new TimeField
19134 * @param {Object} config The config object
19137 Roo.bootstrap.TimeField = function(config){
19138 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19142 * Fires when this field show.
19143 * @param {Roo.bootstrap.DateField} thisthis
19144 * @param {Mixed} date The date value
19149 * Fires when this field hide.
19150 * @param {Roo.bootstrap.DateField} this
19151 * @param {Mixed} date The date value
19156 * Fires when select a date.
19157 * @param {Roo.bootstrap.DateField} this
19158 * @param {Mixed} date The date value
19164 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19167 * @cfg {String} format
19168 * The default time format string which can be overriden for localization support. The format must be
19169 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19173 onRender: function(ct, position)
19176 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19178 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19180 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19182 this.pop = this.picker().select('>.datepicker-time',true).first();
19183 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19185 this.picker().on('mousedown', this.onMousedown, this);
19186 this.picker().on('click', this.onClick, this);
19188 this.picker().addClass('datepicker-dropdown');
19193 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19194 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19195 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19196 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19197 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19198 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19202 fireKey: function(e){
19203 if (!this.picker().isVisible()){
19204 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19210 e.preventDefault();
19218 this.onTogglePeriod();
19221 this.onIncrementMinutes();
19224 this.onDecrementMinutes();
19233 onClick: function(e) {
19234 e.stopPropagation();
19235 e.preventDefault();
19238 picker : function()
19240 return this.el.select('.datepicker', true).first();
19243 fillTime: function()
19245 var time = this.pop.select('tbody', true).first();
19247 time.dom.innerHTML = '';
19262 cls: 'hours-up glyphicon glyphicon-chevron-up'
19282 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19303 cls: 'timepicker-hour',
19318 cls: 'timepicker-minute',
19333 cls: 'btn btn-primary period',
19355 cls: 'hours-down glyphicon glyphicon-chevron-down'
19375 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19393 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19400 var hours = this.time.getHours();
19401 var minutes = this.time.getMinutes();
19414 hours = hours - 12;
19418 hours = '0' + hours;
19422 minutes = '0' + minutes;
19425 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19426 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19427 this.pop.select('button', true).first().dom.innerHTML = period;
19433 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19435 var cls = ['bottom'];
19437 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19444 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19449 this.picker().addClass(cls.join('-'));
19453 Roo.each(cls, function(c){
19455 _this.picker().setTop(_this.inputEl().getHeight());
19459 _this.picker().setTop(0 - _this.picker().getHeight());
19464 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19468 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19475 onFocus : function()
19477 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19481 onBlur : function()
19483 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19489 this.picker().show();
19494 this.fireEvent('show', this, this.date);
19499 this.picker().hide();
19502 this.fireEvent('hide', this, this.date);
19505 setTime : function()
19508 this.setValue(this.time.format(this.format));
19510 this.fireEvent('select', this, this.date);
19515 onMousedown: function(e){
19516 e.stopPropagation();
19517 e.preventDefault();
19520 onIncrementHours: function()
19522 Roo.log('onIncrementHours');
19523 this.time = this.time.add(Date.HOUR, 1);
19528 onDecrementHours: function()
19530 Roo.log('onDecrementHours');
19531 this.time = this.time.add(Date.HOUR, -1);
19535 onIncrementMinutes: function()
19537 Roo.log('onIncrementMinutes');
19538 this.time = this.time.add(Date.MINUTE, 1);
19542 onDecrementMinutes: function()
19544 Roo.log('onDecrementMinutes');
19545 this.time = this.time.add(Date.MINUTE, -1);
19549 onTogglePeriod: function()
19551 Roo.log('onTogglePeriod');
19552 this.time = this.time.add(Date.HOUR, 12);
19559 Roo.apply(Roo.bootstrap.TimeField, {
19589 cls: 'btn btn-info ok',
19601 Roo.apply(Roo.bootstrap.TimeField, {
19605 cls: 'datepicker dropdown-menu',
19609 cls: 'datepicker-time',
19613 cls: 'table-condensed',
19615 Roo.bootstrap.TimeField.content,
19616 Roo.bootstrap.TimeField.footer
19635 * @class Roo.bootstrap.MonthField
19636 * @extends Roo.bootstrap.Input
19637 * Bootstrap MonthField class
19639 * @cfg {String} language default en
19642 * Create a new MonthField
19643 * @param {Object} config The config object
19646 Roo.bootstrap.MonthField = function(config){
19647 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19652 * Fires when this field show.
19653 * @param {Roo.bootstrap.MonthField} this
19654 * @param {Mixed} date The date value
19659 * Fires when this field hide.
19660 * @param {Roo.bootstrap.MonthField} this
19661 * @param {Mixed} date The date value
19666 * Fires when select a date.
19667 * @param {Roo.bootstrap.MonthField} this
19668 * @param {String} oldvalue The old value
19669 * @param {String} newvalue The new value
19675 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19677 onRender: function(ct, position)
19680 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19682 this.language = this.language || 'en';
19683 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19684 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19686 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19687 this.isInline = false;
19688 this.isInput = true;
19689 this.component = this.el.select('.add-on', true).first() || false;
19690 this.component = (this.component && this.component.length === 0) ? false : this.component;
19691 this.hasInput = this.component && this.inputEL().length;
19693 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19695 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19697 this.picker().on('mousedown', this.onMousedown, this);
19698 this.picker().on('click', this.onClick, this);
19700 this.picker().addClass('datepicker-dropdown');
19702 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19703 v.setStyle('width', '189px');
19710 if(this.isInline) {
19716 setValue: function(v, suppressEvent)
19718 var o = this.getValue();
19720 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19724 if(suppressEvent !== true){
19725 this.fireEvent('select', this, o, v);
19730 getValue: function()
19735 onClick: function(e)
19737 e.stopPropagation();
19738 e.preventDefault();
19740 var target = e.getTarget();
19742 if(target.nodeName.toLowerCase() === 'i'){
19743 target = Roo.get(target).dom.parentNode;
19746 var nodeName = target.nodeName;
19747 var className = target.className;
19748 var html = target.innerHTML;
19750 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19754 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19756 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19762 picker : function()
19764 return this.pickerEl;
19767 fillMonths: function()
19770 var months = this.picker().select('>.datepicker-months td', true).first();
19772 months.dom.innerHTML = '';
19778 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19781 months.createChild(month);
19790 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19791 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19794 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19795 e.removeClass('active');
19797 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19798 e.addClass('active');
19805 if(this.isInline) {
19809 this.picker().removeClass(['bottom', 'top']);
19811 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19813 * place to the top of element!
19817 this.picker().addClass('top');
19818 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19823 this.picker().addClass('bottom');
19825 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19828 onFocus : function()
19830 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19834 onBlur : function()
19836 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19838 var d = this.inputEl().getValue();
19847 this.picker().show();
19848 this.picker().select('>.datepicker-months', true).first().show();
19852 this.fireEvent('show', this, this.date);
19857 if(this.isInline) {
19860 this.picker().hide();
19861 this.fireEvent('hide', this, this.date);
19865 onMousedown: function(e)
19867 e.stopPropagation();
19868 e.preventDefault();
19873 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19877 fireKey: function(e)
19879 if (!this.picker().isVisible()){
19880 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19891 e.preventDefault();
19895 dir = e.keyCode == 37 ? -1 : 1;
19897 this.vIndex = this.vIndex + dir;
19899 if(this.vIndex < 0){
19903 if(this.vIndex > 11){
19907 if(isNaN(this.vIndex)){
19911 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19917 dir = e.keyCode == 38 ? -1 : 1;
19919 this.vIndex = this.vIndex + dir * 4;
19921 if(this.vIndex < 0){
19925 if(this.vIndex > 11){
19929 if(isNaN(this.vIndex)){
19933 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19938 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19939 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19943 e.preventDefault();
19946 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19947 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19963 this.picker().remove();
19968 Roo.apply(Roo.bootstrap.MonthField, {
19987 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19988 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19993 Roo.apply(Roo.bootstrap.MonthField, {
19997 cls: 'datepicker dropdown-menu roo-dynamic',
20001 cls: 'datepicker-months',
20005 cls: 'table-condensed',
20007 Roo.bootstrap.DateField.content
20027 * @class Roo.bootstrap.CheckBox
20028 * @extends Roo.bootstrap.Input
20029 * Bootstrap CheckBox class
20031 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20032 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20033 * @cfg {String} boxLabel The text that appears beside the checkbox
20034 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20035 * @cfg {Boolean} checked initnal the element
20036 * @cfg {Boolean} inline inline the element (default false)
20037 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20040 * Create a new CheckBox
20041 * @param {Object} config The config object
20044 Roo.bootstrap.CheckBox = function(config){
20045 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20050 * Fires when the element is checked or unchecked.
20051 * @param {Roo.bootstrap.CheckBox} this This input
20052 * @param {Boolean} checked The new checked value
20059 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20061 inputType: 'checkbox',
20069 getAutoCreate : function()
20071 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20077 cfg.cls = 'form-group ' + this.inputType; //input-group
20080 cfg.cls += ' ' + this.inputType + '-inline';
20086 type : this.inputType,
20087 value : this.inputValue,
20088 cls : 'roo-' + this.inputType, //'form-box',
20089 placeholder : this.placeholder || ''
20093 if(this.inputType != 'radio'){
20097 cls : 'roo-hidden-value',
20098 value : this.checked ? this.valueOff : this.inputValue
20103 if (this.weight) { // Validity check?
20104 cfg.cls += " " + this.inputType + "-" + this.weight;
20107 if (this.disabled) {
20108 input.disabled=true;
20112 input.checked = this.checked;
20119 input.name = this.name;
20121 if(this.inputType != 'radio'){
20122 hidden.name = this.name;
20123 input.name = '_hidden_' + this.name;
20128 input.cls += ' input-' + this.size;
20133 ['xs','sm','md','lg'].map(function(size){
20134 if (settings[size]) {
20135 cfg.cls += ' col-' + size + '-' + settings[size];
20139 var inputblock = input;
20141 if (this.before || this.after) {
20144 cls : 'input-group',
20149 inputblock.cn.push({
20151 cls : 'input-group-addon',
20156 inputblock.cn.push(input);
20158 if(this.inputType != 'radio'){
20159 inputblock.cn.push(hidden);
20163 inputblock.cn.push({
20165 cls : 'input-group-addon',
20172 if (align ==='left' && this.fieldLabel.length) {
20173 // Roo.log("left and has label");
20178 cls : 'control-label',
20179 html : this.fieldLabel
20190 if(this.labelWidth > 12){
20191 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20194 if(this.labelWidth < 13 && this.labelmd == 0){
20195 this.labelmd = this.labelWidth;
20198 if(this.labellg > 0){
20199 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20200 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20203 if(this.labelmd > 0){
20204 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20205 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20208 if(this.labelsm > 0){
20209 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20210 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20213 if(this.labelxs > 0){
20214 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20215 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20218 } else if ( this.fieldLabel.length) {
20219 // Roo.log(" label");
20223 tag: this.boxLabel ? 'span' : 'label',
20225 cls: 'control-label box-input-label',
20226 //cls : 'input-group-addon',
20227 html : this.fieldLabel
20237 // Roo.log(" no label && no align");
20238 cfg.cn = [ inputblock ] ;
20244 var boxLabelCfg = {
20246 //'for': id, // box label is handled by onclick - so no for...
20248 html: this.boxLabel
20252 boxLabelCfg.tooltip = this.tooltip;
20255 cfg.cn.push(boxLabelCfg);
20258 if(this.inputType != 'radio'){
20259 cfg.cn.push(hidden);
20267 * return the real input element.
20269 inputEl: function ()
20271 return this.el.select('input.roo-' + this.inputType,true).first();
20273 hiddenEl: function ()
20275 return this.el.select('input.roo-hidden-value',true).first();
20278 labelEl: function()
20280 return this.el.select('label.control-label',true).first();
20282 /* depricated... */
20286 return this.labelEl();
20289 boxLabelEl: function()
20291 return this.el.select('label.box-label',true).first();
20294 initEvents : function()
20296 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20298 this.inputEl().on('click', this.onClick, this);
20300 if (this.boxLabel) {
20301 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20304 this.startValue = this.getValue();
20307 Roo.bootstrap.CheckBox.register(this);
20311 onClick : function()
20313 this.setChecked(!this.checked);
20316 setChecked : function(state,suppressEvent)
20318 this.startValue = this.getValue();
20320 if(this.inputType == 'radio'){
20322 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20323 e.dom.checked = false;
20326 this.inputEl().dom.checked = true;
20328 this.inputEl().dom.value = this.inputValue;
20330 if(suppressEvent !== true){
20331 this.fireEvent('check', this, true);
20339 this.checked = state;
20341 this.inputEl().dom.checked = state;
20344 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20346 if(suppressEvent !== true){
20347 this.fireEvent('check', this, state);
20353 getValue : function()
20355 if(this.inputType == 'radio'){
20356 return this.getGroupValue();
20359 return this.hiddenEl().dom.value;
20363 getGroupValue : function()
20365 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20369 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20372 setValue : function(v,suppressEvent)
20374 if(this.inputType == 'radio'){
20375 this.setGroupValue(v, suppressEvent);
20379 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20384 setGroupValue : function(v, suppressEvent)
20386 this.startValue = this.getValue();
20388 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20389 e.dom.checked = false;
20391 if(e.dom.value == v){
20392 e.dom.checked = true;
20396 if(suppressEvent !== true){
20397 this.fireEvent('check', this, true);
20405 validate : function()
20409 (this.inputType == 'radio' && this.validateRadio()) ||
20410 (this.inputType == 'checkbox' && this.validateCheckbox())
20416 this.markInvalid();
20420 validateRadio : function()
20422 if(this.allowBlank){
20428 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20429 if(!e.dom.checked){
20441 validateCheckbox : function()
20444 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20445 //return (this.getValue() == this.inputValue) ? true : false;
20448 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20456 for(var i in group){
20461 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20468 * Mark this field as valid
20470 markValid : function()
20474 this.fireEvent('valid', this);
20476 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20479 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20486 if(this.inputType == 'radio'){
20487 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20488 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20489 e.findParent('.form-group', false, true).addClass(_this.validClass);
20496 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20497 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20501 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20507 for(var i in group){
20508 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20509 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20514 * Mark this field as invalid
20515 * @param {String} msg The validation message
20517 markInvalid : function(msg)
20519 if(this.allowBlank){
20525 this.fireEvent('invalid', this, msg);
20527 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20530 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20534 label.markInvalid();
20537 if(this.inputType == 'radio'){
20538 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20539 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20540 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20547 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20548 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20552 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20558 for(var i in group){
20559 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20560 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20565 clearInvalid : function()
20567 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20569 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20571 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20574 label.iconEl.removeClass(label.validClass);
20575 label.iconEl.removeClass(label.invalidClass);
20579 disable : function()
20581 if(this.inputType != 'radio'){
20582 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20589 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20590 _this.getActionEl().addClass(this.disabledClass);
20591 e.dom.disabled = true;
20595 this.disabled = true;
20596 this.fireEvent("disable", this);
20600 enable : function()
20602 if(this.inputType != 'radio'){
20603 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20610 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20611 _this.getActionEl().removeClass(this.disabledClass);
20612 e.dom.disabled = false;
20616 this.disabled = false;
20617 this.fireEvent("enable", this);
20623 Roo.apply(Roo.bootstrap.CheckBox, {
20628 * register a CheckBox Group
20629 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20631 register : function(checkbox)
20633 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20634 this.groups[checkbox.groupId] = {};
20637 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20641 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20645 * fetch a CheckBox Group based on the group ID
20646 * @param {string} the group ID
20647 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20649 get: function(groupId) {
20650 if (typeof(this.groups[groupId]) == 'undefined') {
20654 return this.groups[groupId] ;
20667 * @class Roo.bootstrap.Radio
20668 * @extends Roo.bootstrap.Component
20669 * Bootstrap Radio class
20670 * @cfg {String} boxLabel - the label associated
20671 * @cfg {String} value - the value of radio
20674 * Create a new Radio
20675 * @param {Object} config The config object
20677 Roo.bootstrap.Radio = function(config){
20678 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20682 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20688 getAutoCreate : function()
20692 cls : 'form-group radio',
20697 html : this.boxLabel
20705 initEvents : function()
20707 this.parent().register(this);
20709 this.el.on('click', this.onClick, this);
20713 onClick : function()
20715 this.setChecked(true);
20718 setChecked : function(state, suppressEvent)
20720 this.parent().setValue(this.value, suppressEvent);
20735 * @class Roo.bootstrap.SecurePass
20736 * @extends Roo.bootstrap.Input
20737 * Bootstrap SecurePass class
20741 * Create a new SecurePass
20742 * @param {Object} config The config object
20745 Roo.bootstrap.SecurePass = function (config) {
20746 // these go here, so the translation tool can replace them..
20748 PwdEmpty: "Please type a password, and then retype it to confirm.",
20749 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20750 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20751 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20752 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20753 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20754 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20755 TooWeak: "Your password is Too Weak."
20757 this.meterLabel = "Password strength:";
20758 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20759 this.meterClass = [
20760 "roo-password-meter-tooweak",
20761 "roo-password-meter-weak",
20762 "roo-password-meter-medium",
20763 "roo-password-meter-strong",
20764 "roo-password-meter-grey"
20769 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20772 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20774 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20776 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20777 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20778 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20779 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20780 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20781 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20782 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20792 * @cfg {String/Object} Label for the strength meter (defaults to
20793 * 'Password strength:')
20798 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20799 * ['Weak', 'Medium', 'Strong'])
20802 pwdStrengths: false,
20815 initEvents: function ()
20817 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20819 if (this.el.is('input[type=password]') && Roo.isSafari) {
20820 this.el.on('keydown', this.SafariOnKeyDown, this);
20823 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20826 onRender: function (ct, position)
20828 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20829 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20830 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20832 this.trigger.createChild({
20837 cls: 'roo-password-meter-grey col-xs-12',
20840 //width: this.meterWidth + 'px'
20844 cls: 'roo-password-meter-text'
20850 if (this.hideTrigger) {
20851 this.trigger.setDisplayed(false);
20853 this.setSize(this.width || '', this.height || '');
20856 onDestroy: function ()
20858 if (this.trigger) {
20859 this.trigger.removeAllListeners();
20860 this.trigger.remove();
20863 this.wrap.remove();
20865 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20868 checkStrength: function ()
20870 var pwd = this.inputEl().getValue();
20871 if (pwd == this._lastPwd) {
20876 if (this.ClientSideStrongPassword(pwd)) {
20878 } else if (this.ClientSideMediumPassword(pwd)) {
20880 } else if (this.ClientSideWeakPassword(pwd)) {
20886 Roo.log('strength1: ' + strength);
20888 //var pm = this.trigger.child('div/div/div').dom;
20889 var pm = this.trigger.child('div/div');
20890 pm.removeClass(this.meterClass);
20891 pm.addClass(this.meterClass[strength]);
20894 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20896 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20898 this._lastPwd = pwd;
20902 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20904 this._lastPwd = '';
20906 var pm = this.trigger.child('div/div');
20907 pm.removeClass(this.meterClass);
20908 pm.addClass('roo-password-meter-grey');
20911 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20914 this.inputEl().dom.type='password';
20917 validateValue: function (value)
20920 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20923 if (value.length == 0) {
20924 if (this.allowBlank) {
20925 this.clearInvalid();
20929 this.markInvalid(this.errors.PwdEmpty);
20930 this.errorMsg = this.errors.PwdEmpty;
20938 if ('[\x21-\x7e]*'.match(value)) {
20939 this.markInvalid(this.errors.PwdBadChar);
20940 this.errorMsg = this.errors.PwdBadChar;
20943 if (value.length < 6) {
20944 this.markInvalid(this.errors.PwdShort);
20945 this.errorMsg = this.errors.PwdShort;
20948 if (value.length > 16) {
20949 this.markInvalid(this.errors.PwdLong);
20950 this.errorMsg = this.errors.PwdLong;
20954 if (this.ClientSideStrongPassword(value)) {
20956 } else if (this.ClientSideMediumPassword(value)) {
20958 } else if (this.ClientSideWeakPassword(value)) {
20965 if (strength < 2) {
20966 //this.markInvalid(this.errors.TooWeak);
20967 this.errorMsg = this.errors.TooWeak;
20972 console.log('strength2: ' + strength);
20974 //var pm = this.trigger.child('div/div/div').dom;
20976 var pm = this.trigger.child('div/div');
20977 pm.removeClass(this.meterClass);
20978 pm.addClass(this.meterClass[strength]);
20980 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20982 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20984 this.errorMsg = '';
20988 CharacterSetChecks: function (type)
20991 this.fResult = false;
20994 isctype: function (character, type)
20997 case this.kCapitalLetter:
20998 if (character >= 'A' && character <= 'Z') {
21003 case this.kSmallLetter:
21004 if (character >= 'a' && character <= 'z') {
21010 if (character >= '0' && character <= '9') {
21015 case this.kPunctuation:
21016 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21027 IsLongEnough: function (pwd, size)
21029 return !(pwd == null || isNaN(size) || pwd.length < size);
21032 SpansEnoughCharacterSets: function (word, nb)
21034 if (!this.IsLongEnough(word, nb))
21039 var characterSetChecks = new Array(
21040 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21041 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21044 for (var index = 0; index < word.length; ++index) {
21045 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21046 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21047 characterSetChecks[nCharSet].fResult = true;
21054 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21055 if (characterSetChecks[nCharSet].fResult) {
21060 if (nCharSets < nb) {
21066 ClientSideStrongPassword: function (pwd)
21068 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21071 ClientSideMediumPassword: function (pwd)
21073 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21076 ClientSideWeakPassword: function (pwd)
21078 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21081 })//<script type="text/javascript">
21084 * Based Ext JS Library 1.1.1
21085 * Copyright(c) 2006-2007, Ext JS, LLC.
21091 * @class Roo.HtmlEditorCore
21092 * @extends Roo.Component
21093 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21095 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21098 Roo.HtmlEditorCore = function(config){
21101 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21106 * @event initialize
21107 * Fires when the editor is fully initialized (including the iframe)
21108 * @param {Roo.HtmlEditorCore} this
21113 * Fires when the editor is first receives the focus. Any insertion must wait
21114 * until after this event.
21115 * @param {Roo.HtmlEditorCore} this
21119 * @event beforesync
21120 * Fires before the textarea is updated with content from the editor iframe. Return false
21121 * to cancel the sync.
21122 * @param {Roo.HtmlEditorCore} this
21123 * @param {String} html
21127 * @event beforepush
21128 * Fires before the iframe editor is updated with content from the textarea. Return false
21129 * to cancel the push.
21130 * @param {Roo.HtmlEditorCore} this
21131 * @param {String} html
21136 * Fires when the textarea is updated with content from the editor iframe.
21137 * @param {Roo.HtmlEditorCore} this
21138 * @param {String} html
21143 * Fires when the iframe editor is updated with content from the textarea.
21144 * @param {Roo.HtmlEditorCore} this
21145 * @param {String} html
21150 * @event editorevent
21151 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21152 * @param {Roo.HtmlEditorCore} this
21158 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21160 // defaults : white / black...
21161 this.applyBlacklists();
21168 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21172 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21178 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21183 * @cfg {Number} height (in pixels)
21187 * @cfg {Number} width (in pixels)
21192 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21195 stylesheets: false,
21200 // private properties
21201 validationEvent : false,
21203 initialized : false,
21205 sourceEditMode : false,
21206 onFocus : Roo.emptyFn,
21208 hideMode:'offsets',
21212 // blacklist + whitelisted elements..
21219 * Protected method that will not generally be called directly. It
21220 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21221 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21223 getDocMarkup : function(){
21227 // inherit styels from page...??
21228 if (this.stylesheets === false) {
21230 Roo.get(document.head).select('style').each(function(node) {
21231 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21234 Roo.get(document.head).select('link').each(function(node) {
21235 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21238 } else if (!this.stylesheets.length) {
21240 st = '<style type="text/css">' +
21241 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21247 st += '<style type="text/css">' +
21248 'IMG { cursor: pointer } ' +
21252 return '<html><head>' + st +
21253 //<style type="text/css">' +
21254 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21256 ' </head><body class="roo-htmleditor-body"></body></html>';
21260 onRender : function(ct, position)
21263 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21264 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21267 this.el.dom.style.border = '0 none';
21268 this.el.dom.setAttribute('tabIndex', -1);
21269 this.el.addClass('x-hidden hide');
21273 if(Roo.isIE){ // fix IE 1px bogus margin
21274 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21278 this.frameId = Roo.id();
21282 var iframe = this.owner.wrap.createChild({
21284 cls: 'form-control', // bootstrap..
21286 name: this.frameId,
21287 frameBorder : 'no',
21288 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21293 this.iframe = iframe.dom;
21295 this.assignDocWin();
21297 this.doc.designMode = 'on';
21300 this.doc.write(this.getDocMarkup());
21304 var task = { // must defer to wait for browser to be ready
21306 //console.log("run task?" + this.doc.readyState);
21307 this.assignDocWin();
21308 if(this.doc.body || this.doc.readyState == 'complete'){
21310 this.doc.designMode="on";
21314 Roo.TaskMgr.stop(task);
21315 this.initEditor.defer(10, this);
21322 Roo.TaskMgr.start(task);
21327 onResize : function(w, h)
21329 Roo.log('resize: ' +w + ',' + h );
21330 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21334 if(typeof w == 'number'){
21336 this.iframe.style.width = w + 'px';
21338 if(typeof h == 'number'){
21340 this.iframe.style.height = h + 'px';
21342 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21349 * Toggles the editor between standard and source edit mode.
21350 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21352 toggleSourceEdit : function(sourceEditMode){
21354 this.sourceEditMode = sourceEditMode === true;
21356 if(this.sourceEditMode){
21358 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21361 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21362 //this.iframe.className = '';
21365 //this.setSize(this.owner.wrap.getSize());
21366 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21373 * Protected method that will not generally be called directly. If you need/want
21374 * custom HTML cleanup, this is the method you should override.
21375 * @param {String} html The HTML to be cleaned
21376 * return {String} The cleaned HTML
21378 cleanHtml : function(html){
21379 html = String(html);
21380 if(html.length > 5){
21381 if(Roo.isSafari){ // strip safari nonsense
21382 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21385 if(html == ' '){
21392 * HTML Editor -> Textarea
21393 * Protected method that will not generally be called directly. Syncs the contents
21394 * of the editor iframe with the textarea.
21396 syncValue : function(){
21397 if(this.initialized){
21398 var bd = (this.doc.body || this.doc.documentElement);
21399 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21400 var html = bd.innerHTML;
21402 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21403 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21405 html = '<div style="'+m[0]+'">' + html + '</div>';
21408 html = this.cleanHtml(html);
21409 // fix up the special chars.. normaly like back quotes in word...
21410 // however we do not want to do this with chinese..
21411 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21412 var cc = b.charCodeAt();
21414 (cc >= 0x4E00 && cc < 0xA000 ) ||
21415 (cc >= 0x3400 && cc < 0x4E00 ) ||
21416 (cc >= 0xf900 && cc < 0xfb00 )
21422 if(this.owner.fireEvent('beforesync', this, html) !== false){
21423 this.el.dom.value = html;
21424 this.owner.fireEvent('sync', this, html);
21430 * Protected method that will not generally be called directly. Pushes the value of the textarea
21431 * into the iframe editor.
21433 pushValue : function(){
21434 if(this.initialized){
21435 var v = this.el.dom.value.trim();
21437 // if(v.length < 1){
21441 if(this.owner.fireEvent('beforepush', this, v) !== false){
21442 var d = (this.doc.body || this.doc.documentElement);
21444 this.cleanUpPaste();
21445 this.el.dom.value = d.innerHTML;
21446 this.owner.fireEvent('push', this, v);
21452 deferFocus : function(){
21453 this.focus.defer(10, this);
21457 focus : function(){
21458 if(this.win && !this.sourceEditMode){
21465 assignDocWin: function()
21467 var iframe = this.iframe;
21470 this.doc = iframe.contentWindow.document;
21471 this.win = iframe.contentWindow;
21473 // if (!Roo.get(this.frameId)) {
21476 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21477 // this.win = Roo.get(this.frameId).dom.contentWindow;
21479 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21483 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21484 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21489 initEditor : function(){
21490 //console.log("INIT EDITOR");
21491 this.assignDocWin();
21495 this.doc.designMode="on";
21497 this.doc.write(this.getDocMarkup());
21500 var dbody = (this.doc.body || this.doc.documentElement);
21501 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21502 // this copies styles from the containing element into thsi one..
21503 // not sure why we need all of this..
21504 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21506 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21507 //ss['background-attachment'] = 'fixed'; // w3c
21508 dbody.bgProperties = 'fixed'; // ie
21509 //Roo.DomHelper.applyStyles(dbody, ss);
21510 Roo.EventManager.on(this.doc, {
21511 //'mousedown': this.onEditorEvent,
21512 'mouseup': this.onEditorEvent,
21513 'dblclick': this.onEditorEvent,
21514 'click': this.onEditorEvent,
21515 'keyup': this.onEditorEvent,
21520 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21522 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21523 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21525 this.initialized = true;
21527 this.owner.fireEvent('initialize', this);
21532 onDestroy : function(){
21538 //for (var i =0; i < this.toolbars.length;i++) {
21539 // // fixme - ask toolbars for heights?
21540 // this.toolbars[i].onDestroy();
21543 //this.wrap.dom.innerHTML = '';
21544 //this.wrap.remove();
21549 onFirstFocus : function(){
21551 this.assignDocWin();
21554 this.activated = true;
21557 if(Roo.isGecko){ // prevent silly gecko errors
21559 var s = this.win.getSelection();
21560 if(!s.focusNode || s.focusNode.nodeType != 3){
21561 var r = s.getRangeAt(0);
21562 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21567 this.execCmd('useCSS', true);
21568 this.execCmd('styleWithCSS', false);
21571 this.owner.fireEvent('activate', this);
21575 adjustFont: function(btn){
21576 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21577 //if(Roo.isSafari){ // safari
21580 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21581 if(Roo.isSafari){ // safari
21582 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21583 v = (v < 10) ? 10 : v;
21584 v = (v > 48) ? 48 : v;
21585 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21590 v = Math.max(1, v+adjust);
21592 this.execCmd('FontSize', v );
21595 onEditorEvent : function(e)
21597 this.owner.fireEvent('editorevent', this, e);
21598 // this.updateToolbar();
21599 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21602 insertTag : function(tg)
21604 // could be a bit smarter... -> wrap the current selected tRoo..
21605 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21607 range = this.createRange(this.getSelection());
21608 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21609 wrappingNode.appendChild(range.extractContents());
21610 range.insertNode(wrappingNode);
21617 this.execCmd("formatblock", tg);
21621 insertText : function(txt)
21625 var range = this.createRange();
21626 range.deleteContents();
21627 //alert(Sender.getAttribute('label'));
21629 range.insertNode(this.doc.createTextNode(txt));
21635 * Executes a Midas editor command on the editor document and performs necessary focus and
21636 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21637 * @param {String} cmd The Midas command
21638 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21640 relayCmd : function(cmd, value){
21642 this.execCmd(cmd, value);
21643 this.owner.fireEvent('editorevent', this);
21644 //this.updateToolbar();
21645 this.owner.deferFocus();
21649 * Executes a Midas editor command directly on the editor document.
21650 * For visual commands, you should use {@link #relayCmd} instead.
21651 * <b>This should only be called after the editor is initialized.</b>
21652 * @param {String} cmd The Midas command
21653 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21655 execCmd : function(cmd, value){
21656 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21663 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21665 * @param {String} text | dom node..
21667 insertAtCursor : function(text)
21670 if(!this.activated){
21676 var r = this.doc.selection.createRange();
21687 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21691 // from jquery ui (MIT licenced)
21693 var win = this.win;
21695 if (win.getSelection && win.getSelection().getRangeAt) {
21696 range = win.getSelection().getRangeAt(0);
21697 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21698 range.insertNode(node);
21699 } else if (win.document.selection && win.document.selection.createRange) {
21700 // no firefox support
21701 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21702 win.document.selection.createRange().pasteHTML(txt);
21704 // no firefox support
21705 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21706 this.execCmd('InsertHTML', txt);
21715 mozKeyPress : function(e){
21717 var c = e.getCharCode(), cmd;
21720 c = String.fromCharCode(c).toLowerCase();
21734 this.cleanUpPaste.defer(100, this);
21742 e.preventDefault();
21750 fixKeys : function(){ // load time branching for fastest keydown performance
21752 return function(e){
21753 var k = e.getKey(), r;
21756 r = this.doc.selection.createRange();
21759 r.pasteHTML('    ');
21766 r = this.doc.selection.createRange();
21768 var target = r.parentElement();
21769 if(!target || target.tagName.toLowerCase() != 'li'){
21771 r.pasteHTML('<br />');
21777 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21778 this.cleanUpPaste.defer(100, this);
21784 }else if(Roo.isOpera){
21785 return function(e){
21786 var k = e.getKey();
21790 this.execCmd('InsertHTML','    ');
21793 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21794 this.cleanUpPaste.defer(100, this);
21799 }else if(Roo.isSafari){
21800 return function(e){
21801 var k = e.getKey();
21805 this.execCmd('InsertText','\t');
21809 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21810 this.cleanUpPaste.defer(100, this);
21818 getAllAncestors: function()
21820 var p = this.getSelectedNode();
21823 a.push(p); // push blank onto stack..
21824 p = this.getParentElement();
21828 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21832 a.push(this.doc.body);
21836 lastSelNode : false,
21839 getSelection : function()
21841 this.assignDocWin();
21842 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21845 getSelectedNode: function()
21847 // this may only work on Gecko!!!
21849 // should we cache this!!!!
21854 var range = this.createRange(this.getSelection()).cloneRange();
21857 var parent = range.parentElement();
21859 var testRange = range.duplicate();
21860 testRange.moveToElementText(parent);
21861 if (testRange.inRange(range)) {
21864 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21867 parent = parent.parentElement;
21872 // is ancestor a text element.
21873 var ac = range.commonAncestorContainer;
21874 if (ac.nodeType == 3) {
21875 ac = ac.parentNode;
21878 var ar = ac.childNodes;
21881 var other_nodes = [];
21882 var has_other_nodes = false;
21883 for (var i=0;i<ar.length;i++) {
21884 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21887 // fullly contained node.
21889 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21894 // probably selected..
21895 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21896 other_nodes.push(ar[i]);
21900 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21905 has_other_nodes = true;
21907 if (!nodes.length && other_nodes.length) {
21908 nodes= other_nodes;
21910 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21916 createRange: function(sel)
21918 // this has strange effects when using with
21919 // top toolbar - not sure if it's a great idea.
21920 //this.editor.contentWindow.focus();
21921 if (typeof sel != "undefined") {
21923 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21925 return this.doc.createRange();
21928 return this.doc.createRange();
21931 getParentElement: function()
21934 this.assignDocWin();
21935 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21937 var range = this.createRange(sel);
21940 var p = range.commonAncestorContainer;
21941 while (p.nodeType == 3) { // text node
21952 * Range intersection.. the hard stuff...
21956 * [ -- selected range --- ]
21960 * if end is before start or hits it. fail.
21961 * if start is after end or hits it fail.
21963 * if either hits (but other is outside. - then it's not
21969 // @see http://www.thismuchiknow.co.uk/?p=64.
21970 rangeIntersectsNode : function(range, node)
21972 var nodeRange = node.ownerDocument.createRange();
21974 nodeRange.selectNode(node);
21976 nodeRange.selectNodeContents(node);
21979 var rangeStartRange = range.cloneRange();
21980 rangeStartRange.collapse(true);
21982 var rangeEndRange = range.cloneRange();
21983 rangeEndRange.collapse(false);
21985 var nodeStartRange = nodeRange.cloneRange();
21986 nodeStartRange.collapse(true);
21988 var nodeEndRange = nodeRange.cloneRange();
21989 nodeEndRange.collapse(false);
21991 return rangeStartRange.compareBoundaryPoints(
21992 Range.START_TO_START, nodeEndRange) == -1 &&
21993 rangeEndRange.compareBoundaryPoints(
21994 Range.START_TO_START, nodeStartRange) == 1;
21998 rangeCompareNode : function(range, node)
22000 var nodeRange = node.ownerDocument.createRange();
22002 nodeRange.selectNode(node);
22004 nodeRange.selectNodeContents(node);
22008 range.collapse(true);
22010 nodeRange.collapse(true);
22012 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22013 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22015 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22017 var nodeIsBefore = ss == 1;
22018 var nodeIsAfter = ee == -1;
22020 if (nodeIsBefore && nodeIsAfter) {
22023 if (!nodeIsBefore && nodeIsAfter) {
22024 return 1; //right trailed.
22027 if (nodeIsBefore && !nodeIsAfter) {
22028 return 2; // left trailed.
22034 // private? - in a new class?
22035 cleanUpPaste : function()
22037 // cleans up the whole document..
22038 Roo.log('cleanuppaste');
22040 this.cleanUpChildren(this.doc.body);
22041 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22042 if (clean != this.doc.body.innerHTML) {
22043 this.doc.body.innerHTML = clean;
22048 cleanWordChars : function(input) {// change the chars to hex code
22049 var he = Roo.HtmlEditorCore;
22051 var output = input;
22052 Roo.each(he.swapCodes, function(sw) {
22053 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22055 output = output.replace(swapper, sw[1]);
22062 cleanUpChildren : function (n)
22064 if (!n.childNodes.length) {
22067 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22068 this.cleanUpChild(n.childNodes[i]);
22075 cleanUpChild : function (node)
22078 //console.log(node);
22079 if (node.nodeName == "#text") {
22080 // clean up silly Windows -- stuff?
22083 if (node.nodeName == "#comment") {
22084 node.parentNode.removeChild(node);
22085 // clean up silly Windows -- stuff?
22088 var lcname = node.tagName.toLowerCase();
22089 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22090 // whitelist of tags..
22092 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22094 node.parentNode.removeChild(node);
22099 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22101 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22102 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22104 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22105 // remove_keep_children = true;
22108 if (remove_keep_children) {
22109 this.cleanUpChildren(node);
22110 // inserts everything just before this node...
22111 while (node.childNodes.length) {
22112 var cn = node.childNodes[0];
22113 node.removeChild(cn);
22114 node.parentNode.insertBefore(cn, node);
22116 node.parentNode.removeChild(node);
22120 if (!node.attributes || !node.attributes.length) {
22121 this.cleanUpChildren(node);
22125 function cleanAttr(n,v)
22128 if (v.match(/^\./) || v.match(/^\//)) {
22131 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22134 if (v.match(/^#/)) {
22137 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22138 node.removeAttribute(n);
22142 var cwhite = this.cwhite;
22143 var cblack = this.cblack;
22145 function cleanStyle(n,v)
22147 if (v.match(/expression/)) { //XSS?? should we even bother..
22148 node.removeAttribute(n);
22152 var parts = v.split(/;/);
22155 Roo.each(parts, function(p) {
22156 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22160 var l = p.split(':').shift().replace(/\s+/g,'');
22161 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22163 if ( cwhite.length && cblack.indexOf(l) > -1) {
22164 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22165 //node.removeAttribute(n);
22169 // only allow 'c whitelisted system attributes'
22170 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22171 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22172 //node.removeAttribute(n);
22182 if (clean.length) {
22183 node.setAttribute(n, clean.join(';'));
22185 node.removeAttribute(n);
22191 for (var i = node.attributes.length-1; i > -1 ; i--) {
22192 var a = node.attributes[i];
22195 if (a.name.toLowerCase().substr(0,2)=='on') {
22196 node.removeAttribute(a.name);
22199 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22200 node.removeAttribute(a.name);
22203 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22204 cleanAttr(a.name,a.value); // fixme..
22207 if (a.name == 'style') {
22208 cleanStyle(a.name,a.value);
22211 /// clean up MS crap..
22212 // tecnically this should be a list of valid class'es..
22215 if (a.name == 'class') {
22216 if (a.value.match(/^Mso/)) {
22217 node.className = '';
22220 if (a.value.match(/^body$/)) {
22221 node.className = '';
22232 this.cleanUpChildren(node);
22238 * Clean up MS wordisms...
22240 cleanWord : function(node)
22245 this.cleanWord(this.doc.body);
22248 if (node.nodeName == "#text") {
22249 // clean up silly Windows -- stuff?
22252 if (node.nodeName == "#comment") {
22253 node.parentNode.removeChild(node);
22254 // clean up silly Windows -- stuff?
22258 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22259 node.parentNode.removeChild(node);
22263 // remove - but keep children..
22264 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22265 while (node.childNodes.length) {
22266 var cn = node.childNodes[0];
22267 node.removeChild(cn);
22268 node.parentNode.insertBefore(cn, node);
22270 node.parentNode.removeChild(node);
22271 this.iterateChildren(node, this.cleanWord);
22275 if (node.className.length) {
22277 var cn = node.className.split(/\W+/);
22279 Roo.each(cn, function(cls) {
22280 if (cls.match(/Mso[a-zA-Z]+/)) {
22285 node.className = cna.length ? cna.join(' ') : '';
22287 node.removeAttribute("class");
22291 if (node.hasAttribute("lang")) {
22292 node.removeAttribute("lang");
22295 if (node.hasAttribute("style")) {
22297 var styles = node.getAttribute("style").split(";");
22299 Roo.each(styles, function(s) {
22300 if (!s.match(/:/)) {
22303 var kv = s.split(":");
22304 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22307 // what ever is left... we allow.
22310 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22311 if (!nstyle.length) {
22312 node.removeAttribute('style');
22315 this.iterateChildren(node, this.cleanWord);
22321 * iterateChildren of a Node, calling fn each time, using this as the scole..
22322 * @param {DomNode} node node to iterate children of.
22323 * @param {Function} fn method of this class to call on each item.
22325 iterateChildren : function(node, fn)
22327 if (!node.childNodes.length) {
22330 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22331 fn.call(this, node.childNodes[i])
22337 * cleanTableWidths.
22339 * Quite often pasting from word etc.. results in tables with column and widths.
22340 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22343 cleanTableWidths : function(node)
22348 this.cleanTableWidths(this.doc.body);
22353 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22356 Roo.log(node.tagName);
22357 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22358 this.iterateChildren(node, this.cleanTableWidths);
22361 if (node.hasAttribute('width')) {
22362 node.removeAttribute('width');
22366 if (node.hasAttribute("style")) {
22369 var styles = node.getAttribute("style").split(";");
22371 Roo.each(styles, function(s) {
22372 if (!s.match(/:/)) {
22375 var kv = s.split(":");
22376 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22379 // what ever is left... we allow.
22382 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22383 if (!nstyle.length) {
22384 node.removeAttribute('style');
22388 this.iterateChildren(node, this.cleanTableWidths);
22396 domToHTML : function(currentElement, depth, nopadtext) {
22398 depth = depth || 0;
22399 nopadtext = nopadtext || false;
22401 if (!currentElement) {
22402 return this.domToHTML(this.doc.body);
22405 //Roo.log(currentElement);
22407 var allText = false;
22408 var nodeName = currentElement.nodeName;
22409 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22411 if (nodeName == '#text') {
22413 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22418 if (nodeName != 'BODY') {
22421 // Prints the node tagName, such as <A>, <IMG>, etc
22424 for(i = 0; i < currentElement.attributes.length;i++) {
22426 var aname = currentElement.attributes.item(i).name;
22427 if (!currentElement.attributes.item(i).value.length) {
22430 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22433 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22442 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22445 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22450 // Traverse the tree
22452 var currentElementChild = currentElement.childNodes.item(i);
22453 var allText = true;
22454 var innerHTML = '';
22456 while (currentElementChild) {
22457 // Formatting code (indent the tree so it looks nice on the screen)
22458 var nopad = nopadtext;
22459 if (lastnode == 'SPAN') {
22463 if (currentElementChild.nodeName == '#text') {
22464 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22465 toadd = nopadtext ? toadd : toadd.trim();
22466 if (!nopad && toadd.length > 80) {
22467 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22469 innerHTML += toadd;
22472 currentElementChild = currentElement.childNodes.item(i);
22478 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22480 // Recursively traverse the tree structure of the child node
22481 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22482 lastnode = currentElementChild.nodeName;
22484 currentElementChild=currentElement.childNodes.item(i);
22490 // The remaining code is mostly for formatting the tree
22491 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22496 ret+= "</"+tagName+">";
22502 applyBlacklists : function()
22504 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22505 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22509 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22510 if (b.indexOf(tag) > -1) {
22513 this.white.push(tag);
22517 Roo.each(w, function(tag) {
22518 if (b.indexOf(tag) > -1) {
22521 if (this.white.indexOf(tag) > -1) {
22524 this.white.push(tag);
22529 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22530 if (w.indexOf(tag) > -1) {
22533 this.black.push(tag);
22537 Roo.each(b, function(tag) {
22538 if (w.indexOf(tag) > -1) {
22541 if (this.black.indexOf(tag) > -1) {
22544 this.black.push(tag);
22549 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22550 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22554 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22555 if (b.indexOf(tag) > -1) {
22558 this.cwhite.push(tag);
22562 Roo.each(w, function(tag) {
22563 if (b.indexOf(tag) > -1) {
22566 if (this.cwhite.indexOf(tag) > -1) {
22569 this.cwhite.push(tag);
22574 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22575 if (w.indexOf(tag) > -1) {
22578 this.cblack.push(tag);
22582 Roo.each(b, function(tag) {
22583 if (w.indexOf(tag) > -1) {
22586 if (this.cblack.indexOf(tag) > -1) {
22589 this.cblack.push(tag);
22594 setStylesheets : function(stylesheets)
22596 if(typeof(stylesheets) == 'string'){
22597 Roo.get(this.iframe.contentDocument.head).createChild({
22599 rel : 'stylesheet',
22608 Roo.each(stylesheets, function(s) {
22613 Roo.get(_this.iframe.contentDocument.head).createChild({
22615 rel : 'stylesheet',
22624 removeStylesheets : function()
22628 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22633 // hide stuff that is not compatible
22647 * @event specialkey
22651 * @cfg {String} fieldClass @hide
22654 * @cfg {String} focusClass @hide
22657 * @cfg {String} autoCreate @hide
22660 * @cfg {String} inputType @hide
22663 * @cfg {String} invalidClass @hide
22666 * @cfg {String} invalidText @hide
22669 * @cfg {String} msgFx @hide
22672 * @cfg {String} validateOnBlur @hide
22676 Roo.HtmlEditorCore.white = [
22677 'area', 'br', 'img', 'input', 'hr', 'wbr',
22679 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22680 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22681 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22682 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22683 'table', 'ul', 'xmp',
22685 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22688 'dir', 'menu', 'ol', 'ul', 'dl',
22694 Roo.HtmlEditorCore.black = [
22695 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22697 'base', 'basefont', 'bgsound', 'blink', 'body',
22698 'frame', 'frameset', 'head', 'html', 'ilayer',
22699 'iframe', 'layer', 'link', 'meta', 'object',
22700 'script', 'style' ,'title', 'xml' // clean later..
22702 Roo.HtmlEditorCore.clean = [
22703 'script', 'style', 'title', 'xml'
22705 Roo.HtmlEditorCore.remove = [
22710 Roo.HtmlEditorCore.ablack = [
22714 Roo.HtmlEditorCore.aclean = [
22715 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22719 Roo.HtmlEditorCore.pwhite= [
22720 'http', 'https', 'mailto'
22723 // white listed style attributes.
22724 Roo.HtmlEditorCore.cwhite= [
22725 // 'text-align', /// default is to allow most things..
22731 // black listed style attributes.
22732 Roo.HtmlEditorCore.cblack= [
22733 // 'font-size' -- this can be set by the project
22737 Roo.HtmlEditorCore.swapCodes =[
22756 * @class Roo.bootstrap.HtmlEditor
22757 * @extends Roo.bootstrap.TextArea
22758 * Bootstrap HtmlEditor class
22761 * Create a new HtmlEditor
22762 * @param {Object} config The config object
22765 Roo.bootstrap.HtmlEditor = function(config){
22766 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22767 if (!this.toolbars) {
22768 this.toolbars = [];
22771 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22774 * @event initialize
22775 * Fires when the editor is fully initialized (including the iframe)
22776 * @param {HtmlEditor} this
22781 * Fires when the editor is first receives the focus. Any insertion must wait
22782 * until after this event.
22783 * @param {HtmlEditor} this
22787 * @event beforesync
22788 * Fires before the textarea is updated with content from the editor iframe. Return false
22789 * to cancel the sync.
22790 * @param {HtmlEditor} this
22791 * @param {String} html
22795 * @event beforepush
22796 * Fires before the iframe editor is updated with content from the textarea. Return false
22797 * to cancel the push.
22798 * @param {HtmlEditor} this
22799 * @param {String} html
22804 * Fires when the textarea is updated with content from the editor iframe.
22805 * @param {HtmlEditor} this
22806 * @param {String} html
22811 * Fires when the iframe editor is updated with content from the textarea.
22812 * @param {HtmlEditor} this
22813 * @param {String} html
22817 * @event editmodechange
22818 * Fires when the editor switches edit modes
22819 * @param {HtmlEditor} this
22820 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22822 editmodechange: true,
22824 * @event editorevent
22825 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22826 * @param {HtmlEditor} this
22830 * @event firstfocus
22831 * Fires when on first focus - needed by toolbars..
22832 * @param {HtmlEditor} this
22837 * Auto save the htmlEditor value as a file into Events
22838 * @param {HtmlEditor} this
22842 * @event savedpreview
22843 * preview the saved version of htmlEditor
22844 * @param {HtmlEditor} this
22851 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22855 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22860 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22865 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22870 * @cfg {Number} height (in pixels)
22874 * @cfg {Number} width (in pixels)
22879 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22882 stylesheets: false,
22887 // private properties
22888 validationEvent : false,
22890 initialized : false,
22893 onFocus : Roo.emptyFn,
22895 hideMode:'offsets',
22897 tbContainer : false,
22899 toolbarContainer :function() {
22900 return this.wrap.select('.x-html-editor-tb',true).first();
22904 * Protected method that will not generally be called directly. It
22905 * is called when the editor creates its toolbar. Override this method if you need to
22906 * add custom toolbar buttons.
22907 * @param {HtmlEditor} editor
22909 createToolbar : function(){
22910 Roo.log('renewing');
22911 Roo.log("create toolbars");
22913 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22914 this.toolbars[0].render(this.toolbarContainer());
22918 // if (!editor.toolbars || !editor.toolbars.length) {
22919 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22922 // for (var i =0 ; i < editor.toolbars.length;i++) {
22923 // editor.toolbars[i] = Roo.factory(
22924 // typeof(editor.toolbars[i]) == 'string' ?
22925 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22926 // Roo.bootstrap.HtmlEditor);
22927 // editor.toolbars[i].init(editor);
22933 onRender : function(ct, position)
22935 // Roo.log("Call onRender: " + this.xtype);
22937 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22939 this.wrap = this.inputEl().wrap({
22940 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22943 this.editorcore.onRender(ct, position);
22945 if (this.resizable) {
22946 this.resizeEl = new Roo.Resizable(this.wrap, {
22950 minHeight : this.height,
22951 height: this.height,
22952 handles : this.resizable,
22955 resize : function(r, w, h) {
22956 _t.onResize(w,h); // -something
22962 this.createToolbar(this);
22965 if(!this.width && this.resizable){
22966 this.setSize(this.wrap.getSize());
22968 if (this.resizeEl) {
22969 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22970 // should trigger onReize..
22976 onResize : function(w, h)
22978 Roo.log('resize: ' +w + ',' + h );
22979 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22983 if(this.inputEl() ){
22984 if(typeof w == 'number'){
22985 var aw = w - this.wrap.getFrameWidth('lr');
22986 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22989 if(typeof h == 'number'){
22990 var tbh = -11; // fixme it needs to tool bar size!
22991 for (var i =0; i < this.toolbars.length;i++) {
22992 // fixme - ask toolbars for heights?
22993 tbh += this.toolbars[i].el.getHeight();
22994 //if (this.toolbars[i].footer) {
22995 // tbh += this.toolbars[i].footer.el.getHeight();
23003 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23004 ah -= 5; // knock a few pixes off for look..
23005 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23009 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23010 this.editorcore.onResize(ew,eh);
23015 * Toggles the editor between standard and source edit mode.
23016 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23018 toggleSourceEdit : function(sourceEditMode)
23020 this.editorcore.toggleSourceEdit(sourceEditMode);
23022 if(this.editorcore.sourceEditMode){
23023 Roo.log('editor - showing textarea');
23026 // Roo.log(this.syncValue());
23028 this.inputEl().removeClass(['hide', 'x-hidden']);
23029 this.inputEl().dom.removeAttribute('tabIndex');
23030 this.inputEl().focus();
23032 Roo.log('editor - hiding textarea');
23034 // Roo.log(this.pushValue());
23037 this.inputEl().addClass(['hide', 'x-hidden']);
23038 this.inputEl().dom.setAttribute('tabIndex', -1);
23039 //this.deferFocus();
23042 if(this.resizable){
23043 this.setSize(this.wrap.getSize());
23046 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23049 // private (for BoxComponent)
23050 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23052 // private (for BoxComponent)
23053 getResizeEl : function(){
23057 // private (for BoxComponent)
23058 getPositionEl : function(){
23063 initEvents : function(){
23064 this.originalValue = this.getValue();
23068 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23071 // markInvalid : Roo.emptyFn,
23073 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23076 // clearInvalid : Roo.emptyFn,
23078 setValue : function(v){
23079 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23080 this.editorcore.pushValue();
23085 deferFocus : function(){
23086 this.focus.defer(10, this);
23090 focus : function(){
23091 this.editorcore.focus();
23097 onDestroy : function(){
23103 for (var i =0; i < this.toolbars.length;i++) {
23104 // fixme - ask toolbars for heights?
23105 this.toolbars[i].onDestroy();
23108 this.wrap.dom.innerHTML = '';
23109 this.wrap.remove();
23114 onFirstFocus : function(){
23115 //Roo.log("onFirstFocus");
23116 this.editorcore.onFirstFocus();
23117 for (var i =0; i < this.toolbars.length;i++) {
23118 this.toolbars[i].onFirstFocus();
23124 syncValue : function()
23126 this.editorcore.syncValue();
23129 pushValue : function()
23131 this.editorcore.pushValue();
23135 // hide stuff that is not compatible
23149 * @event specialkey
23153 * @cfg {String} fieldClass @hide
23156 * @cfg {String} focusClass @hide
23159 * @cfg {String} autoCreate @hide
23162 * @cfg {String} inputType @hide
23165 * @cfg {String} invalidClass @hide
23168 * @cfg {String} invalidText @hide
23171 * @cfg {String} msgFx @hide
23174 * @cfg {String} validateOnBlur @hide
23183 Roo.namespace('Roo.bootstrap.htmleditor');
23185 * @class Roo.bootstrap.HtmlEditorToolbar1
23190 new Roo.bootstrap.HtmlEditor({
23193 new Roo.bootstrap.HtmlEditorToolbar1({
23194 disable : { fonts: 1 , format: 1, ..., ... , ...],
23200 * @cfg {Object} disable List of elements to disable..
23201 * @cfg {Array} btns List of additional buttons.
23205 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23208 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23211 Roo.apply(this, config);
23213 // default disabled, based on 'good practice'..
23214 this.disable = this.disable || {};
23215 Roo.applyIf(this.disable, {
23218 specialElements : true
23220 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23222 this.editor = config.editor;
23223 this.editorcore = config.editor.editorcore;
23225 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23227 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23228 // dont call parent... till later.
23230 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23235 editorcore : false,
23240 "h1","h2","h3","h4","h5","h6",
23242 "abbr", "acronym", "address", "cite", "samp", "var",
23246 onRender : function(ct, position)
23248 // Roo.log("Call onRender: " + this.xtype);
23250 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23252 this.el.dom.style.marginBottom = '0';
23254 var editorcore = this.editorcore;
23255 var editor= this.editor;
23258 var btn = function(id,cmd , toggle, handler, html){
23260 var event = toggle ? 'toggle' : 'click';
23265 xns: Roo.bootstrap,
23268 enableToggle:toggle !== false,
23270 pressed : toggle ? false : null,
23273 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23274 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23280 // var cb_box = function...
23285 xns: Roo.bootstrap,
23286 glyphicon : 'font',
23290 xns: Roo.bootstrap,
23294 Roo.each(this.formats, function(f) {
23295 style.menu.items.push({
23297 xns: Roo.bootstrap,
23298 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23303 editorcore.insertTag(this.tagname);
23310 children.push(style);
23312 btn('bold',false,true);
23313 btn('italic',false,true);
23314 btn('align-left', 'justifyleft',true);
23315 btn('align-center', 'justifycenter',true);
23316 btn('align-right' , 'justifyright',true);
23317 btn('link', false, false, function(btn) {
23318 //Roo.log("create link?");
23319 var url = prompt(this.createLinkText, this.defaultLinkValue);
23320 if(url && url != 'http:/'+'/'){
23321 this.editorcore.relayCmd('createlink', url);
23324 btn('list','insertunorderedlist',true);
23325 btn('pencil', false,true, function(btn){
23327 this.toggleSourceEdit(btn.pressed);
23330 if (this.editor.btns.length > 0) {
23331 for (var i = 0; i<this.editor.btns.length; i++) {
23332 children.push(this.editor.btns[i]);
23340 xns: Roo.bootstrap,
23345 xns: Roo.bootstrap,
23350 cog.menu.items.push({
23352 xns: Roo.bootstrap,
23353 html : Clean styles,
23358 editorcore.insertTag(this.tagname);
23367 this.xtype = 'NavSimplebar';
23369 for(var i=0;i< children.length;i++) {
23371 this.buttons.add(this.addxtypeChild(children[i]));
23375 editor.on('editorevent', this.updateToolbar, this);
23377 onBtnClick : function(id)
23379 this.editorcore.relayCmd(id);
23380 this.editorcore.focus();
23384 * Protected method that will not generally be called directly. It triggers
23385 * a toolbar update by reading the markup state of the current selection in the editor.
23387 updateToolbar: function(){
23389 if(!this.editorcore.activated){
23390 this.editor.onFirstFocus(); // is this neeed?
23394 var btns = this.buttons;
23395 var doc = this.editorcore.doc;
23396 btns.get('bold').setActive(doc.queryCommandState('bold'));
23397 btns.get('italic').setActive(doc.queryCommandState('italic'));
23398 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23400 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23401 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23402 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23404 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23405 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23408 var ans = this.editorcore.getAllAncestors();
23409 if (this.formatCombo) {
23412 var store = this.formatCombo.store;
23413 this.formatCombo.setValue("");
23414 for (var i =0; i < ans.length;i++) {
23415 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23417 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23425 // hides menus... - so this cant be on a menu...
23426 Roo.bootstrap.MenuMgr.hideAll();
23428 Roo.bootstrap.MenuMgr.hideAll();
23429 //this.editorsyncValue();
23431 onFirstFocus: function() {
23432 this.buttons.each(function(item){
23436 toggleSourceEdit : function(sourceEditMode){
23439 if(sourceEditMode){
23440 Roo.log("disabling buttons");
23441 this.buttons.each( function(item){
23442 if(item.cmd != 'pencil'){
23448 Roo.log("enabling buttons");
23449 if(this.editorcore.initialized){
23450 this.buttons.each( function(item){
23456 Roo.log("calling toggole on editor");
23457 // tell the editor that it's been pressed..
23458 this.editor.toggleSourceEdit(sourceEditMode);
23468 * @class Roo.bootstrap.Table.AbstractSelectionModel
23469 * @extends Roo.util.Observable
23470 * Abstract base class for grid SelectionModels. It provides the interface that should be
23471 * implemented by descendant classes. This class should not be directly instantiated.
23474 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23475 this.locked = false;
23476 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23480 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23481 /** @ignore Called by the grid automatically. Do not call directly. */
23482 init : function(grid){
23488 * Locks the selections.
23491 this.locked = true;
23495 * Unlocks the selections.
23497 unlock : function(){
23498 this.locked = false;
23502 * Returns true if the selections are locked.
23503 * @return {Boolean}
23505 isLocked : function(){
23506 return this.locked;
23510 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23511 * @class Roo.bootstrap.Table.RowSelectionModel
23512 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23513 * It supports multiple selections and keyboard selection/navigation.
23515 * @param {Object} config
23518 Roo.bootstrap.Table.RowSelectionModel = function(config){
23519 Roo.apply(this, config);
23520 this.selections = new Roo.util.MixedCollection(false, function(o){
23525 this.lastActive = false;
23529 * @event selectionchange
23530 * Fires when the selection changes
23531 * @param {SelectionModel} this
23533 "selectionchange" : true,
23535 * @event afterselectionchange
23536 * Fires after the selection changes (eg. by key press or clicking)
23537 * @param {SelectionModel} this
23539 "afterselectionchange" : true,
23541 * @event beforerowselect
23542 * Fires when a row is selected being selected, return false to cancel.
23543 * @param {SelectionModel} this
23544 * @param {Number} rowIndex The selected index
23545 * @param {Boolean} keepExisting False if other selections will be cleared
23547 "beforerowselect" : true,
23550 * Fires when a row is selected.
23551 * @param {SelectionModel} this
23552 * @param {Number} rowIndex The selected index
23553 * @param {Roo.data.Record} r The record
23555 "rowselect" : true,
23557 * @event rowdeselect
23558 * Fires when a row is deselected.
23559 * @param {SelectionModel} this
23560 * @param {Number} rowIndex The selected index
23562 "rowdeselect" : true
23564 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23565 this.locked = false;
23568 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23570 * @cfg {Boolean} singleSelect
23571 * True to allow selection of only one row at a time (defaults to false)
23573 singleSelect : false,
23576 initEvents : function()
23579 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23580 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23581 //}else{ // allow click to work like normal
23582 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23584 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23585 this.grid.on("rowclick", this.handleMouseDown, this);
23587 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23588 "up" : function(e){
23590 this.selectPrevious(e.shiftKey);
23591 }else if(this.last !== false && this.lastActive !== false){
23592 var last = this.last;
23593 this.selectRange(this.last, this.lastActive-1);
23594 this.grid.getView().focusRow(this.lastActive);
23595 if(last !== false){
23599 this.selectFirstRow();
23601 this.fireEvent("afterselectionchange", this);
23603 "down" : function(e){
23605 this.selectNext(e.shiftKey);
23606 }else if(this.last !== false && this.lastActive !== false){
23607 var last = this.last;
23608 this.selectRange(this.last, this.lastActive+1);
23609 this.grid.getView().focusRow(this.lastActive);
23610 if(last !== false){
23614 this.selectFirstRow();
23616 this.fireEvent("afterselectionchange", this);
23620 this.grid.store.on('load', function(){
23621 this.selections.clear();
23624 var view = this.grid.view;
23625 view.on("refresh", this.onRefresh, this);
23626 view.on("rowupdated", this.onRowUpdated, this);
23627 view.on("rowremoved", this.onRemove, this);
23632 onRefresh : function()
23634 var ds = this.grid.store, i, v = this.grid.view;
23635 var s = this.selections;
23636 s.each(function(r){
23637 if((i = ds.indexOfId(r.id)) != -1){
23646 onRemove : function(v, index, r){
23647 this.selections.remove(r);
23651 onRowUpdated : function(v, index, r){
23652 if(this.isSelected(r)){
23653 v.onRowSelect(index);
23659 * @param {Array} records The records to select
23660 * @param {Boolean} keepExisting (optional) True to keep existing selections
23662 selectRecords : function(records, keepExisting)
23665 this.clearSelections();
23667 var ds = this.grid.store;
23668 for(var i = 0, len = records.length; i < len; i++){
23669 this.selectRow(ds.indexOf(records[i]), true);
23674 * Gets the number of selected rows.
23677 getCount : function(){
23678 return this.selections.length;
23682 * Selects the first row in the grid.
23684 selectFirstRow : function(){
23689 * Select the last row.
23690 * @param {Boolean} keepExisting (optional) True to keep existing selections
23692 selectLastRow : function(keepExisting){
23693 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23694 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23698 * Selects the row immediately following the last selected row.
23699 * @param {Boolean} keepExisting (optional) True to keep existing selections
23701 selectNext : function(keepExisting)
23703 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23704 this.selectRow(this.last+1, keepExisting);
23705 this.grid.getView().focusRow(this.last);
23710 * Selects the row that precedes the last selected row.
23711 * @param {Boolean} keepExisting (optional) True to keep existing selections
23713 selectPrevious : function(keepExisting){
23715 this.selectRow(this.last-1, keepExisting);
23716 this.grid.getView().focusRow(this.last);
23721 * Returns the selected records
23722 * @return {Array} Array of selected records
23724 getSelections : function(){
23725 return [].concat(this.selections.items);
23729 * Returns the first selected record.
23732 getSelected : function(){
23733 return this.selections.itemAt(0);
23738 * Clears all selections.
23740 clearSelections : function(fast)
23746 var ds = this.grid.store;
23747 var s = this.selections;
23748 s.each(function(r){
23749 this.deselectRow(ds.indexOfId(r.id));
23753 this.selections.clear();
23760 * Selects all rows.
23762 selectAll : function(){
23766 this.selections.clear();
23767 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23768 this.selectRow(i, true);
23773 * Returns True if there is a selection.
23774 * @return {Boolean}
23776 hasSelection : function(){
23777 return this.selections.length > 0;
23781 * Returns True if the specified row is selected.
23782 * @param {Number/Record} record The record or index of the record to check
23783 * @return {Boolean}
23785 isSelected : function(index){
23786 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23787 return (r && this.selections.key(r.id) ? true : false);
23791 * Returns True if the specified record id is selected.
23792 * @param {String} id The id of record to check
23793 * @return {Boolean}
23795 isIdSelected : function(id){
23796 return (this.selections.key(id) ? true : false);
23801 handleMouseDBClick : function(e, t){
23805 handleMouseDown : function(e, t)
23807 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23808 if(this.isLocked() || rowIndex < 0 ){
23811 if(e.shiftKey && this.last !== false){
23812 var last = this.last;
23813 this.selectRange(last, rowIndex, e.ctrlKey);
23814 this.last = last; // reset the last
23818 var isSelected = this.isSelected(rowIndex);
23819 //Roo.log("select row:" + rowIndex);
23821 this.deselectRow(rowIndex);
23823 this.selectRow(rowIndex, true);
23827 if(e.button !== 0 && isSelected){
23828 alert('rowIndex 2: ' + rowIndex);
23829 view.focusRow(rowIndex);
23830 }else if(e.ctrlKey && isSelected){
23831 this.deselectRow(rowIndex);
23832 }else if(!isSelected){
23833 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23834 view.focusRow(rowIndex);
23838 this.fireEvent("afterselectionchange", this);
23841 handleDragableRowClick : function(grid, rowIndex, e)
23843 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23844 this.selectRow(rowIndex, false);
23845 grid.view.focusRow(rowIndex);
23846 this.fireEvent("afterselectionchange", this);
23851 * Selects multiple rows.
23852 * @param {Array} rows Array of the indexes of the row to select
23853 * @param {Boolean} keepExisting (optional) True to keep existing selections
23855 selectRows : function(rows, keepExisting){
23857 this.clearSelections();
23859 for(var i = 0, len = rows.length; i < len; i++){
23860 this.selectRow(rows[i], true);
23865 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23866 * @param {Number} startRow The index of the first row in the range
23867 * @param {Number} endRow The index of the last row in the range
23868 * @param {Boolean} keepExisting (optional) True to retain existing selections
23870 selectRange : function(startRow, endRow, keepExisting){
23875 this.clearSelections();
23877 if(startRow <= endRow){
23878 for(var i = startRow; i <= endRow; i++){
23879 this.selectRow(i, true);
23882 for(var i = startRow; i >= endRow; i--){
23883 this.selectRow(i, true);
23889 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23890 * @param {Number} startRow The index of the first row in the range
23891 * @param {Number} endRow The index of the last row in the range
23893 deselectRange : function(startRow, endRow, preventViewNotify){
23897 for(var i = startRow; i <= endRow; i++){
23898 this.deselectRow(i, preventViewNotify);
23904 * @param {Number} row The index of the row to select
23905 * @param {Boolean} keepExisting (optional) True to keep existing selections
23907 selectRow : function(index, keepExisting, preventViewNotify)
23909 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23912 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23913 if(!keepExisting || this.singleSelect){
23914 this.clearSelections();
23917 var r = this.grid.store.getAt(index);
23918 //console.log('selectRow - record id :' + r.id);
23920 this.selections.add(r);
23921 this.last = this.lastActive = index;
23922 if(!preventViewNotify){
23923 var proxy = new Roo.Element(
23924 this.grid.getRowDom(index)
23926 proxy.addClass('bg-info info');
23928 this.fireEvent("rowselect", this, index, r);
23929 this.fireEvent("selectionchange", this);
23935 * @param {Number} row The index of the row to deselect
23937 deselectRow : function(index, preventViewNotify)
23942 if(this.last == index){
23945 if(this.lastActive == index){
23946 this.lastActive = false;
23949 var r = this.grid.store.getAt(index);
23954 this.selections.remove(r);
23955 //.console.log('deselectRow - record id :' + r.id);
23956 if(!preventViewNotify){
23958 var proxy = new Roo.Element(
23959 this.grid.getRowDom(index)
23961 proxy.removeClass('bg-info info');
23963 this.fireEvent("rowdeselect", this, index);
23964 this.fireEvent("selectionchange", this);
23968 restoreLast : function(){
23970 this.last = this._last;
23975 acceptsNav : function(row, col, cm){
23976 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23980 onEditorKey : function(field, e){
23981 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23986 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23988 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23990 }else if(k == e.ENTER && !e.ctrlKey){
23994 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23996 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23998 }else if(k == e.ESC){
24002 g.startEditing(newCell[0], newCell[1]);
24008 * Ext JS Library 1.1.1
24009 * Copyright(c) 2006-2007, Ext JS, LLC.
24011 * Originally Released Under LGPL - original licence link has changed is not relivant.
24014 * <script type="text/javascript">
24018 * @class Roo.bootstrap.PagingToolbar
24019 * @extends Roo.bootstrap.NavSimplebar
24020 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24022 * Create a new PagingToolbar
24023 * @param {Object} config The config object
24024 * @param {Roo.data.Store} store
24026 Roo.bootstrap.PagingToolbar = function(config)
24028 // old args format still supported... - xtype is prefered..
24029 // created from xtype...
24031 this.ds = config.dataSource;
24033 if (config.store && !this.ds) {
24034 this.store= Roo.factory(config.store, Roo.data);
24035 this.ds = this.store;
24036 this.ds.xmodule = this.xmodule || false;
24039 this.toolbarItems = [];
24040 if (config.items) {
24041 this.toolbarItems = config.items;
24044 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24049 this.bind(this.ds);
24052 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24056 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24058 * @cfg {Roo.data.Store} dataSource
24059 * The underlying data store providing the paged data
24062 * @cfg {String/HTMLElement/Element} container
24063 * container The id or element that will contain the toolbar
24066 * @cfg {Boolean} displayInfo
24067 * True to display the displayMsg (defaults to false)
24070 * @cfg {Number} pageSize
24071 * The number of records to display per page (defaults to 20)
24075 * @cfg {String} displayMsg
24076 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24078 displayMsg : 'Displaying {0} - {1} of {2}',
24080 * @cfg {String} emptyMsg
24081 * The message to display when no records are found (defaults to "No data to display")
24083 emptyMsg : 'No data to display',
24085 * Customizable piece of the default paging text (defaults to "Page")
24088 beforePageText : "Page",
24090 * Customizable piece of the default paging text (defaults to "of %0")
24093 afterPageText : "of {0}",
24095 * Customizable piece of the default paging text (defaults to "First Page")
24098 firstText : "First Page",
24100 * Customizable piece of the default paging text (defaults to "Previous Page")
24103 prevText : "Previous Page",
24105 * Customizable piece of the default paging text (defaults to "Next Page")
24108 nextText : "Next Page",
24110 * Customizable piece of the default paging text (defaults to "Last Page")
24113 lastText : "Last Page",
24115 * Customizable piece of the default paging text (defaults to "Refresh")
24118 refreshText : "Refresh",
24122 onRender : function(ct, position)
24124 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24125 this.navgroup.parentId = this.id;
24126 this.navgroup.onRender(this.el, null);
24127 // add the buttons to the navgroup
24129 if(this.displayInfo){
24130 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24131 this.displayEl = this.el.select('.x-paging-info', true).first();
24132 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24133 // this.displayEl = navel.el.select('span',true).first();
24139 Roo.each(_this.buttons, function(e){ // this might need to use render????
24140 Roo.factory(e).onRender(_this.el, null);
24144 Roo.each(_this.toolbarItems, function(e) {
24145 _this.navgroup.addItem(e);
24149 this.first = this.navgroup.addItem({
24150 tooltip: this.firstText,
24152 icon : 'fa fa-backward',
24154 preventDefault: true,
24155 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24158 this.prev = this.navgroup.addItem({
24159 tooltip: this.prevText,
24161 icon : 'fa fa-step-backward',
24163 preventDefault: true,
24164 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24166 //this.addSeparator();
24169 var field = this.navgroup.addItem( {
24171 cls : 'x-paging-position',
24173 html : this.beforePageText +
24174 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24175 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24178 this.field = field.el.select('input', true).first();
24179 this.field.on("keydown", this.onPagingKeydown, this);
24180 this.field.on("focus", function(){this.dom.select();});
24183 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24184 //this.field.setHeight(18);
24185 //this.addSeparator();
24186 this.next = this.navgroup.addItem({
24187 tooltip: this.nextText,
24189 html : ' <i class="fa fa-step-forward">',
24191 preventDefault: true,
24192 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24194 this.last = this.navgroup.addItem({
24195 tooltip: this.lastText,
24196 icon : 'fa fa-forward',
24199 preventDefault: true,
24200 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24202 //this.addSeparator();
24203 this.loading = this.navgroup.addItem({
24204 tooltip: this.refreshText,
24205 icon: 'fa fa-refresh',
24206 preventDefault: true,
24207 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24213 updateInfo : function(){
24214 if(this.displayEl){
24215 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24216 var msg = count == 0 ?
24220 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24222 this.displayEl.update(msg);
24227 onLoad : function(ds, r, o)
24229 this.cursor = o.params ? o.params.start : 0;
24230 var d = this.getPageData(),
24235 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24236 this.field.dom.value = ap;
24237 this.first.setDisabled(ap == 1);
24238 this.prev.setDisabled(ap == 1);
24239 this.next.setDisabled(ap == ps);
24240 this.last.setDisabled(ap == ps);
24241 this.loading.enable();
24246 getPageData : function(){
24247 var total = this.ds.getTotalCount();
24250 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24251 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24256 onLoadError : function(){
24257 this.loading.enable();
24261 onPagingKeydown : function(e){
24262 var k = e.getKey();
24263 var d = this.getPageData();
24265 var v = this.field.dom.value, pageNum;
24266 if(!v || isNaN(pageNum = parseInt(v, 10))){
24267 this.field.dom.value = d.activePage;
24270 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24271 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24274 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))
24276 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24277 this.field.dom.value = pageNum;
24278 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24281 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24283 var v = this.field.dom.value, pageNum;
24284 var increment = (e.shiftKey) ? 10 : 1;
24285 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24288 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24289 this.field.dom.value = d.activePage;
24292 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24294 this.field.dom.value = parseInt(v, 10) + increment;
24295 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24296 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24303 beforeLoad : function(){
24305 this.loading.disable();
24310 onClick : function(which){
24319 ds.load({params:{start: 0, limit: this.pageSize}});
24322 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24325 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24328 var total = ds.getTotalCount();
24329 var extra = total % this.pageSize;
24330 var lastStart = extra ? (total - extra) : total-this.pageSize;
24331 ds.load({params:{start: lastStart, limit: this.pageSize}});
24334 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24340 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24341 * @param {Roo.data.Store} store The data store to unbind
24343 unbind : function(ds){
24344 ds.un("beforeload", this.beforeLoad, this);
24345 ds.un("load", this.onLoad, this);
24346 ds.un("loadexception", this.onLoadError, this);
24347 ds.un("remove", this.updateInfo, this);
24348 ds.un("add", this.updateInfo, this);
24349 this.ds = undefined;
24353 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24354 * @param {Roo.data.Store} store The data store to bind
24356 bind : function(ds){
24357 ds.on("beforeload", this.beforeLoad, this);
24358 ds.on("load", this.onLoad, this);
24359 ds.on("loadexception", this.onLoadError, this);
24360 ds.on("remove", this.updateInfo, this);
24361 ds.on("add", this.updateInfo, this);
24372 * @class Roo.bootstrap.MessageBar
24373 * @extends Roo.bootstrap.Component
24374 * Bootstrap MessageBar class
24375 * @cfg {String} html contents of the MessageBar
24376 * @cfg {String} weight (info | success | warning | danger) default info
24377 * @cfg {String} beforeClass insert the bar before the given class
24378 * @cfg {Boolean} closable (true | false) default false
24379 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24382 * Create a new Element
24383 * @param {Object} config The config object
24386 Roo.bootstrap.MessageBar = function(config){
24387 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24390 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24396 beforeClass: 'bootstrap-sticky-wrap',
24398 getAutoCreate : function(){
24402 cls: 'alert alert-dismissable alert-' + this.weight,
24407 html: this.html || ''
24413 cfg.cls += ' alert-messages-fixed';
24427 onRender : function(ct, position)
24429 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24432 var cfg = Roo.apply({}, this.getAutoCreate());
24436 cfg.cls += ' ' + this.cls;
24439 cfg.style = this.style;
24441 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24443 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24446 this.el.select('>button.close').on('click', this.hide, this);
24452 if (!this.rendered) {
24458 this.fireEvent('show', this);
24464 if (!this.rendered) {
24470 this.fireEvent('hide', this);
24473 update : function()
24475 // var e = this.el.dom.firstChild;
24477 // if(this.closable){
24478 // e = e.nextSibling;
24481 // e.data = this.html || '';
24483 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24499 * @class Roo.bootstrap.Graph
24500 * @extends Roo.bootstrap.Component
24501 * Bootstrap Graph class
24505 @cfg {String} graphtype bar | vbar | pie
24506 @cfg {number} g_x coodinator | centre x (pie)
24507 @cfg {number} g_y coodinator | centre y (pie)
24508 @cfg {number} g_r radius (pie)
24509 @cfg {number} g_height height of the chart (respected by all elements in the set)
24510 @cfg {number} g_width width of the chart (respected by all elements in the set)
24511 @cfg {Object} title The title of the chart
24514 -opts (object) options for the chart
24516 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24517 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24519 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.
24520 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24522 o stretch (boolean)
24524 -opts (object) options for the pie
24527 o startAngle (number)
24528 o endAngle (number)
24532 * Create a new Input
24533 * @param {Object} config The config object
24536 Roo.bootstrap.Graph = function(config){
24537 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24543 * The img click event for the img.
24544 * @param {Roo.EventObject} e
24550 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24561 //g_colors: this.colors,
24568 getAutoCreate : function(){
24579 onRender : function(ct,position){
24582 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24584 if (typeof(Raphael) == 'undefined') {
24585 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24589 this.raphael = Raphael(this.el.dom);
24591 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24592 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24593 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24594 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24596 r.text(160, 10, "Single Series Chart").attr(txtattr);
24597 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24598 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24599 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24601 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24602 r.barchart(330, 10, 300, 220, data1);
24603 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24604 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24607 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24608 // r.barchart(30, 30, 560, 250, xdata, {
24609 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24610 // axis : "0 0 1 1",
24611 // axisxlabels : xdata
24612 // //yvalues : cols,
24615 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24617 // this.load(null,xdata,{
24618 // axis : "0 0 1 1",
24619 // axisxlabels : xdata
24624 load : function(graphtype,xdata,opts)
24626 this.raphael.clear();
24628 graphtype = this.graphtype;
24633 var r = this.raphael,
24634 fin = function () {
24635 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24637 fout = function () {
24638 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24640 pfin = function() {
24641 this.sector.stop();
24642 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24645 this.label[0].stop();
24646 this.label[0].attr({ r: 7.5 });
24647 this.label[1].attr({ "font-weight": 800 });
24650 pfout = function() {
24651 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24654 this.label[0].animate({ r: 5 }, 500, "bounce");
24655 this.label[1].attr({ "font-weight": 400 });
24661 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24664 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24667 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24668 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24670 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24677 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24682 setTitle: function(o)
24687 initEvents: function() {
24690 this.el.on('click', this.onClick, this);
24694 onClick : function(e)
24696 Roo.log('img onclick');
24697 this.fireEvent('click', this, e);
24709 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24712 * @class Roo.bootstrap.dash.NumberBox
24713 * @extends Roo.bootstrap.Component
24714 * Bootstrap NumberBox class
24715 * @cfg {String} headline Box headline
24716 * @cfg {String} content Box content
24717 * @cfg {String} icon Box icon
24718 * @cfg {String} footer Footer text
24719 * @cfg {String} fhref Footer href
24722 * Create a new NumberBox
24723 * @param {Object} config The config object
24727 Roo.bootstrap.dash.NumberBox = function(config){
24728 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24732 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24741 getAutoCreate : function(){
24745 cls : 'small-box ',
24753 cls : 'roo-headline',
24754 html : this.headline
24758 cls : 'roo-content',
24759 html : this.content
24773 cls : 'ion ' + this.icon
24782 cls : 'small-box-footer',
24783 href : this.fhref || '#',
24787 cfg.cn.push(footer);
24794 onRender : function(ct,position){
24795 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24802 setHeadline: function (value)
24804 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24807 setFooter: function (value, href)
24809 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24812 this.el.select('a.small-box-footer',true).first().attr('href', href);
24817 setContent: function (value)
24819 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24822 initEvents: function()
24836 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24839 * @class Roo.bootstrap.dash.TabBox
24840 * @extends Roo.bootstrap.Component
24841 * Bootstrap TabBox class
24842 * @cfg {String} title Title of the TabBox
24843 * @cfg {String} icon Icon of the TabBox
24844 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24845 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24848 * Create a new TabBox
24849 * @param {Object} config The config object
24853 Roo.bootstrap.dash.TabBox = function(config){
24854 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24859 * When a pane is added
24860 * @param {Roo.bootstrap.dash.TabPane} pane
24864 * @event activatepane
24865 * When a pane is activated
24866 * @param {Roo.bootstrap.dash.TabPane} pane
24868 "activatepane" : true
24876 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24881 tabScrollable : false,
24883 getChildContainer : function()
24885 return this.el.select('.tab-content', true).first();
24888 getAutoCreate : function(){
24892 cls: 'pull-left header',
24900 cls: 'fa ' + this.icon
24906 cls: 'nav nav-tabs pull-right',
24912 if(this.tabScrollable){
24919 cls: 'nav nav-tabs pull-right',
24930 cls: 'nav-tabs-custom',
24935 cls: 'tab-content no-padding',
24943 initEvents : function()
24945 //Roo.log('add add pane handler');
24946 this.on('addpane', this.onAddPane, this);
24949 * Updates the box title
24950 * @param {String} html to set the title to.
24952 setTitle : function(value)
24954 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24956 onAddPane : function(pane)
24958 this.panes.push(pane);
24959 //Roo.log('addpane');
24961 // tabs are rendere left to right..
24962 if(!this.showtabs){
24966 var ctr = this.el.select('.nav-tabs', true).first();
24969 var existing = ctr.select('.nav-tab',true);
24970 var qty = existing.getCount();;
24973 var tab = ctr.createChild({
24975 cls : 'nav-tab' + (qty ? '' : ' active'),
24983 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24986 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24988 pane.el.addClass('active');
24993 onTabClick : function(ev,un,ob,pane)
24995 //Roo.log('tab - prev default');
24996 ev.preventDefault();
24999 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25000 pane.tab.addClass('active');
25001 //Roo.log(pane.title);
25002 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25003 // technically we should have a deactivate event.. but maybe add later.
25004 // and it should not de-activate the selected tab...
25005 this.fireEvent('activatepane', pane);
25006 pane.el.addClass('active');
25007 pane.fireEvent('activate');
25012 getActivePane : function()
25015 Roo.each(this.panes, function(p) {
25016 if(p.el.hasClass('active')){
25037 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25039 * @class Roo.bootstrap.TabPane
25040 * @extends Roo.bootstrap.Component
25041 * Bootstrap TabPane class
25042 * @cfg {Boolean} active (false | true) Default false
25043 * @cfg {String} title title of panel
25047 * Create a new TabPane
25048 * @param {Object} config The config object
25051 Roo.bootstrap.dash.TabPane = function(config){
25052 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25058 * When a pane is activated
25059 * @param {Roo.bootstrap.dash.TabPane} pane
25066 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25071 // the tabBox that this is attached to.
25074 getAutoCreate : function()
25082 cfg.cls += ' active';
25087 initEvents : function()
25089 //Roo.log('trigger add pane handler');
25090 this.parent().fireEvent('addpane', this)
25094 * Updates the tab title
25095 * @param {String} html to set the title to.
25097 setTitle: function(str)
25103 this.tab.select('a', true).first().dom.innerHTML = str;
25120 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25123 * @class Roo.bootstrap.menu.Menu
25124 * @extends Roo.bootstrap.Component
25125 * Bootstrap Menu class - container for Menu
25126 * @cfg {String} html Text of the menu
25127 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25128 * @cfg {String} icon Font awesome icon
25129 * @cfg {String} pos Menu align to (top | bottom) default bottom
25133 * Create a new Menu
25134 * @param {Object} config The config object
25138 Roo.bootstrap.menu.Menu = function(config){
25139 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25143 * @event beforeshow
25144 * Fires before this menu is displayed
25145 * @param {Roo.bootstrap.menu.Menu} this
25149 * @event beforehide
25150 * Fires before this menu is hidden
25151 * @param {Roo.bootstrap.menu.Menu} this
25156 * Fires after this menu is displayed
25157 * @param {Roo.bootstrap.menu.Menu} this
25162 * Fires after this menu is hidden
25163 * @param {Roo.bootstrap.menu.Menu} this
25168 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25169 * @param {Roo.bootstrap.menu.Menu} this
25170 * @param {Roo.EventObject} e
25177 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25181 weight : 'default',
25186 getChildContainer : function() {
25187 if(this.isSubMenu){
25191 return this.el.select('ul.dropdown-menu', true).first();
25194 getAutoCreate : function()
25199 cls : 'roo-menu-text',
25207 cls : 'fa ' + this.icon
25218 cls : 'dropdown-button btn btn-' + this.weight,
25223 cls : 'dropdown-toggle btn btn-' + this.weight,
25233 cls : 'dropdown-menu'
25239 if(this.pos == 'top'){
25240 cfg.cls += ' dropup';
25243 if(this.isSubMenu){
25246 cls : 'dropdown-menu'
25253 onRender : function(ct, position)
25255 this.isSubMenu = ct.hasClass('dropdown-submenu');
25257 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25260 initEvents : function()
25262 if(this.isSubMenu){
25266 this.hidden = true;
25268 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25269 this.triggerEl.on('click', this.onTriggerPress, this);
25271 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25272 this.buttonEl.on('click', this.onClick, this);
25278 if(this.isSubMenu){
25282 return this.el.select('ul.dropdown-menu', true).first();
25285 onClick : function(e)
25287 this.fireEvent("click", this, e);
25290 onTriggerPress : function(e)
25292 if (this.isVisible()) {
25299 isVisible : function(){
25300 return !this.hidden;
25305 this.fireEvent("beforeshow", this);
25307 this.hidden = false;
25308 this.el.addClass('open');
25310 Roo.get(document).on("mouseup", this.onMouseUp, this);
25312 this.fireEvent("show", this);
25319 this.fireEvent("beforehide", this);
25321 this.hidden = true;
25322 this.el.removeClass('open');
25324 Roo.get(document).un("mouseup", this.onMouseUp);
25326 this.fireEvent("hide", this);
25329 onMouseUp : function()
25343 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25346 * @class Roo.bootstrap.menu.Item
25347 * @extends Roo.bootstrap.Component
25348 * Bootstrap MenuItem class
25349 * @cfg {Boolean} submenu (true | false) default false
25350 * @cfg {String} html text of the item
25351 * @cfg {String} href the link
25352 * @cfg {Boolean} disable (true | false) default false
25353 * @cfg {Boolean} preventDefault (true | false) default true
25354 * @cfg {String} icon Font awesome icon
25355 * @cfg {String} pos Submenu align to (left | right) default right
25359 * Create a new Item
25360 * @param {Object} config The config object
25364 Roo.bootstrap.menu.Item = function(config){
25365 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25369 * Fires when the mouse is hovering over this menu
25370 * @param {Roo.bootstrap.menu.Item} this
25371 * @param {Roo.EventObject} e
25376 * Fires when the mouse exits this menu
25377 * @param {Roo.bootstrap.menu.Item} this
25378 * @param {Roo.EventObject} e
25384 * The raw click event for the entire grid.
25385 * @param {Roo.EventObject} e
25391 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25396 preventDefault: true,
25401 getAutoCreate : function()
25406 cls : 'roo-menu-item-text',
25414 cls : 'fa ' + this.icon
25423 href : this.href || '#',
25430 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25434 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25436 if(this.pos == 'left'){
25437 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25444 initEvents : function()
25446 this.el.on('mouseover', this.onMouseOver, this);
25447 this.el.on('mouseout', this.onMouseOut, this);
25449 this.el.select('a', true).first().on('click', this.onClick, this);
25453 onClick : function(e)
25455 if(this.preventDefault){
25456 e.preventDefault();
25459 this.fireEvent("click", this, e);
25462 onMouseOver : function(e)
25464 if(this.submenu && this.pos == 'left'){
25465 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25468 this.fireEvent("mouseover", this, e);
25471 onMouseOut : function(e)
25473 this.fireEvent("mouseout", this, e);
25485 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25488 * @class Roo.bootstrap.menu.Separator
25489 * @extends Roo.bootstrap.Component
25490 * Bootstrap Separator class
25493 * Create a new Separator
25494 * @param {Object} config The config object
25498 Roo.bootstrap.menu.Separator = function(config){
25499 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25502 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25504 getAutoCreate : function(){
25525 * @class Roo.bootstrap.Tooltip
25526 * Bootstrap Tooltip class
25527 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25528 * to determine which dom element triggers the tooltip.
25530 * It needs to add support for additional attributes like tooltip-position
25533 * Create a new Toolti
25534 * @param {Object} config The config object
25537 Roo.bootstrap.Tooltip = function(config){
25538 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25540 this.alignment = Roo.bootstrap.Tooltip.alignment;
25542 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25543 this.alignment = config.alignment;
25548 Roo.apply(Roo.bootstrap.Tooltip, {
25550 * @function init initialize tooltip monitoring.
25554 currentTip : false,
25555 currentRegion : false,
25561 Roo.get(document).on('mouseover', this.enter ,this);
25562 Roo.get(document).on('mouseout', this.leave, this);
25565 this.currentTip = new Roo.bootstrap.Tooltip();
25568 enter : function(ev)
25570 var dom = ev.getTarget();
25572 //Roo.log(['enter',dom]);
25573 var el = Roo.fly(dom);
25574 if (this.currentEl) {
25576 //Roo.log(this.currentEl);
25577 //Roo.log(this.currentEl.contains(dom));
25578 if (this.currentEl == el) {
25581 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25587 if (this.currentTip.el) {
25588 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25592 if(!el || el.dom == document){
25598 // you can not look for children, as if el is the body.. then everythign is the child..
25599 if (!el.attr('tooltip')) { //
25600 if (!el.select("[tooltip]").elements.length) {
25603 // is the mouse over this child...?
25604 bindEl = el.select("[tooltip]").first();
25605 var xy = ev.getXY();
25606 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25607 //Roo.log("not in region.");
25610 //Roo.log("child element over..");
25613 this.currentEl = bindEl;
25614 this.currentTip.bind(bindEl);
25615 this.currentRegion = Roo.lib.Region.getRegion(dom);
25616 this.currentTip.enter();
25619 leave : function(ev)
25621 var dom = ev.getTarget();
25622 //Roo.log(['leave',dom]);
25623 if (!this.currentEl) {
25628 if (dom != this.currentEl.dom) {
25631 var xy = ev.getXY();
25632 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25635 // only activate leave if mouse cursor is outside... bounding box..
25640 if (this.currentTip) {
25641 this.currentTip.leave();
25643 //Roo.log('clear currentEl');
25644 this.currentEl = false;
25649 'left' : ['r-l', [-2,0], 'right'],
25650 'right' : ['l-r', [2,0], 'left'],
25651 'bottom' : ['t-b', [0,2], 'top'],
25652 'top' : [ 'b-t', [0,-2], 'bottom']
25658 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25663 delay : null, // can be { show : 300 , hide: 500}
25667 hoverState : null, //???
25669 placement : 'bottom',
25673 getAutoCreate : function(){
25680 cls : 'tooltip-arrow'
25683 cls : 'tooltip-inner'
25690 bind : function(el)
25696 enter : function () {
25698 if (this.timeout != null) {
25699 clearTimeout(this.timeout);
25702 this.hoverState = 'in';
25703 //Roo.log("enter - show");
25704 if (!this.delay || !this.delay.show) {
25709 this.timeout = setTimeout(function () {
25710 if (_t.hoverState == 'in') {
25713 }, this.delay.show);
25717 clearTimeout(this.timeout);
25719 this.hoverState = 'out';
25720 if (!this.delay || !this.delay.hide) {
25726 this.timeout = setTimeout(function () {
25727 //Roo.log("leave - timeout");
25729 if (_t.hoverState == 'out') {
25731 Roo.bootstrap.Tooltip.currentEl = false;
25736 show : function (msg)
25739 this.render(document.body);
25742 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25744 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25746 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25748 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25750 var placement = typeof this.placement == 'function' ?
25751 this.placement.call(this, this.el, on_el) :
25754 var autoToken = /\s?auto?\s?/i;
25755 var autoPlace = autoToken.test(placement);
25757 placement = placement.replace(autoToken, '') || 'top';
25761 //this.el.setXY([0,0]);
25763 //this.el.dom.style.display='block';
25765 //this.el.appendTo(on_el);
25767 var p = this.getPosition();
25768 var box = this.el.getBox();
25774 var align = this.alignment[placement];
25776 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25778 if(placement == 'top' || placement == 'bottom'){
25780 placement = 'right';
25783 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25784 placement = 'left';
25787 var scroll = Roo.select('body', true).first().getScroll();
25789 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25795 this.el.alignTo(this.bindEl, align[0],align[1]);
25796 //var arrow = this.el.select('.arrow',true).first();
25797 //arrow.set(align[2],
25799 this.el.addClass(placement);
25801 this.el.addClass('in fade');
25803 this.hoverState = null;
25805 if (this.el.hasClass('fade')) {
25816 //this.el.setXY([0,0]);
25817 this.el.removeClass('in');
25833 * @class Roo.bootstrap.LocationPicker
25834 * @extends Roo.bootstrap.Component
25835 * Bootstrap LocationPicker class
25836 * @cfg {Number} latitude Position when init default 0
25837 * @cfg {Number} longitude Position when init default 0
25838 * @cfg {Number} zoom default 15
25839 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25840 * @cfg {Boolean} mapTypeControl default false
25841 * @cfg {Boolean} disableDoubleClickZoom default false
25842 * @cfg {Boolean} scrollwheel default true
25843 * @cfg {Boolean} streetViewControl default false
25844 * @cfg {Number} radius default 0
25845 * @cfg {String} locationName
25846 * @cfg {Boolean} draggable default true
25847 * @cfg {Boolean} enableAutocomplete default false
25848 * @cfg {Boolean} enableReverseGeocode default true
25849 * @cfg {String} markerTitle
25852 * Create a new LocationPicker
25853 * @param {Object} config The config object
25857 Roo.bootstrap.LocationPicker = function(config){
25859 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25864 * Fires when the picker initialized.
25865 * @param {Roo.bootstrap.LocationPicker} this
25866 * @param {Google Location} location
25870 * @event positionchanged
25871 * Fires when the picker position changed.
25872 * @param {Roo.bootstrap.LocationPicker} this
25873 * @param {Google Location} location
25875 positionchanged : true,
25878 * Fires when the map resize.
25879 * @param {Roo.bootstrap.LocationPicker} this
25884 * Fires when the map show.
25885 * @param {Roo.bootstrap.LocationPicker} this
25890 * Fires when the map hide.
25891 * @param {Roo.bootstrap.LocationPicker} this
25896 * Fires when click the map.
25897 * @param {Roo.bootstrap.LocationPicker} this
25898 * @param {Map event} e
25902 * @event mapRightClick
25903 * Fires when right click the map.
25904 * @param {Roo.bootstrap.LocationPicker} this
25905 * @param {Map event} e
25907 mapRightClick : true,
25909 * @event markerClick
25910 * Fires when click the marker.
25911 * @param {Roo.bootstrap.LocationPicker} this
25912 * @param {Map event} e
25914 markerClick : true,
25916 * @event markerRightClick
25917 * Fires when right click the marker.
25918 * @param {Roo.bootstrap.LocationPicker} this
25919 * @param {Map event} e
25921 markerRightClick : true,
25923 * @event OverlayViewDraw
25924 * Fires when OverlayView Draw
25925 * @param {Roo.bootstrap.LocationPicker} this
25927 OverlayViewDraw : true,
25929 * @event OverlayViewOnAdd
25930 * Fires when OverlayView Draw
25931 * @param {Roo.bootstrap.LocationPicker} this
25933 OverlayViewOnAdd : true,
25935 * @event OverlayViewOnRemove
25936 * Fires when OverlayView Draw
25937 * @param {Roo.bootstrap.LocationPicker} this
25939 OverlayViewOnRemove : true,
25941 * @event OverlayViewShow
25942 * Fires when OverlayView Draw
25943 * @param {Roo.bootstrap.LocationPicker} this
25944 * @param {Pixel} cpx
25946 OverlayViewShow : true,
25948 * @event OverlayViewHide
25949 * Fires when OverlayView Draw
25950 * @param {Roo.bootstrap.LocationPicker} this
25952 OverlayViewHide : true,
25954 * @event loadexception
25955 * Fires when load google lib failed.
25956 * @param {Roo.bootstrap.LocationPicker} this
25958 loadexception : true
25963 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25965 gMapContext: false,
25971 mapTypeControl: false,
25972 disableDoubleClickZoom: false,
25974 streetViewControl: false,
25978 enableAutocomplete: false,
25979 enableReverseGeocode: true,
25982 getAutoCreate: function()
25987 cls: 'roo-location-picker'
25993 initEvents: function(ct, position)
25995 if(!this.el.getWidth() || this.isApplied()){
25999 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26004 initial: function()
26006 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26007 this.fireEvent('loadexception', this);
26011 if(!this.mapTypeId){
26012 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26015 this.gMapContext = this.GMapContext();
26017 this.initOverlayView();
26019 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26023 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26024 _this.setPosition(_this.gMapContext.marker.position);
26027 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26028 _this.fireEvent('mapClick', this, event);
26032 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26033 _this.fireEvent('mapRightClick', this, event);
26037 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26038 _this.fireEvent('markerClick', this, event);
26042 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26043 _this.fireEvent('markerRightClick', this, event);
26047 this.setPosition(this.gMapContext.location);
26049 this.fireEvent('initial', this, this.gMapContext.location);
26052 initOverlayView: function()
26056 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26060 _this.fireEvent('OverlayViewDraw', _this);
26065 _this.fireEvent('OverlayViewOnAdd', _this);
26068 onRemove: function()
26070 _this.fireEvent('OverlayViewOnRemove', _this);
26073 show: function(cpx)
26075 _this.fireEvent('OverlayViewShow', _this, cpx);
26080 _this.fireEvent('OverlayViewHide', _this);
26086 fromLatLngToContainerPixel: function(event)
26088 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26091 isApplied: function()
26093 return this.getGmapContext() == false ? false : true;
26096 getGmapContext: function()
26098 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26101 GMapContext: function()
26103 var position = new google.maps.LatLng(this.latitude, this.longitude);
26105 var _map = new google.maps.Map(this.el.dom, {
26108 mapTypeId: this.mapTypeId,
26109 mapTypeControl: this.mapTypeControl,
26110 disableDoubleClickZoom: this.disableDoubleClickZoom,
26111 scrollwheel: this.scrollwheel,
26112 streetViewControl: this.streetViewControl,
26113 locationName: this.locationName,
26114 draggable: this.draggable,
26115 enableAutocomplete: this.enableAutocomplete,
26116 enableReverseGeocode: this.enableReverseGeocode
26119 var _marker = new google.maps.Marker({
26120 position: position,
26122 title: this.markerTitle,
26123 draggable: this.draggable
26130 location: position,
26131 radius: this.radius,
26132 locationName: this.locationName,
26133 addressComponents: {
26134 formatted_address: null,
26135 addressLine1: null,
26136 addressLine2: null,
26138 streetNumber: null,
26142 stateOrProvince: null
26145 domContainer: this.el.dom,
26146 geodecoder: new google.maps.Geocoder()
26150 drawCircle: function(center, radius, options)
26152 if (this.gMapContext.circle != null) {
26153 this.gMapContext.circle.setMap(null);
26157 options = Roo.apply({}, options, {
26158 strokeColor: "#0000FF",
26159 strokeOpacity: .35,
26161 fillColor: "#0000FF",
26165 options.map = this.gMapContext.map;
26166 options.radius = radius;
26167 options.center = center;
26168 this.gMapContext.circle = new google.maps.Circle(options);
26169 return this.gMapContext.circle;
26175 setPosition: function(location)
26177 this.gMapContext.location = location;
26178 this.gMapContext.marker.setPosition(location);
26179 this.gMapContext.map.panTo(location);
26180 this.drawCircle(location, this.gMapContext.radius, {});
26184 if (this.gMapContext.settings.enableReverseGeocode) {
26185 this.gMapContext.geodecoder.geocode({
26186 latLng: this.gMapContext.location
26187 }, function(results, status) {
26189 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26190 _this.gMapContext.locationName = results[0].formatted_address;
26191 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26193 _this.fireEvent('positionchanged', this, location);
26200 this.fireEvent('positionchanged', this, location);
26205 google.maps.event.trigger(this.gMapContext.map, "resize");
26207 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26209 this.fireEvent('resize', this);
26212 setPositionByLatLng: function(latitude, longitude)
26214 this.setPosition(new google.maps.LatLng(latitude, longitude));
26217 getCurrentPosition: function()
26220 latitude: this.gMapContext.location.lat(),
26221 longitude: this.gMapContext.location.lng()
26225 getAddressName: function()
26227 return this.gMapContext.locationName;
26230 getAddressComponents: function()
26232 return this.gMapContext.addressComponents;
26235 address_component_from_google_geocode: function(address_components)
26239 for (var i = 0; i < address_components.length; i++) {
26240 var component = address_components[i];
26241 if (component.types.indexOf("postal_code") >= 0) {
26242 result.postalCode = component.short_name;
26243 } else if (component.types.indexOf("street_number") >= 0) {
26244 result.streetNumber = component.short_name;
26245 } else if (component.types.indexOf("route") >= 0) {
26246 result.streetName = component.short_name;
26247 } else if (component.types.indexOf("neighborhood") >= 0) {
26248 result.city = component.short_name;
26249 } else if (component.types.indexOf("locality") >= 0) {
26250 result.city = component.short_name;
26251 } else if (component.types.indexOf("sublocality") >= 0) {
26252 result.district = component.short_name;
26253 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26254 result.stateOrProvince = component.short_name;
26255 } else if (component.types.indexOf("country") >= 0) {
26256 result.country = component.short_name;
26260 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26261 result.addressLine2 = "";
26265 setZoomLevel: function(zoom)
26267 this.gMapContext.map.setZoom(zoom);
26280 this.fireEvent('show', this);
26291 this.fireEvent('hide', this);
26296 Roo.apply(Roo.bootstrap.LocationPicker, {
26298 OverlayView : function(map, options)
26300 options = options || {};
26314 * @class Roo.bootstrap.Alert
26315 * @extends Roo.bootstrap.Component
26316 * Bootstrap Alert class
26317 * @cfg {String} title The title of alert
26318 * @cfg {String} html The content of alert
26319 * @cfg {String} weight ( success | info | warning | danger )
26320 * @cfg {String} faicon font-awesomeicon
26323 * Create a new alert
26324 * @param {Object} config The config object
26328 Roo.bootstrap.Alert = function(config){
26329 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26333 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26340 getAutoCreate : function()
26349 cls : 'roo-alert-icon'
26354 cls : 'roo-alert-title',
26359 cls : 'roo-alert-text',
26366 cfg.cn[0].cls += ' fa ' + this.faicon;
26370 cfg.cls += ' alert-' + this.weight;
26376 initEvents: function()
26378 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26381 setTitle : function(str)
26383 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26386 setText : function(str)
26388 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26391 setWeight : function(weight)
26394 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26397 this.weight = weight;
26399 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26402 setIcon : function(icon)
26405 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26408 this.faicon = icon;
26410 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26431 * @class Roo.bootstrap.UploadCropbox
26432 * @extends Roo.bootstrap.Component
26433 * Bootstrap UploadCropbox class
26434 * @cfg {String} emptyText show when image has been loaded
26435 * @cfg {String} rotateNotify show when image too small to rotate
26436 * @cfg {Number} errorTimeout default 3000
26437 * @cfg {Number} minWidth default 300
26438 * @cfg {Number} minHeight default 300
26439 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26440 * @cfg {Boolean} isDocument (true|false) default false
26441 * @cfg {String} url action url
26442 * @cfg {String} paramName default 'imageUpload'
26443 * @cfg {String} method default POST
26444 * @cfg {Boolean} loadMask (true|false) default true
26445 * @cfg {Boolean} loadingText default 'Loading...'
26448 * Create a new UploadCropbox
26449 * @param {Object} config The config object
26452 Roo.bootstrap.UploadCropbox = function(config){
26453 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26457 * @event beforeselectfile
26458 * Fire before select file
26459 * @param {Roo.bootstrap.UploadCropbox} this
26461 "beforeselectfile" : true,
26464 * Fire after initEvent
26465 * @param {Roo.bootstrap.UploadCropbox} this
26470 * Fire after initEvent
26471 * @param {Roo.bootstrap.UploadCropbox} this
26472 * @param {String} data
26477 * Fire when preparing the file data
26478 * @param {Roo.bootstrap.UploadCropbox} this
26479 * @param {Object} file
26484 * Fire when get exception
26485 * @param {Roo.bootstrap.UploadCropbox} this
26486 * @param {XMLHttpRequest} xhr
26488 "exception" : true,
26490 * @event beforeloadcanvas
26491 * Fire before load the canvas
26492 * @param {Roo.bootstrap.UploadCropbox} this
26493 * @param {String} src
26495 "beforeloadcanvas" : true,
26498 * Fire when trash image
26499 * @param {Roo.bootstrap.UploadCropbox} this
26504 * Fire when download the image
26505 * @param {Roo.bootstrap.UploadCropbox} this
26509 * @event footerbuttonclick
26510 * Fire when footerbuttonclick
26511 * @param {Roo.bootstrap.UploadCropbox} this
26512 * @param {String} type
26514 "footerbuttonclick" : true,
26518 * @param {Roo.bootstrap.UploadCropbox} this
26523 * Fire when rotate the image
26524 * @param {Roo.bootstrap.UploadCropbox} this
26525 * @param {String} pos
26530 * Fire when inspect the file
26531 * @param {Roo.bootstrap.UploadCropbox} this
26532 * @param {Object} file
26537 * Fire when xhr upload the file
26538 * @param {Roo.bootstrap.UploadCropbox} this
26539 * @param {Object} data
26544 * Fire when arrange the file data
26545 * @param {Roo.bootstrap.UploadCropbox} this
26546 * @param {Object} formData
26551 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26554 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26556 emptyText : 'Click to upload image',
26557 rotateNotify : 'Image is too small to rotate',
26558 errorTimeout : 3000,
26572 cropType : 'image/jpeg',
26574 canvasLoaded : false,
26575 isDocument : false,
26577 paramName : 'imageUpload',
26579 loadingText : 'Loading...',
26582 getAutoCreate : function()
26586 cls : 'roo-upload-cropbox',
26590 cls : 'roo-upload-cropbox-selector',
26595 cls : 'roo-upload-cropbox-body',
26596 style : 'cursor:pointer',
26600 cls : 'roo-upload-cropbox-preview'
26604 cls : 'roo-upload-cropbox-thumb'
26608 cls : 'roo-upload-cropbox-empty-notify',
26609 html : this.emptyText
26613 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26614 html : this.rotateNotify
26620 cls : 'roo-upload-cropbox-footer',
26623 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26633 onRender : function(ct, position)
26635 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26637 if (this.buttons.length) {
26639 Roo.each(this.buttons, function(bb) {
26641 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26643 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26649 this.maskEl = this.el;
26653 initEvents : function()
26655 this.urlAPI = (window.createObjectURL && window) ||
26656 (window.URL && URL.revokeObjectURL && URL) ||
26657 (window.webkitURL && webkitURL);
26659 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26660 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26662 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26663 this.selectorEl.hide();
26665 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26666 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26668 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26669 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26670 this.thumbEl.hide();
26672 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26673 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26675 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26676 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26677 this.errorEl.hide();
26679 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26680 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26681 this.footerEl.hide();
26683 this.setThumbBoxSize();
26689 this.fireEvent('initial', this);
26696 window.addEventListener("resize", function() { _this.resize(); } );
26698 this.bodyEl.on('click', this.beforeSelectFile, this);
26701 this.bodyEl.on('touchstart', this.onTouchStart, this);
26702 this.bodyEl.on('touchmove', this.onTouchMove, this);
26703 this.bodyEl.on('touchend', this.onTouchEnd, this);
26707 this.bodyEl.on('mousedown', this.onMouseDown, this);
26708 this.bodyEl.on('mousemove', this.onMouseMove, this);
26709 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26710 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26711 Roo.get(document).on('mouseup', this.onMouseUp, this);
26714 this.selectorEl.on('change', this.onFileSelected, this);
26720 this.baseScale = 1;
26722 this.baseRotate = 1;
26723 this.dragable = false;
26724 this.pinching = false;
26727 this.cropData = false;
26728 this.notifyEl.dom.innerHTML = this.emptyText;
26730 this.selectorEl.dom.value = '';
26734 resize : function()
26736 if(this.fireEvent('resize', this) != false){
26737 this.setThumbBoxPosition();
26738 this.setCanvasPosition();
26742 onFooterButtonClick : function(e, el, o, type)
26745 case 'rotate-left' :
26746 this.onRotateLeft(e);
26748 case 'rotate-right' :
26749 this.onRotateRight(e);
26752 this.beforeSelectFile(e);
26767 this.fireEvent('footerbuttonclick', this, type);
26770 beforeSelectFile : function(e)
26772 e.preventDefault();
26774 if(this.fireEvent('beforeselectfile', this) != false){
26775 this.selectorEl.dom.click();
26779 onFileSelected : function(e)
26781 e.preventDefault();
26783 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26787 var file = this.selectorEl.dom.files[0];
26789 if(this.fireEvent('inspect', this, file) != false){
26790 this.prepare(file);
26795 trash : function(e)
26797 this.fireEvent('trash', this);
26800 download : function(e)
26802 this.fireEvent('download', this);
26805 loadCanvas : function(src)
26807 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26811 this.imageEl = document.createElement('img');
26815 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26817 this.imageEl.src = src;
26821 onLoadCanvas : function()
26823 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26824 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26826 this.bodyEl.un('click', this.beforeSelectFile, this);
26828 this.notifyEl.hide();
26829 this.thumbEl.show();
26830 this.footerEl.show();
26832 this.baseRotateLevel();
26834 if(this.isDocument){
26835 this.setThumbBoxSize();
26838 this.setThumbBoxPosition();
26840 this.baseScaleLevel();
26846 this.canvasLoaded = true;
26849 this.maskEl.unmask();
26854 setCanvasPosition : function()
26856 if(!this.canvasEl){
26860 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26861 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26863 this.previewEl.setLeft(pw);
26864 this.previewEl.setTop(ph);
26868 onMouseDown : function(e)
26872 this.dragable = true;
26873 this.pinching = false;
26875 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26876 this.dragable = false;
26880 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26881 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26885 onMouseMove : function(e)
26889 if(!this.canvasLoaded){
26893 if (!this.dragable){
26897 var minX = Math.ceil(this.thumbEl.getLeft(true));
26898 var minY = Math.ceil(this.thumbEl.getTop(true));
26900 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26901 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26903 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26904 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26906 x = x - this.mouseX;
26907 y = y - this.mouseY;
26909 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26910 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26912 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26913 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26915 this.previewEl.setLeft(bgX);
26916 this.previewEl.setTop(bgY);
26918 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26919 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26922 onMouseUp : function(e)
26926 this.dragable = false;
26929 onMouseWheel : function(e)
26933 this.startScale = this.scale;
26935 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26937 if(!this.zoomable()){
26938 this.scale = this.startScale;
26947 zoomable : function()
26949 var minScale = this.thumbEl.getWidth() / this.minWidth;
26951 if(this.minWidth < this.minHeight){
26952 minScale = this.thumbEl.getHeight() / this.minHeight;
26955 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26956 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26960 (this.rotate == 0 || this.rotate == 180) &&
26962 width > this.imageEl.OriginWidth ||
26963 height > this.imageEl.OriginHeight ||
26964 (width < this.minWidth && height < this.minHeight)
26972 (this.rotate == 90 || this.rotate == 270) &&
26974 width > this.imageEl.OriginWidth ||
26975 height > this.imageEl.OriginHeight ||
26976 (width < this.minHeight && height < this.minWidth)
26983 !this.isDocument &&
26984 (this.rotate == 0 || this.rotate == 180) &&
26986 width < this.minWidth ||
26987 width > this.imageEl.OriginWidth ||
26988 height < this.minHeight ||
26989 height > this.imageEl.OriginHeight
26996 !this.isDocument &&
26997 (this.rotate == 90 || this.rotate == 270) &&
26999 width < this.minHeight ||
27000 width > this.imageEl.OriginWidth ||
27001 height < this.minWidth ||
27002 height > this.imageEl.OriginHeight
27012 onRotateLeft : function(e)
27014 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27016 var minScale = this.thumbEl.getWidth() / this.minWidth;
27018 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27019 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27021 this.startScale = this.scale;
27023 while (this.getScaleLevel() < minScale){
27025 this.scale = this.scale + 1;
27027 if(!this.zoomable()){
27032 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27033 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27038 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27045 this.scale = this.startScale;
27047 this.onRotateFail();
27052 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27054 if(this.isDocument){
27055 this.setThumbBoxSize();
27056 this.setThumbBoxPosition();
27057 this.setCanvasPosition();
27062 this.fireEvent('rotate', this, 'left');
27066 onRotateRight : function(e)
27068 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27070 var minScale = this.thumbEl.getWidth() / this.minWidth;
27072 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27073 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27075 this.startScale = this.scale;
27077 while (this.getScaleLevel() < minScale){
27079 this.scale = this.scale + 1;
27081 if(!this.zoomable()){
27086 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27087 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27092 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27099 this.scale = this.startScale;
27101 this.onRotateFail();
27106 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27108 if(this.isDocument){
27109 this.setThumbBoxSize();
27110 this.setThumbBoxPosition();
27111 this.setCanvasPosition();
27116 this.fireEvent('rotate', this, 'right');
27119 onRotateFail : function()
27121 this.errorEl.show(true);
27125 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27130 this.previewEl.dom.innerHTML = '';
27132 var canvasEl = document.createElement("canvas");
27134 var contextEl = canvasEl.getContext("2d");
27136 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27137 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27138 var center = this.imageEl.OriginWidth / 2;
27140 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27141 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27142 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27143 center = this.imageEl.OriginHeight / 2;
27146 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27148 contextEl.translate(center, center);
27149 contextEl.rotate(this.rotate * Math.PI / 180);
27151 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27153 this.canvasEl = document.createElement("canvas");
27155 this.contextEl = this.canvasEl.getContext("2d");
27157 switch (this.rotate) {
27160 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27161 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27163 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27168 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27169 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27171 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27172 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);
27176 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27181 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27182 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27184 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27185 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);
27189 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);
27194 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27195 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27197 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27198 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27202 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);
27209 this.previewEl.appendChild(this.canvasEl);
27211 this.setCanvasPosition();
27216 if(!this.canvasLoaded){
27220 var imageCanvas = document.createElement("canvas");
27222 var imageContext = imageCanvas.getContext("2d");
27224 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27225 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27227 var center = imageCanvas.width / 2;
27229 imageContext.translate(center, center);
27231 imageContext.rotate(this.rotate * Math.PI / 180);
27233 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27235 var canvas = document.createElement("canvas");
27237 var context = canvas.getContext("2d");
27239 canvas.width = this.minWidth;
27240 canvas.height = this.minHeight;
27242 switch (this.rotate) {
27245 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27246 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27248 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27249 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27251 var targetWidth = this.minWidth - 2 * x;
27252 var targetHeight = this.minHeight - 2 * y;
27256 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27257 scale = targetWidth / width;
27260 if(x > 0 && y == 0){
27261 scale = targetHeight / height;
27264 if(x > 0 && y > 0){
27265 scale = targetWidth / width;
27267 if(width < height){
27268 scale = targetHeight / height;
27272 context.scale(scale, scale);
27274 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27275 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27277 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27278 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27280 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27285 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27286 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27288 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27289 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27291 var targetWidth = this.minWidth - 2 * x;
27292 var targetHeight = this.minHeight - 2 * y;
27296 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27297 scale = targetWidth / width;
27300 if(x > 0 && y == 0){
27301 scale = targetHeight / height;
27304 if(x > 0 && y > 0){
27305 scale = targetWidth / width;
27307 if(width < height){
27308 scale = targetHeight / height;
27312 context.scale(scale, scale);
27314 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27315 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27317 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27318 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27320 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27322 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27327 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27328 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27330 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27331 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27333 var targetWidth = this.minWidth - 2 * x;
27334 var targetHeight = this.minHeight - 2 * y;
27338 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27339 scale = targetWidth / width;
27342 if(x > 0 && y == 0){
27343 scale = targetHeight / height;
27346 if(x > 0 && y > 0){
27347 scale = targetWidth / width;
27349 if(width < height){
27350 scale = targetHeight / height;
27354 context.scale(scale, scale);
27356 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27357 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27359 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27360 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27362 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27363 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27365 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27370 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27371 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27373 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27374 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27376 var targetWidth = this.minWidth - 2 * x;
27377 var targetHeight = this.minHeight - 2 * y;
27381 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27382 scale = targetWidth / width;
27385 if(x > 0 && y == 0){
27386 scale = targetHeight / height;
27389 if(x > 0 && y > 0){
27390 scale = targetWidth / width;
27392 if(width < height){
27393 scale = targetHeight / height;
27397 context.scale(scale, scale);
27399 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27400 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27402 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27403 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27405 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27407 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27414 this.cropData = canvas.toDataURL(this.cropType);
27416 if(this.fireEvent('crop', this, this.cropData) !== false){
27417 this.process(this.file, this.cropData);
27424 setThumbBoxSize : function()
27428 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27429 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27430 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27432 this.minWidth = width;
27433 this.minHeight = height;
27435 if(this.rotate == 90 || this.rotate == 270){
27436 this.minWidth = height;
27437 this.minHeight = width;
27442 width = Math.ceil(this.minWidth * height / this.minHeight);
27444 if(this.minWidth > this.minHeight){
27446 height = Math.ceil(this.minHeight * width / this.minWidth);
27449 this.thumbEl.setStyle({
27450 width : width + 'px',
27451 height : height + 'px'
27458 setThumbBoxPosition : function()
27460 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27461 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27463 this.thumbEl.setLeft(x);
27464 this.thumbEl.setTop(y);
27468 baseRotateLevel : function()
27470 this.baseRotate = 1;
27473 typeof(this.exif) != 'undefined' &&
27474 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27475 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27477 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27480 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27484 baseScaleLevel : function()
27488 if(this.isDocument){
27490 if(this.baseRotate == 6 || this.baseRotate == 8){
27492 height = this.thumbEl.getHeight();
27493 this.baseScale = height / this.imageEl.OriginWidth;
27495 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27496 width = this.thumbEl.getWidth();
27497 this.baseScale = width / this.imageEl.OriginHeight;
27503 height = this.thumbEl.getHeight();
27504 this.baseScale = height / this.imageEl.OriginHeight;
27506 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27507 width = this.thumbEl.getWidth();
27508 this.baseScale = width / this.imageEl.OriginWidth;
27514 if(this.baseRotate == 6 || this.baseRotate == 8){
27516 width = this.thumbEl.getHeight();
27517 this.baseScale = width / this.imageEl.OriginHeight;
27519 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27520 height = this.thumbEl.getWidth();
27521 this.baseScale = height / this.imageEl.OriginHeight;
27524 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27525 height = this.thumbEl.getWidth();
27526 this.baseScale = height / this.imageEl.OriginHeight;
27528 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27529 width = this.thumbEl.getHeight();
27530 this.baseScale = width / this.imageEl.OriginWidth;
27537 width = this.thumbEl.getWidth();
27538 this.baseScale = width / this.imageEl.OriginWidth;
27540 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27541 height = this.thumbEl.getHeight();
27542 this.baseScale = height / this.imageEl.OriginHeight;
27545 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27547 height = this.thumbEl.getHeight();
27548 this.baseScale = height / this.imageEl.OriginHeight;
27550 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27551 width = this.thumbEl.getWidth();
27552 this.baseScale = width / this.imageEl.OriginWidth;
27560 getScaleLevel : function()
27562 return this.baseScale * Math.pow(1.1, this.scale);
27565 onTouchStart : function(e)
27567 if(!this.canvasLoaded){
27568 this.beforeSelectFile(e);
27572 var touches = e.browserEvent.touches;
27578 if(touches.length == 1){
27579 this.onMouseDown(e);
27583 if(touches.length != 2){
27589 for(var i = 0, finger; finger = touches[i]; i++){
27590 coords.push(finger.pageX, finger.pageY);
27593 var x = Math.pow(coords[0] - coords[2], 2);
27594 var y = Math.pow(coords[1] - coords[3], 2);
27596 this.startDistance = Math.sqrt(x + y);
27598 this.startScale = this.scale;
27600 this.pinching = true;
27601 this.dragable = false;
27605 onTouchMove : function(e)
27607 if(!this.pinching && !this.dragable){
27611 var touches = e.browserEvent.touches;
27618 this.onMouseMove(e);
27624 for(var i = 0, finger; finger = touches[i]; i++){
27625 coords.push(finger.pageX, finger.pageY);
27628 var x = Math.pow(coords[0] - coords[2], 2);
27629 var y = Math.pow(coords[1] - coords[3], 2);
27631 this.endDistance = Math.sqrt(x + y);
27633 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27635 if(!this.zoomable()){
27636 this.scale = this.startScale;
27644 onTouchEnd : function(e)
27646 this.pinching = false;
27647 this.dragable = false;
27651 process : function(file, crop)
27654 this.maskEl.mask(this.loadingText);
27657 this.xhr = new XMLHttpRequest();
27659 file.xhr = this.xhr;
27661 this.xhr.open(this.method, this.url, true);
27664 "Accept": "application/json",
27665 "Cache-Control": "no-cache",
27666 "X-Requested-With": "XMLHttpRequest"
27669 for (var headerName in headers) {
27670 var headerValue = headers[headerName];
27672 this.xhr.setRequestHeader(headerName, headerValue);
27678 this.xhr.onload = function()
27680 _this.xhrOnLoad(_this.xhr);
27683 this.xhr.onerror = function()
27685 _this.xhrOnError(_this.xhr);
27688 var formData = new FormData();
27690 formData.append('returnHTML', 'NO');
27693 formData.append('crop', crop);
27696 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27697 formData.append(this.paramName, file, file.name);
27700 if(typeof(file.filename) != 'undefined'){
27701 formData.append('filename', file.filename);
27704 if(typeof(file.mimetype) != 'undefined'){
27705 formData.append('mimetype', file.mimetype);
27708 if(this.fireEvent('arrange', this, formData) != false){
27709 this.xhr.send(formData);
27713 xhrOnLoad : function(xhr)
27716 this.maskEl.unmask();
27719 if (xhr.readyState !== 4) {
27720 this.fireEvent('exception', this, xhr);
27724 var response = Roo.decode(xhr.responseText);
27726 if(!response.success){
27727 this.fireEvent('exception', this, xhr);
27731 var response = Roo.decode(xhr.responseText);
27733 this.fireEvent('upload', this, response);
27737 xhrOnError : function()
27740 this.maskEl.unmask();
27743 Roo.log('xhr on error');
27745 var response = Roo.decode(xhr.responseText);
27751 prepare : function(file)
27754 this.maskEl.mask(this.loadingText);
27760 if(typeof(file) === 'string'){
27761 this.loadCanvas(file);
27765 if(!file || !this.urlAPI){
27770 this.cropType = file.type;
27774 if(this.fireEvent('prepare', this, this.file) != false){
27776 var reader = new FileReader();
27778 reader.onload = function (e) {
27779 if (e.target.error) {
27780 Roo.log(e.target.error);
27784 var buffer = e.target.result,
27785 dataView = new DataView(buffer),
27787 maxOffset = dataView.byteLength - 4,
27791 if (dataView.getUint16(0) === 0xffd8) {
27792 while (offset < maxOffset) {
27793 markerBytes = dataView.getUint16(offset);
27795 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27796 markerLength = dataView.getUint16(offset + 2) + 2;
27797 if (offset + markerLength > dataView.byteLength) {
27798 Roo.log('Invalid meta data: Invalid segment size.');
27802 if(markerBytes == 0xffe1){
27803 _this.parseExifData(
27810 offset += markerLength;
27820 var url = _this.urlAPI.createObjectURL(_this.file);
27822 _this.loadCanvas(url);
27827 reader.readAsArrayBuffer(this.file);
27833 parseExifData : function(dataView, offset, length)
27835 var tiffOffset = offset + 10,
27839 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27840 // No Exif data, might be XMP data instead
27844 // Check for the ASCII code for "Exif" (0x45786966):
27845 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27846 // No Exif data, might be XMP data instead
27849 if (tiffOffset + 8 > dataView.byteLength) {
27850 Roo.log('Invalid Exif data: Invalid segment size.');
27853 // Check for the two null bytes:
27854 if (dataView.getUint16(offset + 8) !== 0x0000) {
27855 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27858 // Check the byte alignment:
27859 switch (dataView.getUint16(tiffOffset)) {
27861 littleEndian = true;
27864 littleEndian = false;
27867 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27870 // Check for the TIFF tag marker (0x002A):
27871 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27872 Roo.log('Invalid Exif data: Missing TIFF marker.');
27875 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27876 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27878 this.parseExifTags(
27881 tiffOffset + dirOffset,
27886 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27891 if (dirOffset + 6 > dataView.byteLength) {
27892 Roo.log('Invalid Exif data: Invalid directory offset.');
27895 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27896 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27897 if (dirEndOffset + 4 > dataView.byteLength) {
27898 Roo.log('Invalid Exif data: Invalid directory size.');
27901 for (i = 0; i < tagsNumber; i += 1) {
27905 dirOffset + 2 + 12 * i, // tag offset
27909 // Return the offset to the next directory:
27910 return dataView.getUint32(dirEndOffset, littleEndian);
27913 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27915 var tag = dataView.getUint16(offset, littleEndian);
27917 this.exif[tag] = this.getExifValue(
27921 dataView.getUint16(offset + 2, littleEndian), // tag type
27922 dataView.getUint32(offset + 4, littleEndian), // tag length
27927 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27929 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27938 Roo.log('Invalid Exif data: Invalid tag type.');
27942 tagSize = tagType.size * length;
27943 // Determine if the value is contained in the dataOffset bytes,
27944 // or if the value at the dataOffset is a pointer to the actual data:
27945 dataOffset = tagSize > 4 ?
27946 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27947 if (dataOffset + tagSize > dataView.byteLength) {
27948 Roo.log('Invalid Exif data: Invalid data offset.');
27951 if (length === 1) {
27952 return tagType.getValue(dataView, dataOffset, littleEndian);
27955 for (i = 0; i < length; i += 1) {
27956 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27959 if (tagType.ascii) {
27961 // Concatenate the chars:
27962 for (i = 0; i < values.length; i += 1) {
27964 // Ignore the terminating NULL byte(s):
27965 if (c === '\u0000') {
27977 Roo.apply(Roo.bootstrap.UploadCropbox, {
27979 'Orientation': 0x0112
27983 1: 0, //'top-left',
27985 3: 180, //'bottom-right',
27986 // 4: 'bottom-left',
27988 6: 90, //'right-top',
27989 // 7: 'right-bottom',
27990 8: 270 //'left-bottom'
27994 // byte, 8-bit unsigned int:
27996 getValue: function (dataView, dataOffset) {
27997 return dataView.getUint8(dataOffset);
28001 // ascii, 8-bit byte:
28003 getValue: function (dataView, dataOffset) {
28004 return String.fromCharCode(dataView.getUint8(dataOffset));
28009 // short, 16 bit int:
28011 getValue: function (dataView, dataOffset, littleEndian) {
28012 return dataView.getUint16(dataOffset, littleEndian);
28016 // long, 32 bit int:
28018 getValue: function (dataView, dataOffset, littleEndian) {
28019 return dataView.getUint32(dataOffset, littleEndian);
28023 // rational = two long values, first is numerator, second is denominator:
28025 getValue: function (dataView, dataOffset, littleEndian) {
28026 return dataView.getUint32(dataOffset, littleEndian) /
28027 dataView.getUint32(dataOffset + 4, littleEndian);
28031 // slong, 32 bit signed int:
28033 getValue: function (dataView, dataOffset, littleEndian) {
28034 return dataView.getInt32(dataOffset, littleEndian);
28038 // srational, two slongs, first is numerator, second is denominator:
28040 getValue: function (dataView, dataOffset, littleEndian) {
28041 return dataView.getInt32(dataOffset, littleEndian) /
28042 dataView.getInt32(dataOffset + 4, littleEndian);
28052 cls : 'btn-group roo-upload-cropbox-rotate-left',
28053 action : 'rotate-left',
28057 cls : 'btn btn-default',
28058 html : '<i class="fa fa-undo"></i>'
28064 cls : 'btn-group roo-upload-cropbox-picture',
28065 action : 'picture',
28069 cls : 'btn btn-default',
28070 html : '<i class="fa fa-picture-o"></i>'
28076 cls : 'btn-group roo-upload-cropbox-rotate-right',
28077 action : 'rotate-right',
28081 cls : 'btn btn-default',
28082 html : '<i class="fa fa-repeat"></i>'
28090 cls : 'btn-group roo-upload-cropbox-rotate-left',
28091 action : 'rotate-left',
28095 cls : 'btn btn-default',
28096 html : '<i class="fa fa-undo"></i>'
28102 cls : 'btn-group roo-upload-cropbox-download',
28103 action : 'download',
28107 cls : 'btn btn-default',
28108 html : '<i class="fa fa-download"></i>'
28114 cls : 'btn-group roo-upload-cropbox-crop',
28119 cls : 'btn btn-default',
28120 html : '<i class="fa fa-crop"></i>'
28126 cls : 'btn-group roo-upload-cropbox-trash',
28131 cls : 'btn btn-default',
28132 html : '<i class="fa fa-trash"></i>'
28138 cls : 'btn-group roo-upload-cropbox-rotate-right',
28139 action : 'rotate-right',
28143 cls : 'btn btn-default',
28144 html : '<i class="fa fa-repeat"></i>'
28152 cls : 'btn-group roo-upload-cropbox-rotate-left',
28153 action : 'rotate-left',
28157 cls : 'btn btn-default',
28158 html : '<i class="fa fa-undo"></i>'
28164 cls : 'btn-group roo-upload-cropbox-rotate-right',
28165 action : 'rotate-right',
28169 cls : 'btn btn-default',
28170 html : '<i class="fa fa-repeat"></i>'
28183 * @class Roo.bootstrap.DocumentManager
28184 * @extends Roo.bootstrap.Component
28185 * Bootstrap DocumentManager class
28186 * @cfg {String} paramName default 'imageUpload'
28187 * @cfg {String} toolTipName default 'filename'
28188 * @cfg {String} method default POST
28189 * @cfg {String} url action url
28190 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28191 * @cfg {Boolean} multiple multiple upload default true
28192 * @cfg {Number} thumbSize default 300
28193 * @cfg {String} fieldLabel
28194 * @cfg {Number} labelWidth default 4
28195 * @cfg {String} labelAlign (left|top) default left
28196 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28197 * @cfg {Number} labellg set the width of label (1-12)
28198 * @cfg {Number} labelmd set the width of label (1-12)
28199 * @cfg {Number} labelsm set the width of label (1-12)
28200 * @cfg {Number} labelxs set the width of label (1-12)
28203 * Create a new DocumentManager
28204 * @param {Object} config The config object
28207 Roo.bootstrap.DocumentManager = function(config){
28208 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28211 this.delegates = [];
28216 * Fire when initial the DocumentManager
28217 * @param {Roo.bootstrap.DocumentManager} this
28222 * inspect selected file
28223 * @param {Roo.bootstrap.DocumentManager} this
28224 * @param {File} file
28229 * Fire when xhr load exception
28230 * @param {Roo.bootstrap.DocumentManager} this
28231 * @param {XMLHttpRequest} xhr
28233 "exception" : true,
28235 * @event afterupload
28236 * Fire when xhr load exception
28237 * @param {Roo.bootstrap.DocumentManager} this
28238 * @param {XMLHttpRequest} xhr
28240 "afterupload" : true,
28243 * prepare the form data
28244 * @param {Roo.bootstrap.DocumentManager} this
28245 * @param {Object} formData
28250 * Fire when remove the file
28251 * @param {Roo.bootstrap.DocumentManager} this
28252 * @param {Object} file
28257 * Fire after refresh the file
28258 * @param {Roo.bootstrap.DocumentManager} this
28263 * Fire after click the image
28264 * @param {Roo.bootstrap.DocumentManager} this
28265 * @param {Object} file
28270 * Fire when upload a image and editable set to true
28271 * @param {Roo.bootstrap.DocumentManager} this
28272 * @param {Object} file
28276 * @event beforeselectfile
28277 * Fire before select file
28278 * @param {Roo.bootstrap.DocumentManager} this
28280 "beforeselectfile" : true,
28283 * Fire before process file
28284 * @param {Roo.bootstrap.DocumentManager} this
28285 * @param {Object} file
28292 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28301 paramName : 'imageUpload',
28302 toolTipName : 'filename',
28305 labelAlign : 'left',
28315 getAutoCreate : function()
28317 var managerWidget = {
28319 cls : 'roo-document-manager',
28323 cls : 'roo-document-manager-selector',
28328 cls : 'roo-document-manager-uploader',
28332 cls : 'roo-document-manager-upload-btn',
28333 html : '<i class="fa fa-plus"></i>'
28344 cls : 'column col-md-12',
28349 if(this.fieldLabel.length){
28354 cls : 'column col-md-12',
28355 html : this.fieldLabel
28359 cls : 'column col-md-12',
28364 if(this.labelAlign == 'left'){
28369 html : this.fieldLabel
28378 if(this.labelWidth > 12){
28379 content[0].style = "width: " + this.labelWidth + 'px';
28382 if(this.labelWidth < 13 && this.labelmd == 0){
28383 this.labelmd = this.labelWidth;
28386 if(this.labellg > 0){
28387 content[0].cls += ' col-lg-' + this.labellg;
28388 content[1].cls += ' col-lg-' + (12 - this.labellg);
28391 if(this.labelmd > 0){
28392 content[0].cls += ' col-md-' + this.labelmd;
28393 content[1].cls += ' col-md-' + (12 - this.labelmd);
28396 if(this.labelsm > 0){
28397 content[0].cls += ' col-sm-' + this.labelsm;
28398 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28401 if(this.labelxs > 0){
28402 content[0].cls += ' col-xs-' + this.labelxs;
28403 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28411 cls : 'row clearfix',
28419 initEvents : function()
28421 this.managerEl = this.el.select('.roo-document-manager', true).first();
28422 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28424 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28425 this.selectorEl.hide();
28428 this.selectorEl.attr('multiple', 'multiple');
28431 this.selectorEl.on('change', this.onFileSelected, this);
28433 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28434 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28436 this.uploader.on('click', this.onUploaderClick, this);
28438 this.renderProgressDialog();
28442 window.addEventListener("resize", function() { _this.refresh(); } );
28444 this.fireEvent('initial', this);
28447 renderProgressDialog : function()
28451 this.progressDialog = new Roo.bootstrap.Modal({
28452 cls : 'roo-document-manager-progress-dialog',
28453 allow_close : false,
28463 btnclick : function() {
28464 _this.uploadCancel();
28470 this.progressDialog.render(Roo.get(document.body));
28472 this.progress = new Roo.bootstrap.Progress({
28473 cls : 'roo-document-manager-progress',
28478 this.progress.render(this.progressDialog.getChildContainer());
28480 this.progressBar = new Roo.bootstrap.ProgressBar({
28481 cls : 'roo-document-manager-progress-bar',
28484 aria_valuemax : 12,
28488 this.progressBar.render(this.progress.getChildContainer());
28491 onUploaderClick : function(e)
28493 e.preventDefault();
28495 if(this.fireEvent('beforeselectfile', this) != false){
28496 this.selectorEl.dom.click();
28501 onFileSelected : function(e)
28503 e.preventDefault();
28505 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28509 Roo.each(this.selectorEl.dom.files, function(file){
28510 if(this.fireEvent('inspect', this, file) != false){
28511 this.files.push(file);
28521 this.selectorEl.dom.value = '';
28523 if(!this.files.length){
28527 if(this.boxes > 0 && this.files.length > this.boxes){
28528 this.files = this.files.slice(0, this.boxes);
28531 this.uploader.show();
28533 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28534 this.uploader.hide();
28543 Roo.each(this.files, function(file){
28545 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28546 var f = this.renderPreview(file);
28551 if(file.type.indexOf('image') != -1){
28552 this.delegates.push(
28554 _this.process(file);
28555 }).createDelegate(this)
28563 _this.process(file);
28564 }).createDelegate(this)
28569 this.files = files;
28571 this.delegates = this.delegates.concat(docs);
28573 if(!this.delegates.length){
28578 this.progressBar.aria_valuemax = this.delegates.length;
28585 arrange : function()
28587 if(!this.delegates.length){
28588 this.progressDialog.hide();
28593 var delegate = this.delegates.shift();
28595 this.progressDialog.show();
28597 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28599 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28604 refresh : function()
28606 this.uploader.show();
28608 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28609 this.uploader.hide();
28612 Roo.isTouch ? this.closable(false) : this.closable(true);
28614 this.fireEvent('refresh', this);
28617 onRemove : function(e, el, o)
28619 e.preventDefault();
28621 this.fireEvent('remove', this, o);
28625 remove : function(o)
28629 Roo.each(this.files, function(file){
28630 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28639 this.files = files;
28646 Roo.each(this.files, function(file){
28651 file.target.remove();
28660 onClick : function(e, el, o)
28662 e.preventDefault();
28664 this.fireEvent('click', this, o);
28668 closable : function(closable)
28670 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28672 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28684 xhrOnLoad : function(xhr)
28686 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28690 if (xhr.readyState !== 4) {
28692 this.fireEvent('exception', this, xhr);
28696 var response = Roo.decode(xhr.responseText);
28698 if(!response.success){
28700 this.fireEvent('exception', this, xhr);
28704 var file = this.renderPreview(response.data);
28706 this.files.push(file);
28710 this.fireEvent('afterupload', this, xhr);
28714 xhrOnError : function(xhr)
28716 Roo.log('xhr on error');
28718 var response = Roo.decode(xhr.responseText);
28725 process : function(file)
28727 if(this.fireEvent('process', this, file) !== false){
28728 if(this.editable && file.type.indexOf('image') != -1){
28729 this.fireEvent('edit', this, file);
28733 this.uploadStart(file, false);
28740 uploadStart : function(file, crop)
28742 this.xhr = new XMLHttpRequest();
28744 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28749 file.xhr = this.xhr;
28751 this.managerEl.createChild({
28753 cls : 'roo-document-manager-loading',
28757 tooltip : file.name,
28758 cls : 'roo-document-manager-thumb',
28759 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28765 this.xhr.open(this.method, this.url, true);
28768 "Accept": "application/json",
28769 "Cache-Control": "no-cache",
28770 "X-Requested-With": "XMLHttpRequest"
28773 for (var headerName in headers) {
28774 var headerValue = headers[headerName];
28776 this.xhr.setRequestHeader(headerName, headerValue);
28782 this.xhr.onload = function()
28784 _this.xhrOnLoad(_this.xhr);
28787 this.xhr.onerror = function()
28789 _this.xhrOnError(_this.xhr);
28792 var formData = new FormData();
28794 formData.append('returnHTML', 'NO');
28797 formData.append('crop', crop);
28800 formData.append(this.paramName, file, file.name);
28807 if(this.fireEvent('prepare', this, formData, options) != false){
28809 if(options.manually){
28813 this.xhr.send(formData);
28817 this.uploadCancel();
28820 uploadCancel : function()
28826 this.delegates = [];
28828 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28835 renderPreview : function(file)
28837 if(typeof(file.target) != 'undefined' && file.target){
28841 var previewEl = this.managerEl.createChild({
28843 cls : 'roo-document-manager-preview',
28847 tooltip : file[this.toolTipName],
28848 cls : 'roo-document-manager-thumb',
28849 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28854 html : '<i class="fa fa-times-circle"></i>'
28859 var close = previewEl.select('button.close', true).first();
28861 close.on('click', this.onRemove, this, file);
28863 file.target = previewEl;
28865 var image = previewEl.select('img', true).first();
28869 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28871 image.on('click', this.onClick, this, file);
28877 onPreviewLoad : function(file, image)
28879 if(typeof(file.target) == 'undefined' || !file.target){
28883 var width = image.dom.naturalWidth || image.dom.width;
28884 var height = image.dom.naturalHeight || image.dom.height;
28886 if(width > height){
28887 file.target.addClass('wide');
28891 file.target.addClass('tall');
28896 uploadFromSource : function(file, crop)
28898 this.xhr = new XMLHttpRequest();
28900 this.managerEl.createChild({
28902 cls : 'roo-document-manager-loading',
28906 tooltip : file.name,
28907 cls : 'roo-document-manager-thumb',
28908 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28914 this.xhr.open(this.method, this.url, true);
28917 "Accept": "application/json",
28918 "Cache-Control": "no-cache",
28919 "X-Requested-With": "XMLHttpRequest"
28922 for (var headerName in headers) {
28923 var headerValue = headers[headerName];
28925 this.xhr.setRequestHeader(headerName, headerValue);
28931 this.xhr.onload = function()
28933 _this.xhrOnLoad(_this.xhr);
28936 this.xhr.onerror = function()
28938 _this.xhrOnError(_this.xhr);
28941 var formData = new FormData();
28943 formData.append('returnHTML', 'NO');
28945 formData.append('crop', crop);
28947 if(typeof(file.filename) != 'undefined'){
28948 formData.append('filename', file.filename);
28951 if(typeof(file.mimetype) != 'undefined'){
28952 formData.append('mimetype', file.mimetype);
28957 if(this.fireEvent('prepare', this, formData) != false){
28958 this.xhr.send(formData);
28968 * @class Roo.bootstrap.DocumentViewer
28969 * @extends Roo.bootstrap.Component
28970 * Bootstrap DocumentViewer class
28971 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28972 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28975 * Create a new DocumentViewer
28976 * @param {Object} config The config object
28979 Roo.bootstrap.DocumentViewer = function(config){
28980 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28985 * Fire after initEvent
28986 * @param {Roo.bootstrap.DocumentViewer} this
28992 * @param {Roo.bootstrap.DocumentViewer} this
28997 * Fire after download button
28998 * @param {Roo.bootstrap.DocumentViewer} this
29003 * Fire after trash button
29004 * @param {Roo.bootstrap.DocumentViewer} this
29011 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29013 showDownload : true,
29017 getAutoCreate : function()
29021 cls : 'roo-document-viewer',
29025 cls : 'roo-document-viewer-body',
29029 cls : 'roo-document-viewer-thumb',
29033 cls : 'roo-document-viewer-image'
29041 cls : 'roo-document-viewer-footer',
29044 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29048 cls : 'btn-group roo-document-viewer-download',
29052 cls : 'btn btn-default',
29053 html : '<i class="fa fa-download"></i>'
29059 cls : 'btn-group roo-document-viewer-trash',
29063 cls : 'btn btn-default',
29064 html : '<i class="fa fa-trash"></i>'
29077 initEvents : function()
29079 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29080 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29082 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29083 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29085 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29086 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29088 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29089 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29091 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29092 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29094 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29095 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29097 this.bodyEl.on('click', this.onClick, this);
29098 this.downloadBtn.on('click', this.onDownload, this);
29099 this.trashBtn.on('click', this.onTrash, this);
29101 this.downloadBtn.hide();
29102 this.trashBtn.hide();
29104 if(this.showDownload){
29105 this.downloadBtn.show();
29108 if(this.showTrash){
29109 this.trashBtn.show();
29112 if(!this.showDownload && !this.showTrash) {
29113 this.footerEl.hide();
29118 initial : function()
29120 this.fireEvent('initial', this);
29124 onClick : function(e)
29126 e.preventDefault();
29128 this.fireEvent('click', this);
29131 onDownload : function(e)
29133 e.preventDefault();
29135 this.fireEvent('download', this);
29138 onTrash : function(e)
29140 e.preventDefault();
29142 this.fireEvent('trash', this);
29154 * @class Roo.bootstrap.NavProgressBar
29155 * @extends Roo.bootstrap.Component
29156 * Bootstrap NavProgressBar class
29159 * Create a new nav progress bar
29160 * @param {Object} config The config object
29163 Roo.bootstrap.NavProgressBar = function(config){
29164 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29166 this.bullets = this.bullets || [];
29168 // Roo.bootstrap.NavProgressBar.register(this);
29172 * Fires when the active item changes
29173 * @param {Roo.bootstrap.NavProgressBar} this
29174 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29175 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29182 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29187 getAutoCreate : function()
29189 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29193 cls : 'roo-navigation-bar-group',
29197 cls : 'roo-navigation-top-bar'
29201 cls : 'roo-navigation-bullets-bar',
29205 cls : 'roo-navigation-bar'
29212 cls : 'roo-navigation-bottom-bar'
29222 initEvents: function()
29227 onRender : function(ct, position)
29229 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29231 if(this.bullets.length){
29232 Roo.each(this.bullets, function(b){
29241 addItem : function(cfg)
29243 var item = new Roo.bootstrap.NavProgressItem(cfg);
29245 item.parentId = this.id;
29246 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29249 var top = new Roo.bootstrap.Element({
29251 cls : 'roo-navigation-bar-text'
29254 var bottom = new Roo.bootstrap.Element({
29256 cls : 'roo-navigation-bar-text'
29259 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29260 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29262 var topText = new Roo.bootstrap.Element({
29264 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29267 var bottomText = new Roo.bootstrap.Element({
29269 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29272 topText.onRender(top.el, null);
29273 bottomText.onRender(bottom.el, null);
29276 item.bottomEl = bottom;
29279 this.barItems.push(item);
29284 getActive : function()
29286 var active = false;
29288 Roo.each(this.barItems, function(v){
29290 if (!v.isActive()) {
29302 setActiveItem : function(item)
29306 Roo.each(this.barItems, function(v){
29307 if (v.rid == item.rid) {
29311 if (v.isActive()) {
29312 v.setActive(false);
29317 item.setActive(true);
29319 this.fireEvent('changed', this, item, prev);
29322 getBarItem: function(rid)
29326 Roo.each(this.barItems, function(e) {
29327 if (e.rid != rid) {
29338 indexOfItem : function(item)
29342 Roo.each(this.barItems, function(v, i){
29344 if (v.rid != item.rid) {
29355 setActiveNext : function()
29357 var i = this.indexOfItem(this.getActive());
29359 if (i > this.barItems.length) {
29363 this.setActiveItem(this.barItems[i+1]);
29366 setActivePrev : function()
29368 var i = this.indexOfItem(this.getActive());
29374 this.setActiveItem(this.barItems[i-1]);
29377 format : function()
29379 if(!this.barItems.length){
29383 var width = 100 / this.barItems.length;
29385 Roo.each(this.barItems, function(i){
29386 i.el.setStyle('width', width + '%');
29387 i.topEl.el.setStyle('width', width + '%');
29388 i.bottomEl.el.setStyle('width', width + '%');
29397 * Nav Progress Item
29402 * @class Roo.bootstrap.NavProgressItem
29403 * @extends Roo.bootstrap.Component
29404 * Bootstrap NavProgressItem class
29405 * @cfg {String} rid the reference id
29406 * @cfg {Boolean} active (true|false) Is item active default false
29407 * @cfg {Boolean} disabled (true|false) Is item active default false
29408 * @cfg {String} html
29409 * @cfg {String} position (top|bottom) text position default bottom
29410 * @cfg {String} icon show icon instead of number
29413 * Create a new NavProgressItem
29414 * @param {Object} config The config object
29416 Roo.bootstrap.NavProgressItem = function(config){
29417 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29422 * The raw click event for the entire grid.
29423 * @param {Roo.bootstrap.NavProgressItem} this
29424 * @param {Roo.EventObject} e
29431 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29437 position : 'bottom',
29440 getAutoCreate : function()
29442 var iconCls = 'roo-navigation-bar-item-icon';
29444 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29448 cls: 'roo-navigation-bar-item',
29458 cfg.cls += ' active';
29461 cfg.cls += ' disabled';
29467 disable : function()
29469 this.setDisabled(true);
29472 enable : function()
29474 this.setDisabled(false);
29477 initEvents: function()
29479 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29481 this.iconEl.on('click', this.onClick, this);
29484 onClick : function(e)
29486 e.preventDefault();
29492 if(this.fireEvent('click', this, e) === false){
29496 this.parent().setActiveItem(this);
29499 isActive: function ()
29501 return this.active;
29504 setActive : function(state)
29506 if(this.active == state){
29510 this.active = state;
29513 this.el.addClass('active');
29517 this.el.removeClass('active');
29522 setDisabled : function(state)
29524 if(this.disabled == state){
29528 this.disabled = state;
29531 this.el.addClass('disabled');
29535 this.el.removeClass('disabled');
29538 tooltipEl : function()
29540 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29553 * @class Roo.bootstrap.FieldLabel
29554 * @extends Roo.bootstrap.Component
29555 * Bootstrap FieldLabel class
29556 * @cfg {String} html contents of the element
29557 * @cfg {String} tag tag of the element default label
29558 * @cfg {String} cls class of the element
29559 * @cfg {String} target label target
29560 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29561 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29562 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29563 * @cfg {String} iconTooltip default "This field is required"
29566 * Create a new FieldLabel
29567 * @param {Object} config The config object
29570 Roo.bootstrap.FieldLabel = function(config){
29571 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29576 * Fires after the field has been marked as invalid.
29577 * @param {Roo.form.FieldLabel} this
29578 * @param {String} msg The validation message
29583 * Fires after the field has been validated with no errors.
29584 * @param {Roo.form.FieldLabel} this
29590 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29597 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29598 validClass : 'text-success fa fa-lg fa-check',
29599 iconTooltip : 'This field is required',
29601 getAutoCreate : function(){
29605 cls : 'roo-bootstrap-field-label ' + this.cls,
29611 tooltip : this.iconTooltip
29623 initEvents: function()
29625 Roo.bootstrap.Element.superclass.initEvents.call(this);
29627 this.iconEl = this.el.select('i', true).first();
29629 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29631 Roo.bootstrap.FieldLabel.register(this);
29635 * Mark this field as valid
29637 markValid : function()
29639 this.iconEl.show();
29641 this.iconEl.removeClass(this.invalidClass);
29643 this.iconEl.addClass(this.validClass);
29645 this.fireEvent('valid', this);
29649 * Mark this field as invalid
29650 * @param {String} msg The validation message
29652 markInvalid : function(msg)
29654 this.iconEl.show();
29656 this.iconEl.removeClass(this.validClass);
29658 this.iconEl.addClass(this.invalidClass);
29660 this.fireEvent('invalid', this, msg);
29666 Roo.apply(Roo.bootstrap.FieldLabel, {
29671 * register a FieldLabel Group
29672 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29674 register : function(label)
29676 if(this.groups.hasOwnProperty(label.target)){
29680 this.groups[label.target] = label;
29684 * fetch a FieldLabel Group based on the target
29685 * @param {string} target
29686 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29688 get: function(target) {
29689 if (typeof(this.groups[target]) == 'undefined') {
29693 return this.groups[target] ;
29702 * page DateSplitField.
29708 * @class Roo.bootstrap.DateSplitField
29709 * @extends Roo.bootstrap.Component
29710 * Bootstrap DateSplitField class
29711 * @cfg {string} fieldLabel - the label associated
29712 * @cfg {Number} labelWidth set the width of label (0-12)
29713 * @cfg {String} labelAlign (top|left)
29714 * @cfg {Boolean} dayAllowBlank (true|false) default false
29715 * @cfg {Boolean} monthAllowBlank (true|false) default false
29716 * @cfg {Boolean} yearAllowBlank (true|false) default false
29717 * @cfg {string} dayPlaceholder
29718 * @cfg {string} monthPlaceholder
29719 * @cfg {string} yearPlaceholder
29720 * @cfg {string} dayFormat default 'd'
29721 * @cfg {string} monthFormat default 'm'
29722 * @cfg {string} yearFormat default 'Y'
29723 * @cfg {Number} labellg set the width of label (1-12)
29724 * @cfg {Number} labelmd set the width of label (1-12)
29725 * @cfg {Number} labelsm set the width of label (1-12)
29726 * @cfg {Number} labelxs set the width of label (1-12)
29730 * Create a new DateSplitField
29731 * @param {Object} config The config object
29734 Roo.bootstrap.DateSplitField = function(config){
29735 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29741 * getting the data of years
29742 * @param {Roo.bootstrap.DateSplitField} this
29743 * @param {Object} years
29748 * getting the data of days
29749 * @param {Roo.bootstrap.DateSplitField} this
29750 * @param {Object} days
29755 * Fires after the field has been marked as invalid.
29756 * @param {Roo.form.Field} this
29757 * @param {String} msg The validation message
29762 * Fires after the field has been validated with no errors.
29763 * @param {Roo.form.Field} this
29769 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29772 labelAlign : 'top',
29774 dayAllowBlank : false,
29775 monthAllowBlank : false,
29776 yearAllowBlank : false,
29777 dayPlaceholder : '',
29778 monthPlaceholder : '',
29779 yearPlaceholder : '',
29783 isFormField : true,
29789 getAutoCreate : function()
29793 cls : 'row roo-date-split-field-group',
29798 cls : 'form-hidden-field roo-date-split-field-group-value',
29804 var labelCls = 'col-md-12';
29805 var contentCls = 'col-md-4';
29807 if(this.fieldLabel){
29811 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29815 html : this.fieldLabel
29820 if(this.labelAlign == 'left'){
29822 if(this.labelWidth > 12){
29823 label.style = "width: " + this.labelWidth + 'px';
29826 if(this.labelWidth < 13 && this.labelmd == 0){
29827 this.labelmd = this.labelWidth;
29830 if(this.labellg > 0){
29831 labelCls = ' col-lg-' + this.labellg;
29832 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29835 if(this.labelmd > 0){
29836 labelCls = ' col-md-' + this.labelmd;
29837 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29840 if(this.labelsm > 0){
29841 labelCls = ' col-sm-' + this.labelsm;
29842 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29845 if(this.labelxs > 0){
29846 labelCls = ' col-xs-' + this.labelxs;
29847 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29851 label.cls += ' ' + labelCls;
29853 cfg.cn.push(label);
29856 Roo.each(['day', 'month', 'year'], function(t){
29859 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29866 inputEl: function ()
29868 return this.el.select('.roo-date-split-field-group-value', true).first();
29871 onRender : function(ct, position)
29875 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29877 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29879 this.dayField = new Roo.bootstrap.ComboBox({
29880 allowBlank : this.dayAllowBlank,
29881 alwaysQuery : true,
29882 displayField : 'value',
29885 forceSelection : true,
29887 placeholder : this.dayPlaceholder,
29888 selectOnFocus : true,
29889 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29890 triggerAction : 'all',
29892 valueField : 'value',
29893 store : new Roo.data.SimpleStore({
29894 data : (function() {
29896 _this.fireEvent('days', _this, days);
29899 fields : [ 'value' ]
29902 select : function (_self, record, index)
29904 _this.setValue(_this.getValue());
29909 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29911 this.monthField = new Roo.bootstrap.MonthField({
29912 after : '<i class=\"fa fa-calendar\"></i>',
29913 allowBlank : this.monthAllowBlank,
29914 placeholder : this.monthPlaceholder,
29917 render : function (_self)
29919 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29920 e.preventDefault();
29924 select : function (_self, oldvalue, newvalue)
29926 _this.setValue(_this.getValue());
29931 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29933 this.yearField = new Roo.bootstrap.ComboBox({
29934 allowBlank : this.yearAllowBlank,
29935 alwaysQuery : true,
29936 displayField : 'value',
29939 forceSelection : true,
29941 placeholder : this.yearPlaceholder,
29942 selectOnFocus : true,
29943 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29944 triggerAction : 'all',
29946 valueField : 'value',
29947 store : new Roo.data.SimpleStore({
29948 data : (function() {
29950 _this.fireEvent('years', _this, years);
29953 fields : [ 'value' ]
29956 select : function (_self, record, index)
29958 _this.setValue(_this.getValue());
29963 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29966 setValue : function(v, format)
29968 this.inputEl.dom.value = v;
29970 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29972 var d = Date.parseDate(v, f);
29979 this.setDay(d.format(this.dayFormat));
29980 this.setMonth(d.format(this.monthFormat));
29981 this.setYear(d.format(this.yearFormat));
29988 setDay : function(v)
29990 this.dayField.setValue(v);
29991 this.inputEl.dom.value = this.getValue();
29996 setMonth : function(v)
29998 this.monthField.setValue(v, true);
29999 this.inputEl.dom.value = this.getValue();
30004 setYear : function(v)
30006 this.yearField.setValue(v);
30007 this.inputEl.dom.value = this.getValue();
30012 getDay : function()
30014 return this.dayField.getValue();
30017 getMonth : function()
30019 return this.monthField.getValue();
30022 getYear : function()
30024 return this.yearField.getValue();
30027 getValue : function()
30029 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30031 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30041 this.inputEl.dom.value = '';
30046 validate : function()
30048 var d = this.dayField.validate();
30049 var m = this.monthField.validate();
30050 var y = this.yearField.validate();
30055 (!this.dayAllowBlank && !d) ||
30056 (!this.monthAllowBlank && !m) ||
30057 (!this.yearAllowBlank && !y)
30062 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30071 this.markInvalid();
30076 markValid : function()
30079 var label = this.el.select('label', true).first();
30080 var icon = this.el.select('i.fa-star', true).first();
30086 this.fireEvent('valid', this);
30090 * Mark this field as invalid
30091 * @param {String} msg The validation message
30093 markInvalid : function(msg)
30096 var label = this.el.select('label', true).first();
30097 var icon = this.el.select('i.fa-star', true).first();
30099 if(label && !icon){
30100 this.el.select('.roo-date-split-field-label', true).createChild({
30102 cls : 'text-danger fa fa-lg fa-star',
30103 tooltip : 'This field is required',
30104 style : 'margin-right:5px;'
30108 this.fireEvent('invalid', this, msg);
30111 clearInvalid : function()
30113 var label = this.el.select('label', true).first();
30114 var icon = this.el.select('i.fa-star', true).first();
30120 this.fireEvent('valid', this);
30123 getName: function()
30133 * http://masonry.desandro.com
30135 * The idea is to render all the bricks based on vertical width...
30137 * The original code extends 'outlayer' - we might need to use that....
30143 * @class Roo.bootstrap.LayoutMasonry
30144 * @extends Roo.bootstrap.Component
30145 * Bootstrap Layout Masonry class
30148 * Create a new Element
30149 * @param {Object} config The config object
30152 Roo.bootstrap.LayoutMasonry = function(config){
30154 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30158 Roo.bootstrap.LayoutMasonry.register(this);
30164 * Fire after layout the items
30165 * @param {Roo.bootstrap.LayoutMasonry} this
30166 * @param {Roo.EventObject} e
30173 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30176 * @cfg {Boolean} isLayoutInstant = no animation?
30178 isLayoutInstant : false, // needed?
30181 * @cfg {Number} boxWidth width of the columns
30186 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30191 * @cfg {Number} padWidth padding below box..
30196 * @cfg {Number} gutter gutter width..
30201 * @cfg {Number} maxCols maximum number of columns
30207 * @cfg {Boolean} isAutoInitial defalut true
30209 isAutoInitial : true,
30214 * @cfg {Boolean} isHorizontal defalut false
30216 isHorizontal : false,
30218 currentSize : null,
30224 bricks: null, //CompositeElement
30228 _isLayoutInited : false,
30230 // isAlternative : false, // only use for vertical layout...
30233 * @cfg {Number} alternativePadWidth padding below box..
30235 alternativePadWidth : 50,
30237 selectedBrick : [],
30239 getAutoCreate : function(){
30241 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30245 cls: 'blog-masonary-wrapper ' + this.cls,
30247 cls : 'mas-boxes masonary'
30254 getChildContainer: function( )
30256 if (this.boxesEl) {
30257 return this.boxesEl;
30260 this.boxesEl = this.el.select('.mas-boxes').first();
30262 return this.boxesEl;
30266 initEvents : function()
30270 if(this.isAutoInitial){
30271 Roo.log('hook children rendered');
30272 this.on('childrenrendered', function() {
30273 Roo.log('children rendered');
30279 initial : function()
30281 this.selectedBrick = [];
30283 this.currentSize = this.el.getBox(true);
30285 Roo.EventManager.onWindowResize(this.resize, this);
30287 if(!this.isAutoInitial){
30295 //this.layout.defer(500,this);
30299 resize : function()
30301 var cs = this.el.getBox(true);
30304 this.currentSize.width == cs.width &&
30305 this.currentSize.x == cs.x &&
30306 this.currentSize.height == cs.height &&
30307 this.currentSize.y == cs.y
30309 Roo.log("no change in with or X or Y");
30313 this.currentSize = cs;
30319 layout : function()
30321 this._resetLayout();
30323 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30325 this.layoutItems( isInstant );
30327 this._isLayoutInited = true;
30329 this.fireEvent('layout', this);
30333 _resetLayout : function()
30335 if(this.isHorizontal){
30336 this.horizontalMeasureColumns();
30340 this.verticalMeasureColumns();
30344 verticalMeasureColumns : function()
30346 this.getContainerWidth();
30348 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30349 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30353 var boxWidth = this.boxWidth + this.padWidth;
30355 if(this.containerWidth < this.boxWidth){
30356 boxWidth = this.containerWidth
30359 var containerWidth = this.containerWidth;
30361 var cols = Math.floor(containerWidth / boxWidth);
30363 this.cols = Math.max( cols, 1 );
30365 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30367 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30369 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30371 this.colWidth = boxWidth + avail - this.padWidth;
30373 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30374 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30377 horizontalMeasureColumns : function()
30379 this.getContainerWidth();
30381 var boxWidth = this.boxWidth;
30383 if(this.containerWidth < boxWidth){
30384 boxWidth = this.containerWidth;
30387 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30389 this.el.setHeight(boxWidth);
30393 getContainerWidth : function()
30395 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30398 layoutItems : function( isInstant )
30400 Roo.log(this.bricks);
30402 var items = Roo.apply([], this.bricks);
30404 if(this.isHorizontal){
30405 this._horizontalLayoutItems( items , isInstant );
30409 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30410 // this._verticalAlternativeLayoutItems( items , isInstant );
30414 this._verticalLayoutItems( items , isInstant );
30418 _verticalLayoutItems : function ( items , isInstant)
30420 if ( !items || !items.length ) {
30425 ['xs', 'xs', 'xs', 'tall'],
30426 ['xs', 'xs', 'tall'],
30427 ['xs', 'xs', 'sm'],
30428 ['xs', 'xs', 'xs'],
30434 ['sm', 'xs', 'xs'],
30438 ['tall', 'xs', 'xs', 'xs'],
30439 ['tall', 'xs', 'xs'],
30451 Roo.each(items, function(item, k){
30453 switch (item.size) {
30454 // these layouts take up a full box,
30465 boxes.push([item]);
30488 var filterPattern = function(box, length)
30496 var pattern = box.slice(0, length);
30500 Roo.each(pattern, function(i){
30501 format.push(i.size);
30504 Roo.each(standard, function(s){
30506 if(String(s) != String(format)){
30515 if(!match && length == 1){
30520 filterPattern(box, length - 1);
30524 queue.push(pattern);
30526 box = box.slice(length, box.length);
30528 filterPattern(box, 4);
30534 Roo.each(boxes, function(box, k){
30540 if(box.length == 1){
30545 filterPattern(box, 4);
30549 this._processVerticalLayoutQueue( queue, isInstant );
30553 // _verticalAlternativeLayoutItems : function( items , isInstant )
30555 // if ( !items || !items.length ) {
30559 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30563 _horizontalLayoutItems : function ( items , isInstant)
30565 if ( !items || !items.length || items.length < 3) {
30571 var eItems = items.slice(0, 3);
30573 items = items.slice(3, items.length);
30576 ['xs', 'xs', 'xs', 'wide'],
30577 ['xs', 'xs', 'wide'],
30578 ['xs', 'xs', 'sm'],
30579 ['xs', 'xs', 'xs'],
30585 ['sm', 'xs', 'xs'],
30589 ['wide', 'xs', 'xs', 'xs'],
30590 ['wide', 'xs', 'xs'],
30603 Roo.each(items, function(item, k){
30605 switch (item.size) {
30616 boxes.push([item]);
30640 var filterPattern = function(box, length)
30648 var pattern = box.slice(0, length);
30652 Roo.each(pattern, function(i){
30653 format.push(i.size);
30656 Roo.each(standard, function(s){
30658 if(String(s) != String(format)){
30667 if(!match && length == 1){
30672 filterPattern(box, length - 1);
30676 queue.push(pattern);
30678 box = box.slice(length, box.length);
30680 filterPattern(box, 4);
30686 Roo.each(boxes, function(box, k){
30692 if(box.length == 1){
30697 filterPattern(box, 4);
30704 var pos = this.el.getBox(true);
30708 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30710 var hit_end = false;
30712 Roo.each(queue, function(box){
30716 Roo.each(box, function(b){
30718 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30728 Roo.each(box, function(b){
30730 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30733 mx = Math.max(mx, b.x);
30737 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30741 Roo.each(box, function(b){
30743 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30757 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30760 /** Sets position of item in DOM
30761 * @param {Element} item
30762 * @param {Number} x - horizontal position
30763 * @param {Number} y - vertical position
30764 * @param {Boolean} isInstant - disables transitions
30766 _processVerticalLayoutQueue : function( queue, isInstant )
30768 var pos = this.el.getBox(true);
30773 for (var i = 0; i < this.cols; i++){
30777 Roo.each(queue, function(box, k){
30779 var col = k % this.cols;
30781 Roo.each(box, function(b,kk){
30783 b.el.position('absolute');
30785 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30786 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30788 if(b.size == 'md-left' || b.size == 'md-right'){
30789 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30790 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30793 b.el.setWidth(width);
30794 b.el.setHeight(height);
30796 b.el.select('iframe',true).setSize(width,height);
30800 for (var i = 0; i < this.cols; i++){
30802 if(maxY[i] < maxY[col]){
30807 col = Math.min(col, i);
30811 x = pos.x + col * (this.colWidth + this.padWidth);
30815 var positions = [];
30817 switch (box.length){
30819 positions = this.getVerticalOneBoxColPositions(x, y, box);
30822 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30825 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30828 positions = this.getVerticalFourBoxColPositions(x, y, box);
30834 Roo.each(box, function(b,kk){
30836 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30838 var sz = b.el.getSize();
30840 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30848 for (var i = 0; i < this.cols; i++){
30849 mY = Math.max(mY, maxY[i]);
30852 this.el.setHeight(mY - pos.y);
30856 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30858 // var pos = this.el.getBox(true);
30861 // var maxX = pos.right;
30863 // var maxHeight = 0;
30865 // Roo.each(items, function(item, k){
30869 // item.el.position('absolute');
30871 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30873 // item.el.setWidth(width);
30875 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30877 // item.el.setHeight(height);
30880 // item.el.setXY([x, y], isInstant ? false : true);
30882 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30885 // y = y + height + this.alternativePadWidth;
30887 // maxHeight = maxHeight + height + this.alternativePadWidth;
30891 // this.el.setHeight(maxHeight);
30895 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30897 var pos = this.el.getBox(true);
30902 var maxX = pos.right;
30904 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30906 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30908 Roo.each(queue, function(box, k){
30910 Roo.each(box, function(b, kk){
30912 b.el.position('absolute');
30914 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30915 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30917 if(b.size == 'md-left' || b.size == 'md-right'){
30918 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30919 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30922 b.el.setWidth(width);
30923 b.el.setHeight(height);
30931 var positions = [];
30933 switch (box.length){
30935 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30938 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30941 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30944 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30950 Roo.each(box, function(b,kk){
30952 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30954 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30962 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30964 Roo.each(eItems, function(b,k){
30966 b.size = (k == 0) ? 'sm' : 'xs';
30967 b.x = (k == 0) ? 2 : 1;
30968 b.y = (k == 0) ? 2 : 1;
30970 b.el.position('absolute');
30972 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30974 b.el.setWidth(width);
30976 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30978 b.el.setHeight(height);
30982 var positions = [];
30985 x : maxX - this.unitWidth * 2 - this.gutter,
30990 x : maxX - this.unitWidth,
30991 y : minY + (this.unitWidth + this.gutter) * 2
30995 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30999 Roo.each(eItems, function(b,k){
31001 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31007 getVerticalOneBoxColPositions : function(x, y, box)
31011 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31013 if(box[0].size == 'md-left'){
31017 if(box[0].size == 'md-right'){
31022 x : x + (this.unitWidth + this.gutter) * rand,
31029 getVerticalTwoBoxColPositions : function(x, y, box)
31033 if(box[0].size == 'xs'){
31037 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31041 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31055 x : x + (this.unitWidth + this.gutter) * 2,
31056 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31063 getVerticalThreeBoxColPositions : function(x, y, box)
31067 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31075 x : x + (this.unitWidth + this.gutter) * 1,
31080 x : x + (this.unitWidth + this.gutter) * 2,
31088 if(box[0].size == 'xs' && box[1].size == 'xs'){
31097 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31101 x : x + (this.unitWidth + this.gutter) * 1,
31115 x : x + (this.unitWidth + this.gutter) * 2,
31120 x : x + (this.unitWidth + this.gutter) * 2,
31121 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31128 getVerticalFourBoxColPositions : function(x, y, box)
31132 if(box[0].size == 'xs'){
31141 y : y + (this.unitHeight + this.gutter) * 1
31146 y : y + (this.unitHeight + this.gutter) * 2
31150 x : x + (this.unitWidth + this.gutter) * 1,
31164 x : x + (this.unitWidth + this.gutter) * 2,
31169 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31170 y : y + (this.unitHeight + this.gutter) * 1
31174 x : x + (this.unitWidth + this.gutter) * 2,
31175 y : y + (this.unitWidth + this.gutter) * 2
31182 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31186 if(box[0].size == 'md-left'){
31188 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31195 if(box[0].size == 'md-right'){
31197 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31198 y : minY + (this.unitWidth + this.gutter) * 1
31204 var rand = Math.floor(Math.random() * (4 - box[0].y));
31207 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31208 y : minY + (this.unitWidth + this.gutter) * rand
31215 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31219 if(box[0].size == 'xs'){
31222 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31227 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31228 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31236 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31241 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31242 y : minY + (this.unitWidth + this.gutter) * 2
31249 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31253 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31256 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31261 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31262 y : minY + (this.unitWidth + this.gutter) * 1
31266 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31267 y : minY + (this.unitWidth + this.gutter) * 2
31274 if(box[0].size == 'xs' && box[1].size == 'xs'){
31277 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31282 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31287 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31288 y : minY + (this.unitWidth + this.gutter) * 1
31296 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31301 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31302 y : minY + (this.unitWidth + this.gutter) * 2
31306 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31307 y : minY + (this.unitWidth + this.gutter) * 2
31314 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31318 if(box[0].size == 'xs'){
31321 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31326 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].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) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31336 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31337 y : minY + (this.unitWidth + this.gutter) * 1
31345 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31350 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31351 y : minY + (this.unitWidth + this.gutter) * 2
31355 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].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) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31361 y : minY + (this.unitWidth + this.gutter) * 2
31369 * remove a Masonry Brick
31370 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31372 removeBrick : function(brick_id)
31378 for (var i = 0; i<this.bricks.length; i++) {
31379 if (this.bricks[i].id == brick_id) {
31380 this.bricks.splice(i,1);
31381 this.el.dom.removeChild(Roo.get(brick_id).dom);
31388 * adds a Masonry Brick
31389 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31391 addBrick : function(cfg)
31393 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31394 //this.register(cn);
31395 cn.parentId = this.id;
31396 cn.onRender(this.el, null);
31401 * register a Masonry Brick
31402 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31405 register : function(brick)
31407 this.bricks.push(brick);
31408 brick.masonryId = this.id;
31412 * clear all the Masonry Brick
31414 clearAll : function()
31417 //this.getChildContainer().dom.innerHTML = "";
31418 this.el.dom.innerHTML = '';
31421 getSelected : function()
31423 if (!this.selectedBrick) {
31427 return this.selectedBrick;
31431 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31435 * register a Masonry Layout
31436 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31439 register : function(layout)
31441 this.groups[layout.id] = layout;
31444 * fetch a Masonry Layout based on the masonry layout ID
31445 * @param {string} the masonry layout to add
31446 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31449 get: function(layout_id) {
31450 if (typeof(this.groups[layout_id]) == 'undefined') {
31453 return this.groups[layout_id] ;
31465 * http://masonry.desandro.com
31467 * The idea is to render all the bricks based on vertical width...
31469 * The original code extends 'outlayer' - we might need to use that....
31475 * @class Roo.bootstrap.LayoutMasonryAuto
31476 * @extends Roo.bootstrap.Component
31477 * Bootstrap Layout Masonry class
31480 * Create a new Element
31481 * @param {Object} config The config object
31484 Roo.bootstrap.LayoutMasonryAuto = function(config){
31485 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31488 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31491 * @cfg {Boolean} isFitWidth - resize the width..
31493 isFitWidth : false, // options..
31495 * @cfg {Boolean} isOriginLeft = left align?
31497 isOriginLeft : true,
31499 * @cfg {Boolean} isOriginTop = top align?
31501 isOriginTop : false,
31503 * @cfg {Boolean} isLayoutInstant = no animation?
31505 isLayoutInstant : false, // needed?
31507 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31509 isResizingContainer : true,
31511 * @cfg {Number} columnWidth width of the columns
31517 * @cfg {Number} maxCols maximum number of columns
31522 * @cfg {Number} padHeight padding below box..
31528 * @cfg {Boolean} isAutoInitial defalut true
31531 isAutoInitial : true,
31537 initialColumnWidth : 0,
31538 currentSize : null,
31540 colYs : null, // array.
31547 bricks: null, //CompositeElement
31548 cols : 0, // array?
31549 // element : null, // wrapped now this.el
31550 _isLayoutInited : null,
31553 getAutoCreate : function(){
31557 cls: 'blog-masonary-wrapper ' + this.cls,
31559 cls : 'mas-boxes masonary'
31566 getChildContainer: function( )
31568 if (this.boxesEl) {
31569 return this.boxesEl;
31572 this.boxesEl = this.el.select('.mas-boxes').first();
31574 return this.boxesEl;
31578 initEvents : function()
31582 if(this.isAutoInitial){
31583 Roo.log('hook children rendered');
31584 this.on('childrenrendered', function() {
31585 Roo.log('children rendered');
31592 initial : function()
31594 this.reloadItems();
31596 this.currentSize = this.el.getBox(true);
31598 /// was window resize... - let's see if this works..
31599 Roo.EventManager.onWindowResize(this.resize, this);
31601 if(!this.isAutoInitial){
31606 this.layout.defer(500,this);
31609 reloadItems: function()
31611 this.bricks = this.el.select('.masonry-brick', true);
31613 this.bricks.each(function(b) {
31614 //Roo.log(b.getSize());
31615 if (!b.attr('originalwidth')) {
31616 b.attr('originalwidth', b.getSize().width);
31621 Roo.log(this.bricks.elements.length);
31624 resize : function()
31627 var cs = this.el.getBox(true);
31629 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31630 Roo.log("no change in with or X");
31633 this.currentSize = cs;
31637 layout : function()
31640 this._resetLayout();
31641 //this._manageStamps();
31643 // don't animate first layout
31644 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31645 this.layoutItems( isInstant );
31647 // flag for initalized
31648 this._isLayoutInited = true;
31651 layoutItems : function( isInstant )
31653 //var items = this._getItemsForLayout( this.items );
31654 // original code supports filtering layout items.. we just ignore it..
31656 this._layoutItems( this.bricks , isInstant );
31658 this._postLayout();
31660 _layoutItems : function ( items , isInstant)
31662 //this.fireEvent( 'layout', this, items );
31665 if ( !items || !items.elements.length ) {
31666 // no items, emit event with empty array
31671 items.each(function(item) {
31672 Roo.log("layout item");
31674 // get x/y object from method
31675 var position = this._getItemLayoutPosition( item );
31677 position.item = item;
31678 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31679 queue.push( position );
31682 this._processLayoutQueue( queue );
31684 /** Sets position of item in DOM
31685 * @param {Element} item
31686 * @param {Number} x - horizontal position
31687 * @param {Number} y - vertical position
31688 * @param {Boolean} isInstant - disables transitions
31690 _processLayoutQueue : function( queue )
31692 for ( var i=0, len = queue.length; i < len; i++ ) {
31693 var obj = queue[i];
31694 obj.item.position('absolute');
31695 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31701 * Any logic you want to do after each layout,
31702 * i.e. size the container
31704 _postLayout : function()
31706 this.resizeContainer();
31709 resizeContainer : function()
31711 if ( !this.isResizingContainer ) {
31714 var size = this._getContainerSize();
31716 this.el.setSize(size.width,size.height);
31717 this.boxesEl.setSize(size.width,size.height);
31723 _resetLayout : function()
31725 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31726 this.colWidth = this.el.getWidth();
31727 //this.gutter = this.el.getWidth();
31729 this.measureColumns();
31735 this.colYs.push( 0 );
31741 measureColumns : function()
31743 this.getContainerWidth();
31744 // if columnWidth is 0, default to outerWidth of first item
31745 if ( !this.columnWidth ) {
31746 var firstItem = this.bricks.first();
31747 Roo.log(firstItem);
31748 this.columnWidth = this.containerWidth;
31749 if (firstItem && firstItem.attr('originalwidth') ) {
31750 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31752 // columnWidth fall back to item of first element
31753 Roo.log("set column width?");
31754 this.initialColumnWidth = this.columnWidth ;
31756 // if first elem has no width, default to size of container
31761 if (this.initialColumnWidth) {
31762 this.columnWidth = this.initialColumnWidth;
31767 // column width is fixed at the top - however if container width get's smaller we should
31770 // this bit calcs how man columns..
31772 var columnWidth = this.columnWidth += this.gutter;
31774 // calculate columns
31775 var containerWidth = this.containerWidth + this.gutter;
31777 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31778 // fix rounding errors, typically with gutters
31779 var excess = columnWidth - containerWidth % columnWidth;
31782 // if overshoot is less than a pixel, round up, otherwise floor it
31783 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31784 cols = Math[ mathMethod ]( cols );
31785 this.cols = Math.max( cols, 1 );
31786 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31788 // padding positioning..
31789 var totalColWidth = this.cols * this.columnWidth;
31790 var padavail = this.containerWidth - totalColWidth;
31791 // so for 2 columns - we need 3 'pads'
31793 var padNeeded = (1+this.cols) * this.padWidth;
31795 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31797 this.columnWidth += padExtra
31798 //this.padWidth = Math.floor(padavail / ( this.cols));
31800 // adjust colum width so that padding is fixed??
31802 // we have 3 columns ... total = width * 3
31803 // we have X left over... that should be used by
31805 //if (this.expandC) {
31813 getContainerWidth : function()
31815 /* // container is parent if fit width
31816 var container = this.isFitWidth ? this.element.parentNode : this.element;
31817 // check that this.size and size are there
31818 // IE8 triggers resize on body size change, so they might not be
31820 var size = getSize( container ); //FIXME
31821 this.containerWidth = size && size.innerWidth; //FIXME
31824 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31828 _getItemLayoutPosition : function( item ) // what is item?
31830 // we resize the item to our columnWidth..
31832 item.setWidth(this.columnWidth);
31833 item.autoBoxAdjust = false;
31835 var sz = item.getSize();
31837 // how many columns does this brick span
31838 var remainder = this.containerWidth % this.columnWidth;
31840 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31841 // round if off by 1 pixel, otherwise use ceil
31842 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31843 colSpan = Math.min( colSpan, this.cols );
31845 // normally this should be '1' as we dont' currently allow multi width columns..
31847 var colGroup = this._getColGroup( colSpan );
31848 // get the minimum Y value from the columns
31849 var minimumY = Math.min.apply( Math, colGroup );
31850 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31852 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31854 // position the brick
31856 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31857 y: this.currentSize.y + minimumY + this.padHeight
31861 // apply setHeight to necessary columns
31862 var setHeight = minimumY + sz.height + this.padHeight;
31863 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31865 var setSpan = this.cols + 1 - colGroup.length;
31866 for ( var i = 0; i < setSpan; i++ ) {
31867 this.colYs[ shortColIndex + i ] = setHeight ;
31874 * @param {Number} colSpan - number of columns the element spans
31875 * @returns {Array} colGroup
31877 _getColGroup : function( colSpan )
31879 if ( colSpan < 2 ) {
31880 // if brick spans only one column, use all the column Ys
31885 // how many different places could this brick fit horizontally
31886 var groupCount = this.cols + 1 - colSpan;
31887 // for each group potential horizontal position
31888 for ( var i = 0; i < groupCount; i++ ) {
31889 // make an array of colY values for that one group
31890 var groupColYs = this.colYs.slice( i, i + colSpan );
31891 // and get the max value of the array
31892 colGroup[i] = Math.max.apply( Math, groupColYs );
31897 _manageStamp : function( stamp )
31899 var stampSize = stamp.getSize();
31900 var offset = stamp.getBox();
31901 // get the columns that this stamp affects
31902 var firstX = this.isOriginLeft ? offset.x : offset.right;
31903 var lastX = firstX + stampSize.width;
31904 var firstCol = Math.floor( firstX / this.columnWidth );
31905 firstCol = Math.max( 0, firstCol );
31907 var lastCol = Math.floor( lastX / this.columnWidth );
31908 // lastCol should not go over if multiple of columnWidth #425
31909 lastCol -= lastX % this.columnWidth ? 0 : 1;
31910 lastCol = Math.min( this.cols - 1, lastCol );
31912 // set colYs to bottom of the stamp
31913 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31916 for ( var i = firstCol; i <= lastCol; i++ ) {
31917 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31922 _getContainerSize : function()
31924 this.maxY = Math.max.apply( Math, this.colYs );
31929 if ( this.isFitWidth ) {
31930 size.width = this._getContainerFitWidth();
31936 _getContainerFitWidth : function()
31938 var unusedCols = 0;
31939 // count unused columns
31942 if ( this.colYs[i] !== 0 ) {
31947 // fit container to columns that have been used
31948 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31951 needsResizeLayout : function()
31953 var previousWidth = this.containerWidth;
31954 this.getContainerWidth();
31955 return previousWidth !== this.containerWidth;
31970 * @class Roo.bootstrap.MasonryBrick
31971 * @extends Roo.bootstrap.Component
31972 * Bootstrap MasonryBrick class
31975 * Create a new MasonryBrick
31976 * @param {Object} config The config object
31979 Roo.bootstrap.MasonryBrick = function(config){
31981 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31983 Roo.bootstrap.MasonryBrick.register(this);
31989 * When a MasonryBrick is clcik
31990 * @param {Roo.bootstrap.MasonryBrick} this
31991 * @param {Roo.EventObject} e
31997 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32000 * @cfg {String} title
32004 * @cfg {String} html
32008 * @cfg {String} bgimage
32012 * @cfg {String} videourl
32016 * @cfg {String} cls
32020 * @cfg {String} href
32024 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32029 * @cfg {String} placetitle (center|bottom)
32034 * @cfg {Boolean} isFitContainer defalut true
32036 isFitContainer : true,
32039 * @cfg {Boolean} preventDefault defalut false
32041 preventDefault : false,
32044 * @cfg {Boolean} inverse defalut false
32046 maskInverse : false,
32048 getAutoCreate : function()
32050 if(!this.isFitContainer){
32051 return this.getSplitAutoCreate();
32054 var cls = 'masonry-brick masonry-brick-full';
32056 if(this.href.length){
32057 cls += ' masonry-brick-link';
32060 if(this.bgimage.length){
32061 cls += ' masonry-brick-image';
32064 if(this.maskInverse){
32065 cls += ' mask-inverse';
32068 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32069 cls += ' enable-mask';
32073 cls += ' masonry-' + this.size + '-brick';
32076 if(this.placetitle.length){
32078 switch (this.placetitle) {
32080 cls += ' masonry-center-title';
32083 cls += ' masonry-bottom-title';
32090 if(!this.html.length && !this.bgimage.length){
32091 cls += ' masonry-center-title';
32094 if(!this.html.length && this.bgimage.length){
32095 cls += ' masonry-bottom-title';
32100 cls += ' ' + this.cls;
32104 tag: (this.href.length) ? 'a' : 'div',
32109 cls: 'masonry-brick-mask'
32113 cls: 'masonry-brick-paragraph',
32119 if(this.href.length){
32120 cfg.href = this.href;
32123 var cn = cfg.cn[1].cn;
32125 if(this.title.length){
32128 cls: 'masonry-brick-title',
32133 if(this.html.length){
32136 cls: 'masonry-brick-text',
32141 if (!this.title.length && !this.html.length) {
32142 cfg.cn[1].cls += ' hide';
32145 if(this.bgimage.length){
32148 cls: 'masonry-brick-image-view',
32153 if(this.videourl.length){
32154 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32155 // youtube support only?
32158 cls: 'masonry-brick-image-view',
32161 allowfullscreen : true
32169 getSplitAutoCreate : function()
32171 var cls = 'masonry-brick masonry-brick-split';
32173 if(this.href.length){
32174 cls += ' masonry-brick-link';
32177 if(this.bgimage.length){
32178 cls += ' masonry-brick-image';
32182 cls += ' masonry-' + this.size + '-brick';
32185 switch (this.placetitle) {
32187 cls += ' masonry-center-title';
32190 cls += ' masonry-bottom-title';
32193 if(!this.bgimage.length){
32194 cls += ' masonry-center-title';
32197 if(this.bgimage.length){
32198 cls += ' masonry-bottom-title';
32204 cls += ' ' + this.cls;
32208 tag: (this.href.length) ? 'a' : 'div',
32213 cls: 'masonry-brick-split-head',
32217 cls: 'masonry-brick-paragraph',
32224 cls: 'masonry-brick-split-body',
32230 if(this.href.length){
32231 cfg.href = this.href;
32234 if(this.title.length){
32235 cfg.cn[0].cn[0].cn.push({
32237 cls: 'masonry-brick-title',
32242 if(this.html.length){
32243 cfg.cn[1].cn.push({
32245 cls: 'masonry-brick-text',
32250 if(this.bgimage.length){
32251 cfg.cn[0].cn.push({
32253 cls: 'masonry-brick-image-view',
32258 if(this.videourl.length){
32259 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32260 // youtube support only?
32261 cfg.cn[0].cn.cn.push({
32263 cls: 'masonry-brick-image-view',
32266 allowfullscreen : true
32273 initEvents: function()
32275 switch (this.size) {
32308 this.el.on('touchstart', this.onTouchStart, this);
32309 this.el.on('touchmove', this.onTouchMove, this);
32310 this.el.on('touchend', this.onTouchEnd, this);
32311 this.el.on('contextmenu', this.onContextMenu, this);
32313 this.el.on('mouseenter' ,this.enter, this);
32314 this.el.on('mouseleave', this.leave, this);
32315 this.el.on('click', this.onClick, this);
32318 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32319 this.parent().bricks.push(this);
32324 onClick: function(e, el)
32326 var time = this.endTimer - this.startTimer;
32327 // Roo.log(e.preventDefault());
32330 e.preventDefault();
32335 if(!this.preventDefault){
32339 e.preventDefault();
32341 if (this.activcClass != '') {
32342 this.selectBrick();
32345 this.fireEvent('click', this);
32348 enter: function(e, el)
32350 e.preventDefault();
32352 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32356 if(this.bgimage.length && this.html.length){
32357 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32361 leave: function(e, el)
32363 e.preventDefault();
32365 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32369 if(this.bgimage.length && this.html.length){
32370 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32374 onTouchStart: function(e, el)
32376 // e.preventDefault();
32378 this.touchmoved = false;
32380 if(!this.isFitContainer){
32384 if(!this.bgimage.length || !this.html.length){
32388 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32390 this.timer = new Date().getTime();
32394 onTouchMove: function(e, el)
32396 this.touchmoved = true;
32399 onContextMenu : function(e,el)
32401 e.preventDefault();
32402 e.stopPropagation();
32406 onTouchEnd: function(e, el)
32408 // e.preventDefault();
32410 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32417 if(!this.bgimage.length || !this.html.length){
32419 if(this.href.length){
32420 window.location.href = this.href;
32426 if(!this.isFitContainer){
32430 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32432 window.location.href = this.href;
32435 //selection on single brick only
32436 selectBrick : function() {
32438 if (!this.parentId) {
32442 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32443 var index = m.selectedBrick.indexOf(this.id);
32446 m.selectedBrick.splice(index,1);
32447 this.el.removeClass(this.activeClass);
32451 for(var i = 0; i < m.selectedBrick.length; i++) {
32452 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32453 b.el.removeClass(b.activeClass);
32456 m.selectedBrick = [];
32458 m.selectedBrick.push(this.id);
32459 this.el.addClass(this.activeClass);
32465 Roo.apply(Roo.bootstrap.MasonryBrick, {
32468 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32470 * register a Masonry Brick
32471 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32474 register : function(brick)
32476 //this.groups[brick.id] = brick;
32477 this.groups.add(brick.id, brick);
32480 * fetch a masonry brick based on the masonry brick ID
32481 * @param {string} the masonry brick to add
32482 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32485 get: function(brick_id)
32487 // if (typeof(this.groups[brick_id]) == 'undefined') {
32490 // return this.groups[brick_id] ;
32492 if(this.groups.key(brick_id)) {
32493 return this.groups.key(brick_id);
32511 * @class Roo.bootstrap.Brick
32512 * @extends Roo.bootstrap.Component
32513 * Bootstrap Brick class
32516 * Create a new Brick
32517 * @param {Object} config The config object
32520 Roo.bootstrap.Brick = function(config){
32521 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32527 * When a Brick is click
32528 * @param {Roo.bootstrap.Brick} this
32529 * @param {Roo.EventObject} e
32535 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32538 * @cfg {String} title
32542 * @cfg {String} html
32546 * @cfg {String} bgimage
32550 * @cfg {String} cls
32554 * @cfg {String} href
32558 * @cfg {String} video
32562 * @cfg {Boolean} square
32566 getAutoCreate : function()
32568 var cls = 'roo-brick';
32570 if(this.href.length){
32571 cls += ' roo-brick-link';
32574 if(this.bgimage.length){
32575 cls += ' roo-brick-image';
32578 if(!this.html.length && !this.bgimage.length){
32579 cls += ' roo-brick-center-title';
32582 if(!this.html.length && this.bgimage.length){
32583 cls += ' roo-brick-bottom-title';
32587 cls += ' ' + this.cls;
32591 tag: (this.href.length) ? 'a' : 'div',
32596 cls: 'roo-brick-paragraph',
32602 if(this.href.length){
32603 cfg.href = this.href;
32606 var cn = cfg.cn[0].cn;
32608 if(this.title.length){
32611 cls: 'roo-brick-title',
32616 if(this.html.length){
32619 cls: 'roo-brick-text',
32626 if(this.bgimage.length){
32629 cls: 'roo-brick-image-view',
32637 initEvents: function()
32639 if(this.title.length || this.html.length){
32640 this.el.on('mouseenter' ,this.enter, this);
32641 this.el.on('mouseleave', this.leave, this);
32644 Roo.EventManager.onWindowResize(this.resize, this);
32646 if(this.bgimage.length){
32647 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32648 this.imageEl.on('load', this.onImageLoad, this);
32655 onImageLoad : function()
32660 resize : function()
32662 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32664 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32666 if(this.bgimage.length){
32667 var image = this.el.select('.roo-brick-image-view', true).first();
32669 image.setWidth(paragraph.getWidth());
32672 image.setHeight(paragraph.getWidth());
32675 this.el.setHeight(image.getHeight());
32676 paragraph.setHeight(image.getHeight());
32682 enter: function(e, el)
32684 e.preventDefault();
32686 if(this.bgimage.length){
32687 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32688 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32692 leave: function(e, el)
32694 e.preventDefault();
32696 if(this.bgimage.length){
32697 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32698 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32714 * @class Roo.bootstrap.NumberField
32715 * @extends Roo.bootstrap.Input
32716 * Bootstrap NumberField class
32722 * Create a new NumberField
32723 * @param {Object} config The config object
32726 Roo.bootstrap.NumberField = function(config){
32727 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32730 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32733 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32735 allowDecimals : true,
32737 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32739 decimalSeparator : ".",
32741 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32743 decimalPrecision : 2,
32745 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32747 allowNegative : true,
32749 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32751 minValue : Number.NEGATIVE_INFINITY,
32753 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32755 maxValue : Number.MAX_VALUE,
32757 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32759 minText : "The minimum value for this field is {0}",
32761 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32763 maxText : "The maximum value for this field is {0}",
32765 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32766 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32768 nanText : "{0} is not a valid number",
32770 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32775 initEvents : function()
32777 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32779 var allowed = "0123456789";
32781 if(this.allowDecimals){
32782 allowed += this.decimalSeparator;
32785 if(this.allowNegative){
32789 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32791 var keyPress = function(e){
32793 var k = e.getKey();
32795 var c = e.getCharCode();
32798 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32799 allowed.indexOf(String.fromCharCode(c)) === -1
32805 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32809 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32814 this.el.on("keypress", keyPress, this);
32817 validateValue : function(value)
32820 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32824 var num = this.parseValue(value);
32827 this.markInvalid(String.format(this.nanText, value));
32831 if(num < this.minValue){
32832 this.markInvalid(String.format(this.minText, this.minValue));
32836 if(num > this.maxValue){
32837 this.markInvalid(String.format(this.maxText, this.maxValue));
32844 getValue : function()
32846 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32849 parseValue : function(value)
32851 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32852 return isNaN(value) ? '' : value;
32855 fixPrecision : function(value)
32857 var nan = isNaN(value);
32859 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32860 return nan ? '' : value;
32862 return parseFloat(value).toFixed(this.decimalPrecision);
32865 setValue : function(v)
32867 v = this.fixPrecision(v);
32868 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32871 decimalPrecisionFcn : function(v)
32873 return Math.floor(v);
32876 beforeBlur : function()
32882 var v = this.parseValue(this.getRawValue());
32897 * @class Roo.bootstrap.DocumentSlider
32898 * @extends Roo.bootstrap.Component
32899 * Bootstrap DocumentSlider class
32902 * Create a new DocumentViewer
32903 * @param {Object} config The config object
32906 Roo.bootstrap.DocumentSlider = function(config){
32907 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32914 * Fire after initEvent
32915 * @param {Roo.bootstrap.DocumentSlider} this
32920 * Fire after update
32921 * @param {Roo.bootstrap.DocumentSlider} this
32927 * @param {Roo.bootstrap.DocumentSlider} this
32933 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32939 getAutoCreate : function()
32943 cls : 'roo-document-slider',
32947 cls : 'roo-document-slider-header',
32951 cls : 'roo-document-slider-header-title'
32957 cls : 'roo-document-slider-body',
32961 cls : 'roo-document-slider-prev',
32965 cls : 'fa fa-chevron-left'
32971 cls : 'roo-document-slider-thumb',
32975 cls : 'roo-document-slider-image'
32981 cls : 'roo-document-slider-next',
32985 cls : 'fa fa-chevron-right'
32997 initEvents : function()
32999 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33000 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33002 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33003 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33005 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33006 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33008 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33009 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33011 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33012 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33014 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33015 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33017 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33018 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33020 this.thumbEl.on('click', this.onClick, this);
33022 this.prevIndicator.on('click', this.prev, this);
33024 this.nextIndicator.on('click', this.next, this);
33028 initial : function()
33030 if(this.files.length){
33031 this.indicator = 1;
33035 this.fireEvent('initial', this);
33038 update : function()
33040 this.imageEl.attr('src', this.files[this.indicator - 1]);
33042 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33044 this.prevIndicator.show();
33046 if(this.indicator == 1){
33047 this.prevIndicator.hide();
33050 this.nextIndicator.show();
33052 if(this.indicator == this.files.length){
33053 this.nextIndicator.hide();
33056 this.thumbEl.scrollTo('top');
33058 this.fireEvent('update', this);
33061 onClick : function(e)
33063 e.preventDefault();
33065 this.fireEvent('click', this);
33070 e.preventDefault();
33072 this.indicator = Math.max(1, this.indicator - 1);
33079 e.preventDefault();
33081 this.indicator = Math.min(this.files.length, this.indicator + 1);
33095 * @class Roo.bootstrap.RadioSet
33096 * @extends Roo.bootstrap.Input
33097 * Bootstrap RadioSet class
33098 * @cfg {String} indicatorpos (left|right) default left
33099 * @cfg {Boolean} inline (true|false) inline the element (default true)
33100 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33102 * Create a new RadioSet
33103 * @param {Object} config The config object
33106 Roo.bootstrap.RadioSet = function(config){
33108 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33112 Roo.bootstrap.RadioSet.register(this);
33117 * Fires when the element is checked or unchecked.
33118 * @param {Roo.bootstrap.RadioSet} this This radio
33119 * @param {Roo.bootstrap.Radio} item The checked item
33126 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33134 indicatorpos : 'left',
33136 getAutoCreate : function()
33140 cls : 'roo-radio-set-label',
33144 html : this.fieldLabel
33149 if(this.indicatorpos == 'left'){
33152 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33153 tooltip : 'This field is required'
33158 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33159 tooltip : 'This field is required'
33165 cls : 'roo-radio-set-items'
33168 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33170 if (align === 'left' && this.fieldLabel.length) {
33173 cls : "roo-radio-set-right",
33179 if(this.labelWidth > 12){
33180 label.style = "width: " + this.labelWidth + 'px';
33183 if(this.labelWidth < 13 && this.labelmd == 0){
33184 this.labelmd = this.labelWidth;
33187 if(this.labellg > 0){
33188 label.cls += ' col-lg-' + this.labellg;
33189 items.cls += ' col-lg-' + (12 - this.labellg);
33192 if(this.labelmd > 0){
33193 label.cls += ' col-md-' + this.labelmd;
33194 items.cls += ' col-md-' + (12 - this.labelmd);
33197 if(this.labelsm > 0){
33198 label.cls += ' col-sm-' + this.labelsm;
33199 items.cls += ' col-sm-' + (12 - this.labelsm);
33202 if(this.labelxs > 0){
33203 label.cls += ' col-xs-' + this.labelxs;
33204 items.cls += ' col-xs-' + (12 - this.labelxs);
33210 cls : 'roo-radio-set',
33214 cls : 'roo-radio-set-input',
33217 value : this.value ? this.value : ''
33224 if(this.weight.length){
33225 cfg.cls += ' roo-radio-' + this.weight;
33229 cfg.cls += ' roo-radio-set-inline';
33236 initEvents : function()
33238 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33239 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33241 if(!this.fieldLabel.length){
33242 this.labelEl.hide();
33245 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33246 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33248 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33249 this.indicatorEl().hide();
33251 this.originalValue = this.getValue();
33255 inputEl: function ()
33257 return this.el.select('.roo-radio-set-input', true).first();
33260 getChildContainer : function()
33262 return this.itemsEl;
33265 register : function(item)
33267 this.radioes.push(item);
33271 validate : function()
33275 Roo.each(this.radioes, function(i){
33284 if(this.allowBlank) {
33288 if(this.disabled || valid){
33293 this.markInvalid();
33298 markValid : function()
33300 if(this.labelEl.isVisible(true)){
33301 this.indicatorEl().hide();
33304 this.el.removeClass([this.invalidClass, this.validClass]);
33305 this.el.addClass(this.validClass);
33307 this.fireEvent('valid', this);
33310 markInvalid : function(msg)
33312 if(this.allowBlank || this.disabled){
33316 if(this.labelEl.isVisible(true)){
33317 this.indicatorEl().show();
33320 this.el.removeClass([this.invalidClass, this.validClass]);
33321 this.el.addClass(this.invalidClass);
33323 this.fireEvent('invalid', this, msg);
33327 setValue : function(v, suppressEvent)
33331 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33334 Roo.each(this.radioes, function(i){
33337 i.el.removeClass('checked');
33339 if(i.value === v || i.value.toString() === v.toString()){
33341 i.el.addClass('checked');
33343 if(suppressEvent !== true){
33344 this.fireEvent('check', this, i);
33353 clearInvalid : function(){
33355 if(!this.el || this.preventMark){
33359 this.el.removeClass([this.invalidClass]);
33361 this.fireEvent('valid', this);
33366 Roo.apply(Roo.bootstrap.RadioSet, {
33370 register : function(set)
33372 this.groups[set.name] = set;
33375 get: function(name)
33377 if (typeof(this.groups[name]) == 'undefined') {
33381 return this.groups[name] ;
33387 * Ext JS Library 1.1.1
33388 * Copyright(c) 2006-2007, Ext JS, LLC.
33390 * Originally Released Under LGPL - original licence link has changed is not relivant.
33393 * <script type="text/javascript">
33398 * @class Roo.bootstrap.SplitBar
33399 * @extends Roo.util.Observable
33400 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33404 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33405 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33406 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33407 split.minSize = 100;
33408 split.maxSize = 600;
33409 split.animate = true;
33410 split.on('moved', splitterMoved);
33413 * Create a new SplitBar
33414 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33415 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33416 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33417 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33418 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33419 position of the SplitBar).
33421 Roo.bootstrap.SplitBar = function(cfg){
33426 // dragElement : elm
33427 // resizingElement: el,
33429 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33430 // placement : Roo.bootstrap.SplitBar.LEFT ,
33431 // existingProxy ???
33434 this.el = Roo.get(cfg.dragElement, true);
33435 this.el.dom.unselectable = "on";
33437 this.resizingEl = Roo.get(cfg.resizingElement, true);
33441 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33442 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33445 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33448 * The minimum size of the resizing element. (Defaults to 0)
33454 * The maximum size of the resizing element. (Defaults to 2000)
33457 this.maxSize = 2000;
33460 * Whether to animate the transition to the new size
33463 this.animate = false;
33466 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33469 this.useShim = false;
33474 if(!cfg.existingProxy){
33476 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33478 this.proxy = Roo.get(cfg.existingProxy).dom;
33481 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33484 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33487 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33490 this.dragSpecs = {};
33493 * @private The adapter to use to positon and resize elements
33495 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33496 this.adapter.init(this);
33498 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33500 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33501 this.el.addClass("roo-splitbar-h");
33504 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33505 this.el.addClass("roo-splitbar-v");
33511 * Fires when the splitter is moved (alias for {@link #event-moved})
33512 * @param {Roo.bootstrap.SplitBar} this
33513 * @param {Number} newSize the new width or height
33518 * Fires when the splitter is moved
33519 * @param {Roo.bootstrap.SplitBar} this
33520 * @param {Number} newSize the new width or height
33524 * @event beforeresize
33525 * Fires before the splitter is dragged
33526 * @param {Roo.bootstrap.SplitBar} this
33528 "beforeresize" : true,
33530 "beforeapply" : true
33533 Roo.util.Observable.call(this);
33536 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33537 onStartProxyDrag : function(x, y){
33538 this.fireEvent("beforeresize", this);
33540 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33542 o.enableDisplayMode("block");
33543 // all splitbars share the same overlay
33544 Roo.bootstrap.SplitBar.prototype.overlay = o;
33546 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33547 this.overlay.show();
33548 Roo.get(this.proxy).setDisplayed("block");
33549 var size = this.adapter.getElementSize(this);
33550 this.activeMinSize = this.getMinimumSize();;
33551 this.activeMaxSize = this.getMaximumSize();;
33552 var c1 = size - this.activeMinSize;
33553 var c2 = Math.max(this.activeMaxSize - size, 0);
33554 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33555 this.dd.resetConstraints();
33556 this.dd.setXConstraint(
33557 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33558 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33560 this.dd.setYConstraint(0, 0);
33562 this.dd.resetConstraints();
33563 this.dd.setXConstraint(0, 0);
33564 this.dd.setYConstraint(
33565 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33566 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33569 this.dragSpecs.startSize = size;
33570 this.dragSpecs.startPoint = [x, y];
33571 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33575 * @private Called after the drag operation by the DDProxy
33577 onEndProxyDrag : function(e){
33578 Roo.get(this.proxy).setDisplayed(false);
33579 var endPoint = Roo.lib.Event.getXY(e);
33581 this.overlay.hide();
33584 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33585 newSize = this.dragSpecs.startSize +
33586 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33587 endPoint[0] - this.dragSpecs.startPoint[0] :
33588 this.dragSpecs.startPoint[0] - endPoint[0]
33591 newSize = this.dragSpecs.startSize +
33592 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33593 endPoint[1] - this.dragSpecs.startPoint[1] :
33594 this.dragSpecs.startPoint[1] - endPoint[1]
33597 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33598 if(newSize != this.dragSpecs.startSize){
33599 if(this.fireEvent('beforeapply', this, newSize) !== false){
33600 this.adapter.setElementSize(this, newSize);
33601 this.fireEvent("moved", this, newSize);
33602 this.fireEvent("resize", this, newSize);
33608 * Get the adapter this SplitBar uses
33609 * @return The adapter object
33611 getAdapter : function(){
33612 return this.adapter;
33616 * Set the adapter this SplitBar uses
33617 * @param {Object} adapter A SplitBar adapter object
33619 setAdapter : function(adapter){
33620 this.adapter = adapter;
33621 this.adapter.init(this);
33625 * Gets the minimum size for the resizing element
33626 * @return {Number} The minimum size
33628 getMinimumSize : function(){
33629 return this.minSize;
33633 * Sets the minimum size for the resizing element
33634 * @param {Number} minSize The minimum size
33636 setMinimumSize : function(minSize){
33637 this.minSize = minSize;
33641 * Gets the maximum size for the resizing element
33642 * @return {Number} The maximum size
33644 getMaximumSize : function(){
33645 return this.maxSize;
33649 * Sets the maximum size for the resizing element
33650 * @param {Number} maxSize The maximum size
33652 setMaximumSize : function(maxSize){
33653 this.maxSize = maxSize;
33657 * Sets the initialize size for the resizing element
33658 * @param {Number} size The initial size
33660 setCurrentSize : function(size){
33661 var oldAnimate = this.animate;
33662 this.animate = false;
33663 this.adapter.setElementSize(this, size);
33664 this.animate = oldAnimate;
33668 * Destroy this splitbar.
33669 * @param {Boolean} removeEl True to remove the element
33671 destroy : function(removeEl){
33673 this.shim.remove();
33676 this.proxy.parentNode.removeChild(this.proxy);
33684 * @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.
33686 Roo.bootstrap.SplitBar.createProxy = function(dir){
33687 var proxy = new Roo.Element(document.createElement("div"));
33688 proxy.unselectable();
33689 var cls = 'roo-splitbar-proxy';
33690 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33691 document.body.appendChild(proxy.dom);
33696 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33697 * Default Adapter. It assumes the splitter and resizing element are not positioned
33698 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33700 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33703 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33704 // do nothing for now
33705 init : function(s){
33709 * Called before drag operations to get the current size of the resizing element.
33710 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33712 getElementSize : function(s){
33713 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33714 return s.resizingEl.getWidth();
33716 return s.resizingEl.getHeight();
33721 * Called after drag operations to set the size of the resizing element.
33722 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33723 * @param {Number} newSize The new size to set
33724 * @param {Function} onComplete A function to be invoked when resizing is complete
33726 setElementSize : function(s, newSize, onComplete){
33727 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33729 s.resizingEl.setWidth(newSize);
33731 onComplete(s, newSize);
33734 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33739 s.resizingEl.setHeight(newSize);
33741 onComplete(s, newSize);
33744 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33751 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33752 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33753 * Adapter that moves the splitter element to align with the resized sizing element.
33754 * Used with an absolute positioned SplitBar.
33755 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33756 * document.body, make sure you assign an id to the body element.
33758 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33759 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33760 this.container = Roo.get(container);
33763 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33764 init : function(s){
33765 this.basic.init(s);
33768 getElementSize : function(s){
33769 return this.basic.getElementSize(s);
33772 setElementSize : function(s, newSize, onComplete){
33773 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33776 moveSplitter : function(s){
33777 var yes = Roo.bootstrap.SplitBar;
33778 switch(s.placement){
33780 s.el.setX(s.resizingEl.getRight());
33783 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33786 s.el.setY(s.resizingEl.getBottom());
33789 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33796 * Orientation constant - Create a vertical SplitBar
33800 Roo.bootstrap.SplitBar.VERTICAL = 1;
33803 * Orientation constant - Create a horizontal SplitBar
33807 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33810 * Placement constant - The resizing element is to the left of the splitter element
33814 Roo.bootstrap.SplitBar.LEFT = 1;
33817 * Placement constant - The resizing element is to the right of the splitter element
33821 Roo.bootstrap.SplitBar.RIGHT = 2;
33824 * Placement constant - The resizing element is positioned above the splitter element
33828 Roo.bootstrap.SplitBar.TOP = 3;
33831 * Placement constant - The resizing element is positioned under splitter element
33835 Roo.bootstrap.SplitBar.BOTTOM = 4;
33836 Roo.namespace("Roo.bootstrap.layout");/*
33838 * Ext JS Library 1.1.1
33839 * Copyright(c) 2006-2007, Ext JS, LLC.
33841 * Originally Released Under LGPL - original licence link has changed is not relivant.
33844 * <script type="text/javascript">
33848 * @class Roo.bootstrap.layout.Manager
33849 * @extends Roo.bootstrap.Component
33850 * Base class for layout managers.
33852 Roo.bootstrap.layout.Manager = function(config)
33854 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33860 /** false to disable window resize monitoring @type Boolean */
33861 this.monitorWindowResize = true;
33866 * Fires when a layout is performed.
33867 * @param {Roo.LayoutManager} this
33871 * @event regionresized
33872 * Fires when the user resizes a region.
33873 * @param {Roo.LayoutRegion} region The resized region
33874 * @param {Number} newSize The new size (width for east/west, height for north/south)
33876 "regionresized" : true,
33878 * @event regioncollapsed
33879 * Fires when a region is collapsed.
33880 * @param {Roo.LayoutRegion} region The collapsed region
33882 "regioncollapsed" : true,
33884 * @event regionexpanded
33885 * Fires when a region is expanded.
33886 * @param {Roo.LayoutRegion} region The expanded region
33888 "regionexpanded" : true
33890 this.updating = false;
33893 this.el = Roo.get(config.el);
33899 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33904 monitorWindowResize : true,
33910 onRender : function(ct, position)
33913 this.el = Roo.get(ct);
33916 //this.fireEvent('render',this);
33920 initEvents: function()
33924 // ie scrollbar fix
33925 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33926 document.body.scroll = "no";
33927 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33928 this.el.position('relative');
33930 this.id = this.el.id;
33931 this.el.addClass("roo-layout-container");
33932 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33933 if(this.el.dom != document.body ) {
33934 this.el.on('resize', this.layout,this);
33935 this.el.on('show', this.layout,this);
33941 * Returns true if this layout is currently being updated
33942 * @return {Boolean}
33944 isUpdating : function(){
33945 return this.updating;
33949 * Suspend the LayoutManager from doing auto-layouts while
33950 * making multiple add or remove calls
33952 beginUpdate : function(){
33953 this.updating = true;
33957 * Restore auto-layouts and optionally disable the manager from performing a layout
33958 * @param {Boolean} noLayout true to disable a layout update
33960 endUpdate : function(noLayout){
33961 this.updating = false;
33967 layout: function(){
33971 onRegionResized : function(region, newSize){
33972 this.fireEvent("regionresized", region, newSize);
33976 onRegionCollapsed : function(region){
33977 this.fireEvent("regioncollapsed", region);
33980 onRegionExpanded : function(region){
33981 this.fireEvent("regionexpanded", region);
33985 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33986 * performs box-model adjustments.
33987 * @return {Object} The size as an object {width: (the width), height: (the height)}
33989 getViewSize : function()
33992 if(this.el.dom != document.body){
33993 size = this.el.getSize();
33995 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33997 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33998 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34003 * Returns the Element this layout is bound to.
34004 * @return {Roo.Element}
34006 getEl : function(){
34011 * Returns the specified region.
34012 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34013 * @return {Roo.LayoutRegion}
34015 getRegion : function(target){
34016 return this.regions[target.toLowerCase()];
34019 onWindowResize : function(){
34020 if(this.monitorWindowResize){
34027 * Ext JS Library 1.1.1
34028 * Copyright(c) 2006-2007, Ext JS, LLC.
34030 * Originally Released Under LGPL - original licence link has changed is not relivant.
34033 * <script type="text/javascript">
34036 * @class Roo.bootstrap.layout.Border
34037 * @extends Roo.bootstrap.layout.Manager
34038 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34039 * please see: examples/bootstrap/nested.html<br><br>
34041 <b>The container the layout is rendered into can be either the body element or any other element.
34042 If it is not the body element, the container needs to either be an absolute positioned element,
34043 or you will need to add "position:relative" to the css of the container. You will also need to specify
34044 the container size if it is not the body element.</b>
34047 * Create a new Border
34048 * @param {Object} config Configuration options
34050 Roo.bootstrap.layout.Border = function(config){
34051 config = config || {};
34052 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34056 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34057 if(config[region]){
34058 config[region].region = region;
34059 this.addRegion(config[region]);
34065 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34067 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34069 * Creates and adds a new region if it doesn't already exist.
34070 * @param {String} target The target region key (north, south, east, west or center).
34071 * @param {Object} config The regions config object
34072 * @return {BorderLayoutRegion} The new region
34074 addRegion : function(config)
34076 if(!this.regions[config.region]){
34077 var r = this.factory(config);
34078 this.bindRegion(r);
34080 return this.regions[config.region];
34084 bindRegion : function(r){
34085 this.regions[r.config.region] = r;
34087 r.on("visibilitychange", this.layout, this);
34088 r.on("paneladded", this.layout, this);
34089 r.on("panelremoved", this.layout, this);
34090 r.on("invalidated", this.layout, this);
34091 r.on("resized", this.onRegionResized, this);
34092 r.on("collapsed", this.onRegionCollapsed, this);
34093 r.on("expanded", this.onRegionExpanded, this);
34097 * Performs a layout update.
34099 layout : function()
34101 if(this.updating) {
34105 // render all the rebions if they have not been done alreayd?
34106 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34107 if(this.regions[region] && !this.regions[region].bodyEl){
34108 this.regions[region].onRender(this.el)
34112 var size = this.getViewSize();
34113 var w = size.width;
34114 var h = size.height;
34119 //var x = 0, y = 0;
34121 var rs = this.regions;
34122 var north = rs["north"];
34123 var south = rs["south"];
34124 var west = rs["west"];
34125 var east = rs["east"];
34126 var center = rs["center"];
34127 //if(this.hideOnLayout){ // not supported anymore
34128 //c.el.setStyle("display", "none");
34130 if(north && north.isVisible()){
34131 var b = north.getBox();
34132 var m = north.getMargins();
34133 b.width = w - (m.left+m.right);
34136 centerY = b.height + b.y + m.bottom;
34137 centerH -= centerY;
34138 north.updateBox(this.safeBox(b));
34140 if(south && south.isVisible()){
34141 var b = south.getBox();
34142 var m = south.getMargins();
34143 b.width = w - (m.left+m.right);
34145 var totalHeight = (b.height + m.top + m.bottom);
34146 b.y = h - totalHeight + m.top;
34147 centerH -= totalHeight;
34148 south.updateBox(this.safeBox(b));
34150 if(west && west.isVisible()){
34151 var b = west.getBox();
34152 var m = west.getMargins();
34153 b.height = centerH - (m.top+m.bottom);
34155 b.y = centerY + m.top;
34156 var totalWidth = (b.width + m.left + m.right);
34157 centerX += totalWidth;
34158 centerW -= totalWidth;
34159 west.updateBox(this.safeBox(b));
34161 if(east && east.isVisible()){
34162 var b = east.getBox();
34163 var m = east.getMargins();
34164 b.height = centerH - (m.top+m.bottom);
34165 var totalWidth = (b.width + m.left + m.right);
34166 b.x = w - totalWidth + m.left;
34167 b.y = centerY + m.top;
34168 centerW -= totalWidth;
34169 east.updateBox(this.safeBox(b));
34172 var m = center.getMargins();
34174 x: centerX + m.left,
34175 y: centerY + m.top,
34176 width: centerW - (m.left+m.right),
34177 height: centerH - (m.top+m.bottom)
34179 //if(this.hideOnLayout){
34180 //center.el.setStyle("display", "block");
34182 center.updateBox(this.safeBox(centerBox));
34185 this.fireEvent("layout", this);
34189 safeBox : function(box){
34190 box.width = Math.max(0, box.width);
34191 box.height = Math.max(0, box.height);
34196 * Adds a ContentPanel (or subclass) to this layout.
34197 * @param {String} target The target region key (north, south, east, west or center).
34198 * @param {Roo.ContentPanel} panel The panel to add
34199 * @return {Roo.ContentPanel} The added panel
34201 add : function(target, panel){
34203 target = target.toLowerCase();
34204 return this.regions[target].add(panel);
34208 * Remove a ContentPanel (or subclass) to this layout.
34209 * @param {String} target The target region key (north, south, east, west or center).
34210 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34211 * @return {Roo.ContentPanel} The removed panel
34213 remove : function(target, panel){
34214 target = target.toLowerCase();
34215 return this.regions[target].remove(panel);
34219 * Searches all regions for a panel with the specified id
34220 * @param {String} panelId
34221 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34223 findPanel : function(panelId){
34224 var rs = this.regions;
34225 for(var target in rs){
34226 if(typeof rs[target] != "function"){
34227 var p = rs[target].getPanel(panelId);
34237 * Searches all regions for a panel with the specified id and activates (shows) it.
34238 * @param {String/ContentPanel} panelId The panels id or the panel itself
34239 * @return {Roo.ContentPanel} The shown panel or null
34241 showPanel : function(panelId) {
34242 var rs = this.regions;
34243 for(var target in rs){
34244 var r = rs[target];
34245 if(typeof r != "function"){
34246 if(r.hasPanel(panelId)){
34247 return r.showPanel(panelId);
34255 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34256 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34259 restoreState : function(provider){
34261 provider = Roo.state.Manager;
34263 var sm = new Roo.LayoutStateManager();
34264 sm.init(this, provider);
34270 * Adds a xtype elements to the layout.
34274 xtype : 'ContentPanel',
34281 xtype : 'NestedLayoutPanel',
34287 items : [ ... list of content panels or nested layout panels.. ]
34291 * @param {Object} cfg Xtype definition of item to add.
34293 addxtype : function(cfg)
34295 // basically accepts a pannel...
34296 // can accept a layout region..!?!?
34297 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34300 // theory? children can only be panels??
34302 //if (!cfg.xtype.match(/Panel$/)) {
34307 if (typeof(cfg.region) == 'undefined') {
34308 Roo.log("Failed to add Panel, region was not set");
34312 var region = cfg.region;
34318 xitems = cfg.items;
34325 case 'Content': // ContentPanel (el, cfg)
34326 case 'Scroll': // ContentPanel (el, cfg)
34328 cfg.autoCreate = true;
34329 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34331 // var el = this.el.createChild();
34332 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34335 this.add(region, ret);
34339 case 'TreePanel': // our new panel!
34340 cfg.el = this.el.createChild();
34341 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34342 this.add(region, ret);
34347 // create a new Layout (which is a Border Layout...
34349 var clayout = cfg.layout;
34350 clayout.el = this.el.createChild();
34351 clayout.items = clayout.items || [];
34355 // replace this exitems with the clayout ones..
34356 xitems = clayout.items;
34358 // force background off if it's in center...
34359 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34360 cfg.background = false;
34362 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34365 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34366 //console.log('adding nested layout panel ' + cfg.toSource());
34367 this.add(region, ret);
34368 nb = {}; /// find first...
34373 // needs grid and region
34375 //var el = this.getRegion(region).el.createChild();
34377 *var el = this.el.createChild();
34378 // create the grid first...
34379 cfg.grid.container = el;
34380 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34383 if (region == 'center' && this.active ) {
34384 cfg.background = false;
34387 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34389 this.add(region, ret);
34391 if (cfg.background) {
34392 // render grid on panel activation (if panel background)
34393 ret.on('activate', function(gp) {
34394 if (!gp.grid.rendered) {
34395 // gp.grid.render(el);
34399 // cfg.grid.render(el);
34405 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34406 // it was the old xcomponent building that caused this before.
34407 // espeically if border is the top element in the tree.
34417 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34419 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34420 this.add(region, ret);
34424 throw "Can not add '" + cfg.xtype + "' to Border";
34430 this.beginUpdate();
34434 Roo.each(xitems, function(i) {
34435 region = nb && i.region ? i.region : false;
34437 var add = ret.addxtype(i);
34440 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34441 if (!i.background) {
34442 abn[region] = nb[region] ;
34449 // make the last non-background panel active..
34450 //if (nb) { Roo.log(abn); }
34453 for(var r in abn) {
34454 region = this.getRegion(r);
34456 // tried using nb[r], but it does not work..
34458 region.showPanel(abn[r]);
34469 factory : function(cfg)
34472 var validRegions = Roo.bootstrap.layout.Border.regions;
34474 var target = cfg.region;
34477 var r = Roo.bootstrap.layout;
34481 return new r.North(cfg);
34483 return new r.South(cfg);
34485 return new r.East(cfg);
34487 return new r.West(cfg);
34489 return new r.Center(cfg);
34491 throw 'Layout region "'+target+'" not supported.';
34498 * Ext JS Library 1.1.1
34499 * Copyright(c) 2006-2007, Ext JS, LLC.
34501 * Originally Released Under LGPL - original licence link has changed is not relivant.
34504 * <script type="text/javascript">
34508 * @class Roo.bootstrap.layout.Basic
34509 * @extends Roo.util.Observable
34510 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34511 * and does not have a titlebar, tabs or any other features. All it does is size and position
34512 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34513 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34514 * @cfg {string} region the region that it inhabits..
34515 * @cfg {bool} skipConfig skip config?
34519 Roo.bootstrap.layout.Basic = function(config){
34521 this.mgr = config.mgr;
34523 this.position = config.region;
34525 var skipConfig = config.skipConfig;
34529 * @scope Roo.BasicLayoutRegion
34533 * @event beforeremove
34534 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34535 * @param {Roo.LayoutRegion} this
34536 * @param {Roo.ContentPanel} panel The panel
34537 * @param {Object} e The cancel event object
34539 "beforeremove" : true,
34541 * @event invalidated
34542 * Fires when the layout for this region is changed.
34543 * @param {Roo.LayoutRegion} this
34545 "invalidated" : true,
34547 * @event visibilitychange
34548 * Fires when this region is shown or hidden
34549 * @param {Roo.LayoutRegion} this
34550 * @param {Boolean} visibility true or false
34552 "visibilitychange" : true,
34554 * @event paneladded
34555 * Fires when a panel is added.
34556 * @param {Roo.LayoutRegion} this
34557 * @param {Roo.ContentPanel} panel The panel
34559 "paneladded" : true,
34561 * @event panelremoved
34562 * Fires when a panel is removed.
34563 * @param {Roo.LayoutRegion} this
34564 * @param {Roo.ContentPanel} panel The panel
34566 "panelremoved" : true,
34568 * @event beforecollapse
34569 * Fires when this region before collapse.
34570 * @param {Roo.LayoutRegion} this
34572 "beforecollapse" : true,
34575 * Fires when this region is collapsed.
34576 * @param {Roo.LayoutRegion} this
34578 "collapsed" : true,
34581 * Fires when this region is expanded.
34582 * @param {Roo.LayoutRegion} this
34587 * Fires when this region is slid into view.
34588 * @param {Roo.LayoutRegion} this
34590 "slideshow" : true,
34593 * Fires when this region slides out of view.
34594 * @param {Roo.LayoutRegion} this
34596 "slidehide" : true,
34598 * @event panelactivated
34599 * Fires when a panel is activated.
34600 * @param {Roo.LayoutRegion} this
34601 * @param {Roo.ContentPanel} panel The activated panel
34603 "panelactivated" : true,
34606 * Fires when the user resizes this region.
34607 * @param {Roo.LayoutRegion} this
34608 * @param {Number} newSize The new size (width for east/west, height for north/south)
34612 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34613 this.panels = new Roo.util.MixedCollection();
34614 this.panels.getKey = this.getPanelId.createDelegate(this);
34616 this.activePanel = null;
34617 // ensure listeners are added...
34619 if (config.listeners || config.events) {
34620 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34621 listeners : config.listeners || {},
34622 events : config.events || {}
34626 if(skipConfig !== true){
34627 this.applyConfig(config);
34631 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34633 getPanelId : function(p){
34637 applyConfig : function(config){
34638 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34639 this.config = config;
34644 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34645 * the width, for horizontal (north, south) the height.
34646 * @param {Number} newSize The new width or height
34648 resizeTo : function(newSize){
34649 var el = this.el ? this.el :
34650 (this.activePanel ? this.activePanel.getEl() : null);
34652 switch(this.position){
34655 el.setWidth(newSize);
34656 this.fireEvent("resized", this, newSize);
34660 el.setHeight(newSize);
34661 this.fireEvent("resized", this, newSize);
34667 getBox : function(){
34668 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34671 getMargins : function(){
34672 return this.margins;
34675 updateBox : function(box){
34677 var el = this.activePanel.getEl();
34678 el.dom.style.left = box.x + "px";
34679 el.dom.style.top = box.y + "px";
34680 this.activePanel.setSize(box.width, box.height);
34684 * Returns the container element for this region.
34685 * @return {Roo.Element}
34687 getEl : function(){
34688 return this.activePanel;
34692 * Returns true if this region is currently visible.
34693 * @return {Boolean}
34695 isVisible : function(){
34696 return this.activePanel ? true : false;
34699 setActivePanel : function(panel){
34700 panel = this.getPanel(panel);
34701 if(this.activePanel && this.activePanel != panel){
34702 this.activePanel.setActiveState(false);
34703 this.activePanel.getEl().setLeftTop(-10000,-10000);
34705 this.activePanel = panel;
34706 panel.setActiveState(true);
34708 panel.setSize(this.box.width, this.box.height);
34710 this.fireEvent("panelactivated", this, panel);
34711 this.fireEvent("invalidated");
34715 * Show the specified panel.
34716 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34717 * @return {Roo.ContentPanel} The shown panel or null
34719 showPanel : function(panel){
34720 panel = this.getPanel(panel);
34722 this.setActivePanel(panel);
34728 * Get the active panel for this region.
34729 * @return {Roo.ContentPanel} The active panel or null
34731 getActivePanel : function(){
34732 return this.activePanel;
34736 * Add the passed ContentPanel(s)
34737 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34738 * @return {Roo.ContentPanel} The panel added (if only one was added)
34740 add : function(panel){
34741 if(arguments.length > 1){
34742 for(var i = 0, len = arguments.length; i < len; i++) {
34743 this.add(arguments[i]);
34747 if(this.hasPanel(panel)){
34748 this.showPanel(panel);
34751 var el = panel.getEl();
34752 if(el.dom.parentNode != this.mgr.el.dom){
34753 this.mgr.el.dom.appendChild(el.dom);
34755 if(panel.setRegion){
34756 panel.setRegion(this);
34758 this.panels.add(panel);
34759 el.setStyle("position", "absolute");
34760 if(!panel.background){
34761 this.setActivePanel(panel);
34762 if(this.config.initialSize && this.panels.getCount()==1){
34763 this.resizeTo(this.config.initialSize);
34766 this.fireEvent("paneladded", this, panel);
34771 * Returns true if the panel is in this region.
34772 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34773 * @return {Boolean}
34775 hasPanel : function(panel){
34776 if(typeof panel == "object"){ // must be panel obj
34777 panel = panel.getId();
34779 return this.getPanel(panel) ? true : false;
34783 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34784 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34785 * @param {Boolean} preservePanel Overrides the config preservePanel option
34786 * @return {Roo.ContentPanel} The panel that was removed
34788 remove : function(panel, preservePanel){
34789 panel = this.getPanel(panel);
34794 this.fireEvent("beforeremove", this, panel, e);
34795 if(e.cancel === true){
34798 var panelId = panel.getId();
34799 this.panels.removeKey(panelId);
34804 * Returns the panel specified or null if it's not in this region.
34805 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34806 * @return {Roo.ContentPanel}
34808 getPanel : function(id){
34809 if(typeof id == "object"){ // must be panel obj
34812 return this.panels.get(id);
34816 * Returns this regions position (north/south/east/west/center).
34819 getPosition: function(){
34820 return this.position;
34824 * Ext JS Library 1.1.1
34825 * Copyright(c) 2006-2007, Ext JS, LLC.
34827 * Originally Released Under LGPL - original licence link has changed is not relivant.
34830 * <script type="text/javascript">
34834 * @class Roo.bootstrap.layout.Region
34835 * @extends Roo.bootstrap.layout.Basic
34836 * This class represents a region in a layout manager.
34838 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34839 * @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})
34840 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34841 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34842 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34843 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34844 * @cfg {String} title The title for the region (overrides panel titles)
34845 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34846 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34847 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34848 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34849 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34850 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34851 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34852 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34853 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34854 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34856 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34857 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34858 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34859 * @cfg {Number} width For East/West panels
34860 * @cfg {Number} height For North/South panels
34861 * @cfg {Boolean} split To show the splitter
34862 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34864 * @cfg {string} cls Extra CSS classes to add to region
34866 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34867 * @cfg {string} region the region that it inhabits..
34870 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34871 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34873 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34874 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34875 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34877 Roo.bootstrap.layout.Region = function(config)
34879 this.applyConfig(config);
34881 var mgr = config.mgr;
34882 var pos = config.region;
34883 config.skipConfig = true;
34884 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34887 this.onRender(mgr.el);
34890 this.visible = true;
34891 this.collapsed = false;
34892 this.unrendered_panels = [];
34895 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34897 position: '', // set by wrapper (eg. north/south etc..)
34898 unrendered_panels : null, // unrendered panels.
34899 createBody : function(){
34900 /** This region's body element
34901 * @type Roo.Element */
34902 this.bodyEl = this.el.createChild({
34904 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34908 onRender: function(ctr, pos)
34910 var dh = Roo.DomHelper;
34911 /** This region's container element
34912 * @type Roo.Element */
34913 this.el = dh.append(ctr.dom, {
34915 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34917 /** This region's title element
34918 * @type Roo.Element */
34920 this.titleEl = dh.append(this.el.dom,
34923 unselectable: "on",
34924 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34926 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34927 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34930 this.titleEl.enableDisplayMode();
34931 /** This region's title text element
34932 * @type HTMLElement */
34933 this.titleTextEl = this.titleEl.dom.firstChild;
34934 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34936 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34937 this.closeBtn.enableDisplayMode();
34938 this.closeBtn.on("click", this.closeClicked, this);
34939 this.closeBtn.hide();
34941 this.createBody(this.config);
34942 if(this.config.hideWhenEmpty){
34944 this.on("paneladded", this.validateVisibility, this);
34945 this.on("panelremoved", this.validateVisibility, this);
34947 if(this.autoScroll){
34948 this.bodyEl.setStyle("overflow", "auto");
34950 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34952 //if(c.titlebar !== false){
34953 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34954 this.titleEl.hide();
34956 this.titleEl.show();
34957 if(this.config.title){
34958 this.titleTextEl.innerHTML = this.config.title;
34962 if(this.config.collapsed){
34963 this.collapse(true);
34965 if(this.config.hidden){
34969 if (this.unrendered_panels && this.unrendered_panels.length) {
34970 for (var i =0;i< this.unrendered_panels.length; i++) {
34971 this.add(this.unrendered_panels[i]);
34973 this.unrendered_panels = null;
34979 applyConfig : function(c)
34982 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34983 var dh = Roo.DomHelper;
34984 if(c.titlebar !== false){
34985 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34986 this.collapseBtn.on("click", this.collapse, this);
34987 this.collapseBtn.enableDisplayMode();
34989 if(c.showPin === true || this.showPin){
34990 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34991 this.stickBtn.enableDisplayMode();
34992 this.stickBtn.on("click", this.expand, this);
34993 this.stickBtn.hide();
34998 /** This region's collapsed element
34999 * @type Roo.Element */
35002 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35003 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35006 if(c.floatable !== false){
35007 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35008 this.collapsedEl.on("click", this.collapseClick, this);
35011 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35012 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35013 id: "message", unselectable: "on", style:{"float":"left"}});
35014 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35016 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35017 this.expandBtn.on("click", this.expand, this);
35021 if(this.collapseBtn){
35022 this.collapseBtn.setVisible(c.collapsible == true);
35025 this.cmargins = c.cmargins || this.cmargins ||
35026 (this.position == "west" || this.position == "east" ?
35027 {top: 0, left: 2, right:2, bottom: 0} :
35028 {top: 2, left: 0, right:0, bottom: 2});
35030 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35033 this.bottomTabs = c.tabPosition != "top";
35035 this.autoScroll = c.autoScroll || false;
35040 this.duration = c.duration || .30;
35041 this.slideDuration = c.slideDuration || .45;
35046 * Returns true if this region is currently visible.
35047 * @return {Boolean}
35049 isVisible : function(){
35050 return this.visible;
35054 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35055 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35057 //setCollapsedTitle : function(title){
35058 // title = title || " ";
35059 // if(this.collapsedTitleTextEl){
35060 // this.collapsedTitleTextEl.innerHTML = title;
35064 getBox : function(){
35066 // if(!this.collapsed){
35067 b = this.el.getBox(false, true);
35069 // b = this.collapsedEl.getBox(false, true);
35074 getMargins : function(){
35075 return this.margins;
35076 //return this.collapsed ? this.cmargins : this.margins;
35079 highlight : function(){
35080 this.el.addClass("x-layout-panel-dragover");
35083 unhighlight : function(){
35084 this.el.removeClass("x-layout-panel-dragover");
35087 updateBox : function(box)
35089 if (!this.bodyEl) {
35090 return; // not rendered yet..
35094 if(!this.collapsed){
35095 this.el.dom.style.left = box.x + "px";
35096 this.el.dom.style.top = box.y + "px";
35097 this.updateBody(box.width, box.height);
35099 this.collapsedEl.dom.style.left = box.x + "px";
35100 this.collapsedEl.dom.style.top = box.y + "px";
35101 this.collapsedEl.setSize(box.width, box.height);
35104 this.tabs.autoSizeTabs();
35108 updateBody : function(w, h)
35111 this.el.setWidth(w);
35112 w -= this.el.getBorderWidth("rl");
35113 if(this.config.adjustments){
35114 w += this.config.adjustments[0];
35117 if(h !== null && h > 0){
35118 this.el.setHeight(h);
35119 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35120 h -= this.el.getBorderWidth("tb");
35121 if(this.config.adjustments){
35122 h += this.config.adjustments[1];
35124 this.bodyEl.setHeight(h);
35126 h = this.tabs.syncHeight(h);
35129 if(this.panelSize){
35130 w = w !== null ? w : this.panelSize.width;
35131 h = h !== null ? h : this.panelSize.height;
35133 if(this.activePanel){
35134 var el = this.activePanel.getEl();
35135 w = w !== null ? w : el.getWidth();
35136 h = h !== null ? h : el.getHeight();
35137 this.panelSize = {width: w, height: h};
35138 this.activePanel.setSize(w, h);
35140 if(Roo.isIE && this.tabs){
35141 this.tabs.el.repaint();
35146 * Returns the container element for this region.
35147 * @return {Roo.Element}
35149 getEl : function(){
35154 * Hides this region.
35157 //if(!this.collapsed){
35158 this.el.dom.style.left = "-2000px";
35161 // this.collapsedEl.dom.style.left = "-2000px";
35162 // this.collapsedEl.hide();
35164 this.visible = false;
35165 this.fireEvent("visibilitychange", this, false);
35169 * Shows this region if it was previously hidden.
35172 //if(!this.collapsed){
35175 // this.collapsedEl.show();
35177 this.visible = true;
35178 this.fireEvent("visibilitychange", this, true);
35181 closeClicked : function(){
35182 if(this.activePanel){
35183 this.remove(this.activePanel);
35187 collapseClick : function(e){
35189 e.stopPropagation();
35192 e.stopPropagation();
35198 * Collapses this region.
35199 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35202 collapse : function(skipAnim, skipCheck = false){
35203 if(this.collapsed) {
35207 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35209 this.collapsed = true;
35211 this.split.el.hide();
35213 if(this.config.animate && skipAnim !== true){
35214 this.fireEvent("invalidated", this);
35215 this.animateCollapse();
35217 this.el.setLocation(-20000,-20000);
35219 this.collapsedEl.show();
35220 this.fireEvent("collapsed", this);
35221 this.fireEvent("invalidated", this);
35227 animateCollapse : function(){
35232 * Expands this region if it was previously collapsed.
35233 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35234 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35237 expand : function(e, skipAnim){
35239 e.stopPropagation();
35241 if(!this.collapsed || this.el.hasActiveFx()) {
35245 this.afterSlideIn();
35248 this.collapsed = false;
35249 if(this.config.animate && skipAnim !== true){
35250 this.animateExpand();
35254 this.split.el.show();
35256 this.collapsedEl.setLocation(-2000,-2000);
35257 this.collapsedEl.hide();
35258 this.fireEvent("invalidated", this);
35259 this.fireEvent("expanded", this);
35263 animateExpand : function(){
35267 initTabs : function()
35269 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35271 var ts = new Roo.bootstrap.panel.Tabs({
35272 el: this.bodyEl.dom,
35273 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35274 disableTooltips: this.config.disableTabTips,
35275 toolbar : this.config.toolbar
35278 if(this.config.hideTabs){
35279 ts.stripWrap.setDisplayed(false);
35282 ts.resizeTabs = this.config.resizeTabs === true;
35283 ts.minTabWidth = this.config.minTabWidth || 40;
35284 ts.maxTabWidth = this.config.maxTabWidth || 250;
35285 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35286 ts.monitorResize = false;
35287 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35288 ts.bodyEl.addClass('roo-layout-tabs-body');
35289 this.panels.each(this.initPanelAsTab, this);
35292 initPanelAsTab : function(panel){
35293 var ti = this.tabs.addTab(
35297 this.config.closeOnTab && panel.isClosable(),
35300 if(panel.tabTip !== undefined){
35301 ti.setTooltip(panel.tabTip);
35303 ti.on("activate", function(){
35304 this.setActivePanel(panel);
35307 if(this.config.closeOnTab){
35308 ti.on("beforeclose", function(t, e){
35310 this.remove(panel);
35314 panel.tabItem = ti;
35319 updatePanelTitle : function(panel, title)
35321 if(this.activePanel == panel){
35322 this.updateTitle(title);
35325 var ti = this.tabs.getTab(panel.getEl().id);
35327 if(panel.tabTip !== undefined){
35328 ti.setTooltip(panel.tabTip);
35333 updateTitle : function(title){
35334 if(this.titleTextEl && !this.config.title){
35335 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35339 setActivePanel : function(panel)
35341 panel = this.getPanel(panel);
35342 if(this.activePanel && this.activePanel != panel){
35343 this.activePanel.setActiveState(false);
35345 this.activePanel = panel;
35346 panel.setActiveState(true);
35347 if(this.panelSize){
35348 panel.setSize(this.panelSize.width, this.panelSize.height);
35351 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35353 this.updateTitle(panel.getTitle());
35355 this.fireEvent("invalidated", this);
35357 this.fireEvent("panelactivated", this, panel);
35361 * Shows the specified panel.
35362 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35363 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35365 showPanel : function(panel)
35367 panel = this.getPanel(panel);
35370 var tab = this.tabs.getTab(panel.getEl().id);
35371 if(tab.isHidden()){
35372 this.tabs.unhideTab(tab.id);
35376 this.setActivePanel(panel);
35383 * Get the active panel for this region.
35384 * @return {Roo.ContentPanel} The active panel or null
35386 getActivePanel : function(){
35387 return this.activePanel;
35390 validateVisibility : function(){
35391 if(this.panels.getCount() < 1){
35392 this.updateTitle(" ");
35393 this.closeBtn.hide();
35396 if(!this.isVisible()){
35403 * Adds the passed ContentPanel(s) to this region.
35404 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35405 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35407 add : function(panel)
35409 if(arguments.length > 1){
35410 for(var i = 0, len = arguments.length; i < len; i++) {
35411 this.add(arguments[i]);
35416 // if we have not been rendered yet, then we can not really do much of this..
35417 if (!this.bodyEl) {
35418 this.unrendered_panels.push(panel);
35425 if(this.hasPanel(panel)){
35426 this.showPanel(panel);
35429 panel.setRegion(this);
35430 this.panels.add(panel);
35431 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35432 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35433 // and hide them... ???
35434 this.bodyEl.dom.appendChild(panel.getEl().dom);
35435 if(panel.background !== true){
35436 this.setActivePanel(panel);
35438 this.fireEvent("paneladded", this, panel);
35445 this.initPanelAsTab(panel);
35449 if(panel.background !== true){
35450 this.tabs.activate(panel.getEl().id);
35452 this.fireEvent("paneladded", this, panel);
35457 * Hides the tab for the specified panel.
35458 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35460 hidePanel : function(panel){
35461 if(this.tabs && (panel = this.getPanel(panel))){
35462 this.tabs.hideTab(panel.getEl().id);
35467 * Unhides the tab for a previously hidden panel.
35468 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35470 unhidePanel : function(panel){
35471 if(this.tabs && (panel = this.getPanel(panel))){
35472 this.tabs.unhideTab(panel.getEl().id);
35476 clearPanels : function(){
35477 while(this.panels.getCount() > 0){
35478 this.remove(this.panels.first());
35483 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35484 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35485 * @param {Boolean} preservePanel Overrides the config preservePanel option
35486 * @return {Roo.ContentPanel} The panel that was removed
35488 remove : function(panel, preservePanel)
35490 panel = this.getPanel(panel);
35495 this.fireEvent("beforeremove", this, panel, e);
35496 if(e.cancel === true){
35499 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35500 var panelId = panel.getId();
35501 this.panels.removeKey(panelId);
35503 document.body.appendChild(panel.getEl().dom);
35506 this.tabs.removeTab(panel.getEl().id);
35507 }else if (!preservePanel){
35508 this.bodyEl.dom.removeChild(panel.getEl().dom);
35510 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35511 var p = this.panels.first();
35512 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35513 tempEl.appendChild(p.getEl().dom);
35514 this.bodyEl.update("");
35515 this.bodyEl.dom.appendChild(p.getEl().dom);
35517 this.updateTitle(p.getTitle());
35519 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35520 this.setActivePanel(p);
35522 panel.setRegion(null);
35523 if(this.activePanel == panel){
35524 this.activePanel = null;
35526 if(this.config.autoDestroy !== false && preservePanel !== true){
35527 try{panel.destroy();}catch(e){}
35529 this.fireEvent("panelremoved", this, panel);
35534 * Returns the TabPanel component used by this region
35535 * @return {Roo.TabPanel}
35537 getTabs : function(){
35541 createTool : function(parentEl, className){
35542 var btn = Roo.DomHelper.append(parentEl, {
35544 cls: "x-layout-tools-button",
35547 cls: "roo-layout-tools-button-inner " + className,
35551 btn.addClassOnOver("roo-layout-tools-button-over");
35556 * Ext JS Library 1.1.1
35557 * Copyright(c) 2006-2007, Ext JS, LLC.
35559 * Originally Released Under LGPL - original licence link has changed is not relivant.
35562 * <script type="text/javascript">
35568 * @class Roo.SplitLayoutRegion
35569 * @extends Roo.LayoutRegion
35570 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35572 Roo.bootstrap.layout.Split = function(config){
35573 this.cursor = config.cursor;
35574 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35577 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35579 splitTip : "Drag to resize.",
35580 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35581 useSplitTips : false,
35583 applyConfig : function(config){
35584 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35587 onRender : function(ctr,pos) {
35589 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35590 if(!this.config.split){
35595 var splitEl = Roo.DomHelper.append(ctr.dom, {
35597 id: this.el.id + "-split",
35598 cls: "roo-layout-split roo-layout-split-"+this.position,
35601 /** The SplitBar for this region
35602 * @type Roo.SplitBar */
35603 // does not exist yet...
35604 Roo.log([this.position, this.orientation]);
35606 this.split = new Roo.bootstrap.SplitBar({
35607 dragElement : splitEl,
35608 resizingElement: this.el,
35609 orientation : this.orientation
35612 this.split.on("moved", this.onSplitMove, this);
35613 this.split.useShim = this.config.useShim === true;
35614 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35615 if(this.useSplitTips){
35616 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35618 //if(config.collapsible){
35619 // this.split.el.on("dblclick", this.collapse, this);
35622 if(typeof this.config.minSize != "undefined"){
35623 this.split.minSize = this.config.minSize;
35625 if(typeof this.config.maxSize != "undefined"){
35626 this.split.maxSize = this.config.maxSize;
35628 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35629 this.hideSplitter();
35634 getHMaxSize : function(){
35635 var cmax = this.config.maxSize || 10000;
35636 var center = this.mgr.getRegion("center");
35637 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35640 getVMaxSize : function(){
35641 var cmax = this.config.maxSize || 10000;
35642 var center = this.mgr.getRegion("center");
35643 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35646 onSplitMove : function(split, newSize){
35647 this.fireEvent("resized", this, newSize);
35651 * Returns the {@link Roo.SplitBar} for this region.
35652 * @return {Roo.SplitBar}
35654 getSplitBar : function(){
35659 this.hideSplitter();
35660 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35663 hideSplitter : function(){
35665 this.split.el.setLocation(-2000,-2000);
35666 this.split.el.hide();
35672 this.split.el.show();
35674 Roo.bootstrap.layout.Split.superclass.show.call(this);
35677 beforeSlide: function(){
35678 if(Roo.isGecko){// firefox overflow auto bug workaround
35679 this.bodyEl.clip();
35681 this.tabs.bodyEl.clip();
35683 if(this.activePanel){
35684 this.activePanel.getEl().clip();
35686 if(this.activePanel.beforeSlide){
35687 this.activePanel.beforeSlide();
35693 afterSlide : function(){
35694 if(Roo.isGecko){// firefox overflow auto bug workaround
35695 this.bodyEl.unclip();
35697 this.tabs.bodyEl.unclip();
35699 if(this.activePanel){
35700 this.activePanel.getEl().unclip();
35701 if(this.activePanel.afterSlide){
35702 this.activePanel.afterSlide();
35708 initAutoHide : function(){
35709 if(this.autoHide !== false){
35710 if(!this.autoHideHd){
35711 var st = new Roo.util.DelayedTask(this.slideIn, this);
35712 this.autoHideHd = {
35713 "mouseout": function(e){
35714 if(!e.within(this.el, true)){
35718 "mouseover" : function(e){
35724 this.el.on(this.autoHideHd);
35728 clearAutoHide : function(){
35729 if(this.autoHide !== false){
35730 this.el.un("mouseout", this.autoHideHd.mouseout);
35731 this.el.un("mouseover", this.autoHideHd.mouseover);
35735 clearMonitor : function(){
35736 Roo.get(document).un("click", this.slideInIf, this);
35739 // these names are backwards but not changed for compat
35740 slideOut : function(){
35741 if(this.isSlid || this.el.hasActiveFx()){
35744 this.isSlid = true;
35745 if(this.collapseBtn){
35746 this.collapseBtn.hide();
35748 this.closeBtnState = this.closeBtn.getStyle('display');
35749 this.closeBtn.hide();
35751 this.stickBtn.show();
35754 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35755 this.beforeSlide();
35756 this.el.setStyle("z-index", 10001);
35757 this.el.slideIn(this.getSlideAnchor(), {
35758 callback: function(){
35760 this.initAutoHide();
35761 Roo.get(document).on("click", this.slideInIf, this);
35762 this.fireEvent("slideshow", this);
35769 afterSlideIn : function(){
35770 this.clearAutoHide();
35771 this.isSlid = false;
35772 this.clearMonitor();
35773 this.el.setStyle("z-index", "");
35774 if(this.collapseBtn){
35775 this.collapseBtn.show();
35777 this.closeBtn.setStyle('display', this.closeBtnState);
35779 this.stickBtn.hide();
35781 this.fireEvent("slidehide", this);
35784 slideIn : function(cb){
35785 if(!this.isSlid || this.el.hasActiveFx()){
35789 this.isSlid = false;
35790 this.beforeSlide();
35791 this.el.slideOut(this.getSlideAnchor(), {
35792 callback: function(){
35793 this.el.setLeftTop(-10000, -10000);
35795 this.afterSlideIn();
35803 slideInIf : function(e){
35804 if(!e.within(this.el)){
35809 animateCollapse : function(){
35810 this.beforeSlide();
35811 this.el.setStyle("z-index", 20000);
35812 var anchor = this.getSlideAnchor();
35813 this.el.slideOut(anchor, {
35814 callback : function(){
35815 this.el.setStyle("z-index", "");
35816 this.collapsedEl.slideIn(anchor, {duration:.3});
35818 this.el.setLocation(-10000,-10000);
35820 this.fireEvent("collapsed", this);
35827 animateExpand : function(){
35828 this.beforeSlide();
35829 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35830 this.el.setStyle("z-index", 20000);
35831 this.collapsedEl.hide({
35834 this.el.slideIn(this.getSlideAnchor(), {
35835 callback : function(){
35836 this.el.setStyle("z-index", "");
35839 this.split.el.show();
35841 this.fireEvent("invalidated", this);
35842 this.fireEvent("expanded", this);
35870 getAnchor : function(){
35871 return this.anchors[this.position];
35874 getCollapseAnchor : function(){
35875 return this.canchors[this.position];
35878 getSlideAnchor : function(){
35879 return this.sanchors[this.position];
35882 getAlignAdj : function(){
35883 var cm = this.cmargins;
35884 switch(this.position){
35900 getExpandAdj : function(){
35901 var c = this.collapsedEl, cm = this.cmargins;
35902 switch(this.position){
35904 return [-(cm.right+c.getWidth()+cm.left), 0];
35907 return [cm.right+c.getWidth()+cm.left, 0];
35910 return [0, -(cm.top+cm.bottom+c.getHeight())];
35913 return [0, cm.top+cm.bottom+c.getHeight()];
35919 * Ext JS Library 1.1.1
35920 * Copyright(c) 2006-2007, Ext JS, LLC.
35922 * Originally Released Under LGPL - original licence link has changed is not relivant.
35925 * <script type="text/javascript">
35928 * These classes are private internal classes
35930 Roo.bootstrap.layout.Center = function(config){
35931 config.region = "center";
35932 Roo.bootstrap.layout.Region.call(this, config);
35933 this.visible = true;
35934 this.minWidth = config.minWidth || 20;
35935 this.minHeight = config.minHeight || 20;
35938 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35940 // center panel can't be hidden
35944 // center panel can't be hidden
35947 getMinWidth: function(){
35948 return this.minWidth;
35951 getMinHeight: function(){
35952 return this.minHeight;
35965 Roo.bootstrap.layout.North = function(config)
35967 config.region = 'north';
35968 config.cursor = 'n-resize';
35970 Roo.bootstrap.layout.Split.call(this, config);
35974 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35975 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35976 this.split.el.addClass("roo-layout-split-v");
35978 var size = config.initialSize || config.height;
35979 if(typeof size != "undefined"){
35980 this.el.setHeight(size);
35983 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35985 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35989 getBox : function(){
35990 if(this.collapsed){
35991 return this.collapsedEl.getBox();
35993 var box = this.el.getBox();
35995 box.height += this.split.el.getHeight();
36000 updateBox : function(box){
36001 if(this.split && !this.collapsed){
36002 box.height -= this.split.el.getHeight();
36003 this.split.el.setLeft(box.x);
36004 this.split.el.setTop(box.y+box.height);
36005 this.split.el.setWidth(box.width);
36007 if(this.collapsed){
36008 this.updateBody(box.width, null);
36010 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36018 Roo.bootstrap.layout.South = function(config){
36019 config.region = 'south';
36020 config.cursor = 's-resize';
36021 Roo.bootstrap.layout.Split.call(this, config);
36023 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36024 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36025 this.split.el.addClass("roo-layout-split-v");
36027 var size = config.initialSize || config.height;
36028 if(typeof size != "undefined"){
36029 this.el.setHeight(size);
36033 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36034 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36035 getBox : function(){
36036 if(this.collapsed){
36037 return this.collapsedEl.getBox();
36039 var box = this.el.getBox();
36041 var sh = this.split.el.getHeight();
36048 updateBox : function(box){
36049 if(this.split && !this.collapsed){
36050 var sh = this.split.el.getHeight();
36053 this.split.el.setLeft(box.x);
36054 this.split.el.setTop(box.y-sh);
36055 this.split.el.setWidth(box.width);
36057 if(this.collapsed){
36058 this.updateBody(box.width, null);
36060 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36064 Roo.bootstrap.layout.East = function(config){
36065 config.region = "east";
36066 config.cursor = "e-resize";
36067 Roo.bootstrap.layout.Split.call(this, config);
36069 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36070 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36071 this.split.el.addClass("roo-layout-split-h");
36073 var size = config.initialSize || config.width;
36074 if(typeof size != "undefined"){
36075 this.el.setWidth(size);
36078 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36079 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36080 getBox : function(){
36081 if(this.collapsed){
36082 return this.collapsedEl.getBox();
36084 var box = this.el.getBox();
36086 var sw = this.split.el.getWidth();
36093 updateBox : function(box){
36094 if(this.split && !this.collapsed){
36095 var sw = this.split.el.getWidth();
36097 this.split.el.setLeft(box.x);
36098 this.split.el.setTop(box.y);
36099 this.split.el.setHeight(box.height);
36102 if(this.collapsed){
36103 this.updateBody(null, box.height);
36105 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36109 Roo.bootstrap.layout.West = function(config){
36110 config.region = "west";
36111 config.cursor = "w-resize";
36113 Roo.bootstrap.layout.Split.call(this, config);
36115 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36116 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36117 this.split.el.addClass("roo-layout-split-h");
36121 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36122 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36124 onRender: function(ctr, pos)
36126 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36127 var size = this.config.initialSize || this.config.width;
36128 if(typeof size != "undefined"){
36129 this.el.setWidth(size);
36133 getBox : function(){
36134 if(this.collapsed){
36135 return this.collapsedEl.getBox();
36137 var box = this.el.getBox();
36139 box.width += this.split.el.getWidth();
36144 updateBox : function(box){
36145 if(this.split && !this.collapsed){
36146 var sw = this.split.el.getWidth();
36148 this.split.el.setLeft(box.x+box.width);
36149 this.split.el.setTop(box.y);
36150 this.split.el.setHeight(box.height);
36152 if(this.collapsed){
36153 this.updateBody(null, box.height);
36155 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36158 Roo.namespace("Roo.bootstrap.panel");/*
36160 * Ext JS Library 1.1.1
36161 * Copyright(c) 2006-2007, Ext JS, LLC.
36163 * Originally Released Under LGPL - original licence link has changed is not relivant.
36166 * <script type="text/javascript">
36169 * @class Roo.ContentPanel
36170 * @extends Roo.util.Observable
36171 * A basic ContentPanel element.
36172 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36173 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36174 * @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
36175 * @cfg {Boolean} closable True if the panel can be closed/removed
36176 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36177 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36178 * @cfg {Toolbar} toolbar A toolbar for this panel
36179 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36180 * @cfg {String} title The title for this panel
36181 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36182 * @cfg {String} url Calls {@link #setUrl} with this value
36183 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36184 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36185 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36186 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36187 * @cfg {Boolean} badges render the badges
36190 * Create a new ContentPanel.
36191 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36192 * @param {String/Object} config A string to set only the title or a config object
36193 * @param {String} content (optional) Set the HTML content for this panel
36194 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36196 Roo.bootstrap.panel.Content = function( config){
36198 this.tpl = config.tpl || false;
36200 var el = config.el;
36201 var content = config.content;
36203 if(config.autoCreate){ // xtype is available if this is called from factory
36206 this.el = Roo.get(el);
36207 if(!this.el && config && config.autoCreate){
36208 if(typeof config.autoCreate == "object"){
36209 if(!config.autoCreate.id){
36210 config.autoCreate.id = config.id||el;
36212 this.el = Roo.DomHelper.append(document.body,
36213 config.autoCreate, true);
36215 var elcfg = { tag: "div",
36216 cls: "roo-layout-inactive-content",
36220 elcfg.html = config.html;
36224 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36227 this.closable = false;
36228 this.loaded = false;
36229 this.active = false;
36232 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36234 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36236 this.wrapEl = this.el; //this.el.wrap();
36238 if (config.toolbar.items) {
36239 ti = config.toolbar.items ;
36240 delete config.toolbar.items ;
36244 this.toolbar.render(this.wrapEl, 'before');
36245 for(var i =0;i < ti.length;i++) {
36246 // Roo.log(['add child', items[i]]);
36247 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36249 this.toolbar.items = nitems;
36250 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36251 delete config.toolbar;
36255 // xtype created footer. - not sure if will work as we normally have to render first..
36256 if (this.footer && !this.footer.el && this.footer.xtype) {
36257 if (!this.wrapEl) {
36258 this.wrapEl = this.el.wrap();
36261 this.footer.container = this.wrapEl.createChild();
36263 this.footer = Roo.factory(this.footer, Roo);
36268 if(typeof config == "string"){
36269 this.title = config;
36271 Roo.apply(this, config);
36275 this.resizeEl = Roo.get(this.resizeEl, true);
36277 this.resizeEl = this.el;
36279 // handle view.xtype
36287 * Fires when this panel is activated.
36288 * @param {Roo.ContentPanel} this
36292 * @event deactivate
36293 * Fires when this panel is activated.
36294 * @param {Roo.ContentPanel} this
36296 "deactivate" : true,
36300 * Fires when this panel is resized if fitToFrame is true.
36301 * @param {Roo.ContentPanel} this
36302 * @param {Number} width The width after any component adjustments
36303 * @param {Number} height The height after any component adjustments
36309 * Fires when this tab is created
36310 * @param {Roo.ContentPanel} this
36321 if(this.autoScroll){
36322 this.resizeEl.setStyle("overflow", "auto");
36324 // fix randome scrolling
36325 //this.el.on('scroll', function() {
36326 // Roo.log('fix random scolling');
36327 // this.scrollTo('top',0);
36330 content = content || this.content;
36332 this.setContent(content);
36334 if(config && config.url){
36335 this.setUrl(this.url, this.params, this.loadOnce);
36340 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36342 if (this.view && typeof(this.view.xtype) != 'undefined') {
36343 this.view.el = this.el.appendChild(document.createElement("div"));
36344 this.view = Roo.factory(this.view);
36345 this.view.render && this.view.render(false, '');
36349 this.fireEvent('render', this);
36352 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36356 setRegion : function(region){
36357 this.region = region;
36358 this.setActiveClass(region && !this.background);
36362 setActiveClass: function(state)
36365 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36366 this.el.setStyle('position','relative');
36368 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36369 this.el.setStyle('position', 'absolute');
36374 * Returns the toolbar for this Panel if one was configured.
36375 * @return {Roo.Toolbar}
36377 getToolbar : function(){
36378 return this.toolbar;
36381 setActiveState : function(active)
36383 this.active = active;
36384 this.setActiveClass(active);
36386 this.fireEvent("deactivate", this);
36388 this.fireEvent("activate", this);
36392 * Updates this panel's element
36393 * @param {String} content The new content
36394 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36396 setContent : function(content, loadScripts){
36397 this.el.update(content, loadScripts);
36400 ignoreResize : function(w, h){
36401 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36404 this.lastSize = {width: w, height: h};
36409 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36410 * @return {Roo.UpdateManager} The UpdateManager
36412 getUpdateManager : function(){
36413 return this.el.getUpdateManager();
36416 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36417 * @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:
36420 url: "your-url.php",
36421 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36422 callback: yourFunction,
36423 scope: yourObject, //(optional scope)
36426 text: "Loading...",
36431 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36432 * 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.
36433 * @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}
36434 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36435 * @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.
36436 * @return {Roo.ContentPanel} this
36439 var um = this.el.getUpdateManager();
36440 um.update.apply(um, arguments);
36446 * 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.
36447 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36448 * @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)
36449 * @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)
36450 * @return {Roo.UpdateManager} The UpdateManager
36452 setUrl : function(url, params, loadOnce){
36453 if(this.refreshDelegate){
36454 this.removeListener("activate", this.refreshDelegate);
36456 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36457 this.on("activate", this.refreshDelegate);
36458 return this.el.getUpdateManager();
36461 _handleRefresh : function(url, params, loadOnce){
36462 if(!loadOnce || !this.loaded){
36463 var updater = this.el.getUpdateManager();
36464 updater.update(url, params, this._setLoaded.createDelegate(this));
36468 _setLoaded : function(){
36469 this.loaded = true;
36473 * Returns this panel's id
36476 getId : function(){
36481 * Returns this panel's element - used by regiosn to add.
36482 * @return {Roo.Element}
36484 getEl : function(){
36485 return this.wrapEl || this.el;
36490 adjustForComponents : function(width, height)
36492 //Roo.log('adjustForComponents ');
36493 if(this.resizeEl != this.el){
36494 width -= this.el.getFrameWidth('lr');
36495 height -= this.el.getFrameWidth('tb');
36498 var te = this.toolbar.getEl();
36499 te.setWidth(width);
36500 height -= te.getHeight();
36503 var te = this.footer.getEl();
36504 te.setWidth(width);
36505 height -= te.getHeight();
36509 if(this.adjustments){
36510 width += this.adjustments[0];
36511 height += this.adjustments[1];
36513 return {"width": width, "height": height};
36516 setSize : function(width, height){
36517 if(this.fitToFrame && !this.ignoreResize(width, height)){
36518 if(this.fitContainer && this.resizeEl != this.el){
36519 this.el.setSize(width, height);
36521 var size = this.adjustForComponents(width, height);
36522 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36523 this.fireEvent('resize', this, size.width, size.height);
36528 * Returns this panel's title
36531 getTitle : function(){
36533 if (typeof(this.title) != 'object') {
36538 for (var k in this.title) {
36539 if (!this.title.hasOwnProperty(k)) {
36543 if (k.indexOf('-') >= 0) {
36544 var s = k.split('-');
36545 for (var i = 0; i<s.length; i++) {
36546 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36549 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36556 * Set this panel's title
36557 * @param {String} title
36559 setTitle : function(title){
36560 this.title = title;
36562 this.region.updatePanelTitle(this, title);
36567 * Returns true is this panel was configured to be closable
36568 * @return {Boolean}
36570 isClosable : function(){
36571 return this.closable;
36574 beforeSlide : function(){
36576 this.resizeEl.clip();
36579 afterSlide : function(){
36581 this.resizeEl.unclip();
36585 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36586 * Will fail silently if the {@link #setUrl} method has not been called.
36587 * This does not activate the panel, just updates its content.
36589 refresh : function(){
36590 if(this.refreshDelegate){
36591 this.loaded = false;
36592 this.refreshDelegate();
36597 * Destroys this panel
36599 destroy : function(){
36600 this.el.removeAllListeners();
36601 var tempEl = document.createElement("span");
36602 tempEl.appendChild(this.el.dom);
36603 tempEl.innerHTML = "";
36609 * form - if the content panel contains a form - this is a reference to it.
36610 * @type {Roo.form.Form}
36614 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36615 * This contains a reference to it.
36621 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36631 * @param {Object} cfg Xtype definition of item to add.
36635 getChildContainer: function () {
36636 return this.getEl();
36641 var ret = new Roo.factory(cfg);
36646 if (cfg.xtype.match(/^Form$/)) {
36649 //if (this.footer) {
36650 // el = this.footer.container.insertSibling(false, 'before');
36652 el = this.el.createChild();
36655 this.form = new Roo.form.Form(cfg);
36658 if ( this.form.allItems.length) {
36659 this.form.render(el.dom);
36663 // should only have one of theses..
36664 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36665 // views.. should not be just added - used named prop 'view''
36667 cfg.el = this.el.appendChild(document.createElement("div"));
36670 var ret = new Roo.factory(cfg);
36672 ret.render && ret.render(false, ''); // render blank..
36682 * @class Roo.bootstrap.panel.Grid
36683 * @extends Roo.bootstrap.panel.Content
36685 * Create a new GridPanel.
36686 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36687 * @param {Object} config A the config object
36693 Roo.bootstrap.panel.Grid = function(config)
36697 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36698 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36700 config.el = this.wrapper;
36701 //this.el = this.wrapper;
36703 if (config.container) {
36704 // ctor'ed from a Border/panel.grid
36707 this.wrapper.setStyle("overflow", "hidden");
36708 this.wrapper.addClass('roo-grid-container');
36713 if(config.toolbar){
36714 var tool_el = this.wrapper.createChild();
36715 this.toolbar = Roo.factory(config.toolbar);
36717 if (config.toolbar.items) {
36718 ti = config.toolbar.items ;
36719 delete config.toolbar.items ;
36723 this.toolbar.render(tool_el);
36724 for(var i =0;i < ti.length;i++) {
36725 // Roo.log(['add child', items[i]]);
36726 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36728 this.toolbar.items = nitems;
36730 delete config.toolbar;
36733 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36734 config.grid.scrollBody = true;;
36735 config.grid.monitorWindowResize = false; // turn off autosizing
36736 config.grid.autoHeight = false;
36737 config.grid.autoWidth = false;
36739 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36741 if (config.background) {
36742 // render grid on panel activation (if panel background)
36743 this.on('activate', function(gp) {
36744 if (!gp.grid.rendered) {
36745 gp.grid.render(this.wrapper);
36746 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36751 this.grid.render(this.wrapper);
36752 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36755 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36756 // ??? needed ??? config.el = this.wrapper;
36761 // xtype created footer. - not sure if will work as we normally have to render first..
36762 if (this.footer && !this.footer.el && this.footer.xtype) {
36764 var ctr = this.grid.getView().getFooterPanel(true);
36765 this.footer.dataSource = this.grid.dataSource;
36766 this.footer = Roo.factory(this.footer, Roo);
36767 this.footer.render(ctr);
36777 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36778 getId : function(){
36779 return this.grid.id;
36783 * Returns the grid for this panel
36784 * @return {Roo.bootstrap.Table}
36786 getGrid : function(){
36790 setSize : function(width, height){
36791 if(!this.ignoreResize(width, height)){
36792 var grid = this.grid;
36793 var size = this.adjustForComponents(width, height);
36794 var gridel = grid.getGridEl();
36795 gridel.setSize(size.width, size.height);
36797 var thd = grid.getGridEl().select('thead',true).first();
36798 var tbd = grid.getGridEl().select('tbody', true).first();
36800 tbd.setSize(width, height - thd.getHeight());
36809 beforeSlide : function(){
36810 this.grid.getView().scroller.clip();
36813 afterSlide : function(){
36814 this.grid.getView().scroller.unclip();
36817 destroy : function(){
36818 this.grid.destroy();
36820 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36825 * @class Roo.bootstrap.panel.Nest
36826 * @extends Roo.bootstrap.panel.Content
36828 * Create a new Panel, that can contain a layout.Border.
36831 * @param {Roo.BorderLayout} layout The layout for this panel
36832 * @param {String/Object} config A string to set only the title or a config object
36834 Roo.bootstrap.panel.Nest = function(config)
36836 // construct with only one argument..
36837 /* FIXME - implement nicer consturctors
36838 if (layout.layout) {
36840 layout = config.layout;
36841 delete config.layout;
36843 if (layout.xtype && !layout.getEl) {
36844 // then layout needs constructing..
36845 layout = Roo.factory(layout, Roo);
36849 config.el = config.layout.getEl();
36851 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36853 config.layout.monitorWindowResize = false; // turn off autosizing
36854 this.layout = config.layout;
36855 this.layout.getEl().addClass("roo-layout-nested-layout");
36862 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36864 setSize : function(width, height){
36865 if(!this.ignoreResize(width, height)){
36866 var size = this.adjustForComponents(width, height);
36867 var el = this.layout.getEl();
36868 if (size.height < 1) {
36869 el.setWidth(size.width);
36871 el.setSize(size.width, size.height);
36873 var touch = el.dom.offsetWidth;
36874 this.layout.layout();
36875 // ie requires a double layout on the first pass
36876 if(Roo.isIE && !this.initialized){
36877 this.initialized = true;
36878 this.layout.layout();
36883 // activate all subpanels if not currently active..
36885 setActiveState : function(active){
36886 this.active = active;
36887 this.setActiveClass(active);
36890 this.fireEvent("deactivate", this);
36894 this.fireEvent("activate", this);
36895 // not sure if this should happen before or after..
36896 if (!this.layout) {
36897 return; // should not happen..
36900 for (var r in this.layout.regions) {
36901 reg = this.layout.getRegion(r);
36902 if (reg.getActivePanel()) {
36903 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36904 reg.setActivePanel(reg.getActivePanel());
36907 if (!reg.panels.length) {
36910 reg.showPanel(reg.getPanel(0));
36919 * Returns the nested BorderLayout for this panel
36920 * @return {Roo.BorderLayout}
36922 getLayout : function(){
36923 return this.layout;
36927 * Adds a xtype elements to the layout of the nested panel
36931 xtype : 'ContentPanel',
36938 xtype : 'NestedLayoutPanel',
36944 items : [ ... list of content panels or nested layout panels.. ]
36948 * @param {Object} cfg Xtype definition of item to add.
36950 addxtype : function(cfg) {
36951 return this.layout.addxtype(cfg);
36956 * Ext JS Library 1.1.1
36957 * Copyright(c) 2006-2007, Ext JS, LLC.
36959 * Originally Released Under LGPL - original licence link has changed is not relivant.
36962 * <script type="text/javascript">
36965 * @class Roo.TabPanel
36966 * @extends Roo.util.Observable
36967 * A lightweight tab container.
36971 // basic tabs 1, built from existing content
36972 var tabs = new Roo.TabPanel("tabs1");
36973 tabs.addTab("script", "View Script");
36974 tabs.addTab("markup", "View Markup");
36975 tabs.activate("script");
36977 // more advanced tabs, built from javascript
36978 var jtabs = new Roo.TabPanel("jtabs");
36979 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36981 // set up the UpdateManager
36982 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36983 var updater = tab2.getUpdateManager();
36984 updater.setDefaultUrl("ajax1.htm");
36985 tab2.on('activate', updater.refresh, updater, true);
36987 // Use setUrl for Ajax loading
36988 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36989 tab3.setUrl("ajax2.htm", null, true);
36992 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36995 jtabs.activate("jtabs-1");
36998 * Create a new TabPanel.
36999 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37000 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37002 Roo.bootstrap.panel.Tabs = function(config){
37004 * The container element for this TabPanel.
37005 * @type Roo.Element
37007 this.el = Roo.get(config.el);
37010 if(typeof config == "boolean"){
37011 this.tabPosition = config ? "bottom" : "top";
37013 Roo.apply(this, config);
37017 if(this.tabPosition == "bottom"){
37018 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37019 this.el.addClass("roo-tabs-bottom");
37021 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37022 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37023 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37025 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37027 if(this.tabPosition != "bottom"){
37028 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37029 * @type Roo.Element
37031 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37032 this.el.addClass("roo-tabs-top");
37036 this.bodyEl.setStyle("position", "relative");
37038 this.active = null;
37039 this.activateDelegate = this.activate.createDelegate(this);
37044 * Fires when the active tab changes
37045 * @param {Roo.TabPanel} this
37046 * @param {Roo.TabPanelItem} activePanel The new active tab
37050 * @event beforetabchange
37051 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37052 * @param {Roo.TabPanel} this
37053 * @param {Object} e Set cancel to true on this object to cancel the tab change
37054 * @param {Roo.TabPanelItem} tab The tab being changed to
37056 "beforetabchange" : true
37059 Roo.EventManager.onWindowResize(this.onResize, this);
37060 this.cpad = this.el.getPadding("lr");
37061 this.hiddenCount = 0;
37064 // toolbar on the tabbar support...
37065 if (this.toolbar) {
37066 alert("no toolbar support yet");
37067 this.toolbar = false;
37069 var tcfg = this.toolbar;
37070 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37071 this.toolbar = new Roo.Toolbar(tcfg);
37072 if (Roo.isSafari) {
37073 var tbl = tcfg.container.child('table', true);
37074 tbl.setAttribute('width', '100%');
37082 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37085 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37087 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37089 tabPosition : "top",
37091 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37093 currentTabWidth : 0,
37095 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37099 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37103 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37105 preferredTabWidth : 175,
37107 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37109 resizeTabs : false,
37111 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37113 monitorResize : true,
37115 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37120 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37121 * @param {String} id The id of the div to use <b>or create</b>
37122 * @param {String} text The text for the tab
37123 * @param {String} content (optional) Content to put in the TabPanelItem body
37124 * @param {Boolean} closable (optional) True to create a close icon on the tab
37125 * @return {Roo.TabPanelItem} The created TabPanelItem
37127 addTab : function(id, text, content, closable, tpl)
37129 var item = new Roo.bootstrap.panel.TabItem({
37133 closable : closable,
37136 this.addTabItem(item);
37138 item.setContent(content);
37144 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37145 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37146 * @return {Roo.TabPanelItem}
37148 getTab : function(id){
37149 return this.items[id];
37153 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37154 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37156 hideTab : function(id){
37157 var t = this.items[id];
37160 this.hiddenCount++;
37161 this.autoSizeTabs();
37166 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37167 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37169 unhideTab : function(id){
37170 var t = this.items[id];
37172 t.setHidden(false);
37173 this.hiddenCount--;
37174 this.autoSizeTabs();
37179 * Adds an existing {@link Roo.TabPanelItem}.
37180 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37182 addTabItem : function(item){
37183 this.items[item.id] = item;
37184 this.items.push(item);
37185 // if(this.resizeTabs){
37186 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37187 // this.autoSizeTabs();
37189 // item.autoSize();
37194 * Removes a {@link Roo.TabPanelItem}.
37195 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37197 removeTab : function(id){
37198 var items = this.items;
37199 var tab = items[id];
37200 if(!tab) { return; }
37201 var index = items.indexOf(tab);
37202 if(this.active == tab && items.length > 1){
37203 var newTab = this.getNextAvailable(index);
37208 this.stripEl.dom.removeChild(tab.pnode.dom);
37209 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37210 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37212 items.splice(index, 1);
37213 delete this.items[tab.id];
37214 tab.fireEvent("close", tab);
37215 tab.purgeListeners();
37216 this.autoSizeTabs();
37219 getNextAvailable : function(start){
37220 var items = this.items;
37222 // look for a next tab that will slide over to
37223 // replace the one being removed
37224 while(index < items.length){
37225 var item = items[++index];
37226 if(item && !item.isHidden()){
37230 // if one isn't found select the previous tab (on the left)
37233 var item = items[--index];
37234 if(item && !item.isHidden()){
37242 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37243 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37245 disableTab : function(id){
37246 var tab = this.items[id];
37247 if(tab && this.active != tab){
37253 * Enables a {@link Roo.TabPanelItem} that is disabled.
37254 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37256 enableTab : function(id){
37257 var tab = this.items[id];
37262 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37263 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37264 * @return {Roo.TabPanelItem} The TabPanelItem.
37266 activate : function(id){
37267 var tab = this.items[id];
37271 if(tab == this.active || tab.disabled){
37275 this.fireEvent("beforetabchange", this, e, tab);
37276 if(e.cancel !== true && !tab.disabled){
37278 this.active.hide();
37280 this.active = this.items[id];
37281 this.active.show();
37282 this.fireEvent("tabchange", this, this.active);
37288 * Gets the active {@link Roo.TabPanelItem}.
37289 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37291 getActiveTab : function(){
37292 return this.active;
37296 * Updates the tab body element to fit the height of the container element
37297 * for overflow scrolling
37298 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37300 syncHeight : function(targetHeight){
37301 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37302 var bm = this.bodyEl.getMargins();
37303 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37304 this.bodyEl.setHeight(newHeight);
37308 onResize : function(){
37309 if(this.monitorResize){
37310 this.autoSizeTabs();
37315 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37317 beginUpdate : function(){
37318 this.updating = true;
37322 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37324 endUpdate : function(){
37325 this.updating = false;
37326 this.autoSizeTabs();
37330 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37332 autoSizeTabs : function(){
37333 var count = this.items.length;
37334 var vcount = count - this.hiddenCount;
37335 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37338 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37339 var availWidth = Math.floor(w / vcount);
37340 var b = this.stripBody;
37341 if(b.getWidth() > w){
37342 var tabs = this.items;
37343 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37344 if(availWidth < this.minTabWidth){
37345 /*if(!this.sleft){ // incomplete scrolling code
37346 this.createScrollButtons();
37349 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37352 if(this.currentTabWidth < this.preferredTabWidth){
37353 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37359 * Returns the number of tabs in this TabPanel.
37362 getCount : function(){
37363 return this.items.length;
37367 * Resizes all the tabs to the passed width
37368 * @param {Number} The new width
37370 setTabWidth : function(width){
37371 this.currentTabWidth = width;
37372 for(var i = 0, len = this.items.length; i < len; i++) {
37373 if(!this.items[i].isHidden()) {
37374 this.items[i].setWidth(width);
37380 * Destroys this TabPanel
37381 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37383 destroy : function(removeEl){
37384 Roo.EventManager.removeResizeListener(this.onResize, this);
37385 for(var i = 0, len = this.items.length; i < len; i++){
37386 this.items[i].purgeListeners();
37388 if(removeEl === true){
37389 this.el.update("");
37394 createStrip : function(container)
37396 var strip = document.createElement("nav");
37397 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37398 container.appendChild(strip);
37402 createStripList : function(strip)
37404 // div wrapper for retard IE
37405 // returns the "tr" element.
37406 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37407 //'<div class="x-tabs-strip-wrap">'+
37408 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37409 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37410 return strip.firstChild; //.firstChild.firstChild.firstChild;
37412 createBody : function(container)
37414 var body = document.createElement("div");
37415 Roo.id(body, "tab-body");
37416 //Roo.fly(body).addClass("x-tabs-body");
37417 Roo.fly(body).addClass("tab-content");
37418 container.appendChild(body);
37421 createItemBody :function(bodyEl, id){
37422 var body = Roo.getDom(id);
37424 body = document.createElement("div");
37427 //Roo.fly(body).addClass("x-tabs-item-body");
37428 Roo.fly(body).addClass("tab-pane");
37429 bodyEl.insertBefore(body, bodyEl.firstChild);
37433 createStripElements : function(stripEl, text, closable, tpl)
37435 var td = document.createElement("li"); // was td..
37438 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37441 stripEl.appendChild(td);
37443 td.className = "x-tabs-closable";
37444 if(!this.closeTpl){
37445 this.closeTpl = new Roo.Template(
37446 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37447 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37448 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37451 var el = this.closeTpl.overwrite(td, {"text": text});
37452 var close = el.getElementsByTagName("div")[0];
37453 var inner = el.getElementsByTagName("em")[0];
37454 return {"el": el, "close": close, "inner": inner};
37457 // not sure what this is..
37458 // if(!this.tabTpl){
37459 //this.tabTpl = new Roo.Template(
37460 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37461 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37463 // this.tabTpl = new Roo.Template(
37464 // '<a href="#">' +
37465 // '<span unselectable="on"' +
37466 // (this.disableTooltips ? '' : ' title="{text}"') +
37467 // ' >{text}</span></a>'
37473 var template = tpl || this.tabTpl || false;
37477 template = new Roo.Template(
37479 '<span unselectable="on"' +
37480 (this.disableTooltips ? '' : ' title="{text}"') +
37481 ' >{text}</span></a>'
37485 switch (typeof(template)) {
37489 template = new Roo.Template(template);
37495 var el = template.overwrite(td, {"text": text});
37497 var inner = el.getElementsByTagName("span")[0];
37499 return {"el": el, "inner": inner};
37507 * @class Roo.TabPanelItem
37508 * @extends Roo.util.Observable
37509 * Represents an individual item (tab plus body) in a TabPanel.
37510 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37511 * @param {String} id The id of this TabPanelItem
37512 * @param {String} text The text for the tab of this TabPanelItem
37513 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37515 Roo.bootstrap.panel.TabItem = function(config){
37517 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37518 * @type Roo.TabPanel
37520 this.tabPanel = config.panel;
37522 * The id for this TabPanelItem
37525 this.id = config.id;
37527 this.disabled = false;
37529 this.text = config.text;
37531 this.loaded = false;
37532 this.closable = config.closable;
37535 * The body element for this TabPanelItem.
37536 * @type Roo.Element
37538 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37539 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37540 this.bodyEl.setStyle("display", "block");
37541 this.bodyEl.setStyle("zoom", "1");
37542 //this.hideAction();
37544 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37546 this.el = Roo.get(els.el);
37547 this.inner = Roo.get(els.inner, true);
37548 this.textEl = Roo.get(this.el.dom.firstChild, true);
37549 this.pnode = Roo.get(els.el.parentNode, true);
37550 this.el.on("mousedown", this.onTabMouseDown, this);
37551 this.el.on("click", this.onTabClick, this);
37553 if(config.closable){
37554 var c = Roo.get(els.close, true);
37555 c.dom.title = this.closeText;
37556 c.addClassOnOver("close-over");
37557 c.on("click", this.closeClick, this);
37563 * Fires when this tab becomes the active tab.
37564 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37565 * @param {Roo.TabPanelItem} this
37569 * @event beforeclose
37570 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37571 * @param {Roo.TabPanelItem} this
37572 * @param {Object} e Set cancel to true on this object to cancel the close.
37574 "beforeclose": true,
37577 * Fires when this tab is closed.
37578 * @param {Roo.TabPanelItem} this
37582 * @event deactivate
37583 * Fires when this tab is no longer the active tab.
37584 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37585 * @param {Roo.TabPanelItem} this
37587 "deactivate" : true
37589 this.hidden = false;
37591 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37594 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37596 purgeListeners : function(){
37597 Roo.util.Observable.prototype.purgeListeners.call(this);
37598 this.el.removeAllListeners();
37601 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37604 this.pnode.addClass("active");
37607 this.tabPanel.stripWrap.repaint();
37609 this.fireEvent("activate", this.tabPanel, this);
37613 * Returns true if this tab is the active tab.
37614 * @return {Boolean}
37616 isActive : function(){
37617 return this.tabPanel.getActiveTab() == this;
37621 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37624 this.pnode.removeClass("active");
37626 this.fireEvent("deactivate", this.tabPanel, this);
37629 hideAction : function(){
37630 this.bodyEl.hide();
37631 this.bodyEl.setStyle("position", "absolute");
37632 this.bodyEl.setLeft("-20000px");
37633 this.bodyEl.setTop("-20000px");
37636 showAction : function(){
37637 this.bodyEl.setStyle("position", "relative");
37638 this.bodyEl.setTop("");
37639 this.bodyEl.setLeft("");
37640 this.bodyEl.show();
37644 * Set the tooltip for the tab.
37645 * @param {String} tooltip The tab's tooltip
37647 setTooltip : function(text){
37648 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37649 this.textEl.dom.qtip = text;
37650 this.textEl.dom.removeAttribute('title');
37652 this.textEl.dom.title = text;
37656 onTabClick : function(e){
37657 e.preventDefault();
37658 this.tabPanel.activate(this.id);
37661 onTabMouseDown : function(e){
37662 e.preventDefault();
37663 this.tabPanel.activate(this.id);
37666 getWidth : function(){
37667 return this.inner.getWidth();
37670 setWidth : function(width){
37671 var iwidth = width - this.pnode.getPadding("lr");
37672 this.inner.setWidth(iwidth);
37673 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37674 this.pnode.setWidth(width);
37678 * Show or hide the tab
37679 * @param {Boolean} hidden True to hide or false to show.
37681 setHidden : function(hidden){
37682 this.hidden = hidden;
37683 this.pnode.setStyle("display", hidden ? "none" : "");
37687 * Returns true if this tab is "hidden"
37688 * @return {Boolean}
37690 isHidden : function(){
37691 return this.hidden;
37695 * Returns the text for this tab
37698 getText : function(){
37702 autoSize : function(){
37703 //this.el.beginMeasure();
37704 this.textEl.setWidth(1);
37706 * #2804 [new] Tabs in Roojs
37707 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37709 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37710 //this.el.endMeasure();
37714 * Sets the text for the tab (Note: this also sets the tooltip text)
37715 * @param {String} text The tab's text and tooltip
37717 setText : function(text){
37719 this.textEl.update(text);
37720 this.setTooltip(text);
37721 //if(!this.tabPanel.resizeTabs){
37722 // this.autoSize();
37726 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37728 activate : function(){
37729 this.tabPanel.activate(this.id);
37733 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37735 disable : function(){
37736 if(this.tabPanel.active != this){
37737 this.disabled = true;
37738 this.pnode.addClass("disabled");
37743 * Enables this TabPanelItem if it was previously disabled.
37745 enable : function(){
37746 this.disabled = false;
37747 this.pnode.removeClass("disabled");
37751 * Sets the content for this TabPanelItem.
37752 * @param {String} content The content
37753 * @param {Boolean} loadScripts true to look for and load scripts
37755 setContent : function(content, loadScripts){
37756 this.bodyEl.update(content, loadScripts);
37760 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37761 * @return {Roo.UpdateManager} The UpdateManager
37763 getUpdateManager : function(){
37764 return this.bodyEl.getUpdateManager();
37768 * Set a URL to be used to load the content for this TabPanelItem.
37769 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37770 * @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)
37771 * @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)
37772 * @return {Roo.UpdateManager} The UpdateManager
37774 setUrl : function(url, params, loadOnce){
37775 if(this.refreshDelegate){
37776 this.un('activate', this.refreshDelegate);
37778 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37779 this.on("activate", this.refreshDelegate);
37780 return this.bodyEl.getUpdateManager();
37784 _handleRefresh : function(url, params, loadOnce){
37785 if(!loadOnce || !this.loaded){
37786 var updater = this.bodyEl.getUpdateManager();
37787 updater.update(url, params, this._setLoaded.createDelegate(this));
37792 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37793 * Will fail silently if the setUrl method has not been called.
37794 * This does not activate the panel, just updates its content.
37796 refresh : function(){
37797 if(this.refreshDelegate){
37798 this.loaded = false;
37799 this.refreshDelegate();
37804 _setLoaded : function(){
37805 this.loaded = true;
37809 closeClick : function(e){
37812 this.fireEvent("beforeclose", this, o);
37813 if(o.cancel !== true){
37814 this.tabPanel.removeTab(this.id);
37818 * The text displayed in the tooltip for the close icon.
37821 closeText : "Close this tab"