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
7591 * @cfg {Number} maskOffset Default 100
7595 getAutoCreate : function(){
7599 method : this.method || 'POST',
7600 id : this.id || Roo.id(),
7603 if (this.parent().xtype.match(/^Nav/)) {
7604 cfg.cls = 'navbar-form navbar-' + this.align;
7608 if (this.labelAlign == 'left' ) {
7609 cfg.cls += ' form-horizontal';
7615 initEvents : function()
7617 this.el.on('submit', this.onSubmit, this);
7618 // this was added as random key presses on the form where triggering form submit.
7619 this.el.on('keypress', function(e) {
7620 if (e.getCharCode() != 13) {
7623 // we might need to allow it for textareas.. and some other items.
7624 // check e.getTarget().
7626 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7630 Roo.log("keypress blocked");
7638 onSubmit : function(e){
7643 * Returns true if client-side validation on the form is successful.
7646 isValid : function(){
7647 var items = this.getItems();
7651 items.each(function(f){
7658 if(!target && f.el.isVisible(true)){
7664 if(this.errorMask && !valid){
7665 Roo.bootstrap.Form.popover.mask(this, target);
7672 * Returns true if any fields in this form have changed since their original load.
7675 isDirty : function(){
7677 var items = this.getItems();
7678 items.each(function(f){
7688 * Performs a predefined action (submit or load) or custom actions you define on this form.
7689 * @param {String} actionName The name of the action type
7690 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7691 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7692 * accept other config options):
7694 Property Type Description
7695 ---------------- --------------- ----------------------------------------------------------------------------------
7696 url String The url for the action (defaults to the form's url)
7697 method String The form method to use (defaults to the form's method, or POST if not defined)
7698 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7699 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7700 validate the form on the client (defaults to false)
7702 * @return {BasicForm} this
7704 doAction : function(action, options){
7705 if(typeof action == 'string'){
7706 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7708 if(this.fireEvent('beforeaction', this, action) !== false){
7709 this.beforeAction(action);
7710 action.run.defer(100, action);
7716 beforeAction : function(action){
7717 var o = action.options;
7720 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7722 // not really supported yet.. ??
7724 //if(this.waitMsgTarget === true){
7725 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7726 //}else if(this.waitMsgTarget){
7727 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7728 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7730 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7736 afterAction : function(action, success){
7737 this.activeAction = null;
7738 var o = action.options;
7740 //if(this.waitMsgTarget === true){
7742 //}else if(this.waitMsgTarget){
7743 // this.waitMsgTarget.unmask();
7745 // Roo.MessageBox.updateProgress(1);
7746 // Roo.MessageBox.hide();
7753 Roo.callback(o.success, o.scope, [this, action]);
7754 this.fireEvent('actioncomplete', this, action);
7758 // failure condition..
7759 // we have a scenario where updates need confirming.
7760 // eg. if a locking scenario exists..
7761 // we look for { errors : { needs_confirm : true }} in the response.
7763 (typeof(action.result) != 'undefined') &&
7764 (typeof(action.result.errors) != 'undefined') &&
7765 (typeof(action.result.errors.needs_confirm) != 'undefined')
7768 Roo.log("not supported yet");
7771 Roo.MessageBox.confirm(
7772 "Change requires confirmation",
7773 action.result.errorMsg,
7778 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7788 Roo.callback(o.failure, o.scope, [this, action]);
7789 // show an error message if no failed handler is set..
7790 if (!this.hasListener('actionfailed')) {
7791 Roo.log("need to add dialog support");
7793 Roo.MessageBox.alert("Error",
7794 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7795 action.result.errorMsg :
7796 "Saving Failed, please check your entries or try again"
7801 this.fireEvent('actionfailed', this, action);
7806 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7807 * @param {String} id The value to search for
7810 findField : function(id){
7811 var items = this.getItems();
7812 var field = items.get(id);
7814 items.each(function(f){
7815 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7822 return field || null;
7825 * Mark fields in this form invalid in bulk.
7826 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7827 * @return {BasicForm} this
7829 markInvalid : function(errors){
7830 if(errors instanceof Array){
7831 for(var i = 0, len = errors.length; i < len; i++){
7832 var fieldError = errors[i];
7833 var f = this.findField(fieldError.id);
7835 f.markInvalid(fieldError.msg);
7841 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7842 field.markInvalid(errors[id]);
7846 //Roo.each(this.childForms || [], function (f) {
7847 // f.markInvalid(errors);
7854 * Set values for fields in this form in bulk.
7855 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7856 * @return {BasicForm} this
7858 setValues : function(values){
7859 if(values instanceof Array){ // array of objects
7860 for(var i = 0, len = values.length; i < len; i++){
7862 var f = this.findField(v.id);
7864 f.setValue(v.value);
7865 if(this.trackResetOnLoad){
7866 f.originalValue = f.getValue();
7870 }else{ // object hash
7873 if(typeof values[id] != 'function' && (field = this.findField(id))){
7875 if (field.setFromData &&
7877 field.displayField &&
7878 // combos' with local stores can
7879 // be queried via setValue()
7880 // to set their value..
7881 (field.store && !field.store.isLocal)
7885 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7886 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7887 field.setFromData(sd);
7890 field.setValue(values[id]);
7894 if(this.trackResetOnLoad){
7895 field.originalValue = field.getValue();
7901 //Roo.each(this.childForms || [], function (f) {
7902 // f.setValues(values);
7909 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7910 * they are returned as an array.
7911 * @param {Boolean} asString
7914 getValues : function(asString){
7915 //if (this.childForms) {
7916 // copy values from the child forms
7917 // Roo.each(this.childForms, function (f) {
7918 // this.setValues(f.getValues());
7924 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7925 if(asString === true){
7928 return Roo.urlDecode(fs);
7932 * Returns the fields in this form as an object with key/value pairs.
7933 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7936 getFieldValues : function(with_hidden)
7938 var items = this.getItems();
7940 items.each(function(f){
7944 var v = f.getValue();
7945 if (f.inputType =='radio') {
7946 if (typeof(ret[f.getName()]) == 'undefined') {
7947 ret[f.getName()] = ''; // empty..
7950 if (!f.el.dom.checked) {
7958 // not sure if this supported any more..
7959 if ((typeof(v) == 'object') && f.getRawValue) {
7960 v = f.getRawValue() ; // dates..
7962 // combo boxes where name != hiddenName...
7963 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7964 ret[f.name] = f.getRawValue();
7966 ret[f.getName()] = v;
7973 * Clears all invalid messages in this form.
7974 * @return {BasicForm} this
7976 clearInvalid : function(){
7977 var items = this.getItems();
7979 items.each(function(f){
7990 * @return {BasicForm} this
7993 var items = this.getItems();
7994 items.each(function(f){
7998 Roo.each(this.childForms || [], function (f) {
8005 getItems : function()
8007 var r=new Roo.util.MixedCollection(false, function(o){
8008 return o.id || (o.id = Roo.id());
8010 var iter = function(el) {
8017 Roo.each(el.items,function(e) {
8034 Roo.apply(Roo.bootstrap.Form, {
8061 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8062 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8063 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8064 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8067 this.maskEl.top.enableDisplayMode("block");
8068 this.maskEl.left.enableDisplayMode("block");
8069 this.maskEl.bottom.enableDisplayMode("block");
8070 this.maskEl.right.enableDisplayMode("block");
8072 this.toolTip = new Roo.bootstrap.Tooltip({
8073 cls : 'roo-form-error-popover',
8075 'left' : ['r-l', [-2,0], 'right'],
8076 'right' : ['l-r', [2,0], 'left'],
8077 'bottom' : ['tl-bl', [0,2], 'top'],
8078 'top' : [ 'bl-tl', [0,-2], 'bottom']
8082 this.toolTip.render(Roo.get(document.body));
8084 this.toolTip.el.enableDisplayMode("block");
8086 Roo.get(document.body).on('click', function(){
8090 Roo.get(document.body).on('touchstart', function(){
8094 this.isApplied = true
8097 mask : function(form, target)
8101 this.target = target;
8103 if(!this.form.errorMask || !target.el){
8107 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8109 var ot = this.target.el.calcOffsetsTo(scrollable);
8111 var scrollTo = ot[1] - this.form.maskOffset;
8113 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8115 scrollable.scrollTo('top', scrollTo);
8117 var box = this.target.el.getBox();
8119 var zIndex = Roo.bootstrap.Modal.zIndex++;
8122 this.maskEl.top.setStyle('position', 'absolute');
8123 this.maskEl.top.setStyle('z-index', zIndex);
8124 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8125 this.maskEl.top.setLeft(0);
8126 this.maskEl.top.setTop(0);
8127 this.maskEl.top.show();
8129 this.maskEl.left.setStyle('position', 'absolute');
8130 this.maskEl.left.setStyle('z-index', zIndex);
8131 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8132 this.maskEl.left.setLeft(0);
8133 this.maskEl.left.setTop(box.y - this.padding);
8134 this.maskEl.left.show();
8136 this.maskEl.bottom.setStyle('position', 'absolute');
8137 this.maskEl.bottom.setStyle('z-index', zIndex);
8138 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8139 this.maskEl.bottom.setLeft(0);
8140 this.maskEl.bottom.setTop(box.bottom + this.padding);
8141 this.maskEl.bottom.show();
8143 this.maskEl.right.setStyle('position', 'absolute');
8144 this.maskEl.right.setStyle('z-index', zIndex);
8145 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8146 this.maskEl.right.setLeft(box.right + this.padding);
8147 this.maskEl.right.setTop(box.y - this.padding);
8148 this.maskEl.right.show();
8150 this.toolTip.bindEl = this.target.el;
8152 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8154 var tip = this.target.blankText;
8156 if(this.target.getValue() !== '' && this.target.regexText.length){
8157 tip = this.target.regexText;
8160 this.toolTip.show(tip);
8162 this.intervalID = window.setInterval(function() {
8163 Roo.bootstrap.Form.popover.unmask();
8166 window.onwheel = function(){ return false;};
8168 (function(){ this.isMasked = true; }).defer(500, this);
8174 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8178 this.maskEl.top.setStyle('position', 'absolute');
8179 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8180 this.maskEl.top.hide();
8182 this.maskEl.left.setStyle('position', 'absolute');
8183 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8184 this.maskEl.left.hide();
8186 this.maskEl.bottom.setStyle('position', 'absolute');
8187 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8188 this.maskEl.bottom.hide();
8190 this.maskEl.right.setStyle('position', 'absolute');
8191 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8192 this.maskEl.right.hide();
8194 this.toolTip.hide();
8196 this.toolTip.el.hide();
8198 window.onwheel = function(){ return true;};
8200 if(this.intervalID){
8201 window.clearInterval(this.intervalID);
8202 this.intervalID = false;
8205 this.isMasked = false;
8215 * Ext JS Library 1.1.1
8216 * Copyright(c) 2006-2007, Ext JS, LLC.
8218 * Originally Released Under LGPL - original licence link has changed is not relivant.
8221 * <script type="text/javascript">
8224 * @class Roo.form.VTypes
8225 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8228 Roo.form.VTypes = function(){
8229 // closure these in so they are only created once.
8230 var alpha = /^[a-zA-Z_]+$/;
8231 var alphanum = /^[a-zA-Z0-9_]+$/;
8232 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8233 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8235 // All these messages and functions are configurable
8238 * The function used to validate email addresses
8239 * @param {String} value The email address
8241 'email' : function(v){
8242 return email.test(v);
8245 * The error text to display when the email validation function returns false
8248 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8250 * The keystroke filter mask to be applied on email input
8253 'emailMask' : /[a-z0-9_\.\-@]/i,
8256 * The function used to validate URLs
8257 * @param {String} value The URL
8259 'url' : function(v){
8263 * The error text to display when the url validation function returns false
8266 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8269 * The function used to validate alpha values
8270 * @param {String} value The value
8272 'alpha' : function(v){
8273 return alpha.test(v);
8276 * The error text to display when the alpha validation function returns false
8279 'alphaText' : 'This field should only contain letters and _',
8281 * The keystroke filter mask to be applied on alpha input
8284 'alphaMask' : /[a-z_]/i,
8287 * The function used to validate alphanumeric values
8288 * @param {String} value The value
8290 'alphanum' : function(v){
8291 return alphanum.test(v);
8294 * The error text to display when the alphanumeric validation function returns false
8297 'alphanumText' : 'This field should only contain letters, numbers and _',
8299 * The keystroke filter mask to be applied on alphanumeric input
8302 'alphanumMask' : /[a-z0-9_]/i
8312 * @class Roo.bootstrap.Input
8313 * @extends Roo.bootstrap.Component
8314 * Bootstrap Input class
8315 * @cfg {Boolean} disabled is it disabled
8316 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8317 * @cfg {String} name name of the input
8318 * @cfg {string} fieldLabel - the label associated
8319 * @cfg {string} placeholder - placeholder to put in text.
8320 * @cfg {string} before - input group add on before
8321 * @cfg {string} after - input group add on after
8322 * @cfg {string} size - (lg|sm) or leave empty..
8323 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8324 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8325 * @cfg {Number} md colspan out of 12 for computer-sized screens
8326 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8327 * @cfg {string} value default value of the input
8328 * @cfg {Number} labelWidth set the width of label
8329 * @cfg {Number} labellg set the width of label (1-12)
8330 * @cfg {Number} labelmd set the width of label (1-12)
8331 * @cfg {Number} labelsm set the width of label (1-12)
8332 * @cfg {Number} labelxs set the width of label (1-12)
8333 * @cfg {String} labelAlign (top|left)
8334 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8335 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8336 * @cfg {String} indicatorpos (left|right) default left
8338 * @cfg {String} align (left|center|right) Default left
8339 * @cfg {Boolean} forceFeedback (true|false) Default false
8345 * Create a new Input
8346 * @param {Object} config The config object
8349 Roo.bootstrap.Input = function(config){
8351 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8356 * Fires when this field receives input focus.
8357 * @param {Roo.form.Field} this
8362 * Fires when this field loses input focus.
8363 * @param {Roo.form.Field} this
8368 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8369 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8370 * @param {Roo.form.Field} this
8371 * @param {Roo.EventObject} e The event object
8376 * Fires just before the field blurs if the field value has changed.
8377 * @param {Roo.form.Field} this
8378 * @param {Mixed} newValue The new value
8379 * @param {Mixed} oldValue The original value
8384 * Fires after the field has been marked as invalid.
8385 * @param {Roo.form.Field} this
8386 * @param {String} msg The validation message
8391 * Fires after the field has been validated with no errors.
8392 * @param {Roo.form.Field} this
8397 * Fires after the key up
8398 * @param {Roo.form.Field} this
8399 * @param {Roo.EventObject} e The event Object
8405 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8407 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8408 automatic validation (defaults to "keyup").
8410 validationEvent : "keyup",
8412 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8414 validateOnBlur : true,
8416 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8418 validationDelay : 250,
8420 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8422 focusClass : "x-form-focus", // not needed???
8426 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8428 invalidClass : "has-warning",
8431 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8433 validClass : "has-success",
8436 * @cfg {Boolean} hasFeedback (true|false) default true
8441 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8443 invalidFeedbackClass : "glyphicon-warning-sign",
8446 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8448 validFeedbackClass : "glyphicon-ok",
8451 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8453 selectOnFocus : false,
8456 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8460 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8465 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8467 disableKeyFilter : false,
8470 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8474 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8478 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8480 blankText : "Please complete this mandatory field",
8483 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8487 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8489 maxLength : Number.MAX_VALUE,
8491 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8493 minLengthText : "The minimum length for this field is {0}",
8495 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8497 maxLengthText : "The maximum length for this field is {0}",
8501 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8502 * If available, this function will be called only after the basic validators all return true, and will be passed the
8503 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8507 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8508 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8509 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8513 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8517 autocomplete: false,
8536 formatedValue : false,
8537 forceFeedback : false,
8539 indicatorpos : 'left',
8546 parentLabelAlign : function()
8549 while (parent.parent()) {
8550 parent = parent.parent();
8551 if (typeof(parent.labelAlign) !='undefined') {
8552 return parent.labelAlign;
8559 getAutoCreate : function()
8561 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8567 if(this.inputType != 'hidden'){
8568 cfg.cls = 'form-group' //input-group
8574 type : this.inputType,
8576 cls : 'form-control',
8577 placeholder : this.placeholder || '',
8578 autocomplete : this.autocomplete || 'new-password'
8582 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8585 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8586 input.maxLength = this.maxLength;
8589 if (this.disabled) {
8590 input.disabled=true;
8593 if (this.readOnly) {
8594 input.readonly=true;
8598 input.name = this.name;
8602 input.cls += ' input-' + this.size;
8606 ['xs','sm','md','lg'].map(function(size){
8607 if (settings[size]) {
8608 cfg.cls += ' col-' + size + '-' + settings[size];
8612 var inputblock = input;
8616 cls: 'glyphicon form-control-feedback'
8619 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8622 cls : 'has-feedback',
8630 if (this.before || this.after) {
8633 cls : 'input-group',
8637 if (this.before && typeof(this.before) == 'string') {
8639 inputblock.cn.push({
8641 cls : 'roo-input-before input-group-addon',
8645 if (this.before && typeof(this.before) == 'object') {
8646 this.before = Roo.factory(this.before);
8648 inputblock.cn.push({
8650 cls : 'roo-input-before input-group-' +
8651 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8655 inputblock.cn.push(input);
8657 if (this.after && typeof(this.after) == 'string') {
8658 inputblock.cn.push({
8660 cls : 'roo-input-after input-group-addon',
8664 if (this.after && typeof(this.after) == 'object') {
8665 this.after = Roo.factory(this.after);
8667 inputblock.cn.push({
8669 cls : 'roo-input-after input-group-' +
8670 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8674 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8675 inputblock.cls += ' has-feedback';
8676 inputblock.cn.push(feedback);
8680 if (align ==='left' && this.fieldLabel.length) {
8682 cfg.cls += ' roo-form-group-label-left';
8687 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8688 tooltip : 'This field is required'
8693 cls : 'control-label',
8694 html : this.fieldLabel
8705 var labelCfg = cfg.cn[1];
8706 var contentCfg = cfg.cn[2];
8708 if(this.indicatorpos == 'right'){
8713 cls : 'control-label',
8714 html : this.fieldLabel
8719 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8720 tooltip : 'This field is required'
8731 labelCfg = cfg.cn[0];
8732 contentCfg = cfg.cn[2];
8736 if(this.labelWidth > 12){
8737 labelCfg.style = "width: " + this.labelWidth + 'px';
8740 if(this.labelWidth < 13 && this.labelmd == 0){
8741 this.labelmd = this.labelWidth;
8744 if(this.labellg > 0){
8745 labelCfg.cls += ' col-lg-' + this.labellg;
8746 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8749 if(this.labelmd > 0){
8750 labelCfg.cls += ' col-md-' + this.labelmd;
8751 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8754 if(this.labelsm > 0){
8755 labelCfg.cls += ' col-sm-' + this.labelsm;
8756 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8759 if(this.labelxs > 0){
8760 labelCfg.cls += ' col-xs-' + this.labelxs;
8761 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8765 } else if ( this.fieldLabel.length) {
8770 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8771 tooltip : 'This field is required'
8775 //cls : 'input-group-addon',
8776 html : this.fieldLabel
8784 if(this.indicatorpos == 'right'){
8789 //cls : 'input-group-addon',
8790 html : this.fieldLabel
8795 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8796 tooltip : 'This field is required'
8816 if (this.parentType === 'Navbar' && this.parent().bar) {
8817 cfg.cls += ' navbar-form';
8820 if (this.parentType === 'NavGroup') {
8821 cfg.cls += ' navbar-form';
8829 * return the real input element.
8831 inputEl: function ()
8833 return this.el.select('input.form-control',true).first();
8836 tooltipEl : function()
8838 return this.inputEl();
8841 indicatorEl : function()
8843 var indicator = this.el.select('i.roo-required-indicator',true).first();
8853 setDisabled : function(v)
8855 var i = this.inputEl().dom;
8857 i.removeAttribute('disabled');
8861 i.setAttribute('disabled','true');
8863 initEvents : function()
8866 this.inputEl().on("keydown" , this.fireKey, this);
8867 this.inputEl().on("focus", this.onFocus, this);
8868 this.inputEl().on("blur", this.onBlur, this);
8870 this.inputEl().relayEvent('keyup', this);
8872 this.indicator = this.indicatorEl();
8875 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8876 this.indicator.hide();
8879 // reference to original value for reset
8880 this.originalValue = this.getValue();
8881 //Roo.form.TextField.superclass.initEvents.call(this);
8882 if(this.validationEvent == 'keyup'){
8883 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8884 this.inputEl().on('keyup', this.filterValidation, this);
8886 else if(this.validationEvent !== false){
8887 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8890 if(this.selectOnFocus){
8891 this.on("focus", this.preFocus, this);
8894 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8895 this.inputEl().on("keypress", this.filterKeys, this);
8897 this.inputEl().relayEvent('keypress', this);
8900 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8901 this.el.on("click", this.autoSize, this);
8904 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8905 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8908 if (typeof(this.before) == 'object') {
8909 this.before.render(this.el.select('.roo-input-before',true).first());
8911 if (typeof(this.after) == 'object') {
8912 this.after.render(this.el.select('.roo-input-after',true).first());
8917 filterValidation : function(e){
8918 if(!e.isNavKeyPress()){
8919 this.validationTask.delay(this.validationDelay);
8923 * Validates the field value
8924 * @return {Boolean} True if the value is valid, else false
8926 validate : function(){
8927 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8928 if(this.disabled || this.validateValue(this.getRawValue())){
8939 * Validates a value according to the field's validation rules and marks the field as invalid
8940 * if the validation fails
8941 * @param {Mixed} value The value to validate
8942 * @return {Boolean} True if the value is valid, else false
8944 validateValue : function(value){
8945 if(value.length < 1) { // if it's blank
8946 if(this.allowBlank){
8949 return this.inputEl().hasClass('hide') ? true : false;
8952 if(value.length < this.minLength){
8955 if(value.length > this.maxLength){
8959 var vt = Roo.form.VTypes;
8960 if(!vt[this.vtype](value, this)){
8964 if(typeof this.validator == "function"){
8965 var msg = this.validator(value);
8971 if(this.regex && !this.regex.test(value)){
8981 fireKey : function(e){
8982 //Roo.log('field ' + e.getKey());
8983 if(e.isNavKeyPress()){
8984 this.fireEvent("specialkey", this, e);
8987 focus : function (selectText){
8989 this.inputEl().focus();
8990 if(selectText === true){
8991 this.inputEl().dom.select();
8997 onFocus : function(){
8998 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8999 // this.el.addClass(this.focusClass);
9002 this.hasFocus = true;
9003 this.startValue = this.getValue();
9004 this.fireEvent("focus", this);
9008 beforeBlur : Roo.emptyFn,
9012 onBlur : function(){
9014 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9015 //this.el.removeClass(this.focusClass);
9017 this.hasFocus = false;
9018 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9021 var v = this.getValue();
9022 if(String(v) !== String(this.startValue)){
9023 this.fireEvent('change', this, v, this.startValue);
9025 this.fireEvent("blur", this);
9029 * Resets the current field value to the originally loaded value and clears any validation messages
9032 this.setValue(this.originalValue);
9036 * Returns the name of the field
9037 * @return {Mixed} name The name field
9039 getName: function(){
9043 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9044 * @return {Mixed} value The field value
9046 getValue : function(){
9048 var v = this.inputEl().getValue();
9053 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9054 * @return {Mixed} value The field value
9056 getRawValue : function(){
9057 var v = this.inputEl().getValue();
9063 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9064 * @param {Mixed} value The value to set
9066 setRawValue : function(v){
9067 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9070 selectText : function(start, end){
9071 var v = this.getRawValue();
9073 start = start === undefined ? 0 : start;
9074 end = end === undefined ? v.length : end;
9075 var d = this.inputEl().dom;
9076 if(d.setSelectionRange){
9077 d.setSelectionRange(start, end);
9078 }else if(d.createTextRange){
9079 var range = d.createTextRange();
9080 range.moveStart("character", start);
9081 range.moveEnd("character", v.length-end);
9088 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9089 * @param {Mixed} value The value to set
9091 setValue : function(v){
9094 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9100 processValue : function(value){
9101 if(this.stripCharsRe){
9102 var newValue = value.replace(this.stripCharsRe, '');
9103 if(newValue !== value){
9104 this.setRawValue(newValue);
9111 preFocus : function(){
9113 if(this.selectOnFocus){
9114 this.inputEl().dom.select();
9117 filterKeys : function(e){
9119 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9122 var c = e.getCharCode(), cc = String.fromCharCode(c);
9123 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9126 if(!this.maskRe.test(cc)){
9131 * Clear any invalid styles/messages for this field
9133 clearInvalid : function(){
9135 if(!this.el || this.preventMark){ // not rendered
9140 this.el.removeClass(this.invalidClass);
9142 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9144 var feedback = this.el.select('.form-control-feedback', true).first();
9147 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9152 this.fireEvent('valid', this);
9156 * Mark this field as valid
9158 markValid : function()
9160 if(!this.el || this.preventMark){ // not rendered...
9164 this.el.removeClass([this.invalidClass, this.validClass]);
9166 var feedback = this.el.select('.form-control-feedback', true).first();
9169 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9176 if(this.allowBlank && !this.getRawValue().length){
9181 this.indicator.hide();
9184 this.el.addClass(this.validClass);
9186 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9188 var feedback = this.el.select('.form-control-feedback', true).first();
9191 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9192 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9197 this.fireEvent('valid', this);
9201 * Mark this field as invalid
9202 * @param {String} msg The validation message
9204 markInvalid : function(msg)
9206 if(!this.el || this.preventMark){ // not rendered
9210 this.el.removeClass([this.invalidClass, this.validClass]);
9212 var feedback = this.el.select('.form-control-feedback', true).first();
9215 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9222 if(this.allowBlank && !this.getRawValue().length){
9227 this.indicator.show();
9230 this.el.addClass(this.invalidClass);
9232 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9234 var feedback = this.el.select('.form-control-feedback', true).first();
9237 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9239 if(this.getValue().length || this.forceFeedback){
9240 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9247 this.fireEvent('invalid', this, msg);
9250 SafariOnKeyDown : function(event)
9252 // this is a workaround for a password hang bug on chrome/ webkit.
9253 if (this.inputEl().dom.type != 'password') {
9257 var isSelectAll = false;
9259 if(this.inputEl().dom.selectionEnd > 0){
9260 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9262 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9263 event.preventDefault();
9268 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9270 event.preventDefault();
9271 // this is very hacky as keydown always get's upper case.
9273 var cc = String.fromCharCode(event.getCharCode());
9274 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9278 adjustWidth : function(tag, w){
9279 tag = tag.toLowerCase();
9280 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9281 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9285 if(tag == 'textarea'){
9288 }else if(Roo.isOpera){
9292 if(tag == 'textarea'){
9311 * @class Roo.bootstrap.TextArea
9312 * @extends Roo.bootstrap.Input
9313 * Bootstrap TextArea class
9314 * @cfg {Number} cols Specifies the visible width of a text area
9315 * @cfg {Number} rows Specifies the visible number of lines in a text area
9316 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9317 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9318 * @cfg {string} html text
9321 * Create a new TextArea
9322 * @param {Object} config The config object
9325 Roo.bootstrap.TextArea = function(config){
9326 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9330 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9340 getAutoCreate : function(){
9342 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9353 value : this.value || '',
9354 html: this.html || '',
9355 cls : 'form-control',
9356 placeholder : this.placeholder || ''
9360 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9361 input.maxLength = this.maxLength;
9365 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9369 input.cols = this.cols;
9372 if (this.readOnly) {
9373 input.readonly = true;
9377 input.name = this.name;
9381 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9385 ['xs','sm','md','lg'].map(function(size){
9386 if (settings[size]) {
9387 cfg.cls += ' col-' + size + '-' + settings[size];
9391 var inputblock = input;
9393 if(this.hasFeedback && !this.allowBlank){
9397 cls: 'glyphicon form-control-feedback'
9401 cls : 'has-feedback',
9410 if (this.before || this.after) {
9413 cls : 'input-group',
9417 inputblock.cn.push({
9419 cls : 'input-group-addon',
9424 inputblock.cn.push(input);
9426 if(this.hasFeedback && !this.allowBlank){
9427 inputblock.cls += ' has-feedback';
9428 inputblock.cn.push(feedback);
9432 inputblock.cn.push({
9434 cls : 'input-group-addon',
9441 if (align ==='left' && this.fieldLabel.length) {
9446 cls : 'control-label',
9447 html : this.fieldLabel
9458 if(this.labelWidth > 12){
9459 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9462 if(this.labelWidth < 13 && this.labelmd == 0){
9463 this.labelmd = this.labelWidth;
9466 if(this.labellg > 0){
9467 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9468 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9471 if(this.labelmd > 0){
9472 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9473 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9476 if(this.labelsm > 0){
9477 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9478 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9481 if(this.labelxs > 0){
9482 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9483 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9486 } else if ( this.fieldLabel.length) {
9491 //cls : 'input-group-addon',
9492 html : this.fieldLabel
9510 if (this.disabled) {
9511 input.disabled=true;
9518 * return the real textarea element.
9520 inputEl: function ()
9522 return this.el.select('textarea.form-control',true).first();
9526 * Clear any invalid styles/messages for this field
9528 clearInvalid : function()
9531 if(!this.el || this.preventMark){ // not rendered
9535 var label = this.el.select('label', true).first();
9536 var icon = this.el.select('i.fa-star', true).first();
9542 this.el.removeClass(this.invalidClass);
9544 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9546 var feedback = this.el.select('.form-control-feedback', true).first();
9549 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9554 this.fireEvent('valid', this);
9558 * Mark this field as valid
9560 markValid : function()
9562 if(!this.el || this.preventMark){ // not rendered
9566 this.el.removeClass([this.invalidClass, this.validClass]);
9568 var feedback = this.el.select('.form-control-feedback', true).first();
9571 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9574 if(this.disabled || this.allowBlank){
9578 var label = this.el.select('label', true).first();
9579 var icon = this.el.select('i.fa-star', true).first();
9585 this.el.addClass(this.validClass);
9587 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9589 var feedback = this.el.select('.form-control-feedback', true).first();
9592 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9593 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9598 this.fireEvent('valid', this);
9602 * Mark this field as invalid
9603 * @param {String} msg The validation message
9605 markInvalid : function(msg)
9607 if(!this.el || this.preventMark){ // not rendered
9611 this.el.removeClass([this.invalidClass, this.validClass]);
9613 var feedback = this.el.select('.form-control-feedback', true).first();
9616 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9619 if(this.disabled || this.allowBlank){
9623 var label = this.el.select('label', true).first();
9624 var icon = this.el.select('i.fa-star', true).first();
9626 if(!this.getValue().length && label && !icon){
9627 this.el.createChild({
9629 cls : 'text-danger fa fa-lg fa-star',
9630 tooltip : 'This field is required',
9631 style : 'margin-right:5px;'
9635 this.el.addClass(this.invalidClass);
9637 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9639 var feedback = this.el.select('.form-control-feedback', true).first();
9642 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9644 if(this.getValue().length || this.forceFeedback){
9645 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9652 this.fireEvent('invalid', this, msg);
9660 * trigger field - base class for combo..
9665 * @class Roo.bootstrap.TriggerField
9666 * @extends Roo.bootstrap.Input
9667 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9668 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9669 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9670 * for which you can provide a custom implementation. For example:
9672 var trigger = new Roo.bootstrap.TriggerField();
9673 trigger.onTriggerClick = myTriggerFn;
9674 trigger.applyTo('my-field');
9677 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9678 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9679 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9680 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9681 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9684 * Create a new TriggerField.
9685 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9686 * to the base TextField)
9688 Roo.bootstrap.TriggerField = function(config){
9689 this.mimicing = false;
9690 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9693 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9695 * @cfg {String} triggerClass A CSS class to apply to the trigger
9698 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9703 * @cfg {Boolean} removable (true|false) special filter default false
9707 /** @cfg {Boolean} grow @hide */
9708 /** @cfg {Number} growMin @hide */
9709 /** @cfg {Number} growMax @hide */
9715 autoSize: Roo.emptyFn,
9722 actionMode : 'wrap',
9727 getAutoCreate : function(){
9729 var align = this.labelAlign || this.parentLabelAlign();
9734 cls: 'form-group' //input-group
9741 type : this.inputType,
9742 cls : 'form-control',
9743 autocomplete: 'new-password',
9744 placeholder : this.placeholder || ''
9748 input.name = this.name;
9751 input.cls += ' input-' + this.size;
9754 if (this.disabled) {
9755 input.disabled=true;
9758 var inputblock = input;
9760 if(this.hasFeedback && !this.allowBlank){
9764 cls: 'glyphicon form-control-feedback'
9767 if(this.removable && !this.editable && !this.tickable){
9769 cls : 'has-feedback',
9775 cls : 'roo-combo-removable-btn close'
9782 cls : 'has-feedback',
9791 if(this.removable && !this.editable && !this.tickable){
9793 cls : 'roo-removable',
9799 cls : 'roo-combo-removable-btn close'
9806 if (this.before || this.after) {
9809 cls : 'input-group',
9813 inputblock.cn.push({
9815 cls : 'input-group-addon',
9820 inputblock.cn.push(input);
9822 if(this.hasFeedback && !this.allowBlank){
9823 inputblock.cls += ' has-feedback';
9824 inputblock.cn.push(feedback);
9828 inputblock.cn.push({
9830 cls : 'input-group-addon',
9843 cls: 'form-hidden-field'
9857 cls: 'form-hidden-field'
9861 cls: 'roo-select2-choices',
9865 cls: 'roo-select2-search-field',
9878 cls: 'roo-select2-container input-group',
9883 // cls: 'typeahead typeahead-long dropdown-menu',
9884 // style: 'display:none'
9889 if(!this.multiple && this.showToggleBtn){
9895 if (this.caret != false) {
9898 cls: 'fa fa-' + this.caret
9905 cls : 'input-group-addon btn dropdown-toggle',
9910 cls: 'combobox-clear',
9924 combobox.cls += ' roo-select2-container-multi';
9927 if (align ==='left' && this.fieldLabel.length) {
9929 cfg.cls += ' roo-form-group-label-left';
9934 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9935 tooltip : 'This field is required'
9940 cls : 'control-label',
9941 html : this.fieldLabel
9953 var labelCfg = cfg.cn[1];
9954 var contentCfg = cfg.cn[2];
9956 if(this.indicatorpos == 'right'){
9961 cls : 'control-label',
9965 html : this.fieldLabel
9969 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9970 tooltip : 'This field is required'
9983 labelCfg = cfg.cn[0];
9984 contentCfg = cfg.cn[1];
9987 if(this.labelWidth > 12){
9988 labelCfg.style = "width: " + this.labelWidth + 'px';
9991 if(this.labelWidth < 13 && this.labelmd == 0){
9992 this.labelmd = this.labelWidth;
9995 if(this.labellg > 0){
9996 labelCfg.cls += ' col-lg-' + this.labellg;
9997 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10000 if(this.labelmd > 0){
10001 labelCfg.cls += ' col-md-' + this.labelmd;
10002 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10005 if(this.labelsm > 0){
10006 labelCfg.cls += ' col-sm-' + this.labelsm;
10007 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10010 if(this.labelxs > 0){
10011 labelCfg.cls += ' col-xs-' + this.labelxs;
10012 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10015 } else if ( this.fieldLabel.length) {
10016 // Roo.log(" label");
10020 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10021 tooltip : 'This field is required'
10025 //cls : 'input-group-addon',
10026 html : this.fieldLabel
10034 if(this.indicatorpos == 'right'){
10042 html : this.fieldLabel
10046 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10047 tooltip : 'This field is required'
10060 // Roo.log(" no label && no align");
10067 ['xs','sm','md','lg'].map(function(size){
10068 if (settings[size]) {
10069 cfg.cls += ' col-' + size + '-' + settings[size];
10080 onResize : function(w, h){
10081 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10082 // if(typeof w == 'number'){
10083 // var x = w - this.trigger.getWidth();
10084 // this.inputEl().setWidth(this.adjustWidth('input', x));
10085 // this.trigger.setStyle('left', x+'px');
10090 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10093 getResizeEl : function(){
10094 return this.inputEl();
10098 getPositionEl : function(){
10099 return this.inputEl();
10103 alignErrorIcon : function(){
10104 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10108 initEvents : function(){
10112 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10113 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10114 if(!this.multiple && this.showToggleBtn){
10115 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10116 if(this.hideTrigger){
10117 this.trigger.setDisplayed(false);
10119 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10123 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10126 if(this.removable && !this.editable && !this.tickable){
10127 var close = this.closeTriggerEl();
10130 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10131 close.on('click', this.removeBtnClick, this, close);
10135 //this.trigger.addClassOnOver('x-form-trigger-over');
10136 //this.trigger.addClassOnClick('x-form-trigger-click');
10139 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10143 closeTriggerEl : function()
10145 var close = this.el.select('.roo-combo-removable-btn', true).first();
10146 return close ? close : false;
10149 removeBtnClick : function(e, h, el)
10151 e.preventDefault();
10153 if(this.fireEvent("remove", this) !== false){
10155 this.fireEvent("afterremove", this)
10159 createList : function()
10161 this.list = Roo.get(document.body).createChild({
10163 cls: 'typeahead typeahead-long dropdown-menu',
10164 style: 'display:none'
10167 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10172 initTrigger : function(){
10177 onDestroy : function(){
10179 this.trigger.removeAllListeners();
10180 // this.trigger.remove();
10183 // this.wrap.remove();
10185 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10189 onFocus : function(){
10190 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10192 if(!this.mimicing){
10193 this.wrap.addClass('x-trigger-wrap-focus');
10194 this.mimicing = true;
10195 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10196 if(this.monitorTab){
10197 this.el.on("keydown", this.checkTab, this);
10204 checkTab : function(e){
10205 if(e.getKey() == e.TAB){
10206 this.triggerBlur();
10211 onBlur : function(){
10216 mimicBlur : function(e, t){
10218 if(!this.wrap.contains(t) && this.validateBlur()){
10219 this.triggerBlur();
10225 triggerBlur : function(){
10226 this.mimicing = false;
10227 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10228 if(this.monitorTab){
10229 this.el.un("keydown", this.checkTab, this);
10231 //this.wrap.removeClass('x-trigger-wrap-focus');
10232 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10236 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10237 validateBlur : function(e, t){
10242 onDisable : function(){
10243 this.inputEl().dom.disabled = true;
10244 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10246 // this.wrap.addClass('x-item-disabled');
10251 onEnable : function(){
10252 this.inputEl().dom.disabled = false;
10253 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10255 // this.el.removeClass('x-item-disabled');
10260 onShow : function(){
10261 var ae = this.getActionEl();
10264 ae.dom.style.display = '';
10265 ae.dom.style.visibility = 'visible';
10271 onHide : function(){
10272 var ae = this.getActionEl();
10273 ae.dom.style.display = 'none';
10277 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10278 * by an implementing function.
10280 * @param {EventObject} e
10282 onTriggerClick : Roo.emptyFn
10286 * Ext JS Library 1.1.1
10287 * Copyright(c) 2006-2007, Ext JS, LLC.
10289 * Originally Released Under LGPL - original licence link has changed is not relivant.
10292 * <script type="text/javascript">
10297 * @class Roo.data.SortTypes
10299 * Defines the default sorting (casting?) comparison functions used when sorting data.
10301 Roo.data.SortTypes = {
10303 * Default sort that does nothing
10304 * @param {Mixed} s The value being converted
10305 * @return {Mixed} The comparison value
10307 none : function(s){
10312 * The regular expression used to strip tags
10316 stripTagsRE : /<\/?[^>]+>/gi,
10319 * Strips all HTML tags to sort on text only
10320 * @param {Mixed} s The value being converted
10321 * @return {String} The comparison value
10323 asText : function(s){
10324 return String(s).replace(this.stripTagsRE, "");
10328 * Strips all HTML tags to sort on text only - Case insensitive
10329 * @param {Mixed} s The value being converted
10330 * @return {String} The comparison value
10332 asUCText : function(s){
10333 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10337 * Case insensitive string
10338 * @param {Mixed} s The value being converted
10339 * @return {String} The comparison value
10341 asUCString : function(s) {
10342 return String(s).toUpperCase();
10347 * @param {Mixed} s The value being converted
10348 * @return {Number} The comparison value
10350 asDate : function(s) {
10354 if(s instanceof Date){
10355 return s.getTime();
10357 return Date.parse(String(s));
10362 * @param {Mixed} s The value being converted
10363 * @return {Float} The comparison value
10365 asFloat : function(s) {
10366 var val = parseFloat(String(s).replace(/,/g, ""));
10375 * @param {Mixed} s The value being converted
10376 * @return {Number} The comparison value
10378 asInt : function(s) {
10379 var val = parseInt(String(s).replace(/,/g, ""));
10387 * Ext JS Library 1.1.1
10388 * Copyright(c) 2006-2007, Ext JS, LLC.
10390 * Originally Released Under LGPL - original licence link has changed is not relivant.
10393 * <script type="text/javascript">
10397 * @class Roo.data.Record
10398 * Instances of this class encapsulate both record <em>definition</em> information, and record
10399 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10400 * to access Records cached in an {@link Roo.data.Store} object.<br>
10402 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10403 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10406 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10408 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10409 * {@link #create}. The parameters are the same.
10410 * @param {Array} data An associative Array of data values keyed by the field name.
10411 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10412 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10413 * not specified an integer id is generated.
10415 Roo.data.Record = function(data, id){
10416 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10421 * Generate a constructor for a specific record layout.
10422 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10423 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10424 * Each field definition object may contain the following properties: <ul>
10425 * <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,
10426 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10427 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10428 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10429 * is being used, then this is a string containing the javascript expression to reference the data relative to
10430 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10431 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10432 * this may be omitted.</p></li>
10433 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10434 * <ul><li>auto (Default, implies no conversion)</li>
10439 * <li>date</li></ul></p></li>
10440 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10441 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10442 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10443 * by the Reader into an object that will be stored in the Record. It is passed the
10444 * following parameters:<ul>
10445 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10447 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10449 * <br>usage:<br><pre><code>
10450 var TopicRecord = Roo.data.Record.create(
10451 {name: 'title', mapping: 'topic_title'},
10452 {name: 'author', mapping: 'username'},
10453 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10454 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10455 {name: 'lastPoster', mapping: 'user2'},
10456 {name: 'excerpt', mapping: 'post_text'}
10459 var myNewRecord = new TopicRecord({
10460 title: 'Do my job please',
10463 lastPost: new Date(),
10464 lastPoster: 'Animal',
10465 excerpt: 'No way dude!'
10467 myStore.add(myNewRecord);
10472 Roo.data.Record.create = function(o){
10473 var f = function(){
10474 f.superclass.constructor.apply(this, arguments);
10476 Roo.extend(f, Roo.data.Record);
10477 var p = f.prototype;
10478 p.fields = new Roo.util.MixedCollection(false, function(field){
10481 for(var i = 0, len = o.length; i < len; i++){
10482 p.fields.add(new Roo.data.Field(o[i]));
10484 f.getField = function(name){
10485 return p.fields.get(name);
10490 Roo.data.Record.AUTO_ID = 1000;
10491 Roo.data.Record.EDIT = 'edit';
10492 Roo.data.Record.REJECT = 'reject';
10493 Roo.data.Record.COMMIT = 'commit';
10495 Roo.data.Record.prototype = {
10497 * Readonly flag - true if this record has been modified.
10506 join : function(store){
10507 this.store = store;
10511 * Set the named field to the specified value.
10512 * @param {String} name The name of the field to set.
10513 * @param {Object} value The value to set the field to.
10515 set : function(name, value){
10516 if(this.data[name] == value){
10520 if(!this.modified){
10521 this.modified = {};
10523 if(typeof this.modified[name] == 'undefined'){
10524 this.modified[name] = this.data[name];
10526 this.data[name] = value;
10527 if(!this.editing && this.store){
10528 this.store.afterEdit(this);
10533 * Get the value of the named field.
10534 * @param {String} name The name of the field to get the value of.
10535 * @return {Object} The value of the field.
10537 get : function(name){
10538 return this.data[name];
10542 beginEdit : function(){
10543 this.editing = true;
10544 this.modified = {};
10548 cancelEdit : function(){
10549 this.editing = false;
10550 delete this.modified;
10554 endEdit : function(){
10555 this.editing = false;
10556 if(this.dirty && this.store){
10557 this.store.afterEdit(this);
10562 * Usually called by the {@link Roo.data.Store} which owns the Record.
10563 * Rejects all changes made to the Record since either creation, or the last commit operation.
10564 * Modified fields are reverted to their original values.
10566 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10567 * of reject operations.
10569 reject : function(){
10570 var m = this.modified;
10572 if(typeof m[n] != "function"){
10573 this.data[n] = m[n];
10576 this.dirty = false;
10577 delete this.modified;
10578 this.editing = false;
10580 this.store.afterReject(this);
10585 * Usually called by the {@link Roo.data.Store} which owns the Record.
10586 * Commits all changes made to the Record since either creation, or the last commit operation.
10588 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10589 * of commit operations.
10591 commit : function(){
10592 this.dirty = false;
10593 delete this.modified;
10594 this.editing = false;
10596 this.store.afterCommit(this);
10601 hasError : function(){
10602 return this.error != null;
10606 clearError : function(){
10611 * Creates a copy of this record.
10612 * @param {String} id (optional) A new record id if you don't want to use this record's id
10615 copy : function(newId) {
10616 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10620 * Ext JS Library 1.1.1
10621 * Copyright(c) 2006-2007, Ext JS, LLC.
10623 * Originally Released Under LGPL - original licence link has changed is not relivant.
10626 * <script type="text/javascript">
10632 * @class Roo.data.Store
10633 * @extends Roo.util.Observable
10634 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10635 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10637 * 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
10638 * has no knowledge of the format of the data returned by the Proxy.<br>
10640 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10641 * instances from the data object. These records are cached and made available through accessor functions.
10643 * Creates a new Store.
10644 * @param {Object} config A config object containing the objects needed for the Store to access data,
10645 * and read the data into Records.
10647 Roo.data.Store = function(config){
10648 this.data = new Roo.util.MixedCollection(false);
10649 this.data.getKey = function(o){
10652 this.baseParams = {};
10654 this.paramNames = {
10659 "multisort" : "_multisort"
10662 if(config && config.data){
10663 this.inlineData = config.data;
10664 delete config.data;
10667 Roo.apply(this, config);
10669 if(this.reader){ // reader passed
10670 this.reader = Roo.factory(this.reader, Roo.data);
10671 this.reader.xmodule = this.xmodule || false;
10672 if(!this.recordType){
10673 this.recordType = this.reader.recordType;
10675 if(this.reader.onMetaChange){
10676 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10680 if(this.recordType){
10681 this.fields = this.recordType.prototype.fields;
10683 this.modified = [];
10687 * @event datachanged
10688 * Fires when the data cache has changed, and a widget which is using this Store
10689 * as a Record cache should refresh its view.
10690 * @param {Store} this
10692 datachanged : true,
10694 * @event metachange
10695 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10696 * @param {Store} this
10697 * @param {Object} meta The JSON metadata
10702 * Fires when Records have been added to the Store
10703 * @param {Store} this
10704 * @param {Roo.data.Record[]} records The array of Records added
10705 * @param {Number} index The index at which the record(s) were added
10710 * Fires when a Record has been removed from the Store
10711 * @param {Store} this
10712 * @param {Roo.data.Record} record The Record that was removed
10713 * @param {Number} index The index at which the record was removed
10718 * Fires when a Record has been updated
10719 * @param {Store} this
10720 * @param {Roo.data.Record} record The Record that was updated
10721 * @param {String} operation The update operation being performed. Value may be one of:
10723 Roo.data.Record.EDIT
10724 Roo.data.Record.REJECT
10725 Roo.data.Record.COMMIT
10731 * Fires when the data cache has been cleared.
10732 * @param {Store} this
10736 * @event beforeload
10737 * Fires before a request is made for a new data object. If the beforeload handler returns false
10738 * the load action will be canceled.
10739 * @param {Store} this
10740 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10744 * @event beforeloadadd
10745 * Fires after a new set of Records has been loaded.
10746 * @param {Store} this
10747 * @param {Roo.data.Record[]} records The Records that were loaded
10748 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10750 beforeloadadd : true,
10753 * Fires after a new set of Records has been loaded, before they are added to the store.
10754 * @param {Store} this
10755 * @param {Roo.data.Record[]} records The Records that were loaded
10756 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10757 * @params {Object} return from reader
10761 * @event loadexception
10762 * Fires if an exception occurs in the Proxy during loading.
10763 * Called with the signature of the Proxy's "loadexception" event.
10764 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10767 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10768 * @param {Object} load options
10769 * @param {Object} jsonData from your request (normally this contains the Exception)
10771 loadexception : true
10775 this.proxy = Roo.factory(this.proxy, Roo.data);
10776 this.proxy.xmodule = this.xmodule || false;
10777 this.relayEvents(this.proxy, ["loadexception"]);
10779 this.sortToggle = {};
10780 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10782 Roo.data.Store.superclass.constructor.call(this);
10784 if(this.inlineData){
10785 this.loadData(this.inlineData);
10786 delete this.inlineData;
10790 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10792 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10793 * without a remote query - used by combo/forms at present.
10797 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10800 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10803 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10804 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10807 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10808 * on any HTTP request
10811 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10814 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10818 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10819 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10821 remoteSort : false,
10824 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10825 * loaded or when a record is removed. (defaults to false).
10827 pruneModifiedRecords : false,
10830 lastOptions : null,
10833 * Add Records to the Store and fires the add event.
10834 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10836 add : function(records){
10837 records = [].concat(records);
10838 for(var i = 0, len = records.length; i < len; i++){
10839 records[i].join(this);
10841 var index = this.data.length;
10842 this.data.addAll(records);
10843 this.fireEvent("add", this, records, index);
10847 * Remove a Record from the Store and fires the remove event.
10848 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10850 remove : function(record){
10851 var index = this.data.indexOf(record);
10852 this.data.removeAt(index);
10853 if(this.pruneModifiedRecords){
10854 this.modified.remove(record);
10856 this.fireEvent("remove", this, record, index);
10860 * Remove all Records from the Store and fires the clear event.
10862 removeAll : function(){
10864 if(this.pruneModifiedRecords){
10865 this.modified = [];
10867 this.fireEvent("clear", this);
10871 * Inserts Records to the Store at the given index and fires the add event.
10872 * @param {Number} index The start index at which to insert the passed Records.
10873 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10875 insert : function(index, records){
10876 records = [].concat(records);
10877 for(var i = 0, len = records.length; i < len; i++){
10878 this.data.insert(index, records[i]);
10879 records[i].join(this);
10881 this.fireEvent("add", this, records, index);
10885 * Get the index within the cache of the passed Record.
10886 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10887 * @return {Number} The index of the passed Record. Returns -1 if not found.
10889 indexOf : function(record){
10890 return this.data.indexOf(record);
10894 * Get the index within the cache of the Record with the passed id.
10895 * @param {String} id The id of the Record to find.
10896 * @return {Number} The index of the Record. Returns -1 if not found.
10898 indexOfId : function(id){
10899 return this.data.indexOfKey(id);
10903 * Get the Record with the specified id.
10904 * @param {String} id The id of the Record to find.
10905 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10907 getById : function(id){
10908 return this.data.key(id);
10912 * Get the Record at the specified index.
10913 * @param {Number} index The index of the Record to find.
10914 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10916 getAt : function(index){
10917 return this.data.itemAt(index);
10921 * Returns a range of Records between specified indices.
10922 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10923 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10924 * @return {Roo.data.Record[]} An array of Records
10926 getRange : function(start, end){
10927 return this.data.getRange(start, end);
10931 storeOptions : function(o){
10932 o = Roo.apply({}, o);
10935 this.lastOptions = o;
10939 * Loads the Record cache from the configured Proxy using the configured Reader.
10941 * If using remote paging, then the first load call must specify the <em>start</em>
10942 * and <em>limit</em> properties in the options.params property to establish the initial
10943 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10945 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10946 * and this call will return before the new data has been loaded. Perform any post-processing
10947 * in a callback function, or in a "load" event handler.</strong>
10949 * @param {Object} options An object containing properties which control loading options:<ul>
10950 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10951 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10952 * passed the following arguments:<ul>
10953 * <li>r : Roo.data.Record[]</li>
10954 * <li>options: Options object from the load call</li>
10955 * <li>success: Boolean success indicator</li></ul></li>
10956 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10957 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10960 load : function(options){
10961 options = options || {};
10962 if(this.fireEvent("beforeload", this, options) !== false){
10963 this.storeOptions(options);
10964 var p = Roo.apply(options.params || {}, this.baseParams);
10965 // if meta was not loaded from remote source.. try requesting it.
10966 if (!this.reader.metaFromRemote) {
10967 p._requestMeta = 1;
10969 if(this.sortInfo && this.remoteSort){
10970 var pn = this.paramNames;
10971 p[pn["sort"]] = this.sortInfo.field;
10972 p[pn["dir"]] = this.sortInfo.direction;
10974 if (this.multiSort) {
10975 var pn = this.paramNames;
10976 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10979 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10984 * Reloads the Record cache from the configured Proxy using the configured Reader and
10985 * the options from the last load operation performed.
10986 * @param {Object} options (optional) An object containing properties which may override the options
10987 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10988 * the most recently used options are reused).
10990 reload : function(options){
10991 this.load(Roo.applyIf(options||{}, this.lastOptions));
10995 // Called as a callback by the Reader during a load operation.
10996 loadRecords : function(o, options, success){
10997 if(!o || success === false){
10998 if(success !== false){
10999 this.fireEvent("load", this, [], options, o);
11001 if(options.callback){
11002 options.callback.call(options.scope || this, [], options, false);
11006 // if data returned failure - throw an exception.
11007 if (o.success === false) {
11008 // show a message if no listener is registered.
11009 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11010 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11012 // loadmask wil be hooked into this..
11013 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11016 var r = o.records, t = o.totalRecords || r.length;
11018 this.fireEvent("beforeloadadd", this, r, options, o);
11020 if(!options || options.add !== true){
11021 if(this.pruneModifiedRecords){
11022 this.modified = [];
11024 for(var i = 0, len = r.length; i < len; i++){
11028 this.data = this.snapshot;
11029 delete this.snapshot;
11032 this.data.addAll(r);
11033 this.totalLength = t;
11035 this.fireEvent("datachanged", this);
11037 this.totalLength = Math.max(t, this.data.length+r.length);
11041 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11043 var e = new Roo.data.Record({});
11045 e.set(this.parent.displayField, this.parent.emptyTitle);
11046 e.set(this.parent.valueField, '');
11051 this.fireEvent("load", this, r, options, o);
11052 if(options.callback){
11053 options.callback.call(options.scope || this, r, options, true);
11059 * Loads data from a passed data block. A Reader which understands the format of the data
11060 * must have been configured in the constructor.
11061 * @param {Object} data The data block from which to read the Records. The format of the data expected
11062 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11063 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11065 loadData : function(o, append){
11066 var r = this.reader.readRecords(o);
11067 this.loadRecords(r, {add: append}, true);
11071 * Gets the number of cached records.
11073 * <em>If using paging, this may not be the total size of the dataset. If the data object
11074 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11075 * the data set size</em>
11077 getCount : function(){
11078 return this.data.length || 0;
11082 * Gets the total number of records in the dataset as returned by the server.
11084 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11085 * the dataset size</em>
11087 getTotalCount : function(){
11088 return this.totalLength || 0;
11092 * Returns the sort state of the Store as an object with two properties:
11094 field {String} The name of the field by which the Records are sorted
11095 direction {String} The sort order, "ASC" or "DESC"
11098 getSortState : function(){
11099 return this.sortInfo;
11103 applySort : function(){
11104 if(this.sortInfo && !this.remoteSort){
11105 var s = this.sortInfo, f = s.field;
11106 var st = this.fields.get(f).sortType;
11107 var fn = function(r1, r2){
11108 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11109 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11111 this.data.sort(s.direction, fn);
11112 if(this.snapshot && this.snapshot != this.data){
11113 this.snapshot.sort(s.direction, fn);
11119 * Sets the default sort column and order to be used by the next load operation.
11120 * @param {String} fieldName The name of the field to sort by.
11121 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11123 setDefaultSort : function(field, dir){
11124 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11128 * Sort the Records.
11129 * If remote sorting is used, the sort is performed on the server, and the cache is
11130 * reloaded. If local sorting is used, the cache is sorted internally.
11131 * @param {String} fieldName The name of the field to sort by.
11132 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11134 sort : function(fieldName, dir){
11135 var f = this.fields.get(fieldName);
11137 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11139 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11140 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11145 this.sortToggle[f.name] = dir;
11146 this.sortInfo = {field: f.name, direction: dir};
11147 if(!this.remoteSort){
11149 this.fireEvent("datachanged", this);
11151 this.load(this.lastOptions);
11156 * Calls the specified function for each of the Records in the cache.
11157 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11158 * Returning <em>false</em> aborts and exits the iteration.
11159 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11161 each : function(fn, scope){
11162 this.data.each(fn, scope);
11166 * Gets all records modified since the last commit. Modified records are persisted across load operations
11167 * (e.g., during paging).
11168 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11170 getModifiedRecords : function(){
11171 return this.modified;
11175 createFilterFn : function(property, value, anyMatch){
11176 if(!value.exec){ // not a regex
11177 value = String(value);
11178 if(value.length == 0){
11181 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11183 return function(r){
11184 return value.test(r.data[property]);
11189 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11190 * @param {String} property A field on your records
11191 * @param {Number} start The record index to start at (defaults to 0)
11192 * @param {Number} end The last record index to include (defaults to length - 1)
11193 * @return {Number} The sum
11195 sum : function(property, start, end){
11196 var rs = this.data.items, v = 0;
11197 start = start || 0;
11198 end = (end || end === 0) ? end : rs.length-1;
11200 for(var i = start; i <= end; i++){
11201 v += (rs[i].data[property] || 0);
11207 * Filter the records by a specified property.
11208 * @param {String} field A field on your records
11209 * @param {String/RegExp} value Either a string that the field
11210 * should start with or a RegExp to test against the field
11211 * @param {Boolean} anyMatch True to match any part not just the beginning
11213 filter : function(property, value, anyMatch){
11214 var fn = this.createFilterFn(property, value, anyMatch);
11215 return fn ? this.filterBy(fn) : this.clearFilter();
11219 * Filter by a function. The specified function will be called with each
11220 * record in this data source. If the function returns true the record is included,
11221 * otherwise it is filtered.
11222 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11223 * @param {Object} scope (optional) The scope of the function (defaults to this)
11225 filterBy : function(fn, scope){
11226 this.snapshot = this.snapshot || this.data;
11227 this.data = this.queryBy(fn, scope||this);
11228 this.fireEvent("datachanged", this);
11232 * Query the records by a specified property.
11233 * @param {String} field A field on your records
11234 * @param {String/RegExp} value Either a string that the field
11235 * should start with or a RegExp to test against the field
11236 * @param {Boolean} anyMatch True to match any part not just the beginning
11237 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11239 query : function(property, value, anyMatch){
11240 var fn = this.createFilterFn(property, value, anyMatch);
11241 return fn ? this.queryBy(fn) : this.data.clone();
11245 * Query by a function. The specified function will be called with each
11246 * record in this data source. If the function returns true the record is included
11248 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11249 * @param {Object} scope (optional) The scope of the function (defaults to this)
11250 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11252 queryBy : function(fn, scope){
11253 var data = this.snapshot || this.data;
11254 return data.filterBy(fn, scope||this);
11258 * Collects unique values for a particular dataIndex from this store.
11259 * @param {String} dataIndex The property to collect
11260 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11261 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11262 * @return {Array} An array of the unique values
11264 collect : function(dataIndex, allowNull, bypassFilter){
11265 var d = (bypassFilter === true && this.snapshot) ?
11266 this.snapshot.items : this.data.items;
11267 var v, sv, r = [], l = {};
11268 for(var i = 0, len = d.length; i < len; i++){
11269 v = d[i].data[dataIndex];
11271 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11280 * Revert to a view of the Record cache with no filtering applied.
11281 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11283 clearFilter : function(suppressEvent){
11284 if(this.snapshot && this.snapshot != this.data){
11285 this.data = this.snapshot;
11286 delete this.snapshot;
11287 if(suppressEvent !== true){
11288 this.fireEvent("datachanged", this);
11294 afterEdit : function(record){
11295 if(this.modified.indexOf(record) == -1){
11296 this.modified.push(record);
11298 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11302 afterReject : function(record){
11303 this.modified.remove(record);
11304 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11308 afterCommit : function(record){
11309 this.modified.remove(record);
11310 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11314 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11315 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11317 commitChanges : function(){
11318 var m = this.modified.slice(0);
11319 this.modified = [];
11320 for(var i = 0, len = m.length; i < len; i++){
11326 * Cancel outstanding changes on all changed records.
11328 rejectChanges : function(){
11329 var m = this.modified.slice(0);
11330 this.modified = [];
11331 for(var i = 0, len = m.length; i < len; i++){
11336 onMetaChange : function(meta, rtype, o){
11337 this.recordType = rtype;
11338 this.fields = rtype.prototype.fields;
11339 delete this.snapshot;
11340 this.sortInfo = meta.sortInfo || this.sortInfo;
11341 this.modified = [];
11342 this.fireEvent('metachange', this, this.reader.meta);
11345 moveIndex : function(data, type)
11347 var index = this.indexOf(data);
11349 var newIndex = index + type;
11353 this.insert(newIndex, data);
11358 * Ext JS Library 1.1.1
11359 * Copyright(c) 2006-2007, Ext JS, LLC.
11361 * Originally Released Under LGPL - original licence link has changed is not relivant.
11364 * <script type="text/javascript">
11368 * @class Roo.data.SimpleStore
11369 * @extends Roo.data.Store
11370 * Small helper class to make creating Stores from Array data easier.
11371 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11372 * @cfg {Array} fields An array of field definition objects, or field name strings.
11373 * @cfg {Array} data The multi-dimensional array of data
11375 * @param {Object} config
11377 Roo.data.SimpleStore = function(config){
11378 Roo.data.SimpleStore.superclass.constructor.call(this, {
11380 reader: new Roo.data.ArrayReader({
11383 Roo.data.Record.create(config.fields)
11385 proxy : new Roo.data.MemoryProxy(config.data)
11389 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11391 * Ext JS Library 1.1.1
11392 * Copyright(c) 2006-2007, Ext JS, LLC.
11394 * Originally Released Under LGPL - original licence link has changed is not relivant.
11397 * <script type="text/javascript">
11402 * @extends Roo.data.Store
11403 * @class Roo.data.JsonStore
11404 * Small helper class to make creating Stores for JSON data easier. <br/>
11406 var store = new Roo.data.JsonStore({
11407 url: 'get-images.php',
11409 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11412 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11413 * JsonReader and HttpProxy (unless inline data is provided).</b>
11414 * @cfg {Array} fields An array of field definition objects, or field name strings.
11416 * @param {Object} config
11418 Roo.data.JsonStore = function(c){
11419 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11420 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11421 reader: new Roo.data.JsonReader(c, c.fields)
11424 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11426 * Ext JS Library 1.1.1
11427 * Copyright(c) 2006-2007, Ext JS, LLC.
11429 * Originally Released Under LGPL - original licence link has changed is not relivant.
11432 * <script type="text/javascript">
11436 Roo.data.Field = function(config){
11437 if(typeof config == "string"){
11438 config = {name: config};
11440 Roo.apply(this, config);
11443 this.type = "auto";
11446 var st = Roo.data.SortTypes;
11447 // named sortTypes are supported, here we look them up
11448 if(typeof this.sortType == "string"){
11449 this.sortType = st[this.sortType];
11452 // set default sortType for strings and dates
11453 if(!this.sortType){
11456 this.sortType = st.asUCString;
11459 this.sortType = st.asDate;
11462 this.sortType = st.none;
11467 var stripRe = /[\$,%]/g;
11469 // prebuilt conversion function for this field, instead of
11470 // switching every time we're reading a value
11472 var cv, dateFormat = this.dateFormat;
11477 cv = function(v){ return v; };
11480 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11484 return v !== undefined && v !== null && v !== '' ?
11485 parseInt(String(v).replace(stripRe, ""), 10) : '';
11490 return v !== undefined && v !== null && v !== '' ?
11491 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11496 cv = function(v){ return v === true || v === "true" || v == 1; };
11503 if(v instanceof Date){
11507 if(dateFormat == "timestamp"){
11508 return new Date(v*1000);
11510 return Date.parseDate(v, dateFormat);
11512 var parsed = Date.parse(v);
11513 return parsed ? new Date(parsed) : null;
11522 Roo.data.Field.prototype = {
11530 * Ext JS Library 1.1.1
11531 * Copyright(c) 2006-2007, Ext JS, LLC.
11533 * Originally Released Under LGPL - original licence link has changed is not relivant.
11536 * <script type="text/javascript">
11539 // Base class for reading structured data from a data source. This class is intended to be
11540 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11543 * @class Roo.data.DataReader
11544 * Base class for reading structured data from a data source. This class is intended to be
11545 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11548 Roo.data.DataReader = function(meta, recordType){
11552 this.recordType = recordType instanceof Array ?
11553 Roo.data.Record.create(recordType) : recordType;
11556 Roo.data.DataReader.prototype = {
11558 * Create an empty record
11559 * @param {Object} data (optional) - overlay some values
11560 * @return {Roo.data.Record} record created.
11562 newRow : function(d) {
11564 this.recordType.prototype.fields.each(function(c) {
11566 case 'int' : da[c.name] = 0; break;
11567 case 'date' : da[c.name] = new Date(); break;
11568 case 'float' : da[c.name] = 0.0; break;
11569 case 'boolean' : da[c.name] = false; break;
11570 default : da[c.name] = ""; break;
11574 return new this.recordType(Roo.apply(da, d));
11579 * Ext JS Library 1.1.1
11580 * Copyright(c) 2006-2007, Ext JS, LLC.
11582 * Originally Released Under LGPL - original licence link has changed is not relivant.
11585 * <script type="text/javascript">
11589 * @class Roo.data.DataProxy
11590 * @extends Roo.data.Observable
11591 * This class is an abstract base class for implementations which provide retrieval of
11592 * unformatted data objects.<br>
11594 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11595 * (of the appropriate type which knows how to parse the data object) to provide a block of
11596 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11598 * Custom implementations must implement the load method as described in
11599 * {@link Roo.data.HttpProxy#load}.
11601 Roo.data.DataProxy = function(){
11604 * @event beforeload
11605 * Fires before a network request is made to retrieve a data object.
11606 * @param {Object} This DataProxy object.
11607 * @param {Object} params The params parameter to the load function.
11612 * Fires before the load method's callback is called.
11613 * @param {Object} This DataProxy object.
11614 * @param {Object} o The data object.
11615 * @param {Object} arg The callback argument object passed to the load function.
11619 * @event loadexception
11620 * Fires if an Exception occurs during data retrieval.
11621 * @param {Object} This DataProxy object.
11622 * @param {Object} o The data object.
11623 * @param {Object} arg The callback argument object passed to the load function.
11624 * @param {Object} e The Exception.
11626 loadexception : true
11628 Roo.data.DataProxy.superclass.constructor.call(this);
11631 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11634 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11638 * Ext JS Library 1.1.1
11639 * Copyright(c) 2006-2007, Ext JS, LLC.
11641 * Originally Released Under LGPL - original licence link has changed is not relivant.
11644 * <script type="text/javascript">
11647 * @class Roo.data.MemoryProxy
11648 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11649 * to the Reader when its load method is called.
11651 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11653 Roo.data.MemoryProxy = function(data){
11657 Roo.data.MemoryProxy.superclass.constructor.call(this);
11661 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11664 * Load data from the requested source (in this case an in-memory
11665 * data object passed to the constructor), read the data object into
11666 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11667 * process that block using the passed callback.
11668 * @param {Object} params This parameter is not used by the MemoryProxy class.
11669 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11670 * object into a block of Roo.data.Records.
11671 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11672 * The function must be passed <ul>
11673 * <li>The Record block object</li>
11674 * <li>The "arg" argument from the load function</li>
11675 * <li>A boolean success indicator</li>
11677 * @param {Object} scope The scope in which to call the callback
11678 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11680 load : function(params, reader, callback, scope, arg){
11681 params = params || {};
11684 result = reader.readRecords(this.data);
11686 this.fireEvent("loadexception", this, arg, null, e);
11687 callback.call(scope, null, arg, false);
11690 callback.call(scope, result, arg, true);
11694 update : function(params, records){
11699 * Ext JS Library 1.1.1
11700 * Copyright(c) 2006-2007, Ext JS, LLC.
11702 * Originally Released Under LGPL - original licence link has changed is not relivant.
11705 * <script type="text/javascript">
11708 * @class Roo.data.HttpProxy
11709 * @extends Roo.data.DataProxy
11710 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11711 * configured to reference a certain URL.<br><br>
11713 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11714 * from which the running page was served.<br><br>
11716 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11718 * Be aware that to enable the browser to parse an XML document, the server must set
11719 * the Content-Type header in the HTTP response to "text/xml".
11721 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11722 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11723 * will be used to make the request.
11725 Roo.data.HttpProxy = function(conn){
11726 Roo.data.HttpProxy.superclass.constructor.call(this);
11727 // is conn a conn config or a real conn?
11729 this.useAjax = !conn || !conn.events;
11733 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11734 // thse are take from connection...
11737 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11740 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11741 * extra parameters to each request made by this object. (defaults to undefined)
11744 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11745 * to each request made by this object. (defaults to undefined)
11748 * @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)
11751 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11754 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11760 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11764 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11765 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11766 * a finer-grained basis than the DataProxy events.
11768 getConnection : function(){
11769 return this.useAjax ? Roo.Ajax : this.conn;
11773 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11774 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11775 * process that block using the passed callback.
11776 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11777 * for the request to the remote server.
11778 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11779 * object into a block of Roo.data.Records.
11780 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11781 * The function must be passed <ul>
11782 * <li>The Record block object</li>
11783 * <li>The "arg" argument from the load function</li>
11784 * <li>A boolean success indicator</li>
11786 * @param {Object} scope The scope in which to call the callback
11787 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11789 load : function(params, reader, callback, scope, arg){
11790 if(this.fireEvent("beforeload", this, params) !== false){
11792 params : params || {},
11794 callback : callback,
11799 callback : this.loadResponse,
11803 Roo.applyIf(o, this.conn);
11804 if(this.activeRequest){
11805 Roo.Ajax.abort(this.activeRequest);
11807 this.activeRequest = Roo.Ajax.request(o);
11809 this.conn.request(o);
11812 callback.call(scope||this, null, arg, false);
11817 loadResponse : function(o, success, response){
11818 delete this.activeRequest;
11820 this.fireEvent("loadexception", this, o, response);
11821 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11826 result = o.reader.read(response);
11828 this.fireEvent("loadexception", this, o, response, e);
11829 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11833 this.fireEvent("load", this, o, o.request.arg);
11834 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11838 update : function(dataSet){
11843 updateResponse : function(dataSet){
11848 * Ext JS Library 1.1.1
11849 * Copyright(c) 2006-2007, Ext JS, LLC.
11851 * Originally Released Under LGPL - original licence link has changed is not relivant.
11854 * <script type="text/javascript">
11858 * @class Roo.data.ScriptTagProxy
11859 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11860 * other than the originating domain of the running page.<br><br>
11862 * <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
11863 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11865 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11866 * source code that is used as the source inside a <script> tag.<br><br>
11868 * In order for the browser to process the returned data, the server must wrap the data object
11869 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11870 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11871 * depending on whether the callback name was passed:
11874 boolean scriptTag = false;
11875 String cb = request.getParameter("callback");
11878 response.setContentType("text/javascript");
11880 response.setContentType("application/x-json");
11882 Writer out = response.getWriter();
11884 out.write(cb + "(");
11886 out.print(dataBlock.toJsonString());
11893 * @param {Object} config A configuration object.
11895 Roo.data.ScriptTagProxy = function(config){
11896 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11897 Roo.apply(this, config);
11898 this.head = document.getElementsByTagName("head")[0];
11901 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11903 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11905 * @cfg {String} url The URL from which to request the data object.
11908 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11912 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11913 * the server the name of the callback function set up by the load call to process the returned data object.
11914 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11915 * javascript output which calls this named function passing the data object as its only parameter.
11917 callbackParam : "callback",
11919 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11920 * name to the request.
11925 * Load data from the configured URL, read the data object into
11926 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11927 * process that block using the passed callback.
11928 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11929 * for the request to the remote server.
11930 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11931 * object into a block of Roo.data.Records.
11932 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11933 * The function must be passed <ul>
11934 * <li>The Record block object</li>
11935 * <li>The "arg" argument from the load function</li>
11936 * <li>A boolean success indicator</li>
11938 * @param {Object} scope The scope in which to call the callback
11939 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11941 load : function(params, reader, callback, scope, arg){
11942 if(this.fireEvent("beforeload", this, params) !== false){
11944 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11946 var url = this.url;
11947 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11949 url += "&_dc=" + (new Date().getTime());
11951 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11954 cb : "stcCallback"+transId,
11955 scriptId : "stcScript"+transId,
11959 callback : callback,
11965 window[trans.cb] = function(o){
11966 conn.handleResponse(o, trans);
11969 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11971 if(this.autoAbort !== false){
11975 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11977 var script = document.createElement("script");
11978 script.setAttribute("src", url);
11979 script.setAttribute("type", "text/javascript");
11980 script.setAttribute("id", trans.scriptId);
11981 this.head.appendChild(script);
11983 this.trans = trans;
11985 callback.call(scope||this, null, arg, false);
11990 isLoading : function(){
11991 return this.trans ? true : false;
11995 * Abort the current server request.
11997 abort : function(){
11998 if(this.isLoading()){
11999 this.destroyTrans(this.trans);
12004 destroyTrans : function(trans, isLoaded){
12005 this.head.removeChild(document.getElementById(trans.scriptId));
12006 clearTimeout(trans.timeoutId);
12008 window[trans.cb] = undefined;
12010 delete window[trans.cb];
12013 // if hasn't been loaded, wait for load to remove it to prevent script error
12014 window[trans.cb] = function(){
12015 window[trans.cb] = undefined;
12017 delete window[trans.cb];
12024 handleResponse : function(o, trans){
12025 this.trans = false;
12026 this.destroyTrans(trans, true);
12029 result = trans.reader.readRecords(o);
12031 this.fireEvent("loadexception", this, o, trans.arg, e);
12032 trans.callback.call(trans.scope||window, null, trans.arg, false);
12035 this.fireEvent("load", this, o, trans.arg);
12036 trans.callback.call(trans.scope||window, result, trans.arg, true);
12040 handleFailure : function(trans){
12041 this.trans = false;
12042 this.destroyTrans(trans, false);
12043 this.fireEvent("loadexception", this, null, trans.arg);
12044 trans.callback.call(trans.scope||window, null, trans.arg, false);
12048 * Ext JS Library 1.1.1
12049 * Copyright(c) 2006-2007, Ext JS, LLC.
12051 * Originally Released Under LGPL - original licence link has changed is not relivant.
12054 * <script type="text/javascript">
12058 * @class Roo.data.JsonReader
12059 * @extends Roo.data.DataReader
12060 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12061 * based on mappings in a provided Roo.data.Record constructor.
12063 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12064 * in the reply previously.
12069 var RecordDef = Roo.data.Record.create([
12070 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12071 {name: 'occupation'} // This field will use "occupation" as the mapping.
12073 var myReader = new Roo.data.JsonReader({
12074 totalProperty: "results", // The property which contains the total dataset size (optional)
12075 root: "rows", // The property which contains an Array of row objects
12076 id: "id" // The property within each row object that provides an ID for the record (optional)
12080 * This would consume a JSON file like this:
12082 { 'results': 2, 'rows': [
12083 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12084 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12087 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12088 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12089 * paged from the remote server.
12090 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12091 * @cfg {String} root name of the property which contains the Array of row objects.
12092 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12093 * @cfg {Array} fields Array of field definition objects
12095 * Create a new JsonReader
12096 * @param {Object} meta Metadata configuration options
12097 * @param {Object} recordType Either an Array of field definition objects,
12098 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12100 Roo.data.JsonReader = function(meta, recordType){
12103 // set some defaults:
12104 Roo.applyIf(meta, {
12105 totalProperty: 'total',
12106 successProperty : 'success',
12111 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12113 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12116 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12117 * Used by Store query builder to append _requestMeta to params.
12120 metaFromRemote : false,
12122 * This method is only used by a DataProxy which has retrieved data from a remote server.
12123 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12124 * @return {Object} data A data block which is used by an Roo.data.Store object as
12125 * a cache of Roo.data.Records.
12127 read : function(response){
12128 var json = response.responseText;
12130 var o = /* eval:var:o */ eval("("+json+")");
12132 throw {message: "JsonReader.read: Json object not found"};
12138 this.metaFromRemote = true;
12139 this.meta = o.metaData;
12140 this.recordType = Roo.data.Record.create(o.metaData.fields);
12141 this.onMetaChange(this.meta, this.recordType, o);
12143 return this.readRecords(o);
12146 // private function a store will implement
12147 onMetaChange : function(meta, recordType, o){
12154 simpleAccess: function(obj, subsc) {
12161 getJsonAccessor: function(){
12163 return function(expr) {
12165 return(re.test(expr))
12166 ? new Function("obj", "return obj." + expr)
12171 return Roo.emptyFn;
12176 * Create a data block containing Roo.data.Records from an XML document.
12177 * @param {Object} o An object which contains an Array of row objects in the property specified
12178 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12179 * which contains the total size of the dataset.
12180 * @return {Object} data A data block which is used by an Roo.data.Store object as
12181 * a cache of Roo.data.Records.
12183 readRecords : function(o){
12185 * After any data loads, the raw JSON data is available for further custom processing.
12189 var s = this.meta, Record = this.recordType,
12190 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12192 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12194 if(s.totalProperty) {
12195 this.getTotal = this.getJsonAccessor(s.totalProperty);
12197 if(s.successProperty) {
12198 this.getSuccess = this.getJsonAccessor(s.successProperty);
12200 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12202 var g = this.getJsonAccessor(s.id);
12203 this.getId = function(rec) {
12205 return (r === undefined || r === "") ? null : r;
12208 this.getId = function(){return null;};
12211 for(var jj = 0; jj < fl; jj++){
12213 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12214 this.ef[jj] = this.getJsonAccessor(map);
12218 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12219 if(s.totalProperty){
12220 var vt = parseInt(this.getTotal(o), 10);
12225 if(s.successProperty){
12226 var vs = this.getSuccess(o);
12227 if(vs === false || vs === 'false'){
12232 for(var i = 0; i < c; i++){
12235 var id = this.getId(n);
12236 for(var j = 0; j < fl; j++){
12238 var v = this.ef[j](n);
12240 Roo.log('missing convert for ' + f.name);
12244 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12246 var record = new Record(values, id);
12248 records[i] = record;
12254 totalRecords : totalRecords
12259 * Ext JS Library 1.1.1
12260 * Copyright(c) 2006-2007, Ext JS, LLC.
12262 * Originally Released Under LGPL - original licence link has changed is not relivant.
12265 * <script type="text/javascript">
12269 * @class Roo.data.ArrayReader
12270 * @extends Roo.data.DataReader
12271 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12272 * Each element of that Array represents a row of data fields. The
12273 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12274 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12278 var RecordDef = Roo.data.Record.create([
12279 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12280 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12282 var myReader = new Roo.data.ArrayReader({
12283 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12287 * This would consume an Array like this:
12289 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12291 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12293 * Create a new JsonReader
12294 * @param {Object} meta Metadata configuration options.
12295 * @param {Object} recordType Either an Array of field definition objects
12296 * as specified to {@link Roo.data.Record#create},
12297 * or an {@link Roo.data.Record} object
12298 * created using {@link Roo.data.Record#create}.
12300 Roo.data.ArrayReader = function(meta, recordType){
12301 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12304 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12306 * Create a data block containing Roo.data.Records from an XML document.
12307 * @param {Object} o An Array of row objects which represents the dataset.
12308 * @return {Object} data A data block which is used by an Roo.data.Store object as
12309 * a cache of Roo.data.Records.
12311 readRecords : function(o){
12312 var sid = this.meta ? this.meta.id : null;
12313 var recordType = this.recordType, fields = recordType.prototype.fields;
12316 for(var i = 0; i < root.length; i++){
12319 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12320 for(var j = 0, jlen = fields.length; j < jlen; j++){
12321 var f = fields.items[j];
12322 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12323 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12325 values[f.name] = v;
12327 var record = new recordType(values, id);
12329 records[records.length] = record;
12333 totalRecords : records.length
12342 * @class Roo.bootstrap.ComboBox
12343 * @extends Roo.bootstrap.TriggerField
12344 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12345 * @cfg {Boolean} append (true|false) default false
12346 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12347 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12348 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12349 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12350 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12351 * @cfg {Boolean} animate default true
12352 * @cfg {Boolean} emptyResultText only for touch device
12353 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12354 * @cfg {String} emptyTitle default ''
12356 * Create a new ComboBox.
12357 * @param {Object} config Configuration options
12359 Roo.bootstrap.ComboBox = function(config){
12360 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12364 * Fires when the dropdown list is expanded
12365 * @param {Roo.bootstrap.ComboBox} combo This combo box
12370 * Fires when the dropdown list is collapsed
12371 * @param {Roo.bootstrap.ComboBox} combo This combo box
12375 * @event beforeselect
12376 * Fires before a list item is selected. Return false to cancel the selection.
12377 * @param {Roo.bootstrap.ComboBox} combo This combo box
12378 * @param {Roo.data.Record} record The data record returned from the underlying store
12379 * @param {Number} index The index of the selected item in the dropdown list
12381 'beforeselect' : true,
12384 * Fires when a list item is selected
12385 * @param {Roo.bootstrap.ComboBox} combo This combo box
12386 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12387 * @param {Number} index The index of the selected item in the dropdown list
12391 * @event beforequery
12392 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12393 * The event object passed has these properties:
12394 * @param {Roo.bootstrap.ComboBox} combo This combo box
12395 * @param {String} query The query
12396 * @param {Boolean} forceAll true to force "all" query
12397 * @param {Boolean} cancel true to cancel the query
12398 * @param {Object} e The query event object
12400 'beforequery': true,
12403 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12404 * @param {Roo.bootstrap.ComboBox} combo This combo box
12409 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12410 * @param {Roo.bootstrap.ComboBox} combo This combo box
12411 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12416 * Fires when the remove value from the combobox array
12417 * @param {Roo.bootstrap.ComboBox} combo This combo box
12421 * @event afterremove
12422 * Fires when the remove value from the combobox array
12423 * @param {Roo.bootstrap.ComboBox} combo This combo box
12425 'afterremove' : true,
12427 * @event specialfilter
12428 * Fires when specialfilter
12429 * @param {Roo.bootstrap.ComboBox} combo This combo box
12431 'specialfilter' : true,
12434 * Fires when tick the element
12435 * @param {Roo.bootstrap.ComboBox} combo This combo box
12439 * @event touchviewdisplay
12440 * Fires when touch view require special display (default is using displayField)
12441 * @param {Roo.bootstrap.ComboBox} combo This combo box
12442 * @param {Object} cfg set html .
12444 'touchviewdisplay' : true
12449 this.tickItems = [];
12451 this.selectedIndex = -1;
12452 if(this.mode == 'local'){
12453 if(config.queryDelay === undefined){
12454 this.queryDelay = 10;
12456 if(config.minChars === undefined){
12462 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12465 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12466 * rendering into an Roo.Editor, defaults to false)
12469 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12470 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12473 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12476 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12477 * the dropdown list (defaults to undefined, with no header element)
12481 * @cfg {String/Roo.Template} tpl The template to use to render the output
12485 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12487 listWidth: undefined,
12489 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12490 * mode = 'remote' or 'text' if mode = 'local')
12492 displayField: undefined,
12495 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12496 * mode = 'remote' or 'value' if mode = 'local').
12497 * Note: use of a valueField requires the user make a selection
12498 * in order for a value to be mapped.
12500 valueField: undefined,
12502 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12507 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12508 * field's data value (defaults to the underlying DOM element's name)
12510 hiddenName: undefined,
12512 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12516 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12518 selectedClass: 'active',
12521 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12525 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12526 * anchor positions (defaults to 'tl-bl')
12528 listAlign: 'tl-bl?',
12530 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12534 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12535 * query specified by the allQuery config option (defaults to 'query')
12537 triggerAction: 'query',
12539 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12540 * (defaults to 4, does not apply if editable = false)
12544 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12545 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12549 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12550 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12554 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12555 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12559 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12560 * when editable = true (defaults to false)
12562 selectOnFocus:false,
12564 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12566 queryParam: 'query',
12568 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12569 * when mode = 'remote' (defaults to 'Loading...')
12571 loadingText: 'Loading...',
12573 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12577 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12581 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12582 * traditional select (defaults to true)
12586 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12590 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12594 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12595 * listWidth has a higher value)
12599 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12600 * allow the user to set arbitrary text into the field (defaults to false)
12602 forceSelection:false,
12604 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12605 * if typeAhead = true (defaults to 250)
12607 typeAheadDelay : 250,
12609 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12610 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12612 valueNotFoundText : undefined,
12614 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12616 blockFocus : false,
12619 * @cfg {Boolean} disableClear Disable showing of clear button.
12621 disableClear : false,
12623 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12625 alwaysQuery : false,
12628 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12633 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12635 invalidClass : "has-warning",
12638 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12640 validClass : "has-success",
12643 * @cfg {Boolean} specialFilter (true|false) special filter default false
12645 specialFilter : false,
12648 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12650 mobileTouchView : true,
12653 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12655 useNativeIOS : false,
12657 ios_options : false,
12669 btnPosition : 'right',
12670 triggerList : true,
12671 showToggleBtn : true,
12673 emptyResultText: 'Empty',
12674 triggerText : 'Select',
12677 // element that contains real text value.. (when hidden is used..)
12679 getAutoCreate : function()
12684 * Render classic select for iso
12687 if(Roo.isIOS && this.useNativeIOS){
12688 cfg = this.getAutoCreateNativeIOS();
12696 if(Roo.isTouch && this.mobileTouchView){
12697 cfg = this.getAutoCreateTouchView();
12704 if(!this.tickable){
12705 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12710 * ComboBox with tickable selections
12713 var align = this.labelAlign || this.parentLabelAlign();
12716 cls : 'form-group roo-combobox-tickable' //input-group
12719 var btn_text_select = '';
12720 var btn_text_done = '';
12721 var btn_text_cancel = '';
12723 if (this.btn_text_show) {
12724 btn_text_select = 'Select';
12725 btn_text_done = 'Done';
12726 btn_text_cancel = 'Cancel';
12731 cls : 'tickable-buttons',
12736 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12737 //html : this.triggerText
12738 html: btn_text_select
12744 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12746 html: btn_text_done
12752 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12754 html: btn_text_cancel
12760 buttons.cn.unshift({
12762 cls: 'roo-select2-search-field-input'
12768 Roo.each(buttons.cn, function(c){
12770 c.cls += ' btn-' + _this.size;
12773 if (_this.disabled) {
12784 cls: 'form-hidden-field'
12788 cls: 'roo-select2-choices',
12792 cls: 'roo-select2-search-field',
12803 cls: 'roo-select2-container input-group roo-select2-container-multi',
12808 // cls: 'typeahead typeahead-long dropdown-menu',
12809 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12814 if(this.hasFeedback && !this.allowBlank){
12818 cls: 'glyphicon form-control-feedback'
12821 combobox.cn.push(feedback);
12825 if (align ==='left' && this.fieldLabel.length) {
12827 cfg.cls += ' roo-form-group-label-left';
12832 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12833 tooltip : 'This field is required'
12838 cls : 'control-label',
12839 html : this.fieldLabel
12851 var labelCfg = cfg.cn[1];
12852 var contentCfg = cfg.cn[2];
12855 if(this.indicatorpos == 'right'){
12861 cls : 'control-label',
12865 html : this.fieldLabel
12869 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12870 tooltip : 'This field is required'
12885 labelCfg = cfg.cn[0];
12886 contentCfg = cfg.cn[1];
12890 if(this.labelWidth > 12){
12891 labelCfg.style = "width: " + this.labelWidth + 'px';
12894 if(this.labelWidth < 13 && this.labelmd == 0){
12895 this.labelmd = this.labelWidth;
12898 if(this.labellg > 0){
12899 labelCfg.cls += ' col-lg-' + this.labellg;
12900 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12903 if(this.labelmd > 0){
12904 labelCfg.cls += ' col-md-' + this.labelmd;
12905 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12908 if(this.labelsm > 0){
12909 labelCfg.cls += ' col-sm-' + this.labelsm;
12910 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12913 if(this.labelxs > 0){
12914 labelCfg.cls += ' col-xs-' + this.labelxs;
12915 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12919 } else if ( this.fieldLabel.length) {
12920 // Roo.log(" label");
12924 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12925 tooltip : 'This field is required'
12929 //cls : 'input-group-addon',
12930 html : this.fieldLabel
12935 if(this.indicatorpos == 'right'){
12939 //cls : 'input-group-addon',
12940 html : this.fieldLabel
12944 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12945 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) {
12992 // remove this element....
12993 var e = this.el.dom, k=0;
12994 while (e ) { e = e.previousSibling; ++k;}
12999 this.rendered = false;
13001 this.render(this.parent().getChildContainer(true), k);
13004 if(Roo.isIOS && this.useNativeIOS){
13005 this.initIOSView();
13013 if(Roo.isTouch && this.mobileTouchView){
13014 this.initTouchView();
13019 this.initTickableEvents();
13023 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13025 if(this.hiddenName){
13027 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13029 this.hiddenField.dom.value =
13030 this.hiddenValue !== undefined ? this.hiddenValue :
13031 this.value !== undefined ? this.value : '';
13033 // prevent input submission
13034 this.el.dom.removeAttribute('name');
13035 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13040 // this.el.dom.setAttribute('autocomplete', 'off');
13043 var cls = 'x-combo-list';
13045 //this.list = new Roo.Layer({
13046 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13052 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13053 _this.list.setWidth(lw);
13056 this.list.on('mouseover', this.onViewOver, this);
13057 this.list.on('mousemove', this.onViewMove, this);
13059 this.list.on('scroll', this.onViewScroll, this);
13062 this.list.swallowEvent('mousewheel');
13063 this.assetHeight = 0;
13066 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13067 this.assetHeight += this.header.getHeight();
13070 this.innerList = this.list.createChild({cls:cls+'-inner'});
13071 this.innerList.on('mouseover', this.onViewOver, this);
13072 this.innerList.on('mousemove', this.onViewMove, this);
13073 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13075 if(this.allowBlank && !this.pageSize && !this.disableClear){
13076 this.footer = this.list.createChild({cls:cls+'-ft'});
13077 this.pageTb = new Roo.Toolbar(this.footer);
13081 this.footer = this.list.createChild({cls:cls+'-ft'});
13082 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13083 {pageSize: this.pageSize});
13087 if (this.pageTb && this.allowBlank && !this.disableClear) {
13089 this.pageTb.add(new Roo.Toolbar.Fill(), {
13090 cls: 'x-btn-icon x-btn-clear',
13092 handler: function()
13095 _this.clearValue();
13096 _this.onSelect(false, -1);
13101 this.assetHeight += this.footer.getHeight();
13106 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13109 this.view = new Roo.View(this.list, this.tpl, {
13110 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13112 //this.view.wrapEl.setDisplayed(false);
13113 this.view.on('click', this.onViewClick, this);
13116 this.store.on('beforeload', this.onBeforeLoad, this);
13117 this.store.on('load', this.onLoad, this);
13118 this.store.on('loadexception', this.onLoadException, this);
13120 if(this.resizable){
13121 this.resizer = new Roo.Resizable(this.list, {
13122 pinned:true, handles:'se'
13124 this.resizer.on('resize', function(r, w, h){
13125 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13126 this.listWidth = w;
13127 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13128 this.restrictHeight();
13130 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13133 if(!this.editable){
13134 this.editable = true;
13135 this.setEditable(false);
13140 if (typeof(this.events.add.listeners) != 'undefined') {
13142 this.addicon = this.wrap.createChild(
13143 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13145 this.addicon.on('click', function(e) {
13146 this.fireEvent('add', this);
13149 if (typeof(this.events.edit.listeners) != 'undefined') {
13151 this.editicon = this.wrap.createChild(
13152 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13153 if (this.addicon) {
13154 this.editicon.setStyle('margin-left', '40px');
13156 this.editicon.on('click', function(e) {
13158 // we fire even if inothing is selected..
13159 this.fireEvent('edit', this, this.lastData );
13165 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13166 "up" : function(e){
13167 this.inKeyMode = true;
13171 "down" : function(e){
13172 if(!this.isExpanded()){
13173 this.onTriggerClick();
13175 this.inKeyMode = true;
13180 "enter" : function(e){
13181 // this.onViewClick();
13185 if(this.fireEvent("specialkey", this, e)){
13186 this.onViewClick(false);
13192 "esc" : function(e){
13196 "tab" : function(e){
13199 if(this.fireEvent("specialkey", this, e)){
13200 this.onViewClick(false);
13208 doRelay : function(foo, bar, hname){
13209 if(hname == 'down' || this.scope.isExpanded()){
13210 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13219 this.queryDelay = Math.max(this.queryDelay || 10,
13220 this.mode == 'local' ? 10 : 250);
13223 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13225 if(this.typeAhead){
13226 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13228 if(this.editable !== false){
13229 this.inputEl().on("keyup", this.onKeyUp, this);
13231 if(this.forceSelection){
13232 this.inputEl().on('blur', this.doForce, this);
13236 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13237 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13241 initTickableEvents: function()
13245 if(this.hiddenName){
13247 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13249 this.hiddenField.dom.value =
13250 this.hiddenValue !== undefined ? this.hiddenValue :
13251 this.value !== undefined ? this.value : '';
13253 // prevent input submission
13254 this.el.dom.removeAttribute('name');
13255 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13260 // this.list = this.el.select('ul.dropdown-menu',true).first();
13262 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13263 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13264 if(this.triggerList){
13265 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13268 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13269 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13271 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13272 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13274 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13275 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13277 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13278 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13279 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13282 this.cancelBtn.hide();
13287 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13288 _this.list.setWidth(lw);
13291 this.list.on('mouseover', this.onViewOver, this);
13292 this.list.on('mousemove', this.onViewMove, this);
13294 this.list.on('scroll', this.onViewScroll, this);
13297 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>';
13300 this.view = new Roo.View(this.list, this.tpl, {
13301 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13304 //this.view.wrapEl.setDisplayed(false);
13305 this.view.on('click', this.onViewClick, this);
13309 this.store.on('beforeload', this.onBeforeLoad, this);
13310 this.store.on('load', this.onLoad, this);
13311 this.store.on('loadexception', this.onLoadException, this);
13314 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13315 "up" : function(e){
13316 this.inKeyMode = true;
13320 "down" : function(e){
13321 this.inKeyMode = true;
13325 "enter" : function(e){
13326 if(this.fireEvent("specialkey", this, e)){
13327 this.onViewClick(false);
13333 "esc" : function(e){
13334 this.onTickableFooterButtonClick(e, false, false);
13337 "tab" : function(e){
13338 this.fireEvent("specialkey", this, e);
13340 this.onTickableFooterButtonClick(e, false, false);
13347 doRelay : function(e, fn, key){
13348 if(this.scope.isExpanded()){
13349 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13358 this.queryDelay = Math.max(this.queryDelay || 10,
13359 this.mode == 'local' ? 10 : 250);
13362 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13364 if(this.typeAhead){
13365 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13368 if(this.editable !== false){
13369 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13372 this.indicator = this.indicatorEl();
13374 if(this.indicator){
13375 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13376 this.indicator.hide();
13381 onDestroy : function(){
13383 this.view.setStore(null);
13384 this.view.el.removeAllListeners();
13385 this.view.el.remove();
13386 this.view.purgeListeners();
13389 this.list.dom.innerHTML = '';
13393 this.store.un('beforeload', this.onBeforeLoad, this);
13394 this.store.un('load', this.onLoad, this);
13395 this.store.un('loadexception', this.onLoadException, this);
13397 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13401 fireKey : function(e){
13402 if(e.isNavKeyPress() && !this.list.isVisible()){
13403 this.fireEvent("specialkey", this, e);
13408 onResize: function(w, h){
13409 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13411 // if(typeof w != 'number'){
13412 // // we do not handle it!?!?
13415 // var tw = this.trigger.getWidth();
13416 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13417 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13419 // this.inputEl().setWidth( this.adjustWidth('input', x));
13421 // //this.trigger.setStyle('left', x+'px');
13423 // if(this.list && this.listWidth === undefined){
13424 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13425 // this.list.setWidth(lw);
13426 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13434 * Allow or prevent the user from directly editing the field text. If false is passed,
13435 * the user will only be able to select from the items defined in the dropdown list. This method
13436 * is the runtime equivalent of setting the 'editable' config option at config time.
13437 * @param {Boolean} value True to allow the user to directly edit the field text
13439 setEditable : function(value){
13440 if(value == this.editable){
13443 this.editable = value;
13445 this.inputEl().dom.setAttribute('readOnly', true);
13446 this.inputEl().on('mousedown', this.onTriggerClick, this);
13447 this.inputEl().addClass('x-combo-noedit');
13449 this.inputEl().dom.setAttribute('readOnly', false);
13450 this.inputEl().un('mousedown', this.onTriggerClick, this);
13451 this.inputEl().removeClass('x-combo-noedit');
13457 onBeforeLoad : function(combo,opts){
13458 if(!this.hasFocus){
13462 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13464 this.restrictHeight();
13465 this.selectedIndex = -1;
13469 onLoad : function(){
13471 this.hasQuery = false;
13473 if(!this.hasFocus){
13477 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13478 this.loading.hide();
13481 if(this.store.getCount() > 0){
13484 this.restrictHeight();
13485 if(this.lastQuery == this.allQuery){
13486 if(this.editable && !this.tickable){
13487 this.inputEl().dom.select();
13491 !this.selectByValue(this.value, true) &&
13494 !this.store.lastOptions ||
13495 typeof(this.store.lastOptions.add) == 'undefined' ||
13496 this.store.lastOptions.add != true
13499 this.select(0, true);
13502 if(this.autoFocus){
13505 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13506 this.taTask.delay(this.typeAheadDelay);
13510 this.onEmptyResults();
13516 onLoadException : function()
13518 this.hasQuery = false;
13520 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13521 this.loading.hide();
13524 if(this.tickable && this.editable){
13529 // only causes errors at present
13530 //Roo.log(this.store.reader.jsonData);
13531 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13533 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13539 onTypeAhead : function(){
13540 if(this.store.getCount() > 0){
13541 var r = this.store.getAt(0);
13542 var newValue = r.data[this.displayField];
13543 var len = newValue.length;
13544 var selStart = this.getRawValue().length;
13546 if(selStart != len){
13547 this.setRawValue(newValue);
13548 this.selectText(selStart, newValue.length);
13554 onSelect : function(record, index){
13556 if(this.fireEvent('beforeselect', this, record, index) !== false){
13558 this.setFromData(index > -1 ? record.data : false);
13561 this.fireEvent('select', this, record, index);
13566 * Returns the currently selected field value or empty string if no value is set.
13567 * @return {String} value The selected value
13569 getValue : function()
13571 if(Roo.isIOS && this.useNativeIOS){
13572 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13576 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13579 if(this.valueField){
13580 return typeof this.value != 'undefined' ? this.value : '';
13582 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13586 getRawValue : function()
13588 if(Roo.isIOS && this.useNativeIOS){
13589 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13592 var v = this.inputEl().getValue();
13598 * Clears any text/value currently set in the field
13600 clearValue : function(){
13602 if(this.hiddenField){
13603 this.hiddenField.dom.value = '';
13606 this.setRawValue('');
13607 this.lastSelectionText = '';
13608 this.lastData = false;
13610 var close = this.closeTriggerEl();
13621 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13622 * will be displayed in the field. If the value does not match the data value of an existing item,
13623 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13624 * Otherwise the field will be blank (although the value will still be set).
13625 * @param {String} value The value to match
13627 setValue : function(v)
13629 if(Roo.isIOS && this.useNativeIOS){
13630 this.setIOSValue(v);
13640 if(this.valueField){
13641 var r = this.findRecord(this.valueField, v);
13643 text = r.data[this.displayField];
13644 }else if(this.valueNotFoundText !== undefined){
13645 text = this.valueNotFoundText;
13648 this.lastSelectionText = text;
13649 if(this.hiddenField){
13650 this.hiddenField.dom.value = v;
13652 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13655 var close = this.closeTriggerEl();
13658 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13664 * @property {Object} the last set data for the element
13669 * Sets the value of the field based on a object which is related to the record format for the store.
13670 * @param {Object} value the value to set as. or false on reset?
13672 setFromData : function(o){
13679 var dv = ''; // display value
13680 var vv = ''; // value value..
13682 if (this.displayField) {
13683 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13685 // this is an error condition!!!
13686 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13689 if(this.valueField){
13690 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13693 var close = this.closeTriggerEl();
13696 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13699 if(this.hiddenField){
13700 this.hiddenField.dom.value = vv;
13702 this.lastSelectionText = dv;
13703 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13707 // no hidden field.. - we store the value in 'value', but still display
13708 // display field!!!!
13709 this.lastSelectionText = dv;
13710 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13717 reset : function(){
13718 // overridden so that last data is reset..
13725 this.setValue(this.originalValue);
13726 //this.clearInvalid();
13727 this.lastData = false;
13729 this.view.clearSelections();
13735 findRecord : function(prop, value){
13737 if(this.store.getCount() > 0){
13738 this.store.each(function(r){
13739 if(r.data[prop] == value){
13749 getName: function()
13751 // returns hidden if it's set..
13752 if (!this.rendered) {return ''};
13753 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13757 onViewMove : function(e, t){
13758 this.inKeyMode = false;
13762 onViewOver : function(e, t){
13763 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13766 var item = this.view.findItemFromChild(t);
13769 var index = this.view.indexOf(item);
13770 this.select(index, false);
13775 onViewClick : function(view, doFocus, el, e)
13777 var index = this.view.getSelectedIndexes()[0];
13779 var r = this.store.getAt(index);
13783 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13790 Roo.each(this.tickItems, function(v,k){
13792 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13794 _this.tickItems.splice(k, 1);
13796 if(typeof(e) == 'undefined' && view == false){
13797 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13809 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13810 this.tickItems.push(r.data);
13813 if(typeof(e) == 'undefined' && view == false){
13814 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13821 this.onSelect(r, index);
13823 if(doFocus !== false && !this.blockFocus){
13824 this.inputEl().focus();
13829 restrictHeight : function(){
13830 //this.innerList.dom.style.height = '';
13831 //var inner = this.innerList.dom;
13832 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13833 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13834 //this.list.beginUpdate();
13835 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13836 this.list.alignTo(this.inputEl(), this.listAlign);
13837 this.list.alignTo(this.inputEl(), this.listAlign);
13838 //this.list.endUpdate();
13842 onEmptyResults : function(){
13844 if(this.tickable && this.editable){
13845 this.restrictHeight();
13853 * Returns true if the dropdown list is expanded, else false.
13855 isExpanded : function(){
13856 return this.list.isVisible();
13860 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13861 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13862 * @param {String} value The data value of the item to select
13863 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13864 * selected item if it is not currently in view (defaults to true)
13865 * @return {Boolean} True if the value matched an item in the list, else false
13867 selectByValue : function(v, scrollIntoView){
13868 if(v !== undefined && v !== null){
13869 var r = this.findRecord(this.valueField || this.displayField, v);
13871 this.select(this.store.indexOf(r), scrollIntoView);
13879 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13880 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13881 * @param {Number} index The zero-based index of the list item to select
13882 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13883 * selected item if it is not currently in view (defaults to true)
13885 select : function(index, scrollIntoView){
13886 this.selectedIndex = index;
13887 this.view.select(index);
13888 if(scrollIntoView !== false){
13889 var el = this.view.getNode(index);
13891 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13894 this.list.scrollChildIntoView(el, false);
13900 selectNext : function(){
13901 var ct = this.store.getCount();
13903 if(this.selectedIndex == -1){
13905 }else if(this.selectedIndex < ct-1){
13906 this.select(this.selectedIndex+1);
13912 selectPrev : function(){
13913 var ct = this.store.getCount();
13915 if(this.selectedIndex == -1){
13917 }else if(this.selectedIndex != 0){
13918 this.select(this.selectedIndex-1);
13924 onKeyUp : function(e){
13925 if(this.editable !== false && !e.isSpecialKey()){
13926 this.lastKey = e.getKey();
13927 this.dqTask.delay(this.queryDelay);
13932 validateBlur : function(){
13933 return !this.list || !this.list.isVisible();
13937 initQuery : function(){
13939 var v = this.getRawValue();
13941 if(this.tickable && this.editable){
13942 v = this.tickableInputEl().getValue();
13949 doForce : function(){
13950 if(this.inputEl().dom.value.length > 0){
13951 this.inputEl().dom.value =
13952 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13958 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13959 * query allowing the query action to be canceled if needed.
13960 * @param {String} query The SQL query to execute
13961 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13962 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13963 * saved in the current store (defaults to false)
13965 doQuery : function(q, forceAll){
13967 if(q === undefined || q === null){
13972 forceAll: forceAll,
13976 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13981 forceAll = qe.forceAll;
13982 if(forceAll === true || (q.length >= this.minChars)){
13984 this.hasQuery = true;
13986 if(this.lastQuery != q || this.alwaysQuery){
13987 this.lastQuery = q;
13988 if(this.mode == 'local'){
13989 this.selectedIndex = -1;
13991 this.store.clearFilter();
13994 if(this.specialFilter){
13995 this.fireEvent('specialfilter', this);
14000 this.store.filter(this.displayField, q);
14003 this.store.fireEvent("datachanged", this.store);
14010 this.store.baseParams[this.queryParam] = q;
14012 var options = {params : this.getParams(q)};
14015 options.add = true;
14016 options.params.start = this.page * this.pageSize;
14019 this.store.load(options);
14022 * this code will make the page width larger, at the beginning, the list not align correctly,
14023 * we should expand the list on onLoad
14024 * so command out it
14029 this.selectedIndex = -1;
14034 this.loadNext = false;
14038 getParams : function(q){
14040 //p[this.queryParam] = q;
14044 p.limit = this.pageSize;
14050 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14052 collapse : function(){
14053 if(!this.isExpanded()){
14059 this.hasFocus = false;
14063 this.cancelBtn.hide();
14064 this.trigger.show();
14067 this.tickableInputEl().dom.value = '';
14068 this.tickableInputEl().blur();
14073 Roo.get(document).un('mousedown', this.collapseIf, this);
14074 Roo.get(document).un('mousewheel', this.collapseIf, this);
14075 if (!this.editable) {
14076 Roo.get(document).un('keydown', this.listKeyPress, this);
14078 this.fireEvent('collapse', this);
14084 collapseIf : function(e){
14085 var in_combo = e.within(this.el);
14086 var in_list = e.within(this.list);
14087 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14089 if (in_combo || in_list || is_list) {
14090 //e.stopPropagation();
14095 this.onTickableFooterButtonClick(e, false, false);
14103 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14105 expand : function(){
14107 if(this.isExpanded() || !this.hasFocus){
14111 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14112 this.list.setWidth(lw);
14118 this.restrictHeight();
14122 this.tickItems = Roo.apply([], this.item);
14125 this.cancelBtn.show();
14126 this.trigger.hide();
14129 this.tickableInputEl().focus();
14134 Roo.get(document).on('mousedown', this.collapseIf, this);
14135 Roo.get(document).on('mousewheel', this.collapseIf, this);
14136 if (!this.editable) {
14137 Roo.get(document).on('keydown', this.listKeyPress, this);
14140 this.fireEvent('expand', this);
14144 // Implements the default empty TriggerField.onTriggerClick function
14145 onTriggerClick : function(e)
14147 Roo.log('trigger click');
14149 if(this.disabled || !this.triggerList){
14154 this.loadNext = false;
14156 if(this.isExpanded()){
14158 if (!this.blockFocus) {
14159 this.inputEl().focus();
14163 this.hasFocus = true;
14164 if(this.triggerAction == 'all') {
14165 this.doQuery(this.allQuery, true);
14167 this.doQuery(this.getRawValue());
14169 if (!this.blockFocus) {
14170 this.inputEl().focus();
14175 onTickableTriggerClick : function(e)
14182 this.loadNext = false;
14183 this.hasFocus = true;
14185 if(this.triggerAction == 'all') {
14186 this.doQuery(this.allQuery, true);
14188 this.doQuery(this.getRawValue());
14192 onSearchFieldClick : function(e)
14194 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14195 this.onTickableFooterButtonClick(e, false, false);
14199 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14204 this.loadNext = false;
14205 this.hasFocus = true;
14207 if(this.triggerAction == 'all') {
14208 this.doQuery(this.allQuery, true);
14210 this.doQuery(this.getRawValue());
14214 listKeyPress : function(e)
14216 //Roo.log('listkeypress');
14217 // scroll to first matching element based on key pres..
14218 if (e.isSpecialKey()) {
14221 var k = String.fromCharCode(e.getKey()).toUpperCase();
14224 var csel = this.view.getSelectedNodes();
14225 var cselitem = false;
14227 var ix = this.view.indexOf(csel[0]);
14228 cselitem = this.store.getAt(ix);
14229 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14235 this.store.each(function(v) {
14237 // start at existing selection.
14238 if (cselitem.id == v.id) {
14244 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14245 match = this.store.indexOf(v);
14251 if (match === false) {
14252 return true; // no more action?
14255 this.view.select(match);
14256 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14257 sn.scrollIntoView(sn.dom.parentNode, false);
14260 onViewScroll : function(e, t){
14262 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){
14266 this.hasQuery = true;
14268 this.loading = this.list.select('.loading', true).first();
14270 if(this.loading === null){
14271 this.list.createChild({
14273 cls: 'loading roo-select2-more-results roo-select2-active',
14274 html: 'Loading more results...'
14277 this.loading = this.list.select('.loading', true).first();
14279 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14281 this.loading.hide();
14284 this.loading.show();
14289 this.loadNext = true;
14291 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14296 addItem : function(o)
14298 var dv = ''; // display value
14300 if (this.displayField) {
14301 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14303 // this is an error condition!!!
14304 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14311 var choice = this.choices.createChild({
14313 cls: 'roo-select2-search-choice',
14322 cls: 'roo-select2-search-choice-close fa fa-times',
14327 }, this.searchField);
14329 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14331 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14339 this.inputEl().dom.value = '';
14344 onRemoveItem : function(e, _self, o)
14346 e.preventDefault();
14348 this.lastItem = Roo.apply([], this.item);
14350 var index = this.item.indexOf(o.data) * 1;
14353 Roo.log('not this item?!');
14357 this.item.splice(index, 1);
14362 this.fireEvent('remove', this, e);
14368 syncValue : function()
14370 if(!this.item.length){
14377 Roo.each(this.item, function(i){
14378 if(_this.valueField){
14379 value.push(i[_this.valueField]);
14386 this.value = value.join(',');
14388 if(this.hiddenField){
14389 this.hiddenField.dom.value = this.value;
14392 this.store.fireEvent("datachanged", this.store);
14397 clearItem : function()
14399 if(!this.multiple){
14405 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14413 if(this.tickable && !Roo.isTouch){
14414 this.view.refresh();
14418 inputEl: function ()
14420 if(Roo.isIOS && this.useNativeIOS){
14421 return this.el.select('select.roo-ios-select', true).first();
14424 if(Roo.isTouch && this.mobileTouchView){
14425 return this.el.select('input.form-control',true).first();
14429 return this.searchField;
14432 return this.el.select('input.form-control',true).first();
14435 onTickableFooterButtonClick : function(e, btn, el)
14437 e.preventDefault();
14439 this.lastItem = Roo.apply([], this.item);
14441 if(btn && btn.name == 'cancel'){
14442 this.tickItems = Roo.apply([], this.item);
14451 Roo.each(this.tickItems, function(o){
14459 validate : function()
14461 var v = this.getRawValue();
14464 v = this.getValue();
14467 if(this.disabled || this.allowBlank || v.length){
14472 this.markInvalid();
14476 tickableInputEl : function()
14478 if(!this.tickable || !this.editable){
14479 return this.inputEl();
14482 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14486 getAutoCreateTouchView : function()
14491 cls: 'form-group' //input-group
14497 type : this.inputType,
14498 cls : 'form-control x-combo-noedit',
14499 autocomplete: 'new-password',
14500 placeholder : this.placeholder || '',
14505 input.name = this.name;
14509 input.cls += ' input-' + this.size;
14512 if (this.disabled) {
14513 input.disabled = true;
14524 inputblock.cls += ' input-group';
14526 inputblock.cn.unshift({
14528 cls : 'input-group-addon',
14533 if(this.removable && !this.multiple){
14534 inputblock.cls += ' roo-removable';
14536 inputblock.cn.push({
14539 cls : 'roo-combo-removable-btn close'
14543 if(this.hasFeedback && !this.allowBlank){
14545 inputblock.cls += ' has-feedback';
14547 inputblock.cn.push({
14549 cls: 'glyphicon form-control-feedback'
14556 inputblock.cls += (this.before) ? '' : ' input-group';
14558 inputblock.cn.push({
14560 cls : 'input-group-addon',
14571 cls: 'form-hidden-field'
14585 cls: 'form-hidden-field'
14589 cls: 'roo-select2-choices',
14593 cls: 'roo-select2-search-field',
14606 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14612 if(!this.multiple && this.showToggleBtn){
14619 if (this.caret != false) {
14622 cls: 'fa fa-' + this.caret
14629 cls : 'input-group-addon btn dropdown-toggle',
14634 cls: 'combobox-clear',
14648 combobox.cls += ' roo-select2-container-multi';
14651 var align = this.labelAlign || this.parentLabelAlign();
14653 if (align ==='left' && this.fieldLabel.length) {
14658 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14659 tooltip : 'This field is required'
14663 cls : 'control-label',
14664 html : this.fieldLabel
14675 var labelCfg = cfg.cn[1];
14676 var contentCfg = cfg.cn[2];
14679 if(this.indicatorpos == 'right'){
14683 cls : 'control-label',
14684 html : this.fieldLabel,
14688 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14689 tooltip : 'This field is required'
14702 labelCfg = cfg.cn[0];
14703 contentCfg = cfg.cn[2];
14705 if(this.labelWidth > 12){
14706 labelCfg.style = "width: " + this.labelWidth + 'px';
14709 if(this.labelWidth < 13 && this.labelmd == 0){
14710 this.labelmd = this.labelWidth;
14713 if(this.labellg > 0){
14714 labelCfg.cls += ' col-lg-' + this.labellg;
14715 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14718 if(this.labelmd > 0){
14719 labelCfg.cls += ' col-md-' + this.labelmd;
14720 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14723 if(this.labelsm > 0){
14724 labelCfg.cls += ' col-sm-' + this.labelsm;
14725 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14728 if(this.labelxs > 0){
14729 labelCfg.cls += ' col-xs-' + this.labelxs;
14730 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14734 } else if ( this.fieldLabel.length) {
14738 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14739 tooltip : 'This field is required'
14743 cls : 'control-label',
14744 html : this.fieldLabel
14755 if(this.indicatorpos == 'right'){
14759 cls : 'control-label',
14760 html : this.fieldLabel,
14764 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14765 tooltip : 'This field is required'
14782 var settings = this;
14784 ['xs','sm','md','lg'].map(function(size){
14785 if (settings[size]) {
14786 cfg.cls += ' col-' + size + '-' + settings[size];
14793 initTouchView : function()
14795 this.renderTouchView();
14797 this.touchViewEl.on('scroll', function(){
14798 this.el.dom.scrollTop = 0;
14801 this.originalValue = this.getValue();
14803 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14805 this.inputEl().on("click", this.showTouchView, this);
14806 if (this.triggerEl) {
14807 this.triggerEl.on("click", this.showTouchView, this);
14811 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14812 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14814 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14816 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14817 this.store.on('load', this.onTouchViewLoad, this);
14818 this.store.on('loadexception', this.onTouchViewLoadException, this);
14820 if(this.hiddenName){
14822 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14824 this.hiddenField.dom.value =
14825 this.hiddenValue !== undefined ? this.hiddenValue :
14826 this.value !== undefined ? this.value : '';
14828 this.el.dom.removeAttribute('name');
14829 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14833 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14834 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14837 if(this.removable && !this.multiple){
14838 var close = this.closeTriggerEl();
14840 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14841 close.on('click', this.removeBtnClick, this, close);
14845 * fix the bug in Safari iOS8
14847 this.inputEl().on("focus", function(e){
14848 document.activeElement.blur();
14856 renderTouchView : function()
14858 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14859 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14861 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14862 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14864 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14865 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14866 this.touchViewBodyEl.setStyle('overflow', 'auto');
14868 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14869 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14871 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14872 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14876 showTouchView : function()
14882 this.touchViewHeaderEl.hide();
14884 if(this.modalTitle.length){
14885 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14886 this.touchViewHeaderEl.show();
14889 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14890 this.touchViewEl.show();
14892 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14893 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14894 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14896 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14898 if(this.modalTitle.length){
14899 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14902 this.touchViewBodyEl.setHeight(bodyHeight);
14906 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14908 this.touchViewEl.addClass('in');
14911 this.doTouchViewQuery();
14915 hideTouchView : function()
14917 this.touchViewEl.removeClass('in');
14921 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14923 this.touchViewEl.setStyle('display', 'none');
14928 setTouchViewValue : function()
14935 Roo.each(this.tickItems, function(o){
14940 this.hideTouchView();
14943 doTouchViewQuery : function()
14952 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14956 if(!this.alwaysQuery || this.mode == 'local'){
14957 this.onTouchViewLoad();
14964 onTouchViewBeforeLoad : function(combo,opts)
14970 onTouchViewLoad : function()
14972 if(this.store.getCount() < 1){
14973 this.onTouchViewEmptyResults();
14977 this.clearTouchView();
14979 var rawValue = this.getRawValue();
14981 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14983 this.tickItems = [];
14985 this.store.data.each(function(d, rowIndex){
14986 var row = this.touchViewListGroup.createChild(template);
14988 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14989 row.addClass(d.data.cls);
14992 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14995 html : d.data[this.displayField]
14998 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14999 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15002 row.removeClass('selected');
15003 if(!this.multiple && this.valueField &&
15004 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15007 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15008 row.addClass('selected');
15011 if(this.multiple && this.valueField &&
15012 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15016 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15017 this.tickItems.push(d.data);
15020 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15024 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15026 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15028 if(this.modalTitle.length){
15029 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15032 var listHeight = this.touchViewListGroup.getHeight();
15036 if(firstChecked && listHeight > bodyHeight){
15037 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15042 onTouchViewLoadException : function()
15044 this.hideTouchView();
15047 onTouchViewEmptyResults : function()
15049 this.clearTouchView();
15051 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15053 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15057 clearTouchView : function()
15059 this.touchViewListGroup.dom.innerHTML = '';
15062 onTouchViewClick : function(e, el, o)
15064 e.preventDefault();
15067 var rowIndex = o.rowIndex;
15069 var r = this.store.getAt(rowIndex);
15071 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15073 if(!this.multiple){
15074 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15075 c.dom.removeAttribute('checked');
15078 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15080 this.setFromData(r.data);
15082 var close = this.closeTriggerEl();
15088 this.hideTouchView();
15090 this.fireEvent('select', this, r, rowIndex);
15095 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15096 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15097 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15101 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15102 this.addItem(r.data);
15103 this.tickItems.push(r.data);
15107 getAutoCreateNativeIOS : function()
15110 cls: 'form-group' //input-group,
15115 cls : 'roo-ios-select'
15119 combobox.name = this.name;
15122 if (this.disabled) {
15123 combobox.disabled = true;
15126 var settings = this;
15128 ['xs','sm','md','lg'].map(function(size){
15129 if (settings[size]) {
15130 cfg.cls += ' col-' + size + '-' + settings[size];
15140 initIOSView : function()
15142 this.store.on('load', this.onIOSViewLoad, this);
15147 onIOSViewLoad : function()
15149 if(this.store.getCount() < 1){
15153 this.clearIOSView();
15155 if(this.allowBlank) {
15157 var default_text = '-- SELECT --';
15159 var opt = this.inputEl().createChild({
15162 html : default_text
15166 o[this.valueField] = 0;
15167 o[this.displayField] = default_text;
15169 this.ios_options.push({
15176 this.store.data.each(function(d, rowIndex){
15180 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15181 html = d.data[this.displayField];
15186 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15187 value = d.data[this.valueField];
15196 if(this.value == d.data[this.valueField]){
15197 option['selected'] = true;
15200 var opt = this.inputEl().createChild(option);
15202 this.ios_options.push({
15209 this.inputEl().on('change', function(){
15210 this.fireEvent('select', this);
15215 clearIOSView: function()
15217 this.inputEl().dom.innerHTML = '';
15219 this.ios_options = [];
15222 setIOSValue: function(v)
15226 if(!this.ios_options){
15230 Roo.each(this.ios_options, function(opts){
15232 opts.el.dom.removeAttribute('selected');
15234 if(opts.data[this.valueField] != v){
15238 opts.el.dom.setAttribute('selected', true);
15244 * @cfg {Boolean} grow
15248 * @cfg {Number} growMin
15252 * @cfg {Number} growMax
15261 Roo.apply(Roo.bootstrap.ComboBox, {
15265 cls: 'modal-header',
15287 cls: 'list-group-item',
15291 cls: 'roo-combobox-list-group-item-value'
15295 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15309 listItemCheckbox : {
15311 cls: 'list-group-item',
15315 cls: 'roo-combobox-list-group-item-value'
15319 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15335 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15340 cls: 'modal-footer',
15348 cls: 'col-xs-6 text-left',
15351 cls: 'btn btn-danger roo-touch-view-cancel',
15357 cls: 'col-xs-6 text-right',
15360 cls: 'btn btn-success roo-touch-view-ok',
15371 Roo.apply(Roo.bootstrap.ComboBox, {
15373 touchViewTemplate : {
15375 cls: 'modal fade roo-combobox-touch-view',
15379 cls: 'modal-dialog',
15380 style : 'position:fixed', // we have to fix position....
15384 cls: 'modal-content',
15386 Roo.bootstrap.ComboBox.header,
15387 Roo.bootstrap.ComboBox.body,
15388 Roo.bootstrap.ComboBox.footer
15397 * Ext JS Library 1.1.1
15398 * Copyright(c) 2006-2007, Ext JS, LLC.
15400 * Originally Released Under LGPL - original licence link has changed is not relivant.
15403 * <script type="text/javascript">
15408 * @extends Roo.util.Observable
15409 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15410 * This class also supports single and multi selection modes. <br>
15411 * Create a data model bound view:
15413 var store = new Roo.data.Store(...);
15415 var view = new Roo.View({
15417 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15419 singleSelect: true,
15420 selectedClass: "ydataview-selected",
15424 // listen for node click?
15425 view.on("click", function(vw, index, node, e){
15426 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15430 dataModel.load("foobar.xml");
15432 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15434 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15435 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15437 * Note: old style constructor is still suported (container, template, config)
15440 * Create a new View
15441 * @param {Object} config The config object
15444 Roo.View = function(config, depreciated_tpl, depreciated_config){
15446 this.parent = false;
15448 if (typeof(depreciated_tpl) == 'undefined') {
15449 // new way.. - universal constructor.
15450 Roo.apply(this, config);
15451 this.el = Roo.get(this.el);
15454 this.el = Roo.get(config);
15455 this.tpl = depreciated_tpl;
15456 Roo.apply(this, depreciated_config);
15458 this.wrapEl = this.el.wrap().wrap();
15459 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15462 if(typeof(this.tpl) == "string"){
15463 this.tpl = new Roo.Template(this.tpl);
15465 // support xtype ctors..
15466 this.tpl = new Roo.factory(this.tpl, Roo);
15470 this.tpl.compile();
15475 * @event beforeclick
15476 * Fires before a click is processed. Returns false to cancel the default action.
15477 * @param {Roo.View} this
15478 * @param {Number} index The index of the target node
15479 * @param {HTMLElement} node The target node
15480 * @param {Roo.EventObject} e The raw event object
15482 "beforeclick" : true,
15485 * Fires when a template node is clicked.
15486 * @param {Roo.View} this
15487 * @param {Number} index The index of the target node
15488 * @param {HTMLElement} node The target node
15489 * @param {Roo.EventObject} e The raw event object
15494 * Fires when a template node is double clicked.
15495 * @param {Roo.View} this
15496 * @param {Number} index The index of the target node
15497 * @param {HTMLElement} node The target node
15498 * @param {Roo.EventObject} e The raw event object
15502 * @event contextmenu
15503 * Fires when a template node is right clicked.
15504 * @param {Roo.View} this
15505 * @param {Number} index The index of the target node
15506 * @param {HTMLElement} node The target node
15507 * @param {Roo.EventObject} e The raw event object
15509 "contextmenu" : true,
15511 * @event selectionchange
15512 * Fires when the selected nodes change.
15513 * @param {Roo.View} this
15514 * @param {Array} selections Array of the selected nodes
15516 "selectionchange" : true,
15519 * @event beforeselect
15520 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15521 * @param {Roo.View} this
15522 * @param {HTMLElement} node The node to be selected
15523 * @param {Array} selections Array of currently selected nodes
15525 "beforeselect" : true,
15527 * @event preparedata
15528 * Fires on every row to render, to allow you to change the data.
15529 * @param {Roo.View} this
15530 * @param {Object} data to be rendered (change this)
15532 "preparedata" : true
15540 "click": this.onClick,
15541 "dblclick": this.onDblClick,
15542 "contextmenu": this.onContextMenu,
15546 this.selections = [];
15548 this.cmp = new Roo.CompositeElementLite([]);
15550 this.store = Roo.factory(this.store, Roo.data);
15551 this.setStore(this.store, true);
15554 if ( this.footer && this.footer.xtype) {
15556 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15558 this.footer.dataSource = this.store;
15559 this.footer.container = fctr;
15560 this.footer = Roo.factory(this.footer, Roo);
15561 fctr.insertFirst(this.el);
15563 // this is a bit insane - as the paging toolbar seems to detach the el..
15564 // dom.parentNode.parentNode.parentNode
15565 // they get detached?
15569 Roo.View.superclass.constructor.call(this);
15574 Roo.extend(Roo.View, Roo.util.Observable, {
15577 * @cfg {Roo.data.Store} store Data store to load data from.
15582 * @cfg {String|Roo.Element} el The container element.
15587 * @cfg {String|Roo.Template} tpl The template used by this View
15591 * @cfg {String} dataName the named area of the template to use as the data area
15592 * Works with domtemplates roo-name="name"
15596 * @cfg {String} selectedClass The css class to add to selected nodes
15598 selectedClass : "x-view-selected",
15600 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15605 * @cfg {String} text to display on mask (default Loading)
15609 * @cfg {Boolean} multiSelect Allow multiple selection
15611 multiSelect : false,
15613 * @cfg {Boolean} singleSelect Allow single selection
15615 singleSelect: false,
15618 * @cfg {Boolean} toggleSelect - selecting
15620 toggleSelect : false,
15623 * @cfg {Boolean} tickable - selecting
15628 * Returns the element this view is bound to.
15629 * @return {Roo.Element}
15631 getEl : function(){
15632 return this.wrapEl;
15638 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15640 refresh : function(){
15641 //Roo.log('refresh');
15644 // if we are using something like 'domtemplate', then
15645 // the what gets used is:
15646 // t.applySubtemplate(NAME, data, wrapping data..)
15647 // the outer template then get' applied with
15648 // the store 'extra data'
15649 // and the body get's added to the
15650 // roo-name="data" node?
15651 // <span class='roo-tpl-{name}'></span> ?????
15655 this.clearSelections();
15656 this.el.update("");
15658 var records = this.store.getRange();
15659 if(records.length < 1) {
15661 // is this valid?? = should it render a template??
15663 this.el.update(this.emptyText);
15667 if (this.dataName) {
15668 this.el.update(t.apply(this.store.meta)); //????
15669 el = this.el.child('.roo-tpl-' + this.dataName);
15672 for(var i = 0, len = records.length; i < len; i++){
15673 var data = this.prepareData(records[i].data, i, records[i]);
15674 this.fireEvent("preparedata", this, data, i, records[i]);
15676 var d = Roo.apply({}, data);
15679 Roo.apply(d, {'roo-id' : Roo.id()});
15683 Roo.each(this.parent.item, function(item){
15684 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15687 Roo.apply(d, {'roo-data-checked' : 'checked'});
15691 html[html.length] = Roo.util.Format.trim(
15693 t.applySubtemplate(this.dataName, d, this.store.meta) :
15700 el.update(html.join(""));
15701 this.nodes = el.dom.childNodes;
15702 this.updateIndexes(0);
15707 * Function to override to reformat the data that is sent to
15708 * the template for each node.
15709 * DEPRICATED - use the preparedata event handler.
15710 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15711 * a JSON object for an UpdateManager bound view).
15713 prepareData : function(data, index, record)
15715 this.fireEvent("preparedata", this, data, index, record);
15719 onUpdate : function(ds, record){
15720 // Roo.log('on update');
15721 this.clearSelections();
15722 var index = this.store.indexOf(record);
15723 var n = this.nodes[index];
15724 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15725 n.parentNode.removeChild(n);
15726 this.updateIndexes(index, index);
15732 onAdd : function(ds, records, index)
15734 //Roo.log(['on Add', ds, records, index] );
15735 this.clearSelections();
15736 if(this.nodes.length == 0){
15740 var n = this.nodes[index];
15741 for(var i = 0, len = records.length; i < len; i++){
15742 var d = this.prepareData(records[i].data, i, records[i]);
15744 this.tpl.insertBefore(n, d);
15747 this.tpl.append(this.el, d);
15750 this.updateIndexes(index);
15753 onRemove : function(ds, record, index){
15754 // Roo.log('onRemove');
15755 this.clearSelections();
15756 var el = this.dataName ?
15757 this.el.child('.roo-tpl-' + this.dataName) :
15760 el.dom.removeChild(this.nodes[index]);
15761 this.updateIndexes(index);
15765 * Refresh an individual node.
15766 * @param {Number} index
15768 refreshNode : function(index){
15769 this.onUpdate(this.store, this.store.getAt(index));
15772 updateIndexes : function(startIndex, endIndex){
15773 var ns = this.nodes;
15774 startIndex = startIndex || 0;
15775 endIndex = endIndex || ns.length - 1;
15776 for(var i = startIndex; i <= endIndex; i++){
15777 ns[i].nodeIndex = i;
15782 * Changes the data store this view uses and refresh the view.
15783 * @param {Store} store
15785 setStore : function(store, initial){
15786 if(!initial && this.store){
15787 this.store.un("datachanged", this.refresh);
15788 this.store.un("add", this.onAdd);
15789 this.store.un("remove", this.onRemove);
15790 this.store.un("update", this.onUpdate);
15791 this.store.un("clear", this.refresh);
15792 this.store.un("beforeload", this.onBeforeLoad);
15793 this.store.un("load", this.onLoad);
15794 this.store.un("loadexception", this.onLoad);
15798 store.on("datachanged", this.refresh, this);
15799 store.on("add", this.onAdd, this);
15800 store.on("remove", this.onRemove, this);
15801 store.on("update", this.onUpdate, this);
15802 store.on("clear", this.refresh, this);
15803 store.on("beforeload", this.onBeforeLoad, this);
15804 store.on("load", this.onLoad, this);
15805 store.on("loadexception", this.onLoad, this);
15813 * onbeforeLoad - masks the loading area.
15816 onBeforeLoad : function(store,opts)
15818 //Roo.log('onBeforeLoad');
15820 this.el.update("");
15822 this.el.mask(this.mask ? this.mask : "Loading" );
15824 onLoad : function ()
15831 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15832 * @param {HTMLElement} node
15833 * @return {HTMLElement} The template node
15835 findItemFromChild : function(node){
15836 var el = this.dataName ?
15837 this.el.child('.roo-tpl-' + this.dataName,true) :
15840 if(!node || node.parentNode == el){
15843 var p = node.parentNode;
15844 while(p && p != el){
15845 if(p.parentNode == el){
15854 onClick : function(e){
15855 var item = this.findItemFromChild(e.getTarget());
15857 var index = this.indexOf(item);
15858 if(this.onItemClick(item, index, e) !== false){
15859 this.fireEvent("click", this, index, item, e);
15862 this.clearSelections();
15867 onContextMenu : function(e){
15868 var item = this.findItemFromChild(e.getTarget());
15870 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15875 onDblClick : function(e){
15876 var item = this.findItemFromChild(e.getTarget());
15878 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15882 onItemClick : function(item, index, e)
15884 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15887 if (this.toggleSelect) {
15888 var m = this.isSelected(item) ? 'unselect' : 'select';
15891 _t[m](item, true, false);
15894 if(this.multiSelect || this.singleSelect){
15895 if(this.multiSelect && e.shiftKey && this.lastSelection){
15896 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15898 this.select(item, this.multiSelect && e.ctrlKey);
15899 this.lastSelection = item;
15902 if(!this.tickable){
15903 e.preventDefault();
15911 * Get the number of selected nodes.
15914 getSelectionCount : function(){
15915 return this.selections.length;
15919 * Get the currently selected nodes.
15920 * @return {Array} An array of HTMLElements
15922 getSelectedNodes : function(){
15923 return this.selections;
15927 * Get the indexes of the selected nodes.
15930 getSelectedIndexes : function(){
15931 var indexes = [], s = this.selections;
15932 for(var i = 0, len = s.length; i < len; i++){
15933 indexes.push(s[i].nodeIndex);
15939 * Clear all selections
15940 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15942 clearSelections : function(suppressEvent){
15943 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15944 this.cmp.elements = this.selections;
15945 this.cmp.removeClass(this.selectedClass);
15946 this.selections = [];
15947 if(!suppressEvent){
15948 this.fireEvent("selectionchange", this, this.selections);
15954 * Returns true if the passed node is selected
15955 * @param {HTMLElement/Number} node The node or node index
15956 * @return {Boolean}
15958 isSelected : function(node){
15959 var s = this.selections;
15963 node = this.getNode(node);
15964 return s.indexOf(node) !== -1;
15969 * @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
15970 * @param {Boolean} keepExisting (optional) true to keep existing selections
15971 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15973 select : function(nodeInfo, keepExisting, suppressEvent){
15974 if(nodeInfo instanceof Array){
15976 this.clearSelections(true);
15978 for(var i = 0, len = nodeInfo.length; i < len; i++){
15979 this.select(nodeInfo[i], true, true);
15983 var node = this.getNode(nodeInfo);
15984 if(!node || this.isSelected(node)){
15985 return; // already selected.
15988 this.clearSelections(true);
15991 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15992 Roo.fly(node).addClass(this.selectedClass);
15993 this.selections.push(node);
15994 if(!suppressEvent){
15995 this.fireEvent("selectionchange", this, this.selections);
16003 * @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
16004 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16005 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16007 unselect : function(nodeInfo, keepExisting, suppressEvent)
16009 if(nodeInfo instanceof Array){
16010 Roo.each(this.selections, function(s) {
16011 this.unselect(s, nodeInfo);
16015 var node = this.getNode(nodeInfo);
16016 if(!node || !this.isSelected(node)){
16017 //Roo.log("not selected");
16018 return; // not selected.
16022 Roo.each(this.selections, function(s) {
16024 Roo.fly(node).removeClass(this.selectedClass);
16031 this.selections= ns;
16032 this.fireEvent("selectionchange", this, this.selections);
16036 * Gets a template node.
16037 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16038 * @return {HTMLElement} The node or null if it wasn't found
16040 getNode : function(nodeInfo){
16041 if(typeof nodeInfo == "string"){
16042 return document.getElementById(nodeInfo);
16043 }else if(typeof nodeInfo == "number"){
16044 return this.nodes[nodeInfo];
16050 * Gets a range template nodes.
16051 * @param {Number} startIndex
16052 * @param {Number} endIndex
16053 * @return {Array} An array of nodes
16055 getNodes : function(start, end){
16056 var ns = this.nodes;
16057 start = start || 0;
16058 end = typeof end == "undefined" ? ns.length - 1 : end;
16061 for(var i = start; i <= end; i++){
16065 for(var i = start; i >= end; i--){
16073 * Finds the index of the passed node
16074 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16075 * @return {Number} The index of the node or -1
16077 indexOf : function(node){
16078 node = this.getNode(node);
16079 if(typeof node.nodeIndex == "number"){
16080 return node.nodeIndex;
16082 var ns = this.nodes;
16083 for(var i = 0, len = ns.length; i < len; i++){
16094 * based on jquery fullcalendar
16098 Roo.bootstrap = Roo.bootstrap || {};
16100 * @class Roo.bootstrap.Calendar
16101 * @extends Roo.bootstrap.Component
16102 * Bootstrap Calendar class
16103 * @cfg {Boolean} loadMask (true|false) default false
16104 * @cfg {Object} header generate the user specific header of the calendar, default false
16107 * Create a new Container
16108 * @param {Object} config The config object
16113 Roo.bootstrap.Calendar = function(config){
16114 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16118 * Fires when a date is selected
16119 * @param {DatePicker} this
16120 * @param {Date} date The selected date
16124 * @event monthchange
16125 * Fires when the displayed month changes
16126 * @param {DatePicker} this
16127 * @param {Date} date The selected month
16129 'monthchange': true,
16131 * @event evententer
16132 * Fires when mouse over an event
16133 * @param {Calendar} this
16134 * @param {event} Event
16136 'evententer': true,
16138 * @event eventleave
16139 * Fires when the mouse leaves an
16140 * @param {Calendar} this
16143 'eventleave': true,
16145 * @event eventclick
16146 * Fires when the mouse click an
16147 * @param {Calendar} this
16156 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16159 * @cfg {Number} startDay
16160 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16168 getAutoCreate : function(){
16171 var fc_button = function(name, corner, style, content ) {
16172 return Roo.apply({},{
16174 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16176 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16179 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16190 style : 'width:100%',
16197 cls : 'fc-header-left',
16199 fc_button('prev', 'left', 'arrow', '‹' ),
16200 fc_button('next', 'right', 'arrow', '›' ),
16201 { tag: 'span', cls: 'fc-header-space' },
16202 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16210 cls : 'fc-header-center',
16214 cls: 'fc-header-title',
16217 html : 'month / year'
16225 cls : 'fc-header-right',
16227 /* fc_button('month', 'left', '', 'month' ),
16228 fc_button('week', '', '', 'week' ),
16229 fc_button('day', 'right', '', 'day' )
16241 header = this.header;
16244 var cal_heads = function() {
16246 // fixme - handle this.
16248 for (var i =0; i < Date.dayNames.length; i++) {
16249 var d = Date.dayNames[i];
16252 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16253 html : d.substring(0,3)
16257 ret[0].cls += ' fc-first';
16258 ret[6].cls += ' fc-last';
16261 var cal_cell = function(n) {
16264 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16269 cls: 'fc-day-number',
16273 cls: 'fc-day-content',
16277 style: 'position: relative;' // height: 17px;
16289 var cal_rows = function() {
16292 for (var r = 0; r < 6; r++) {
16299 for (var i =0; i < Date.dayNames.length; i++) {
16300 var d = Date.dayNames[i];
16301 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16304 row.cn[0].cls+=' fc-first';
16305 row.cn[0].cn[0].style = 'min-height:90px';
16306 row.cn[6].cls+=' fc-last';
16310 ret[0].cls += ' fc-first';
16311 ret[4].cls += ' fc-prev-last';
16312 ret[5].cls += ' fc-last';
16319 cls: 'fc-border-separate',
16320 style : 'width:100%',
16328 cls : 'fc-first fc-last',
16346 cls : 'fc-content',
16347 style : "position: relative;",
16350 cls : 'fc-view fc-view-month fc-grid',
16351 style : 'position: relative',
16352 unselectable : 'on',
16355 cls : 'fc-event-container',
16356 style : 'position:absolute;z-index:8;top:0;left:0;'
16374 initEvents : function()
16377 throw "can not find store for calendar";
16383 style: "text-align:center",
16387 style: "background-color:white;width:50%;margin:250 auto",
16391 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16402 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16404 var size = this.el.select('.fc-content', true).first().getSize();
16405 this.maskEl.setSize(size.width, size.height);
16406 this.maskEl.enableDisplayMode("block");
16407 if(!this.loadMask){
16408 this.maskEl.hide();
16411 this.store = Roo.factory(this.store, Roo.data);
16412 this.store.on('load', this.onLoad, this);
16413 this.store.on('beforeload', this.onBeforeLoad, this);
16417 this.cells = this.el.select('.fc-day',true);
16418 //Roo.log(this.cells);
16419 this.textNodes = this.el.query('.fc-day-number');
16420 this.cells.addClassOnOver('fc-state-hover');
16422 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16423 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16424 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16425 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16427 this.on('monthchange', this.onMonthChange, this);
16429 this.update(new Date().clearTime());
16432 resize : function() {
16433 var sz = this.el.getSize();
16435 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16436 this.el.select('.fc-day-content div',true).setHeight(34);
16441 showPrevMonth : function(e){
16442 this.update(this.activeDate.add("mo", -1));
16444 showToday : function(e){
16445 this.update(new Date().clearTime());
16448 showNextMonth : function(e){
16449 this.update(this.activeDate.add("mo", 1));
16453 showPrevYear : function(){
16454 this.update(this.activeDate.add("y", -1));
16458 showNextYear : function(){
16459 this.update(this.activeDate.add("y", 1));
16464 update : function(date)
16466 var vd = this.activeDate;
16467 this.activeDate = date;
16468 // if(vd && this.el){
16469 // var t = date.getTime();
16470 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16471 // Roo.log('using add remove');
16473 // this.fireEvent('monthchange', this, date);
16475 // this.cells.removeClass("fc-state-highlight");
16476 // this.cells.each(function(c){
16477 // if(c.dateValue == t){
16478 // c.addClass("fc-state-highlight");
16479 // setTimeout(function(){
16480 // try{c.dom.firstChild.focus();}catch(e){}
16490 var days = date.getDaysInMonth();
16492 var firstOfMonth = date.getFirstDateOfMonth();
16493 var startingPos = firstOfMonth.getDay()-this.startDay;
16495 if(startingPos < this.startDay){
16499 var pm = date.add(Date.MONTH, -1);
16500 var prevStart = pm.getDaysInMonth()-startingPos;
16502 this.cells = this.el.select('.fc-day',true);
16503 this.textNodes = this.el.query('.fc-day-number');
16504 this.cells.addClassOnOver('fc-state-hover');
16506 var cells = this.cells.elements;
16507 var textEls = this.textNodes;
16509 Roo.each(cells, function(cell){
16510 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16513 days += startingPos;
16515 // convert everything to numbers so it's fast
16516 var day = 86400000;
16517 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16520 //Roo.log(prevStart);
16522 var today = new Date().clearTime().getTime();
16523 var sel = date.clearTime().getTime();
16524 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16525 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16526 var ddMatch = this.disabledDatesRE;
16527 var ddText = this.disabledDatesText;
16528 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16529 var ddaysText = this.disabledDaysText;
16530 var format = this.format;
16532 var setCellClass = function(cal, cell){
16536 //Roo.log('set Cell Class');
16538 var t = d.getTime();
16542 cell.dateValue = t;
16544 cell.className += " fc-today";
16545 cell.className += " fc-state-highlight";
16546 cell.title = cal.todayText;
16549 // disable highlight in other month..
16550 //cell.className += " fc-state-highlight";
16555 cell.className = " fc-state-disabled";
16556 cell.title = cal.minText;
16560 cell.className = " fc-state-disabled";
16561 cell.title = cal.maxText;
16565 if(ddays.indexOf(d.getDay()) != -1){
16566 cell.title = ddaysText;
16567 cell.className = " fc-state-disabled";
16570 if(ddMatch && format){
16571 var fvalue = d.dateFormat(format);
16572 if(ddMatch.test(fvalue)){
16573 cell.title = ddText.replace("%0", fvalue);
16574 cell.className = " fc-state-disabled";
16578 if (!cell.initialClassName) {
16579 cell.initialClassName = cell.dom.className;
16582 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16587 for(; i < startingPos; i++) {
16588 textEls[i].innerHTML = (++prevStart);
16589 d.setDate(d.getDate()+1);
16591 cells[i].className = "fc-past fc-other-month";
16592 setCellClass(this, cells[i]);
16597 for(; i < days; i++){
16598 intDay = i - startingPos + 1;
16599 textEls[i].innerHTML = (intDay);
16600 d.setDate(d.getDate()+1);
16602 cells[i].className = ''; // "x-date-active";
16603 setCellClass(this, cells[i]);
16607 for(; i < 42; i++) {
16608 textEls[i].innerHTML = (++extraDays);
16609 d.setDate(d.getDate()+1);
16611 cells[i].className = "fc-future fc-other-month";
16612 setCellClass(this, cells[i]);
16615 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16617 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16619 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16620 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16622 if(totalRows != 6){
16623 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16624 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16627 this.fireEvent('monthchange', this, date);
16631 if(!this.internalRender){
16632 var main = this.el.dom.firstChild;
16633 var w = main.offsetWidth;
16634 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16635 Roo.fly(main).setWidth(w);
16636 this.internalRender = true;
16637 // opera does not respect the auto grow header center column
16638 // then, after it gets a width opera refuses to recalculate
16639 // without a second pass
16640 if(Roo.isOpera && !this.secondPass){
16641 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16642 this.secondPass = true;
16643 this.update.defer(10, this, [date]);
16650 findCell : function(dt) {
16651 dt = dt.clearTime().getTime();
16653 this.cells.each(function(c){
16654 //Roo.log("check " +c.dateValue + '?=' + dt);
16655 if(c.dateValue == dt){
16665 findCells : function(ev) {
16666 var s = ev.start.clone().clearTime().getTime();
16668 var e= ev.end.clone().clearTime().getTime();
16671 this.cells.each(function(c){
16672 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16674 if(c.dateValue > e){
16677 if(c.dateValue < s){
16686 // findBestRow: function(cells)
16690 // for (var i =0 ; i < cells.length;i++) {
16691 // ret = Math.max(cells[i].rows || 0,ret);
16698 addItem : function(ev)
16700 // look for vertical location slot in
16701 var cells = this.findCells(ev);
16703 // ev.row = this.findBestRow(cells);
16705 // work out the location.
16709 for(var i =0; i < cells.length; i++) {
16711 cells[i].row = cells[0].row;
16714 cells[i].row = cells[i].row + 1;
16724 if (crow.start.getY() == cells[i].getY()) {
16726 crow.end = cells[i];
16743 cells[0].events.push(ev);
16745 this.calevents.push(ev);
16748 clearEvents: function() {
16750 if(!this.calevents){
16754 Roo.each(this.cells.elements, function(c){
16760 Roo.each(this.calevents, function(e) {
16761 Roo.each(e.els, function(el) {
16762 el.un('mouseenter' ,this.onEventEnter, this);
16763 el.un('mouseleave' ,this.onEventLeave, this);
16768 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16774 renderEvents: function()
16778 this.cells.each(function(c) {
16787 if(c.row != c.events.length){
16788 r = 4 - (4 - (c.row - c.events.length));
16791 c.events = ev.slice(0, r);
16792 c.more = ev.slice(r);
16794 if(c.more.length && c.more.length == 1){
16795 c.events.push(c.more.pop());
16798 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16802 this.cells.each(function(c) {
16804 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16807 for (var e = 0; e < c.events.length; e++){
16808 var ev = c.events[e];
16809 var rows = ev.rows;
16811 for(var i = 0; i < rows.length; i++) {
16813 // how many rows should it span..
16816 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16817 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16819 unselectable : "on",
16822 cls: 'fc-event-inner',
16826 // cls: 'fc-event-time',
16827 // html : cells.length > 1 ? '' : ev.time
16831 cls: 'fc-event-title',
16832 html : String.format('{0}', ev.title)
16839 cls: 'ui-resizable-handle ui-resizable-e',
16840 html : '  '
16847 cfg.cls += ' fc-event-start';
16849 if ((i+1) == rows.length) {
16850 cfg.cls += ' fc-event-end';
16853 var ctr = _this.el.select('.fc-event-container',true).first();
16854 var cg = ctr.createChild(cfg);
16856 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16857 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16859 var r = (c.more.length) ? 1 : 0;
16860 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16861 cg.setWidth(ebox.right - sbox.x -2);
16863 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16864 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16865 cg.on('click', _this.onEventClick, _this, ev);
16876 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16877 style : 'position: absolute',
16878 unselectable : "on",
16881 cls: 'fc-event-inner',
16885 cls: 'fc-event-title',
16893 cls: 'ui-resizable-handle ui-resizable-e',
16894 html : '  '
16900 var ctr = _this.el.select('.fc-event-container',true).first();
16901 var cg = ctr.createChild(cfg);
16903 var sbox = c.select('.fc-day-content',true).first().getBox();
16904 var ebox = c.select('.fc-day-content',true).first().getBox();
16906 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16907 cg.setWidth(ebox.right - sbox.x -2);
16909 cg.on('click', _this.onMoreEventClick, _this, c.more);
16919 onEventEnter: function (e, el,event,d) {
16920 this.fireEvent('evententer', this, el, event);
16923 onEventLeave: function (e, el,event,d) {
16924 this.fireEvent('eventleave', this, el, event);
16927 onEventClick: function (e, el,event,d) {
16928 this.fireEvent('eventclick', this, el, event);
16931 onMonthChange: function () {
16935 onMoreEventClick: function(e, el, more)
16939 this.calpopover.placement = 'right';
16940 this.calpopover.setTitle('More');
16942 this.calpopover.setContent('');
16944 var ctr = this.calpopover.el.select('.popover-content', true).first();
16946 Roo.each(more, function(m){
16948 cls : 'fc-event-hori fc-event-draggable',
16951 var cg = ctr.createChild(cfg);
16953 cg.on('click', _this.onEventClick, _this, m);
16956 this.calpopover.show(el);
16961 onLoad: function ()
16963 this.calevents = [];
16966 if(this.store.getCount() > 0){
16967 this.store.data.each(function(d){
16970 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16971 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16972 time : d.data.start_time,
16973 title : d.data.title,
16974 description : d.data.description,
16975 venue : d.data.venue
16980 this.renderEvents();
16982 if(this.calevents.length && this.loadMask){
16983 this.maskEl.hide();
16987 onBeforeLoad: function()
16989 this.clearEvents();
16991 this.maskEl.show();
17005 * @class Roo.bootstrap.Popover
17006 * @extends Roo.bootstrap.Component
17007 * Bootstrap Popover class
17008 * @cfg {String} html contents of the popover (or false to use children..)
17009 * @cfg {String} title of popover (or false to hide)
17010 * @cfg {String} placement how it is placed
17011 * @cfg {String} trigger click || hover (or false to trigger manually)
17012 * @cfg {String} over what (parent or false to trigger manually.)
17013 * @cfg {Number} delay - delay before showing
17016 * Create a new Popover
17017 * @param {Object} config The config object
17020 Roo.bootstrap.Popover = function(config){
17021 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17027 * After the popover show
17029 * @param {Roo.bootstrap.Popover} this
17034 * After the popover hide
17036 * @param {Roo.bootstrap.Popover} this
17042 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17044 title: 'Fill in a title',
17047 placement : 'right',
17048 trigger : 'hover', // hover
17054 can_build_overlaid : false,
17056 getChildContainer : function()
17058 return this.el.select('.popover-content',true).first();
17061 getAutoCreate : function(){
17064 cls : 'popover roo-dynamic',
17065 style: 'display:block',
17071 cls : 'popover-inner',
17075 cls: 'popover-title',
17079 cls : 'popover-content',
17090 setTitle: function(str)
17093 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17095 setContent: function(str)
17098 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17100 // as it get's added to the bottom of the page.
17101 onRender : function(ct, position)
17103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17105 var cfg = Roo.apply({}, this.getAutoCreate());
17109 cfg.cls += ' ' + this.cls;
17112 cfg.style = this.style;
17114 //Roo.log("adding to ");
17115 this.el = Roo.get(document.body).createChild(cfg, position);
17116 // Roo.log(this.el);
17121 initEvents : function()
17123 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17124 this.el.enableDisplayMode('block');
17126 if (this.over === false) {
17129 if (this.triggers === false) {
17132 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17133 var triggers = this.trigger ? this.trigger.split(' ') : [];
17134 Roo.each(triggers, function(trigger) {
17136 if (trigger == 'click') {
17137 on_el.on('click', this.toggle, this);
17138 } else if (trigger != 'manual') {
17139 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17140 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17142 on_el.on(eventIn ,this.enter, this);
17143 on_el.on(eventOut, this.leave, this);
17154 toggle : function () {
17155 this.hoverState == 'in' ? this.leave() : this.enter();
17158 enter : function () {
17160 clearTimeout(this.timeout);
17162 this.hoverState = 'in';
17164 if (!this.delay || !this.delay.show) {
17169 this.timeout = setTimeout(function () {
17170 if (_t.hoverState == 'in') {
17173 }, this.delay.show)
17176 leave : function() {
17177 clearTimeout(this.timeout);
17179 this.hoverState = 'out';
17181 if (!this.delay || !this.delay.hide) {
17186 this.timeout = setTimeout(function () {
17187 if (_t.hoverState == 'out') {
17190 }, this.delay.hide)
17193 show : function (on_el)
17196 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17200 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17201 if (this.html !== false) {
17202 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17204 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17205 if (!this.title.length) {
17206 this.el.select('.popover-title',true).hide();
17209 var placement = typeof this.placement == 'function' ?
17210 this.placement.call(this, this.el, on_el) :
17213 var autoToken = /\s?auto?\s?/i;
17214 var autoPlace = autoToken.test(placement);
17216 placement = placement.replace(autoToken, '') || 'top';
17220 //this.el.setXY([0,0]);
17222 this.el.dom.style.display='block';
17223 this.el.addClass(placement);
17225 //this.el.appendTo(on_el);
17227 var p = this.getPosition();
17228 var box = this.el.getBox();
17233 var align = Roo.bootstrap.Popover.alignment[placement];
17234 this.el.alignTo(on_el, align[0],align[1]);
17235 //var arrow = this.el.select('.arrow',true).first();
17236 //arrow.set(align[2],
17238 this.el.addClass('in');
17241 if (this.el.hasClass('fade')) {
17245 this.hoverState = 'in';
17247 this.fireEvent('show', this);
17252 this.el.setXY([0,0]);
17253 this.el.removeClass('in');
17255 this.hoverState = null;
17257 this.fireEvent('hide', this);
17262 Roo.bootstrap.Popover.alignment = {
17263 'left' : ['r-l', [-10,0], 'right'],
17264 'right' : ['l-r', [10,0], 'left'],
17265 'bottom' : ['t-b', [0,10], 'top'],
17266 'top' : [ 'b-t', [0,-10], 'bottom']
17277 * @class Roo.bootstrap.Progress
17278 * @extends Roo.bootstrap.Component
17279 * Bootstrap Progress class
17280 * @cfg {Boolean} striped striped of the progress bar
17281 * @cfg {Boolean} active animated of the progress bar
17285 * Create a new Progress
17286 * @param {Object} config The config object
17289 Roo.bootstrap.Progress = function(config){
17290 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17293 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17298 getAutoCreate : function(){
17306 cfg.cls += ' progress-striped';
17310 cfg.cls += ' active';
17329 * @class Roo.bootstrap.ProgressBar
17330 * @extends Roo.bootstrap.Component
17331 * Bootstrap ProgressBar class
17332 * @cfg {Number} aria_valuenow aria-value now
17333 * @cfg {Number} aria_valuemin aria-value min
17334 * @cfg {Number} aria_valuemax aria-value max
17335 * @cfg {String} label label for the progress bar
17336 * @cfg {String} panel (success | info | warning | danger )
17337 * @cfg {String} role role of the progress bar
17338 * @cfg {String} sr_only text
17342 * Create a new ProgressBar
17343 * @param {Object} config The config object
17346 Roo.bootstrap.ProgressBar = function(config){
17347 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17350 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17354 aria_valuemax : 100,
17360 getAutoCreate : function()
17365 cls: 'progress-bar',
17366 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17378 cfg.role = this.role;
17381 if(this.aria_valuenow){
17382 cfg['aria-valuenow'] = this.aria_valuenow;
17385 if(this.aria_valuemin){
17386 cfg['aria-valuemin'] = this.aria_valuemin;
17389 if(this.aria_valuemax){
17390 cfg['aria-valuemax'] = this.aria_valuemax;
17393 if(this.label && !this.sr_only){
17394 cfg.html = this.label;
17398 cfg.cls += ' progress-bar-' + this.panel;
17404 update : function(aria_valuenow)
17406 this.aria_valuenow = aria_valuenow;
17408 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17423 * @class Roo.bootstrap.TabGroup
17424 * @extends Roo.bootstrap.Column
17425 * Bootstrap Column class
17426 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17427 * @cfg {Boolean} carousel true to make the group behave like a carousel
17428 * @cfg {Boolean} bullets show bullets for the panels
17429 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17430 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17431 * @cfg {Boolean} showarrow (true|false) show arrow default true
17434 * Create a new TabGroup
17435 * @param {Object} config The config object
17438 Roo.bootstrap.TabGroup = function(config){
17439 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17441 this.navId = Roo.id();
17444 Roo.bootstrap.TabGroup.register(this);
17448 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17451 transition : false,
17456 slideOnTouch : false,
17459 getAutoCreate : function()
17461 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17463 cfg.cls += ' tab-content';
17465 if (this.carousel) {
17466 cfg.cls += ' carousel slide';
17469 cls : 'carousel-inner',
17473 if(this.bullets && !Roo.isTouch){
17476 cls : 'carousel-bullets',
17480 if(this.bullets_cls){
17481 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17488 cfg.cn[0].cn.push(bullets);
17491 if(this.showarrow){
17492 cfg.cn[0].cn.push({
17494 class : 'carousel-arrow',
17498 class : 'carousel-prev',
17502 class : 'fa fa-chevron-left'
17508 class : 'carousel-next',
17512 class : 'fa fa-chevron-right'
17525 initEvents: function()
17527 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17528 // this.el.on("touchstart", this.onTouchStart, this);
17531 if(this.autoslide){
17534 this.slideFn = window.setInterval(function() {
17535 _this.showPanelNext();
17539 if(this.showarrow){
17540 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17541 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17547 // onTouchStart : function(e, el, o)
17549 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17553 // this.showPanelNext();
17557 getChildContainer : function()
17559 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17563 * register a Navigation item
17564 * @param {Roo.bootstrap.NavItem} the navitem to add
17566 register : function(item)
17568 this.tabs.push( item);
17569 item.navId = this.navId; // not really needed..
17574 getActivePanel : function()
17577 Roo.each(this.tabs, function(t) {
17587 getPanelByName : function(n)
17590 Roo.each(this.tabs, function(t) {
17591 if (t.tabId == n) {
17599 indexOfPanel : function(p)
17602 Roo.each(this.tabs, function(t,i) {
17603 if (t.tabId == p.tabId) {
17612 * show a specific panel
17613 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17614 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17616 showPanel : function (pan)
17618 if(this.transition || typeof(pan) == 'undefined'){
17619 Roo.log("waiting for the transitionend");
17623 if (typeof(pan) == 'number') {
17624 pan = this.tabs[pan];
17627 if (typeof(pan) == 'string') {
17628 pan = this.getPanelByName(pan);
17631 var cur = this.getActivePanel();
17634 Roo.log('pan or acitve pan is undefined');
17638 if (pan.tabId == this.getActivePanel().tabId) {
17642 if (false === cur.fireEvent('beforedeactivate')) {
17646 if(this.bullets > 0 && !Roo.isTouch){
17647 this.setActiveBullet(this.indexOfPanel(pan));
17650 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17652 this.transition = true;
17653 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17654 var lr = dir == 'next' ? 'left' : 'right';
17655 pan.el.addClass(dir); // or prev
17656 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17657 cur.el.addClass(lr); // or right
17658 pan.el.addClass(lr);
17661 cur.el.on('transitionend', function() {
17662 Roo.log("trans end?");
17664 pan.el.removeClass([lr,dir]);
17665 pan.setActive(true);
17667 cur.el.removeClass([lr]);
17668 cur.setActive(false);
17670 _this.transition = false;
17672 }, this, { single: true } );
17677 cur.setActive(false);
17678 pan.setActive(true);
17683 showPanelNext : function()
17685 var i = this.indexOfPanel(this.getActivePanel());
17687 if (i >= this.tabs.length - 1 && !this.autoslide) {
17691 if (i >= this.tabs.length - 1 && this.autoslide) {
17695 this.showPanel(this.tabs[i+1]);
17698 showPanelPrev : function()
17700 var i = this.indexOfPanel(this.getActivePanel());
17702 if (i < 1 && !this.autoslide) {
17706 if (i < 1 && this.autoslide) {
17707 i = this.tabs.length;
17710 this.showPanel(this.tabs[i-1]);
17714 addBullet: function()
17716 if(!this.bullets || Roo.isTouch){
17719 var ctr = this.el.select('.carousel-bullets',true).first();
17720 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17721 var bullet = ctr.createChild({
17722 cls : 'bullet bullet-' + i
17723 },ctr.dom.lastChild);
17728 bullet.on('click', (function(e, el, o, ii, t){
17730 e.preventDefault();
17732 this.showPanel(ii);
17734 if(this.autoslide && this.slideFn){
17735 clearInterval(this.slideFn);
17736 this.slideFn = window.setInterval(function() {
17737 _this.showPanelNext();
17741 }).createDelegate(this, [i, bullet], true));
17746 setActiveBullet : function(i)
17752 Roo.each(this.el.select('.bullet', true).elements, function(el){
17753 el.removeClass('selected');
17756 var bullet = this.el.select('.bullet-' + i, true).first();
17762 bullet.addClass('selected');
17773 Roo.apply(Roo.bootstrap.TabGroup, {
17777 * register a Navigation Group
17778 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17780 register : function(navgrp)
17782 this.groups[navgrp.navId] = navgrp;
17786 * fetch a Navigation Group based on the navigation ID
17787 * if one does not exist , it will get created.
17788 * @param {string} the navgroup to add
17789 * @returns {Roo.bootstrap.NavGroup} the navgroup
17791 get: function(navId) {
17792 if (typeof(this.groups[navId]) == 'undefined') {
17793 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17795 return this.groups[navId] ;
17810 * @class Roo.bootstrap.TabPanel
17811 * @extends Roo.bootstrap.Component
17812 * Bootstrap TabPanel class
17813 * @cfg {Boolean} active panel active
17814 * @cfg {String} html panel content
17815 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17816 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17817 * @cfg {String} href click to link..
17821 * Create a new TabPanel
17822 * @param {Object} config The config object
17825 Roo.bootstrap.TabPanel = function(config){
17826 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17830 * Fires when the active status changes
17831 * @param {Roo.bootstrap.TabPanel} this
17832 * @param {Boolean} state the new state
17837 * @event beforedeactivate
17838 * Fires before a tab is de-activated - can be used to do validation on a form.
17839 * @param {Roo.bootstrap.TabPanel} this
17840 * @return {Boolean} false if there is an error
17843 'beforedeactivate': true
17846 this.tabId = this.tabId || Roo.id();
17850 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17858 getAutoCreate : function(){
17861 // item is needed for carousel - not sure if it has any effect otherwise
17862 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17863 html: this.html || ''
17867 cfg.cls += ' active';
17871 cfg.tabId = this.tabId;
17878 initEvents: function()
17880 var p = this.parent();
17882 this.navId = this.navId || p.navId;
17884 if (typeof(this.navId) != 'undefined') {
17885 // not really needed.. but just in case.. parent should be a NavGroup.
17886 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17890 var i = tg.tabs.length - 1;
17892 if(this.active && tg.bullets > 0 && i < tg.bullets){
17893 tg.setActiveBullet(i);
17897 this.el.on('click', this.onClick, this);
17900 this.el.on("touchstart", this.onTouchStart, this);
17901 this.el.on("touchmove", this.onTouchMove, this);
17902 this.el.on("touchend", this.onTouchEnd, this);
17907 onRender : function(ct, position)
17909 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17912 setActive : function(state)
17914 Roo.log("panel - set active " + this.tabId + "=" + state);
17916 this.active = state;
17918 this.el.removeClass('active');
17920 } else if (!this.el.hasClass('active')) {
17921 this.el.addClass('active');
17924 this.fireEvent('changed', this, state);
17927 onClick : function(e)
17929 e.preventDefault();
17931 if(!this.href.length){
17935 window.location.href = this.href;
17944 onTouchStart : function(e)
17946 this.swiping = false;
17948 this.startX = e.browserEvent.touches[0].clientX;
17949 this.startY = e.browserEvent.touches[0].clientY;
17952 onTouchMove : function(e)
17954 this.swiping = true;
17956 this.endX = e.browserEvent.touches[0].clientX;
17957 this.endY = e.browserEvent.touches[0].clientY;
17960 onTouchEnd : function(e)
17967 var tabGroup = this.parent();
17969 if(this.endX > this.startX){ // swiping right
17970 tabGroup.showPanelPrev();
17974 if(this.startX > this.endX){ // swiping left
17975 tabGroup.showPanelNext();
17994 * @class Roo.bootstrap.DateField
17995 * @extends Roo.bootstrap.Input
17996 * Bootstrap DateField class
17997 * @cfg {Number} weekStart default 0
17998 * @cfg {String} viewMode default empty, (months|years)
17999 * @cfg {String} minViewMode default empty, (months|years)
18000 * @cfg {Number} startDate default -Infinity
18001 * @cfg {Number} endDate default Infinity
18002 * @cfg {Boolean} todayHighlight default false
18003 * @cfg {Boolean} todayBtn default false
18004 * @cfg {Boolean} calendarWeeks default false
18005 * @cfg {Object} daysOfWeekDisabled default empty
18006 * @cfg {Boolean} singleMode default false (true | false)
18008 * @cfg {Boolean} keyboardNavigation default true
18009 * @cfg {String} language default en
18012 * Create a new DateField
18013 * @param {Object} config The config object
18016 Roo.bootstrap.DateField = function(config){
18017 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18021 * Fires when this field show.
18022 * @param {Roo.bootstrap.DateField} this
18023 * @param {Mixed} date The date value
18028 * Fires when this field hide.
18029 * @param {Roo.bootstrap.DateField} this
18030 * @param {Mixed} date The date value
18035 * Fires when select a date.
18036 * @param {Roo.bootstrap.DateField} this
18037 * @param {Mixed} date The date value
18041 * @event beforeselect
18042 * Fires when before select a date.
18043 * @param {Roo.bootstrap.DateField} this
18044 * @param {Mixed} date The date value
18046 beforeselect : true
18050 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18053 * @cfg {String} format
18054 * The default date format string which can be overriden for localization support. The format must be
18055 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18059 * @cfg {String} altFormats
18060 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18061 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18063 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18071 todayHighlight : false,
18077 keyboardNavigation: true,
18079 calendarWeeks: false,
18081 startDate: -Infinity,
18085 daysOfWeekDisabled: [],
18089 singleMode : false,
18091 UTCDate: function()
18093 return new Date(Date.UTC.apply(Date, arguments));
18096 UTCToday: function()
18098 var today = new Date();
18099 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18102 getDate: function() {
18103 var d = this.getUTCDate();
18104 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18107 getUTCDate: function() {
18111 setDate: function(d) {
18112 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18115 setUTCDate: function(d) {
18117 this.setValue(this.formatDate(this.date));
18120 onRender: function(ct, position)
18123 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18125 this.language = this.language || 'en';
18126 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18127 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18129 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18130 this.format = this.format || 'm/d/y';
18131 this.isInline = false;
18132 this.isInput = true;
18133 this.component = this.el.select('.add-on', true).first() || false;
18134 this.component = (this.component && this.component.length === 0) ? false : this.component;
18135 this.hasInput = this.component && this.inputEl().length;
18137 if (typeof(this.minViewMode === 'string')) {
18138 switch (this.minViewMode) {
18140 this.minViewMode = 1;
18143 this.minViewMode = 2;
18146 this.minViewMode = 0;
18151 if (typeof(this.viewMode === 'string')) {
18152 switch (this.viewMode) {
18165 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18167 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18169 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18171 this.picker().on('mousedown', this.onMousedown, this);
18172 this.picker().on('click', this.onClick, this);
18174 this.picker().addClass('datepicker-dropdown');
18176 this.startViewMode = this.viewMode;
18178 if(this.singleMode){
18179 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18180 v.setVisibilityMode(Roo.Element.DISPLAY);
18184 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18185 v.setStyle('width', '189px');
18189 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18190 if(!this.calendarWeeks){
18195 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18196 v.attr('colspan', function(i, val){
18197 return parseInt(val) + 1;
18202 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18204 this.setStartDate(this.startDate);
18205 this.setEndDate(this.endDate);
18207 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18214 if(this.isInline) {
18219 picker : function()
18221 return this.pickerEl;
18222 // return this.el.select('.datepicker', true).first();
18225 fillDow: function()
18227 var dowCnt = this.weekStart;
18236 if(this.calendarWeeks){
18244 while (dowCnt < this.weekStart + 7) {
18248 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18252 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18255 fillMonths: function()
18258 var months = this.picker().select('>.datepicker-months td', true).first();
18260 months.dom.innerHTML = '';
18266 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18269 months.createChild(month);
18276 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;
18278 if (this.date < this.startDate) {
18279 this.viewDate = new Date(this.startDate);
18280 } else if (this.date > this.endDate) {
18281 this.viewDate = new Date(this.endDate);
18283 this.viewDate = new Date(this.date);
18291 var d = new Date(this.viewDate),
18292 year = d.getUTCFullYear(),
18293 month = d.getUTCMonth(),
18294 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18295 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18296 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18297 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18298 currentDate = this.date && this.date.valueOf(),
18299 today = this.UTCToday();
18301 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18303 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18305 // this.picker.select('>tfoot th.today').
18306 // .text(dates[this.language].today)
18307 // .toggle(this.todayBtn !== false);
18309 this.updateNavArrows();
18312 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18314 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18316 prevMonth.setUTCDate(day);
18318 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18320 var nextMonth = new Date(prevMonth);
18322 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18324 nextMonth = nextMonth.valueOf();
18326 var fillMonths = false;
18328 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18330 while(prevMonth.valueOf() < nextMonth) {
18333 if (prevMonth.getUTCDay() === this.weekStart) {
18335 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18343 if(this.calendarWeeks){
18344 // ISO 8601: First week contains first thursday.
18345 // ISO also states week starts on Monday, but we can be more abstract here.
18347 // Start of current week: based on weekstart/current date
18348 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18349 // Thursday of this week
18350 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18351 // First Thursday of year, year from thursday
18352 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18353 // Calendar week: ms between thursdays, div ms per day, div 7 days
18354 calWeek = (th - yth) / 864e5 / 7 + 1;
18356 fillMonths.cn.push({
18364 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18366 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18369 if (this.todayHighlight &&
18370 prevMonth.getUTCFullYear() == today.getFullYear() &&
18371 prevMonth.getUTCMonth() == today.getMonth() &&
18372 prevMonth.getUTCDate() == today.getDate()) {
18373 clsName += ' today';
18376 if (currentDate && prevMonth.valueOf() === currentDate) {
18377 clsName += ' active';
18380 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18381 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18382 clsName += ' disabled';
18385 fillMonths.cn.push({
18387 cls: 'day ' + clsName,
18388 html: prevMonth.getDate()
18391 prevMonth.setDate(prevMonth.getDate()+1);
18394 var currentYear = this.date && this.date.getUTCFullYear();
18395 var currentMonth = this.date && this.date.getUTCMonth();
18397 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18399 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18400 v.removeClass('active');
18402 if(currentYear === year && k === currentMonth){
18403 v.addClass('active');
18406 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18407 v.addClass('disabled');
18413 year = parseInt(year/10, 10) * 10;
18415 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18417 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18420 for (var i = -1; i < 11; i++) {
18421 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18423 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18431 showMode: function(dir)
18434 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18437 Roo.each(this.picker().select('>div',true).elements, function(v){
18438 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18441 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18446 if(this.isInline) {
18450 this.picker().removeClass(['bottom', 'top']);
18452 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18454 * place to the top of element!
18458 this.picker().addClass('top');
18459 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18464 this.picker().addClass('bottom');
18466 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18469 parseDate : function(value)
18471 if(!value || value instanceof Date){
18474 var v = Date.parseDate(value, this.format);
18475 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18476 v = Date.parseDate(value, 'Y-m-d');
18478 if(!v && this.altFormats){
18479 if(!this.altFormatsArray){
18480 this.altFormatsArray = this.altFormats.split("|");
18482 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18483 v = Date.parseDate(value, this.altFormatsArray[i]);
18489 formatDate : function(date, fmt)
18491 return (!date || !(date instanceof Date)) ?
18492 date : date.dateFormat(fmt || this.format);
18495 onFocus : function()
18497 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18501 onBlur : function()
18503 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18505 var d = this.inputEl().getValue();
18514 this.picker().show();
18518 this.fireEvent('show', this, this.date);
18523 if(this.isInline) {
18526 this.picker().hide();
18527 this.viewMode = this.startViewMode;
18530 this.fireEvent('hide', this, this.date);
18534 onMousedown: function(e)
18536 e.stopPropagation();
18537 e.preventDefault();
18542 Roo.bootstrap.DateField.superclass.keyup.call(this);
18546 setValue: function(v)
18548 if(this.fireEvent('beforeselect', this, v) !== false){
18549 var d = new Date(this.parseDate(v) ).clearTime();
18551 if(isNaN(d.getTime())){
18552 this.date = this.viewDate = '';
18553 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18557 v = this.formatDate(d);
18559 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18561 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18565 this.fireEvent('select', this, this.date);
18569 getValue: function()
18571 return this.formatDate(this.date);
18574 fireKey: function(e)
18576 if (!this.picker().isVisible()){
18577 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18583 var dateChanged = false,
18585 newDate, newViewDate;
18590 e.preventDefault();
18594 if (!this.keyboardNavigation) {
18597 dir = e.keyCode == 37 ? -1 : 1;
18600 newDate = this.moveYear(this.date, dir);
18601 newViewDate = this.moveYear(this.viewDate, dir);
18602 } else if (e.shiftKey){
18603 newDate = this.moveMonth(this.date, dir);
18604 newViewDate = this.moveMonth(this.viewDate, dir);
18606 newDate = new Date(this.date);
18607 newDate.setUTCDate(this.date.getUTCDate() + dir);
18608 newViewDate = new Date(this.viewDate);
18609 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18611 if (this.dateWithinRange(newDate)){
18612 this.date = newDate;
18613 this.viewDate = newViewDate;
18614 this.setValue(this.formatDate(this.date));
18616 e.preventDefault();
18617 dateChanged = true;
18622 if (!this.keyboardNavigation) {
18625 dir = e.keyCode == 38 ? -1 : 1;
18627 newDate = this.moveYear(this.date, dir);
18628 newViewDate = this.moveYear(this.viewDate, dir);
18629 } else if (e.shiftKey){
18630 newDate = this.moveMonth(this.date, dir);
18631 newViewDate = this.moveMonth(this.viewDate, dir);
18633 newDate = new Date(this.date);
18634 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18635 newViewDate = new Date(this.viewDate);
18636 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18638 if (this.dateWithinRange(newDate)){
18639 this.date = newDate;
18640 this.viewDate = newViewDate;
18641 this.setValue(this.formatDate(this.date));
18643 e.preventDefault();
18644 dateChanged = true;
18648 this.setValue(this.formatDate(this.date));
18650 e.preventDefault();
18653 this.setValue(this.formatDate(this.date));
18667 onClick: function(e)
18669 e.stopPropagation();
18670 e.preventDefault();
18672 var target = e.getTarget();
18674 if(target.nodeName.toLowerCase() === 'i'){
18675 target = Roo.get(target).dom.parentNode;
18678 var nodeName = target.nodeName;
18679 var className = target.className;
18680 var html = target.innerHTML;
18681 //Roo.log(nodeName);
18683 switch(nodeName.toLowerCase()) {
18685 switch(className) {
18691 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18692 switch(this.viewMode){
18694 this.viewDate = this.moveMonth(this.viewDate, dir);
18698 this.viewDate = this.moveYear(this.viewDate, dir);
18704 var date = new Date();
18705 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18707 this.setValue(this.formatDate(this.date));
18714 if (className.indexOf('disabled') < 0) {
18715 this.viewDate.setUTCDate(1);
18716 if (className.indexOf('month') > -1) {
18717 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18719 var year = parseInt(html, 10) || 0;
18720 this.viewDate.setUTCFullYear(year);
18724 if(this.singleMode){
18725 this.setValue(this.formatDate(this.viewDate));
18736 //Roo.log(className);
18737 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18738 var day = parseInt(html, 10) || 1;
18739 var year = this.viewDate.getUTCFullYear(),
18740 month = this.viewDate.getUTCMonth();
18742 if (className.indexOf('old') > -1) {
18749 } else if (className.indexOf('new') > -1) {
18757 //Roo.log([year,month,day]);
18758 this.date = this.UTCDate(year, month, day,0,0,0,0);
18759 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18761 //Roo.log(this.formatDate(this.date));
18762 this.setValue(this.formatDate(this.date));
18769 setStartDate: function(startDate)
18771 this.startDate = startDate || -Infinity;
18772 if (this.startDate !== -Infinity) {
18773 this.startDate = this.parseDate(this.startDate);
18776 this.updateNavArrows();
18779 setEndDate: function(endDate)
18781 this.endDate = endDate || Infinity;
18782 if (this.endDate !== Infinity) {
18783 this.endDate = this.parseDate(this.endDate);
18786 this.updateNavArrows();
18789 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18791 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18792 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18793 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18795 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18796 return parseInt(d, 10);
18799 this.updateNavArrows();
18802 updateNavArrows: function()
18804 if(this.singleMode){
18808 var d = new Date(this.viewDate),
18809 year = d.getUTCFullYear(),
18810 month = d.getUTCMonth();
18812 Roo.each(this.picker().select('.prev', true).elements, function(v){
18814 switch (this.viewMode) {
18817 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18823 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18830 Roo.each(this.picker().select('.next', true).elements, function(v){
18832 switch (this.viewMode) {
18835 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18841 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18849 moveMonth: function(date, dir)
18854 var new_date = new Date(date.valueOf()),
18855 day = new_date.getUTCDate(),
18856 month = new_date.getUTCMonth(),
18857 mag = Math.abs(dir),
18859 dir = dir > 0 ? 1 : -1;
18862 // If going back one month, make sure month is not current month
18863 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18865 return new_date.getUTCMonth() == month;
18867 // If going forward one month, make sure month is as expected
18868 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18870 return new_date.getUTCMonth() != new_month;
18872 new_month = month + dir;
18873 new_date.setUTCMonth(new_month);
18874 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18875 if (new_month < 0 || new_month > 11) {
18876 new_month = (new_month + 12) % 12;
18879 // For magnitudes >1, move one month at a time...
18880 for (var i=0; i<mag; i++) {
18881 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18882 new_date = this.moveMonth(new_date, dir);
18884 // ...then reset the day, keeping it in the new month
18885 new_month = new_date.getUTCMonth();
18886 new_date.setUTCDate(day);
18888 return new_month != new_date.getUTCMonth();
18891 // Common date-resetting loop -- if date is beyond end of month, make it
18894 new_date.setUTCDate(--day);
18895 new_date.setUTCMonth(new_month);
18900 moveYear: function(date, dir)
18902 return this.moveMonth(date, dir*12);
18905 dateWithinRange: function(date)
18907 return date >= this.startDate && date <= this.endDate;
18913 this.picker().remove();
18916 validateValue : function(value)
18918 if(value.length < 1) {
18919 if(this.allowBlank){
18925 if(value.length < this.minLength){
18928 if(value.length > this.maxLength){
18932 var vt = Roo.form.VTypes;
18933 if(!vt[this.vtype](value, this)){
18937 if(typeof this.validator == "function"){
18938 var msg = this.validator(value);
18944 if(this.regex && !this.regex.test(value)){
18948 if(typeof(this.parseDate(value)) == 'undefined'){
18952 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18956 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18966 Roo.apply(Roo.bootstrap.DateField, {
18977 html: '<i class="fa fa-arrow-left"/>'
18987 html: '<i class="fa fa-arrow-right"/>'
19029 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19030 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19031 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19032 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19033 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19046 navFnc: 'FullYear',
19051 navFnc: 'FullYear',
19056 Roo.apply(Roo.bootstrap.DateField, {
19060 cls: 'datepicker dropdown-menu roo-dynamic',
19064 cls: 'datepicker-days',
19068 cls: 'table-condensed',
19070 Roo.bootstrap.DateField.head,
19074 Roo.bootstrap.DateField.footer
19081 cls: 'datepicker-months',
19085 cls: 'table-condensed',
19087 Roo.bootstrap.DateField.head,
19088 Roo.bootstrap.DateField.content,
19089 Roo.bootstrap.DateField.footer
19096 cls: 'datepicker-years',
19100 cls: 'table-condensed',
19102 Roo.bootstrap.DateField.head,
19103 Roo.bootstrap.DateField.content,
19104 Roo.bootstrap.DateField.footer
19123 * @class Roo.bootstrap.TimeField
19124 * @extends Roo.bootstrap.Input
19125 * Bootstrap DateField class
19129 * Create a new TimeField
19130 * @param {Object} config The config object
19133 Roo.bootstrap.TimeField = function(config){
19134 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19138 * Fires when this field show.
19139 * @param {Roo.bootstrap.DateField} thisthis
19140 * @param {Mixed} date The date value
19145 * Fires when this field hide.
19146 * @param {Roo.bootstrap.DateField} this
19147 * @param {Mixed} date The date value
19152 * Fires when select a date.
19153 * @param {Roo.bootstrap.DateField} this
19154 * @param {Mixed} date The date value
19160 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19163 * @cfg {String} format
19164 * The default time format string which can be overriden for localization support. The format must be
19165 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19169 onRender: function(ct, position)
19172 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19174 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19176 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19178 this.pop = this.picker().select('>.datepicker-time',true).first();
19179 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19181 this.picker().on('mousedown', this.onMousedown, this);
19182 this.picker().on('click', this.onClick, this);
19184 this.picker().addClass('datepicker-dropdown');
19189 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19190 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19191 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19192 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19193 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19194 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19198 fireKey: function(e){
19199 if (!this.picker().isVisible()){
19200 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19206 e.preventDefault();
19214 this.onTogglePeriod();
19217 this.onIncrementMinutes();
19220 this.onDecrementMinutes();
19229 onClick: function(e) {
19230 e.stopPropagation();
19231 e.preventDefault();
19234 picker : function()
19236 return this.el.select('.datepicker', true).first();
19239 fillTime: function()
19241 var time = this.pop.select('tbody', true).first();
19243 time.dom.innerHTML = '';
19258 cls: 'hours-up glyphicon glyphicon-chevron-up'
19278 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19299 cls: 'timepicker-hour',
19314 cls: 'timepicker-minute',
19329 cls: 'btn btn-primary period',
19351 cls: 'hours-down glyphicon glyphicon-chevron-down'
19371 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19389 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19396 var hours = this.time.getHours();
19397 var minutes = this.time.getMinutes();
19410 hours = hours - 12;
19414 hours = '0' + hours;
19418 minutes = '0' + minutes;
19421 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19422 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19423 this.pop.select('button', true).first().dom.innerHTML = period;
19429 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19431 var cls = ['bottom'];
19433 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19440 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19445 this.picker().addClass(cls.join('-'));
19449 Roo.each(cls, function(c){
19451 _this.picker().setTop(_this.inputEl().getHeight());
19455 _this.picker().setTop(0 - _this.picker().getHeight());
19460 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19464 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19471 onFocus : function()
19473 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19477 onBlur : function()
19479 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19485 this.picker().show();
19490 this.fireEvent('show', this, this.date);
19495 this.picker().hide();
19498 this.fireEvent('hide', this, this.date);
19501 setTime : function()
19504 this.setValue(this.time.format(this.format));
19506 this.fireEvent('select', this, this.date);
19511 onMousedown: function(e){
19512 e.stopPropagation();
19513 e.preventDefault();
19516 onIncrementHours: function()
19518 Roo.log('onIncrementHours');
19519 this.time = this.time.add(Date.HOUR, 1);
19524 onDecrementHours: function()
19526 Roo.log('onDecrementHours');
19527 this.time = this.time.add(Date.HOUR, -1);
19531 onIncrementMinutes: function()
19533 Roo.log('onIncrementMinutes');
19534 this.time = this.time.add(Date.MINUTE, 1);
19538 onDecrementMinutes: function()
19540 Roo.log('onDecrementMinutes');
19541 this.time = this.time.add(Date.MINUTE, -1);
19545 onTogglePeriod: function()
19547 Roo.log('onTogglePeriod');
19548 this.time = this.time.add(Date.HOUR, 12);
19555 Roo.apply(Roo.bootstrap.TimeField, {
19585 cls: 'btn btn-info ok',
19597 Roo.apply(Roo.bootstrap.TimeField, {
19601 cls: 'datepicker dropdown-menu',
19605 cls: 'datepicker-time',
19609 cls: 'table-condensed',
19611 Roo.bootstrap.TimeField.content,
19612 Roo.bootstrap.TimeField.footer
19631 * @class Roo.bootstrap.MonthField
19632 * @extends Roo.bootstrap.Input
19633 * Bootstrap MonthField class
19635 * @cfg {String} language default en
19638 * Create a new MonthField
19639 * @param {Object} config The config object
19642 Roo.bootstrap.MonthField = function(config){
19643 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19648 * Fires when this field show.
19649 * @param {Roo.bootstrap.MonthField} this
19650 * @param {Mixed} date The date value
19655 * Fires when this field hide.
19656 * @param {Roo.bootstrap.MonthField} this
19657 * @param {Mixed} date The date value
19662 * Fires when select a date.
19663 * @param {Roo.bootstrap.MonthField} this
19664 * @param {String} oldvalue The old value
19665 * @param {String} newvalue The new value
19671 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19673 onRender: function(ct, position)
19676 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19678 this.language = this.language || 'en';
19679 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19680 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19682 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19683 this.isInline = false;
19684 this.isInput = true;
19685 this.component = this.el.select('.add-on', true).first() || false;
19686 this.component = (this.component && this.component.length === 0) ? false : this.component;
19687 this.hasInput = this.component && this.inputEL().length;
19689 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19691 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19693 this.picker().on('mousedown', this.onMousedown, this);
19694 this.picker().on('click', this.onClick, this);
19696 this.picker().addClass('datepicker-dropdown');
19698 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19699 v.setStyle('width', '189px');
19706 if(this.isInline) {
19712 setValue: function(v, suppressEvent)
19714 var o = this.getValue();
19716 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19720 if(suppressEvent !== true){
19721 this.fireEvent('select', this, o, v);
19726 getValue: function()
19731 onClick: function(e)
19733 e.stopPropagation();
19734 e.preventDefault();
19736 var target = e.getTarget();
19738 if(target.nodeName.toLowerCase() === 'i'){
19739 target = Roo.get(target).dom.parentNode;
19742 var nodeName = target.nodeName;
19743 var className = target.className;
19744 var html = target.innerHTML;
19746 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19750 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19752 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19758 picker : function()
19760 return this.pickerEl;
19763 fillMonths: function()
19766 var months = this.picker().select('>.datepicker-months td', true).first();
19768 months.dom.innerHTML = '';
19774 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19777 months.createChild(month);
19786 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19787 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19790 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19791 e.removeClass('active');
19793 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19794 e.addClass('active');
19801 if(this.isInline) {
19805 this.picker().removeClass(['bottom', 'top']);
19807 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19809 * place to the top of element!
19813 this.picker().addClass('top');
19814 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19819 this.picker().addClass('bottom');
19821 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19824 onFocus : function()
19826 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19830 onBlur : function()
19832 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19834 var d = this.inputEl().getValue();
19843 this.picker().show();
19844 this.picker().select('>.datepicker-months', true).first().show();
19848 this.fireEvent('show', this, this.date);
19853 if(this.isInline) {
19856 this.picker().hide();
19857 this.fireEvent('hide', this, this.date);
19861 onMousedown: function(e)
19863 e.stopPropagation();
19864 e.preventDefault();
19869 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19873 fireKey: function(e)
19875 if (!this.picker().isVisible()){
19876 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19887 e.preventDefault();
19891 dir = e.keyCode == 37 ? -1 : 1;
19893 this.vIndex = this.vIndex + dir;
19895 if(this.vIndex < 0){
19899 if(this.vIndex > 11){
19903 if(isNaN(this.vIndex)){
19907 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19913 dir = e.keyCode == 38 ? -1 : 1;
19915 this.vIndex = this.vIndex + dir * 4;
19917 if(this.vIndex < 0){
19921 if(this.vIndex > 11){
19925 if(isNaN(this.vIndex)){
19929 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19934 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19935 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19939 e.preventDefault();
19942 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19943 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19959 this.picker().remove();
19964 Roo.apply(Roo.bootstrap.MonthField, {
19983 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19984 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19989 Roo.apply(Roo.bootstrap.MonthField, {
19993 cls: 'datepicker dropdown-menu roo-dynamic',
19997 cls: 'datepicker-months',
20001 cls: 'table-condensed',
20003 Roo.bootstrap.DateField.content
20023 * @class Roo.bootstrap.CheckBox
20024 * @extends Roo.bootstrap.Input
20025 * Bootstrap CheckBox class
20027 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20028 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20029 * @cfg {String} boxLabel The text that appears beside the checkbox
20030 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20031 * @cfg {Boolean} checked initnal the element
20032 * @cfg {Boolean} inline inline the element (default false)
20033 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20036 * Create a new CheckBox
20037 * @param {Object} config The config object
20040 Roo.bootstrap.CheckBox = function(config){
20041 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20046 * Fires when the element is checked or unchecked.
20047 * @param {Roo.bootstrap.CheckBox} this This input
20048 * @param {Boolean} checked The new checked value
20055 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20057 inputType: 'checkbox',
20065 getAutoCreate : function()
20067 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20073 cfg.cls = 'form-group ' + this.inputType; //input-group
20076 cfg.cls += ' ' + this.inputType + '-inline';
20082 type : this.inputType,
20083 value : this.inputValue,
20084 cls : 'roo-' + this.inputType, //'form-box',
20085 placeholder : this.placeholder || ''
20089 if(this.inputType != 'radio'){
20093 cls : 'roo-hidden-value',
20094 value : this.checked ? this.valueOff : this.inputValue
20099 if (this.weight) { // Validity check?
20100 cfg.cls += " " + this.inputType + "-" + this.weight;
20103 if (this.disabled) {
20104 input.disabled=true;
20108 input.checked = this.checked;
20115 input.name = this.name;
20117 if(this.inputType != 'radio'){
20118 hidden.name = this.name;
20119 input.name = '_hidden_' + this.name;
20124 input.cls += ' input-' + this.size;
20129 ['xs','sm','md','lg'].map(function(size){
20130 if (settings[size]) {
20131 cfg.cls += ' col-' + size + '-' + settings[size];
20135 var inputblock = input;
20137 if (this.before || this.after) {
20140 cls : 'input-group',
20145 inputblock.cn.push({
20147 cls : 'input-group-addon',
20152 inputblock.cn.push(input);
20154 if(this.inputType != 'radio'){
20155 inputblock.cn.push(hidden);
20159 inputblock.cn.push({
20161 cls : 'input-group-addon',
20168 if (align ==='left' && this.fieldLabel.length) {
20169 // Roo.log("left and has label");
20174 cls : 'control-label',
20175 html : this.fieldLabel
20186 if(this.labelWidth > 12){
20187 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20190 if(this.labelWidth < 13 && this.labelmd == 0){
20191 this.labelmd = this.labelWidth;
20194 if(this.labellg > 0){
20195 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20196 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20199 if(this.labelmd > 0){
20200 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20201 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20204 if(this.labelsm > 0){
20205 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20206 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20209 if(this.labelxs > 0){
20210 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20211 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20214 } else if ( this.fieldLabel.length) {
20215 // Roo.log(" label");
20219 tag: this.boxLabel ? 'span' : 'label',
20221 cls: 'control-label box-input-label',
20222 //cls : 'input-group-addon',
20223 html : this.fieldLabel
20233 // Roo.log(" no label && no align");
20234 cfg.cn = [ inputblock ] ;
20240 var boxLabelCfg = {
20242 //'for': id, // box label is handled by onclick - so no for...
20244 html: this.boxLabel
20248 boxLabelCfg.tooltip = this.tooltip;
20251 cfg.cn.push(boxLabelCfg);
20254 if(this.inputType != 'radio'){
20255 cfg.cn.push(hidden);
20263 * return the real input element.
20265 inputEl: function ()
20267 return this.el.select('input.roo-' + this.inputType,true).first();
20269 hiddenEl: function ()
20271 return this.el.select('input.roo-hidden-value',true).first();
20274 labelEl: function()
20276 return this.el.select('label.control-label',true).first();
20278 /* depricated... */
20282 return this.labelEl();
20285 boxLabelEl: function()
20287 return this.el.select('label.box-label',true).first();
20290 initEvents : function()
20292 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20294 this.inputEl().on('click', this.onClick, this);
20296 if (this.boxLabel) {
20297 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20300 this.startValue = this.getValue();
20303 Roo.bootstrap.CheckBox.register(this);
20307 onClick : function()
20309 this.setChecked(!this.checked);
20312 setChecked : function(state,suppressEvent)
20314 this.startValue = this.getValue();
20316 if(this.inputType == 'radio'){
20318 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20319 e.dom.checked = false;
20322 this.inputEl().dom.checked = true;
20324 this.inputEl().dom.value = this.inputValue;
20326 if(suppressEvent !== true){
20327 this.fireEvent('check', this, true);
20335 this.checked = state;
20337 this.inputEl().dom.checked = state;
20340 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20342 if(suppressEvent !== true){
20343 this.fireEvent('check', this, state);
20349 getValue : function()
20351 if(this.inputType == 'radio'){
20352 return this.getGroupValue();
20355 return this.hiddenEl().dom.value;
20359 getGroupValue : function()
20361 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20365 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20368 setValue : function(v,suppressEvent)
20370 if(this.inputType == 'radio'){
20371 this.setGroupValue(v, suppressEvent);
20375 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20380 setGroupValue : function(v, suppressEvent)
20382 this.startValue = this.getValue();
20384 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20385 e.dom.checked = false;
20387 if(e.dom.value == v){
20388 e.dom.checked = true;
20392 if(suppressEvent !== true){
20393 this.fireEvent('check', this, true);
20401 validate : function()
20405 (this.inputType == 'radio' && this.validateRadio()) ||
20406 (this.inputType == 'checkbox' && this.validateCheckbox())
20412 this.markInvalid();
20416 validateRadio : function()
20418 if(this.allowBlank){
20424 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20425 if(!e.dom.checked){
20437 validateCheckbox : function()
20440 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20441 //return (this.getValue() == this.inputValue) ? true : false;
20444 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20452 for(var i in group){
20457 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20464 * Mark this field as valid
20466 markValid : function()
20470 this.fireEvent('valid', this);
20472 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20475 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20482 if(this.inputType == 'radio'){
20483 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20484 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20485 e.findParent('.form-group', false, true).addClass(_this.validClass);
20492 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20493 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20497 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20503 for(var i in group){
20504 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20505 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20510 * Mark this field as invalid
20511 * @param {String} msg The validation message
20513 markInvalid : function(msg)
20515 if(this.allowBlank){
20521 this.fireEvent('invalid', this, msg);
20523 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20526 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20530 label.markInvalid();
20533 if(this.inputType == 'radio'){
20534 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20535 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20536 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20543 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20544 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20548 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20554 for(var i in group){
20555 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20556 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20561 clearInvalid : function()
20563 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20565 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20567 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20570 label.iconEl.removeClass(label.validClass);
20571 label.iconEl.removeClass(label.invalidClass);
20575 disable : function()
20577 if(this.inputType != 'radio'){
20578 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20585 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20586 _this.getActionEl().addClass(this.disabledClass);
20587 e.dom.disabled = true;
20591 this.disabled = true;
20592 this.fireEvent("disable", this);
20596 enable : function()
20598 if(this.inputType != 'radio'){
20599 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20606 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20607 _this.getActionEl().removeClass(this.disabledClass);
20608 e.dom.disabled = false;
20612 this.disabled = false;
20613 this.fireEvent("enable", this);
20619 Roo.apply(Roo.bootstrap.CheckBox, {
20624 * register a CheckBox Group
20625 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20627 register : function(checkbox)
20629 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20630 this.groups[checkbox.groupId] = {};
20633 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20637 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20641 * fetch a CheckBox Group based on the group ID
20642 * @param {string} the group ID
20643 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20645 get: function(groupId) {
20646 if (typeof(this.groups[groupId]) == 'undefined') {
20650 return this.groups[groupId] ;
20663 * @class Roo.bootstrap.Radio
20664 * @extends Roo.bootstrap.Component
20665 * Bootstrap Radio class
20666 * @cfg {String} boxLabel - the label associated
20667 * @cfg {String} value - the value of radio
20670 * Create a new Radio
20671 * @param {Object} config The config object
20673 Roo.bootstrap.Radio = function(config){
20674 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20678 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20684 getAutoCreate : function()
20688 cls : 'form-group radio',
20693 html : this.boxLabel
20701 initEvents : function()
20703 this.parent().register(this);
20705 this.el.on('click', this.onClick, this);
20709 onClick : function()
20711 this.setChecked(true);
20714 setChecked : function(state, suppressEvent)
20716 this.parent().setValue(this.value, suppressEvent);
20731 * @class Roo.bootstrap.SecurePass
20732 * @extends Roo.bootstrap.Input
20733 * Bootstrap SecurePass class
20737 * Create a new SecurePass
20738 * @param {Object} config The config object
20741 Roo.bootstrap.SecurePass = function (config) {
20742 // these go here, so the translation tool can replace them..
20744 PwdEmpty: "Please type a password, and then retype it to confirm.",
20745 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20746 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20747 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20748 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20749 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20750 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20751 TooWeak: "Your password is Too Weak."
20753 this.meterLabel = "Password strength:";
20754 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20755 this.meterClass = [
20756 "roo-password-meter-tooweak",
20757 "roo-password-meter-weak",
20758 "roo-password-meter-medium",
20759 "roo-password-meter-strong",
20760 "roo-password-meter-grey"
20765 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20768 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20770 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20772 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20773 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20774 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20775 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20776 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20777 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20778 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20788 * @cfg {String/Object} Label for the strength meter (defaults to
20789 * 'Password strength:')
20794 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20795 * ['Weak', 'Medium', 'Strong'])
20798 pwdStrengths: false,
20811 initEvents: function ()
20813 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20815 if (this.el.is('input[type=password]') && Roo.isSafari) {
20816 this.el.on('keydown', this.SafariOnKeyDown, this);
20819 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20822 onRender: function (ct, position)
20824 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20825 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20826 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20828 this.trigger.createChild({
20833 cls: 'roo-password-meter-grey col-xs-12',
20836 //width: this.meterWidth + 'px'
20840 cls: 'roo-password-meter-text'
20846 if (this.hideTrigger) {
20847 this.trigger.setDisplayed(false);
20849 this.setSize(this.width || '', this.height || '');
20852 onDestroy: function ()
20854 if (this.trigger) {
20855 this.trigger.removeAllListeners();
20856 this.trigger.remove();
20859 this.wrap.remove();
20861 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20864 checkStrength: function ()
20866 var pwd = this.inputEl().getValue();
20867 if (pwd == this._lastPwd) {
20872 if (this.ClientSideStrongPassword(pwd)) {
20874 } else if (this.ClientSideMediumPassword(pwd)) {
20876 } else if (this.ClientSideWeakPassword(pwd)) {
20882 Roo.log('strength1: ' + strength);
20884 //var pm = this.trigger.child('div/div/div').dom;
20885 var pm = this.trigger.child('div/div');
20886 pm.removeClass(this.meterClass);
20887 pm.addClass(this.meterClass[strength]);
20890 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20892 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20894 this._lastPwd = pwd;
20898 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20900 this._lastPwd = '';
20902 var pm = this.trigger.child('div/div');
20903 pm.removeClass(this.meterClass);
20904 pm.addClass('roo-password-meter-grey');
20907 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20910 this.inputEl().dom.type='password';
20913 validateValue: function (value)
20916 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20919 if (value.length == 0) {
20920 if (this.allowBlank) {
20921 this.clearInvalid();
20925 this.markInvalid(this.errors.PwdEmpty);
20926 this.errorMsg = this.errors.PwdEmpty;
20934 if ('[\x21-\x7e]*'.match(value)) {
20935 this.markInvalid(this.errors.PwdBadChar);
20936 this.errorMsg = this.errors.PwdBadChar;
20939 if (value.length < 6) {
20940 this.markInvalid(this.errors.PwdShort);
20941 this.errorMsg = this.errors.PwdShort;
20944 if (value.length > 16) {
20945 this.markInvalid(this.errors.PwdLong);
20946 this.errorMsg = this.errors.PwdLong;
20950 if (this.ClientSideStrongPassword(value)) {
20952 } else if (this.ClientSideMediumPassword(value)) {
20954 } else if (this.ClientSideWeakPassword(value)) {
20961 if (strength < 2) {
20962 //this.markInvalid(this.errors.TooWeak);
20963 this.errorMsg = this.errors.TooWeak;
20968 console.log('strength2: ' + strength);
20970 //var pm = this.trigger.child('div/div/div').dom;
20972 var pm = this.trigger.child('div/div');
20973 pm.removeClass(this.meterClass);
20974 pm.addClass(this.meterClass[strength]);
20976 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20978 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20980 this.errorMsg = '';
20984 CharacterSetChecks: function (type)
20987 this.fResult = false;
20990 isctype: function (character, type)
20993 case this.kCapitalLetter:
20994 if (character >= 'A' && character <= 'Z') {
20999 case this.kSmallLetter:
21000 if (character >= 'a' && character <= 'z') {
21006 if (character >= '0' && character <= '9') {
21011 case this.kPunctuation:
21012 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21023 IsLongEnough: function (pwd, size)
21025 return !(pwd == null || isNaN(size) || pwd.length < size);
21028 SpansEnoughCharacterSets: function (word, nb)
21030 if (!this.IsLongEnough(word, nb))
21035 var characterSetChecks = new Array(
21036 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21037 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21040 for (var index = 0; index < word.length; ++index) {
21041 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21042 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21043 characterSetChecks[nCharSet].fResult = true;
21050 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21051 if (characterSetChecks[nCharSet].fResult) {
21056 if (nCharSets < nb) {
21062 ClientSideStrongPassword: function (pwd)
21064 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21067 ClientSideMediumPassword: function (pwd)
21069 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21072 ClientSideWeakPassword: function (pwd)
21074 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21077 })//<script type="text/javascript">
21080 * Based Ext JS Library 1.1.1
21081 * Copyright(c) 2006-2007, Ext JS, LLC.
21087 * @class Roo.HtmlEditorCore
21088 * @extends Roo.Component
21089 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21091 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21094 Roo.HtmlEditorCore = function(config){
21097 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21102 * @event initialize
21103 * Fires when the editor is fully initialized (including the iframe)
21104 * @param {Roo.HtmlEditorCore} this
21109 * Fires when the editor is first receives the focus. Any insertion must wait
21110 * until after this event.
21111 * @param {Roo.HtmlEditorCore} this
21115 * @event beforesync
21116 * Fires before the textarea is updated with content from the editor iframe. Return false
21117 * to cancel the sync.
21118 * @param {Roo.HtmlEditorCore} this
21119 * @param {String} html
21123 * @event beforepush
21124 * Fires before the iframe editor is updated with content from the textarea. Return false
21125 * to cancel the push.
21126 * @param {Roo.HtmlEditorCore} this
21127 * @param {String} html
21132 * Fires when the textarea is updated with content from the editor iframe.
21133 * @param {Roo.HtmlEditorCore} this
21134 * @param {String} html
21139 * Fires when the iframe editor is updated with content from the textarea.
21140 * @param {Roo.HtmlEditorCore} this
21141 * @param {String} html
21146 * @event editorevent
21147 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21148 * @param {Roo.HtmlEditorCore} this
21154 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21156 // defaults : white / black...
21157 this.applyBlacklists();
21164 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21168 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21174 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21179 * @cfg {Number} height (in pixels)
21183 * @cfg {Number} width (in pixels)
21188 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21191 stylesheets: false,
21196 // private properties
21197 validationEvent : false,
21199 initialized : false,
21201 sourceEditMode : false,
21202 onFocus : Roo.emptyFn,
21204 hideMode:'offsets',
21208 // blacklist + whitelisted elements..
21215 * Protected method that will not generally be called directly. It
21216 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21217 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21219 getDocMarkup : function(){
21223 // inherit styels from page...??
21224 if (this.stylesheets === false) {
21226 Roo.get(document.head).select('style').each(function(node) {
21227 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21230 Roo.get(document.head).select('link').each(function(node) {
21231 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21234 } else if (!this.stylesheets.length) {
21236 st = '<style type="text/css">' +
21237 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21243 st += '<style type="text/css">' +
21244 'IMG { cursor: pointer } ' +
21248 return '<html><head>' + st +
21249 //<style type="text/css">' +
21250 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21252 ' </head><body class="roo-htmleditor-body"></body></html>';
21256 onRender : function(ct, position)
21259 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21260 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21263 this.el.dom.style.border = '0 none';
21264 this.el.dom.setAttribute('tabIndex', -1);
21265 this.el.addClass('x-hidden hide');
21269 if(Roo.isIE){ // fix IE 1px bogus margin
21270 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21274 this.frameId = Roo.id();
21278 var iframe = this.owner.wrap.createChild({
21280 cls: 'form-control', // bootstrap..
21282 name: this.frameId,
21283 frameBorder : 'no',
21284 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21289 this.iframe = iframe.dom;
21291 this.assignDocWin();
21293 this.doc.designMode = 'on';
21296 this.doc.write(this.getDocMarkup());
21300 var task = { // must defer to wait for browser to be ready
21302 //console.log("run task?" + this.doc.readyState);
21303 this.assignDocWin();
21304 if(this.doc.body || this.doc.readyState == 'complete'){
21306 this.doc.designMode="on";
21310 Roo.TaskMgr.stop(task);
21311 this.initEditor.defer(10, this);
21318 Roo.TaskMgr.start(task);
21323 onResize : function(w, h)
21325 Roo.log('resize: ' +w + ',' + h );
21326 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21330 if(typeof w == 'number'){
21332 this.iframe.style.width = w + 'px';
21334 if(typeof h == 'number'){
21336 this.iframe.style.height = h + 'px';
21338 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21345 * Toggles the editor between standard and source edit mode.
21346 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21348 toggleSourceEdit : function(sourceEditMode){
21350 this.sourceEditMode = sourceEditMode === true;
21352 if(this.sourceEditMode){
21354 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21357 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21358 //this.iframe.className = '';
21361 //this.setSize(this.owner.wrap.getSize());
21362 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21369 * Protected method that will not generally be called directly. If you need/want
21370 * custom HTML cleanup, this is the method you should override.
21371 * @param {String} html The HTML to be cleaned
21372 * return {String} The cleaned HTML
21374 cleanHtml : function(html){
21375 html = String(html);
21376 if(html.length > 5){
21377 if(Roo.isSafari){ // strip safari nonsense
21378 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21381 if(html == ' '){
21388 * HTML Editor -> Textarea
21389 * Protected method that will not generally be called directly. Syncs the contents
21390 * of the editor iframe with the textarea.
21392 syncValue : function(){
21393 if(this.initialized){
21394 var bd = (this.doc.body || this.doc.documentElement);
21395 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21396 var html = bd.innerHTML;
21398 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21399 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21401 html = '<div style="'+m[0]+'">' + html + '</div>';
21404 html = this.cleanHtml(html);
21405 // fix up the special chars.. normaly like back quotes in word...
21406 // however we do not want to do this with chinese..
21407 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21408 var cc = b.charCodeAt();
21410 (cc >= 0x4E00 && cc < 0xA000 ) ||
21411 (cc >= 0x3400 && cc < 0x4E00 ) ||
21412 (cc >= 0xf900 && cc < 0xfb00 )
21418 if(this.owner.fireEvent('beforesync', this, html) !== false){
21419 this.el.dom.value = html;
21420 this.owner.fireEvent('sync', this, html);
21426 * Protected method that will not generally be called directly. Pushes the value of the textarea
21427 * into the iframe editor.
21429 pushValue : function(){
21430 if(this.initialized){
21431 var v = this.el.dom.value.trim();
21433 // if(v.length < 1){
21437 if(this.owner.fireEvent('beforepush', this, v) !== false){
21438 var d = (this.doc.body || this.doc.documentElement);
21440 this.cleanUpPaste();
21441 this.el.dom.value = d.innerHTML;
21442 this.owner.fireEvent('push', this, v);
21448 deferFocus : function(){
21449 this.focus.defer(10, this);
21453 focus : function(){
21454 if(this.win && !this.sourceEditMode){
21461 assignDocWin: function()
21463 var iframe = this.iframe;
21466 this.doc = iframe.contentWindow.document;
21467 this.win = iframe.contentWindow;
21469 // if (!Roo.get(this.frameId)) {
21472 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21473 // this.win = Roo.get(this.frameId).dom.contentWindow;
21475 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21479 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21480 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21485 initEditor : function(){
21486 //console.log("INIT EDITOR");
21487 this.assignDocWin();
21491 this.doc.designMode="on";
21493 this.doc.write(this.getDocMarkup());
21496 var dbody = (this.doc.body || this.doc.documentElement);
21497 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21498 // this copies styles from the containing element into thsi one..
21499 // not sure why we need all of this..
21500 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21502 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21503 //ss['background-attachment'] = 'fixed'; // w3c
21504 dbody.bgProperties = 'fixed'; // ie
21505 //Roo.DomHelper.applyStyles(dbody, ss);
21506 Roo.EventManager.on(this.doc, {
21507 //'mousedown': this.onEditorEvent,
21508 'mouseup': this.onEditorEvent,
21509 'dblclick': this.onEditorEvent,
21510 'click': this.onEditorEvent,
21511 'keyup': this.onEditorEvent,
21516 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21518 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21519 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21521 this.initialized = true;
21523 this.owner.fireEvent('initialize', this);
21528 onDestroy : function(){
21534 //for (var i =0; i < this.toolbars.length;i++) {
21535 // // fixme - ask toolbars for heights?
21536 // this.toolbars[i].onDestroy();
21539 //this.wrap.dom.innerHTML = '';
21540 //this.wrap.remove();
21545 onFirstFocus : function(){
21547 this.assignDocWin();
21550 this.activated = true;
21553 if(Roo.isGecko){ // prevent silly gecko errors
21555 var s = this.win.getSelection();
21556 if(!s.focusNode || s.focusNode.nodeType != 3){
21557 var r = s.getRangeAt(0);
21558 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21563 this.execCmd('useCSS', true);
21564 this.execCmd('styleWithCSS', false);
21567 this.owner.fireEvent('activate', this);
21571 adjustFont: function(btn){
21572 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21573 //if(Roo.isSafari){ // safari
21576 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21577 if(Roo.isSafari){ // safari
21578 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21579 v = (v < 10) ? 10 : v;
21580 v = (v > 48) ? 48 : v;
21581 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21586 v = Math.max(1, v+adjust);
21588 this.execCmd('FontSize', v );
21591 onEditorEvent : function(e)
21593 this.owner.fireEvent('editorevent', this, e);
21594 // this.updateToolbar();
21595 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21598 insertTag : function(tg)
21600 // could be a bit smarter... -> wrap the current selected tRoo..
21601 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21603 range = this.createRange(this.getSelection());
21604 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21605 wrappingNode.appendChild(range.extractContents());
21606 range.insertNode(wrappingNode);
21613 this.execCmd("formatblock", tg);
21617 insertText : function(txt)
21621 var range = this.createRange();
21622 range.deleteContents();
21623 //alert(Sender.getAttribute('label'));
21625 range.insertNode(this.doc.createTextNode(txt));
21631 * Executes a Midas editor command on the editor document and performs necessary focus and
21632 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21633 * @param {String} cmd The Midas command
21634 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21636 relayCmd : function(cmd, value){
21638 this.execCmd(cmd, value);
21639 this.owner.fireEvent('editorevent', this);
21640 //this.updateToolbar();
21641 this.owner.deferFocus();
21645 * Executes a Midas editor command directly on the editor document.
21646 * For visual commands, you should use {@link #relayCmd} instead.
21647 * <b>This should only be called after the editor is initialized.</b>
21648 * @param {String} cmd The Midas command
21649 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21651 execCmd : function(cmd, value){
21652 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21659 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21661 * @param {String} text | dom node..
21663 insertAtCursor : function(text)
21666 if(!this.activated){
21672 var r = this.doc.selection.createRange();
21683 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21687 // from jquery ui (MIT licenced)
21689 var win = this.win;
21691 if (win.getSelection && win.getSelection().getRangeAt) {
21692 range = win.getSelection().getRangeAt(0);
21693 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21694 range.insertNode(node);
21695 } else if (win.document.selection && win.document.selection.createRange) {
21696 // no firefox support
21697 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21698 win.document.selection.createRange().pasteHTML(txt);
21700 // no firefox support
21701 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21702 this.execCmd('InsertHTML', txt);
21711 mozKeyPress : function(e){
21713 var c = e.getCharCode(), cmd;
21716 c = String.fromCharCode(c).toLowerCase();
21730 this.cleanUpPaste.defer(100, this);
21738 e.preventDefault();
21746 fixKeys : function(){ // load time branching for fastest keydown performance
21748 return function(e){
21749 var k = e.getKey(), r;
21752 r = this.doc.selection.createRange();
21755 r.pasteHTML('    ');
21762 r = this.doc.selection.createRange();
21764 var target = r.parentElement();
21765 if(!target || target.tagName.toLowerCase() != 'li'){
21767 r.pasteHTML('<br />');
21773 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21774 this.cleanUpPaste.defer(100, this);
21780 }else if(Roo.isOpera){
21781 return function(e){
21782 var k = e.getKey();
21786 this.execCmd('InsertHTML','    ');
21789 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21790 this.cleanUpPaste.defer(100, this);
21795 }else if(Roo.isSafari){
21796 return function(e){
21797 var k = e.getKey();
21801 this.execCmd('InsertText','\t');
21805 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21806 this.cleanUpPaste.defer(100, this);
21814 getAllAncestors: function()
21816 var p = this.getSelectedNode();
21819 a.push(p); // push blank onto stack..
21820 p = this.getParentElement();
21824 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21828 a.push(this.doc.body);
21832 lastSelNode : false,
21835 getSelection : function()
21837 this.assignDocWin();
21838 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21841 getSelectedNode: function()
21843 // this may only work on Gecko!!!
21845 // should we cache this!!!!
21850 var range = this.createRange(this.getSelection()).cloneRange();
21853 var parent = range.parentElement();
21855 var testRange = range.duplicate();
21856 testRange.moveToElementText(parent);
21857 if (testRange.inRange(range)) {
21860 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21863 parent = parent.parentElement;
21868 // is ancestor a text element.
21869 var ac = range.commonAncestorContainer;
21870 if (ac.nodeType == 3) {
21871 ac = ac.parentNode;
21874 var ar = ac.childNodes;
21877 var other_nodes = [];
21878 var has_other_nodes = false;
21879 for (var i=0;i<ar.length;i++) {
21880 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21883 // fullly contained node.
21885 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21890 // probably selected..
21891 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21892 other_nodes.push(ar[i]);
21896 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21901 has_other_nodes = true;
21903 if (!nodes.length && other_nodes.length) {
21904 nodes= other_nodes;
21906 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21912 createRange: function(sel)
21914 // this has strange effects when using with
21915 // top toolbar - not sure if it's a great idea.
21916 //this.editor.contentWindow.focus();
21917 if (typeof sel != "undefined") {
21919 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21921 return this.doc.createRange();
21924 return this.doc.createRange();
21927 getParentElement: function()
21930 this.assignDocWin();
21931 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21933 var range = this.createRange(sel);
21936 var p = range.commonAncestorContainer;
21937 while (p.nodeType == 3) { // text node
21948 * Range intersection.. the hard stuff...
21952 * [ -- selected range --- ]
21956 * if end is before start or hits it. fail.
21957 * if start is after end or hits it fail.
21959 * if either hits (but other is outside. - then it's not
21965 // @see http://www.thismuchiknow.co.uk/?p=64.
21966 rangeIntersectsNode : function(range, node)
21968 var nodeRange = node.ownerDocument.createRange();
21970 nodeRange.selectNode(node);
21972 nodeRange.selectNodeContents(node);
21975 var rangeStartRange = range.cloneRange();
21976 rangeStartRange.collapse(true);
21978 var rangeEndRange = range.cloneRange();
21979 rangeEndRange.collapse(false);
21981 var nodeStartRange = nodeRange.cloneRange();
21982 nodeStartRange.collapse(true);
21984 var nodeEndRange = nodeRange.cloneRange();
21985 nodeEndRange.collapse(false);
21987 return rangeStartRange.compareBoundaryPoints(
21988 Range.START_TO_START, nodeEndRange) == -1 &&
21989 rangeEndRange.compareBoundaryPoints(
21990 Range.START_TO_START, nodeStartRange) == 1;
21994 rangeCompareNode : function(range, node)
21996 var nodeRange = node.ownerDocument.createRange();
21998 nodeRange.selectNode(node);
22000 nodeRange.selectNodeContents(node);
22004 range.collapse(true);
22006 nodeRange.collapse(true);
22008 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22009 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22011 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22013 var nodeIsBefore = ss == 1;
22014 var nodeIsAfter = ee == -1;
22016 if (nodeIsBefore && nodeIsAfter) {
22019 if (!nodeIsBefore && nodeIsAfter) {
22020 return 1; //right trailed.
22023 if (nodeIsBefore && !nodeIsAfter) {
22024 return 2; // left trailed.
22030 // private? - in a new class?
22031 cleanUpPaste : function()
22033 // cleans up the whole document..
22034 Roo.log('cleanuppaste');
22036 this.cleanUpChildren(this.doc.body);
22037 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22038 if (clean != this.doc.body.innerHTML) {
22039 this.doc.body.innerHTML = clean;
22044 cleanWordChars : function(input) {// change the chars to hex code
22045 var he = Roo.HtmlEditorCore;
22047 var output = input;
22048 Roo.each(he.swapCodes, function(sw) {
22049 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22051 output = output.replace(swapper, sw[1]);
22058 cleanUpChildren : function (n)
22060 if (!n.childNodes.length) {
22063 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22064 this.cleanUpChild(n.childNodes[i]);
22071 cleanUpChild : function (node)
22074 //console.log(node);
22075 if (node.nodeName == "#text") {
22076 // clean up silly Windows -- stuff?
22079 if (node.nodeName == "#comment") {
22080 node.parentNode.removeChild(node);
22081 // clean up silly Windows -- stuff?
22084 var lcname = node.tagName.toLowerCase();
22085 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22086 // whitelist of tags..
22088 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22090 node.parentNode.removeChild(node);
22095 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22097 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22098 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22100 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22101 // remove_keep_children = true;
22104 if (remove_keep_children) {
22105 this.cleanUpChildren(node);
22106 // inserts everything just before this node...
22107 while (node.childNodes.length) {
22108 var cn = node.childNodes[0];
22109 node.removeChild(cn);
22110 node.parentNode.insertBefore(cn, node);
22112 node.parentNode.removeChild(node);
22116 if (!node.attributes || !node.attributes.length) {
22117 this.cleanUpChildren(node);
22121 function cleanAttr(n,v)
22124 if (v.match(/^\./) || v.match(/^\//)) {
22127 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22130 if (v.match(/^#/)) {
22133 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22134 node.removeAttribute(n);
22138 var cwhite = this.cwhite;
22139 var cblack = this.cblack;
22141 function cleanStyle(n,v)
22143 if (v.match(/expression/)) { //XSS?? should we even bother..
22144 node.removeAttribute(n);
22148 var parts = v.split(/;/);
22151 Roo.each(parts, function(p) {
22152 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22156 var l = p.split(':').shift().replace(/\s+/g,'');
22157 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22159 if ( cwhite.length && cblack.indexOf(l) > -1) {
22160 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22161 //node.removeAttribute(n);
22165 // only allow 'c whitelisted system attributes'
22166 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22167 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22168 //node.removeAttribute(n);
22178 if (clean.length) {
22179 node.setAttribute(n, clean.join(';'));
22181 node.removeAttribute(n);
22187 for (var i = node.attributes.length-1; i > -1 ; i--) {
22188 var a = node.attributes[i];
22191 if (a.name.toLowerCase().substr(0,2)=='on') {
22192 node.removeAttribute(a.name);
22195 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22196 node.removeAttribute(a.name);
22199 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22200 cleanAttr(a.name,a.value); // fixme..
22203 if (a.name == 'style') {
22204 cleanStyle(a.name,a.value);
22207 /// clean up MS crap..
22208 // tecnically this should be a list of valid class'es..
22211 if (a.name == 'class') {
22212 if (a.value.match(/^Mso/)) {
22213 node.className = '';
22216 if (a.value.match(/^body$/)) {
22217 node.className = '';
22228 this.cleanUpChildren(node);
22234 * Clean up MS wordisms...
22236 cleanWord : function(node)
22241 this.cleanWord(this.doc.body);
22244 if (node.nodeName == "#text") {
22245 // clean up silly Windows -- stuff?
22248 if (node.nodeName == "#comment") {
22249 node.parentNode.removeChild(node);
22250 // clean up silly Windows -- stuff?
22254 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22255 node.parentNode.removeChild(node);
22259 // remove - but keep children..
22260 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22261 while (node.childNodes.length) {
22262 var cn = node.childNodes[0];
22263 node.removeChild(cn);
22264 node.parentNode.insertBefore(cn, node);
22266 node.parentNode.removeChild(node);
22267 this.iterateChildren(node, this.cleanWord);
22271 if (node.className.length) {
22273 var cn = node.className.split(/\W+/);
22275 Roo.each(cn, function(cls) {
22276 if (cls.match(/Mso[a-zA-Z]+/)) {
22281 node.className = cna.length ? cna.join(' ') : '';
22283 node.removeAttribute("class");
22287 if (node.hasAttribute("lang")) {
22288 node.removeAttribute("lang");
22291 if (node.hasAttribute("style")) {
22293 var styles = node.getAttribute("style").split(";");
22295 Roo.each(styles, function(s) {
22296 if (!s.match(/:/)) {
22299 var kv = s.split(":");
22300 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22303 // what ever is left... we allow.
22306 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22307 if (!nstyle.length) {
22308 node.removeAttribute('style');
22311 this.iterateChildren(node, this.cleanWord);
22317 * iterateChildren of a Node, calling fn each time, using this as the scole..
22318 * @param {DomNode} node node to iterate children of.
22319 * @param {Function} fn method of this class to call on each item.
22321 iterateChildren : function(node, fn)
22323 if (!node.childNodes.length) {
22326 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22327 fn.call(this, node.childNodes[i])
22333 * cleanTableWidths.
22335 * Quite often pasting from word etc.. results in tables with column and widths.
22336 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22339 cleanTableWidths : function(node)
22344 this.cleanTableWidths(this.doc.body);
22349 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22352 Roo.log(node.tagName);
22353 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22354 this.iterateChildren(node, this.cleanTableWidths);
22357 if (node.hasAttribute('width')) {
22358 node.removeAttribute('width');
22362 if (node.hasAttribute("style")) {
22365 var styles = node.getAttribute("style").split(";");
22367 Roo.each(styles, function(s) {
22368 if (!s.match(/:/)) {
22371 var kv = s.split(":");
22372 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22375 // what ever is left... we allow.
22378 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22379 if (!nstyle.length) {
22380 node.removeAttribute('style');
22384 this.iterateChildren(node, this.cleanTableWidths);
22392 domToHTML : function(currentElement, depth, nopadtext) {
22394 depth = depth || 0;
22395 nopadtext = nopadtext || false;
22397 if (!currentElement) {
22398 return this.domToHTML(this.doc.body);
22401 //Roo.log(currentElement);
22403 var allText = false;
22404 var nodeName = currentElement.nodeName;
22405 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22407 if (nodeName == '#text') {
22409 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22414 if (nodeName != 'BODY') {
22417 // Prints the node tagName, such as <A>, <IMG>, etc
22420 for(i = 0; i < currentElement.attributes.length;i++) {
22422 var aname = currentElement.attributes.item(i).name;
22423 if (!currentElement.attributes.item(i).value.length) {
22426 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22429 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22438 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22441 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22446 // Traverse the tree
22448 var currentElementChild = currentElement.childNodes.item(i);
22449 var allText = true;
22450 var innerHTML = '';
22452 while (currentElementChild) {
22453 // Formatting code (indent the tree so it looks nice on the screen)
22454 var nopad = nopadtext;
22455 if (lastnode == 'SPAN') {
22459 if (currentElementChild.nodeName == '#text') {
22460 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22461 toadd = nopadtext ? toadd : toadd.trim();
22462 if (!nopad && toadd.length > 80) {
22463 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22465 innerHTML += toadd;
22468 currentElementChild = currentElement.childNodes.item(i);
22474 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22476 // Recursively traverse the tree structure of the child node
22477 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22478 lastnode = currentElementChild.nodeName;
22480 currentElementChild=currentElement.childNodes.item(i);
22486 // The remaining code is mostly for formatting the tree
22487 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22492 ret+= "</"+tagName+">";
22498 applyBlacklists : function()
22500 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22501 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22505 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22506 if (b.indexOf(tag) > -1) {
22509 this.white.push(tag);
22513 Roo.each(w, function(tag) {
22514 if (b.indexOf(tag) > -1) {
22517 if (this.white.indexOf(tag) > -1) {
22520 this.white.push(tag);
22525 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22526 if (w.indexOf(tag) > -1) {
22529 this.black.push(tag);
22533 Roo.each(b, function(tag) {
22534 if (w.indexOf(tag) > -1) {
22537 if (this.black.indexOf(tag) > -1) {
22540 this.black.push(tag);
22545 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22546 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22550 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22551 if (b.indexOf(tag) > -1) {
22554 this.cwhite.push(tag);
22558 Roo.each(w, function(tag) {
22559 if (b.indexOf(tag) > -1) {
22562 if (this.cwhite.indexOf(tag) > -1) {
22565 this.cwhite.push(tag);
22570 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22571 if (w.indexOf(tag) > -1) {
22574 this.cblack.push(tag);
22578 Roo.each(b, function(tag) {
22579 if (w.indexOf(tag) > -1) {
22582 if (this.cblack.indexOf(tag) > -1) {
22585 this.cblack.push(tag);
22590 setStylesheets : function(stylesheets)
22592 if(typeof(stylesheets) == 'string'){
22593 Roo.get(this.iframe.contentDocument.head).createChild({
22595 rel : 'stylesheet',
22604 Roo.each(stylesheets, function(s) {
22609 Roo.get(_this.iframe.contentDocument.head).createChild({
22611 rel : 'stylesheet',
22620 removeStylesheets : function()
22624 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22629 // hide stuff that is not compatible
22643 * @event specialkey
22647 * @cfg {String} fieldClass @hide
22650 * @cfg {String} focusClass @hide
22653 * @cfg {String} autoCreate @hide
22656 * @cfg {String} inputType @hide
22659 * @cfg {String} invalidClass @hide
22662 * @cfg {String} invalidText @hide
22665 * @cfg {String} msgFx @hide
22668 * @cfg {String} validateOnBlur @hide
22672 Roo.HtmlEditorCore.white = [
22673 'area', 'br', 'img', 'input', 'hr', 'wbr',
22675 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22676 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22677 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22678 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22679 'table', 'ul', 'xmp',
22681 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22684 'dir', 'menu', 'ol', 'ul', 'dl',
22690 Roo.HtmlEditorCore.black = [
22691 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22693 'base', 'basefont', 'bgsound', 'blink', 'body',
22694 'frame', 'frameset', 'head', 'html', 'ilayer',
22695 'iframe', 'layer', 'link', 'meta', 'object',
22696 'script', 'style' ,'title', 'xml' // clean later..
22698 Roo.HtmlEditorCore.clean = [
22699 'script', 'style', 'title', 'xml'
22701 Roo.HtmlEditorCore.remove = [
22706 Roo.HtmlEditorCore.ablack = [
22710 Roo.HtmlEditorCore.aclean = [
22711 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22715 Roo.HtmlEditorCore.pwhite= [
22716 'http', 'https', 'mailto'
22719 // white listed style attributes.
22720 Roo.HtmlEditorCore.cwhite= [
22721 // 'text-align', /// default is to allow most things..
22727 // black listed style attributes.
22728 Roo.HtmlEditorCore.cblack= [
22729 // 'font-size' -- this can be set by the project
22733 Roo.HtmlEditorCore.swapCodes =[
22752 * @class Roo.bootstrap.HtmlEditor
22753 * @extends Roo.bootstrap.TextArea
22754 * Bootstrap HtmlEditor class
22757 * Create a new HtmlEditor
22758 * @param {Object} config The config object
22761 Roo.bootstrap.HtmlEditor = function(config){
22762 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22763 if (!this.toolbars) {
22764 this.toolbars = [];
22767 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22770 * @event initialize
22771 * Fires when the editor is fully initialized (including the iframe)
22772 * @param {HtmlEditor} this
22777 * Fires when the editor is first receives the focus. Any insertion must wait
22778 * until after this event.
22779 * @param {HtmlEditor} this
22783 * @event beforesync
22784 * Fires before the textarea is updated with content from the editor iframe. Return false
22785 * to cancel the sync.
22786 * @param {HtmlEditor} this
22787 * @param {String} html
22791 * @event beforepush
22792 * Fires before the iframe editor is updated with content from the textarea. Return false
22793 * to cancel the push.
22794 * @param {HtmlEditor} this
22795 * @param {String} html
22800 * Fires when the textarea is updated with content from the editor iframe.
22801 * @param {HtmlEditor} this
22802 * @param {String} html
22807 * Fires when the iframe editor is updated with content from the textarea.
22808 * @param {HtmlEditor} this
22809 * @param {String} html
22813 * @event editmodechange
22814 * Fires when the editor switches edit modes
22815 * @param {HtmlEditor} this
22816 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22818 editmodechange: true,
22820 * @event editorevent
22821 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22822 * @param {HtmlEditor} this
22826 * @event firstfocus
22827 * Fires when on first focus - needed by toolbars..
22828 * @param {HtmlEditor} this
22833 * Auto save the htmlEditor value as a file into Events
22834 * @param {HtmlEditor} this
22838 * @event savedpreview
22839 * preview the saved version of htmlEditor
22840 * @param {HtmlEditor} this
22847 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22851 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22856 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22861 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22866 * @cfg {Number} height (in pixels)
22870 * @cfg {Number} width (in pixels)
22875 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22878 stylesheets: false,
22883 // private properties
22884 validationEvent : false,
22886 initialized : false,
22889 onFocus : Roo.emptyFn,
22891 hideMode:'offsets',
22893 tbContainer : false,
22895 toolbarContainer :function() {
22896 return this.wrap.select('.x-html-editor-tb',true).first();
22900 * Protected method that will not generally be called directly. It
22901 * is called when the editor creates its toolbar. Override this method if you need to
22902 * add custom toolbar buttons.
22903 * @param {HtmlEditor} editor
22905 createToolbar : function(){
22906 Roo.log('renewing');
22907 Roo.log("create toolbars");
22909 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22910 this.toolbars[0].render(this.toolbarContainer());
22914 // if (!editor.toolbars || !editor.toolbars.length) {
22915 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22918 // for (var i =0 ; i < editor.toolbars.length;i++) {
22919 // editor.toolbars[i] = Roo.factory(
22920 // typeof(editor.toolbars[i]) == 'string' ?
22921 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22922 // Roo.bootstrap.HtmlEditor);
22923 // editor.toolbars[i].init(editor);
22929 onRender : function(ct, position)
22931 // Roo.log("Call onRender: " + this.xtype);
22933 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22935 this.wrap = this.inputEl().wrap({
22936 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22939 this.editorcore.onRender(ct, position);
22941 if (this.resizable) {
22942 this.resizeEl = new Roo.Resizable(this.wrap, {
22946 minHeight : this.height,
22947 height: this.height,
22948 handles : this.resizable,
22951 resize : function(r, w, h) {
22952 _t.onResize(w,h); // -something
22958 this.createToolbar(this);
22961 if(!this.width && this.resizable){
22962 this.setSize(this.wrap.getSize());
22964 if (this.resizeEl) {
22965 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22966 // should trigger onReize..
22972 onResize : function(w, h)
22974 Roo.log('resize: ' +w + ',' + h );
22975 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22979 if(this.inputEl() ){
22980 if(typeof w == 'number'){
22981 var aw = w - this.wrap.getFrameWidth('lr');
22982 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22985 if(typeof h == 'number'){
22986 var tbh = -11; // fixme it needs to tool bar size!
22987 for (var i =0; i < this.toolbars.length;i++) {
22988 // fixme - ask toolbars for heights?
22989 tbh += this.toolbars[i].el.getHeight();
22990 //if (this.toolbars[i].footer) {
22991 // tbh += this.toolbars[i].footer.el.getHeight();
22999 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23000 ah -= 5; // knock a few pixes off for look..
23001 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23005 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23006 this.editorcore.onResize(ew,eh);
23011 * Toggles the editor between standard and source edit mode.
23012 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23014 toggleSourceEdit : function(sourceEditMode)
23016 this.editorcore.toggleSourceEdit(sourceEditMode);
23018 if(this.editorcore.sourceEditMode){
23019 Roo.log('editor - showing textarea');
23022 // Roo.log(this.syncValue());
23024 this.inputEl().removeClass(['hide', 'x-hidden']);
23025 this.inputEl().dom.removeAttribute('tabIndex');
23026 this.inputEl().focus();
23028 Roo.log('editor - hiding textarea');
23030 // Roo.log(this.pushValue());
23033 this.inputEl().addClass(['hide', 'x-hidden']);
23034 this.inputEl().dom.setAttribute('tabIndex', -1);
23035 //this.deferFocus();
23038 if(this.resizable){
23039 this.setSize(this.wrap.getSize());
23042 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23045 // private (for BoxComponent)
23046 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23048 // private (for BoxComponent)
23049 getResizeEl : function(){
23053 // private (for BoxComponent)
23054 getPositionEl : function(){
23059 initEvents : function(){
23060 this.originalValue = this.getValue();
23064 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23067 // markInvalid : Roo.emptyFn,
23069 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23072 // clearInvalid : Roo.emptyFn,
23074 setValue : function(v){
23075 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23076 this.editorcore.pushValue();
23081 deferFocus : function(){
23082 this.focus.defer(10, this);
23086 focus : function(){
23087 this.editorcore.focus();
23093 onDestroy : function(){
23099 for (var i =0; i < this.toolbars.length;i++) {
23100 // fixme - ask toolbars for heights?
23101 this.toolbars[i].onDestroy();
23104 this.wrap.dom.innerHTML = '';
23105 this.wrap.remove();
23110 onFirstFocus : function(){
23111 //Roo.log("onFirstFocus");
23112 this.editorcore.onFirstFocus();
23113 for (var i =0; i < this.toolbars.length;i++) {
23114 this.toolbars[i].onFirstFocus();
23120 syncValue : function()
23122 this.editorcore.syncValue();
23125 pushValue : function()
23127 this.editorcore.pushValue();
23131 // hide stuff that is not compatible
23145 * @event specialkey
23149 * @cfg {String} fieldClass @hide
23152 * @cfg {String} focusClass @hide
23155 * @cfg {String} autoCreate @hide
23158 * @cfg {String} inputType @hide
23161 * @cfg {String} invalidClass @hide
23164 * @cfg {String} invalidText @hide
23167 * @cfg {String} msgFx @hide
23170 * @cfg {String} validateOnBlur @hide
23179 Roo.namespace('Roo.bootstrap.htmleditor');
23181 * @class Roo.bootstrap.HtmlEditorToolbar1
23186 new Roo.bootstrap.HtmlEditor({
23189 new Roo.bootstrap.HtmlEditorToolbar1({
23190 disable : { fonts: 1 , format: 1, ..., ... , ...],
23196 * @cfg {Object} disable List of elements to disable..
23197 * @cfg {Array} btns List of additional buttons.
23201 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23204 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23207 Roo.apply(this, config);
23209 // default disabled, based on 'good practice'..
23210 this.disable = this.disable || {};
23211 Roo.applyIf(this.disable, {
23214 specialElements : true
23216 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23218 this.editor = config.editor;
23219 this.editorcore = config.editor.editorcore;
23221 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23223 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23224 // dont call parent... till later.
23226 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23231 editorcore : false,
23236 "h1","h2","h3","h4","h5","h6",
23238 "abbr", "acronym", "address", "cite", "samp", "var",
23242 onRender : function(ct, position)
23244 // Roo.log("Call onRender: " + this.xtype);
23246 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23248 this.el.dom.style.marginBottom = '0';
23250 var editorcore = this.editorcore;
23251 var editor= this.editor;
23254 var btn = function(id,cmd , toggle, handler, html){
23256 var event = toggle ? 'toggle' : 'click';
23261 xns: Roo.bootstrap,
23264 enableToggle:toggle !== false,
23266 pressed : toggle ? false : null,
23269 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23270 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23276 // var cb_box = function...
23281 xns: Roo.bootstrap,
23282 glyphicon : 'font',
23286 xns: Roo.bootstrap,
23290 Roo.each(this.formats, function(f) {
23291 style.menu.items.push({
23293 xns: Roo.bootstrap,
23294 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23299 editorcore.insertTag(this.tagname);
23306 children.push(style);
23308 btn('bold',false,true);
23309 btn('italic',false,true);
23310 btn('align-left', 'justifyleft',true);
23311 btn('align-center', 'justifycenter',true);
23312 btn('align-right' , 'justifyright',true);
23313 btn('link', false, false, function(btn) {
23314 //Roo.log("create link?");
23315 var url = prompt(this.createLinkText, this.defaultLinkValue);
23316 if(url && url != 'http:/'+'/'){
23317 this.editorcore.relayCmd('createlink', url);
23320 btn('list','insertunorderedlist',true);
23321 btn('pencil', false,true, function(btn){
23323 this.toggleSourceEdit(btn.pressed);
23326 if (this.editor.btns.length > 0) {
23327 for (var i = 0; i<this.editor.btns.length; i++) {
23328 children.push(this.editor.btns[i]);
23336 xns: Roo.bootstrap,
23341 xns: Roo.bootstrap,
23346 cog.menu.items.push({
23348 xns: Roo.bootstrap,
23349 html : Clean styles,
23354 editorcore.insertTag(this.tagname);
23363 this.xtype = 'NavSimplebar';
23365 for(var i=0;i< children.length;i++) {
23367 this.buttons.add(this.addxtypeChild(children[i]));
23371 editor.on('editorevent', this.updateToolbar, this);
23373 onBtnClick : function(id)
23375 this.editorcore.relayCmd(id);
23376 this.editorcore.focus();
23380 * Protected method that will not generally be called directly. It triggers
23381 * a toolbar update by reading the markup state of the current selection in the editor.
23383 updateToolbar: function(){
23385 if(!this.editorcore.activated){
23386 this.editor.onFirstFocus(); // is this neeed?
23390 var btns = this.buttons;
23391 var doc = this.editorcore.doc;
23392 btns.get('bold').setActive(doc.queryCommandState('bold'));
23393 btns.get('italic').setActive(doc.queryCommandState('italic'));
23394 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23396 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23397 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23398 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23400 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23401 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23404 var ans = this.editorcore.getAllAncestors();
23405 if (this.formatCombo) {
23408 var store = this.formatCombo.store;
23409 this.formatCombo.setValue("");
23410 for (var i =0; i < ans.length;i++) {
23411 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23413 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23421 // hides menus... - so this cant be on a menu...
23422 Roo.bootstrap.MenuMgr.hideAll();
23424 Roo.bootstrap.MenuMgr.hideAll();
23425 //this.editorsyncValue();
23427 onFirstFocus: function() {
23428 this.buttons.each(function(item){
23432 toggleSourceEdit : function(sourceEditMode){
23435 if(sourceEditMode){
23436 Roo.log("disabling buttons");
23437 this.buttons.each( function(item){
23438 if(item.cmd != 'pencil'){
23444 Roo.log("enabling buttons");
23445 if(this.editorcore.initialized){
23446 this.buttons.each( function(item){
23452 Roo.log("calling toggole on editor");
23453 // tell the editor that it's been pressed..
23454 this.editor.toggleSourceEdit(sourceEditMode);
23464 * @class Roo.bootstrap.Table.AbstractSelectionModel
23465 * @extends Roo.util.Observable
23466 * Abstract base class for grid SelectionModels. It provides the interface that should be
23467 * implemented by descendant classes. This class should not be directly instantiated.
23470 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23471 this.locked = false;
23472 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23476 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23477 /** @ignore Called by the grid automatically. Do not call directly. */
23478 init : function(grid){
23484 * Locks the selections.
23487 this.locked = true;
23491 * Unlocks the selections.
23493 unlock : function(){
23494 this.locked = false;
23498 * Returns true if the selections are locked.
23499 * @return {Boolean}
23501 isLocked : function(){
23502 return this.locked;
23506 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23507 * @class Roo.bootstrap.Table.RowSelectionModel
23508 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23509 * It supports multiple selections and keyboard selection/navigation.
23511 * @param {Object} config
23514 Roo.bootstrap.Table.RowSelectionModel = function(config){
23515 Roo.apply(this, config);
23516 this.selections = new Roo.util.MixedCollection(false, function(o){
23521 this.lastActive = false;
23525 * @event selectionchange
23526 * Fires when the selection changes
23527 * @param {SelectionModel} this
23529 "selectionchange" : true,
23531 * @event afterselectionchange
23532 * Fires after the selection changes (eg. by key press or clicking)
23533 * @param {SelectionModel} this
23535 "afterselectionchange" : true,
23537 * @event beforerowselect
23538 * Fires when a row is selected being selected, return false to cancel.
23539 * @param {SelectionModel} this
23540 * @param {Number} rowIndex The selected index
23541 * @param {Boolean} keepExisting False if other selections will be cleared
23543 "beforerowselect" : true,
23546 * Fires when a row is selected.
23547 * @param {SelectionModel} this
23548 * @param {Number} rowIndex The selected index
23549 * @param {Roo.data.Record} r The record
23551 "rowselect" : true,
23553 * @event rowdeselect
23554 * Fires when a row is deselected.
23555 * @param {SelectionModel} this
23556 * @param {Number} rowIndex The selected index
23558 "rowdeselect" : true
23560 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23561 this.locked = false;
23564 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23566 * @cfg {Boolean} singleSelect
23567 * True to allow selection of only one row at a time (defaults to false)
23569 singleSelect : false,
23572 initEvents : function()
23575 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23576 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23577 //}else{ // allow click to work like normal
23578 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23580 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23581 this.grid.on("rowclick", this.handleMouseDown, this);
23583 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23584 "up" : function(e){
23586 this.selectPrevious(e.shiftKey);
23587 }else if(this.last !== false && this.lastActive !== false){
23588 var last = this.last;
23589 this.selectRange(this.last, this.lastActive-1);
23590 this.grid.getView().focusRow(this.lastActive);
23591 if(last !== false){
23595 this.selectFirstRow();
23597 this.fireEvent("afterselectionchange", this);
23599 "down" : function(e){
23601 this.selectNext(e.shiftKey);
23602 }else if(this.last !== false && this.lastActive !== false){
23603 var last = this.last;
23604 this.selectRange(this.last, this.lastActive+1);
23605 this.grid.getView().focusRow(this.lastActive);
23606 if(last !== false){
23610 this.selectFirstRow();
23612 this.fireEvent("afterselectionchange", this);
23616 this.grid.store.on('load', function(){
23617 this.selections.clear();
23620 var view = this.grid.view;
23621 view.on("refresh", this.onRefresh, this);
23622 view.on("rowupdated", this.onRowUpdated, this);
23623 view.on("rowremoved", this.onRemove, this);
23628 onRefresh : function()
23630 var ds = this.grid.store, i, v = this.grid.view;
23631 var s = this.selections;
23632 s.each(function(r){
23633 if((i = ds.indexOfId(r.id)) != -1){
23642 onRemove : function(v, index, r){
23643 this.selections.remove(r);
23647 onRowUpdated : function(v, index, r){
23648 if(this.isSelected(r)){
23649 v.onRowSelect(index);
23655 * @param {Array} records The records to select
23656 * @param {Boolean} keepExisting (optional) True to keep existing selections
23658 selectRecords : function(records, keepExisting)
23661 this.clearSelections();
23663 var ds = this.grid.store;
23664 for(var i = 0, len = records.length; i < len; i++){
23665 this.selectRow(ds.indexOf(records[i]), true);
23670 * Gets the number of selected rows.
23673 getCount : function(){
23674 return this.selections.length;
23678 * Selects the first row in the grid.
23680 selectFirstRow : function(){
23685 * Select the last row.
23686 * @param {Boolean} keepExisting (optional) True to keep existing selections
23688 selectLastRow : function(keepExisting){
23689 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23690 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23694 * Selects the row immediately following the last selected row.
23695 * @param {Boolean} keepExisting (optional) True to keep existing selections
23697 selectNext : function(keepExisting)
23699 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23700 this.selectRow(this.last+1, keepExisting);
23701 this.grid.getView().focusRow(this.last);
23706 * Selects the row that precedes the last selected row.
23707 * @param {Boolean} keepExisting (optional) True to keep existing selections
23709 selectPrevious : function(keepExisting){
23711 this.selectRow(this.last-1, keepExisting);
23712 this.grid.getView().focusRow(this.last);
23717 * Returns the selected records
23718 * @return {Array} Array of selected records
23720 getSelections : function(){
23721 return [].concat(this.selections.items);
23725 * Returns the first selected record.
23728 getSelected : function(){
23729 return this.selections.itemAt(0);
23734 * Clears all selections.
23736 clearSelections : function(fast)
23742 var ds = this.grid.store;
23743 var s = this.selections;
23744 s.each(function(r){
23745 this.deselectRow(ds.indexOfId(r.id));
23749 this.selections.clear();
23756 * Selects all rows.
23758 selectAll : function(){
23762 this.selections.clear();
23763 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23764 this.selectRow(i, true);
23769 * Returns True if there is a selection.
23770 * @return {Boolean}
23772 hasSelection : function(){
23773 return this.selections.length > 0;
23777 * Returns True if the specified row is selected.
23778 * @param {Number/Record} record The record or index of the record to check
23779 * @return {Boolean}
23781 isSelected : function(index){
23782 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23783 return (r && this.selections.key(r.id) ? true : false);
23787 * Returns True if the specified record id is selected.
23788 * @param {String} id The id of record to check
23789 * @return {Boolean}
23791 isIdSelected : function(id){
23792 return (this.selections.key(id) ? true : false);
23797 handleMouseDBClick : function(e, t){
23801 handleMouseDown : function(e, t)
23803 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23804 if(this.isLocked() || rowIndex < 0 ){
23807 if(e.shiftKey && this.last !== false){
23808 var last = this.last;
23809 this.selectRange(last, rowIndex, e.ctrlKey);
23810 this.last = last; // reset the last
23814 var isSelected = this.isSelected(rowIndex);
23815 //Roo.log("select row:" + rowIndex);
23817 this.deselectRow(rowIndex);
23819 this.selectRow(rowIndex, true);
23823 if(e.button !== 0 && isSelected){
23824 alert('rowIndex 2: ' + rowIndex);
23825 view.focusRow(rowIndex);
23826 }else if(e.ctrlKey && isSelected){
23827 this.deselectRow(rowIndex);
23828 }else if(!isSelected){
23829 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23830 view.focusRow(rowIndex);
23834 this.fireEvent("afterselectionchange", this);
23837 handleDragableRowClick : function(grid, rowIndex, e)
23839 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23840 this.selectRow(rowIndex, false);
23841 grid.view.focusRow(rowIndex);
23842 this.fireEvent("afterselectionchange", this);
23847 * Selects multiple rows.
23848 * @param {Array} rows Array of the indexes of the row to select
23849 * @param {Boolean} keepExisting (optional) True to keep existing selections
23851 selectRows : function(rows, keepExisting){
23853 this.clearSelections();
23855 for(var i = 0, len = rows.length; i < len; i++){
23856 this.selectRow(rows[i], true);
23861 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23862 * @param {Number} startRow The index of the first row in the range
23863 * @param {Number} endRow The index of the last row in the range
23864 * @param {Boolean} keepExisting (optional) True to retain existing selections
23866 selectRange : function(startRow, endRow, keepExisting){
23871 this.clearSelections();
23873 if(startRow <= endRow){
23874 for(var i = startRow; i <= endRow; i++){
23875 this.selectRow(i, true);
23878 for(var i = startRow; i >= endRow; i--){
23879 this.selectRow(i, true);
23885 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23886 * @param {Number} startRow The index of the first row in the range
23887 * @param {Number} endRow The index of the last row in the range
23889 deselectRange : function(startRow, endRow, preventViewNotify){
23893 for(var i = startRow; i <= endRow; i++){
23894 this.deselectRow(i, preventViewNotify);
23900 * @param {Number} row The index of the row to select
23901 * @param {Boolean} keepExisting (optional) True to keep existing selections
23903 selectRow : function(index, keepExisting, preventViewNotify)
23905 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23908 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23909 if(!keepExisting || this.singleSelect){
23910 this.clearSelections();
23913 var r = this.grid.store.getAt(index);
23914 //console.log('selectRow - record id :' + r.id);
23916 this.selections.add(r);
23917 this.last = this.lastActive = index;
23918 if(!preventViewNotify){
23919 var proxy = new Roo.Element(
23920 this.grid.getRowDom(index)
23922 proxy.addClass('bg-info info');
23924 this.fireEvent("rowselect", this, index, r);
23925 this.fireEvent("selectionchange", this);
23931 * @param {Number} row The index of the row to deselect
23933 deselectRow : function(index, preventViewNotify)
23938 if(this.last == index){
23941 if(this.lastActive == index){
23942 this.lastActive = false;
23945 var r = this.grid.store.getAt(index);
23950 this.selections.remove(r);
23951 //.console.log('deselectRow - record id :' + r.id);
23952 if(!preventViewNotify){
23954 var proxy = new Roo.Element(
23955 this.grid.getRowDom(index)
23957 proxy.removeClass('bg-info info');
23959 this.fireEvent("rowdeselect", this, index);
23960 this.fireEvent("selectionchange", this);
23964 restoreLast : function(){
23966 this.last = this._last;
23971 acceptsNav : function(row, col, cm){
23972 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23976 onEditorKey : function(field, e){
23977 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23982 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23984 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23986 }else if(k == e.ENTER && !e.ctrlKey){
23990 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23992 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23994 }else if(k == e.ESC){
23998 g.startEditing(newCell[0], newCell[1]);
24004 * Ext JS Library 1.1.1
24005 * Copyright(c) 2006-2007, Ext JS, LLC.
24007 * Originally Released Under LGPL - original licence link has changed is not relivant.
24010 * <script type="text/javascript">
24014 * @class Roo.bootstrap.PagingToolbar
24015 * @extends Roo.bootstrap.NavSimplebar
24016 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24018 * Create a new PagingToolbar
24019 * @param {Object} config The config object
24020 * @param {Roo.data.Store} store
24022 Roo.bootstrap.PagingToolbar = function(config)
24024 // old args format still supported... - xtype is prefered..
24025 // created from xtype...
24027 this.ds = config.dataSource;
24029 if (config.store && !this.ds) {
24030 this.store= Roo.factory(config.store, Roo.data);
24031 this.ds = this.store;
24032 this.ds.xmodule = this.xmodule || false;
24035 this.toolbarItems = [];
24036 if (config.items) {
24037 this.toolbarItems = config.items;
24040 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24045 this.bind(this.ds);
24048 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24052 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24054 * @cfg {Roo.data.Store} dataSource
24055 * The underlying data store providing the paged data
24058 * @cfg {String/HTMLElement/Element} container
24059 * container The id or element that will contain the toolbar
24062 * @cfg {Boolean} displayInfo
24063 * True to display the displayMsg (defaults to false)
24066 * @cfg {Number} pageSize
24067 * The number of records to display per page (defaults to 20)
24071 * @cfg {String} displayMsg
24072 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24074 displayMsg : 'Displaying {0} - {1} of {2}',
24076 * @cfg {String} emptyMsg
24077 * The message to display when no records are found (defaults to "No data to display")
24079 emptyMsg : 'No data to display',
24081 * Customizable piece of the default paging text (defaults to "Page")
24084 beforePageText : "Page",
24086 * Customizable piece of the default paging text (defaults to "of %0")
24089 afterPageText : "of {0}",
24091 * Customizable piece of the default paging text (defaults to "First Page")
24094 firstText : "First Page",
24096 * Customizable piece of the default paging text (defaults to "Previous Page")
24099 prevText : "Previous Page",
24101 * Customizable piece of the default paging text (defaults to "Next Page")
24104 nextText : "Next Page",
24106 * Customizable piece of the default paging text (defaults to "Last Page")
24109 lastText : "Last Page",
24111 * Customizable piece of the default paging text (defaults to "Refresh")
24114 refreshText : "Refresh",
24118 onRender : function(ct, position)
24120 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24121 this.navgroup.parentId = this.id;
24122 this.navgroup.onRender(this.el, null);
24123 // add the buttons to the navgroup
24125 if(this.displayInfo){
24126 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24127 this.displayEl = this.el.select('.x-paging-info', true).first();
24128 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24129 // this.displayEl = navel.el.select('span',true).first();
24135 Roo.each(_this.buttons, function(e){ // this might need to use render????
24136 Roo.factory(e).onRender(_this.el, null);
24140 Roo.each(_this.toolbarItems, function(e) {
24141 _this.navgroup.addItem(e);
24145 this.first = this.navgroup.addItem({
24146 tooltip: this.firstText,
24148 icon : 'fa fa-backward',
24150 preventDefault: true,
24151 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24154 this.prev = this.navgroup.addItem({
24155 tooltip: this.prevText,
24157 icon : 'fa fa-step-backward',
24159 preventDefault: true,
24160 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24162 //this.addSeparator();
24165 var field = this.navgroup.addItem( {
24167 cls : 'x-paging-position',
24169 html : this.beforePageText +
24170 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24171 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24174 this.field = field.el.select('input', true).first();
24175 this.field.on("keydown", this.onPagingKeydown, this);
24176 this.field.on("focus", function(){this.dom.select();});
24179 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24180 //this.field.setHeight(18);
24181 //this.addSeparator();
24182 this.next = this.navgroup.addItem({
24183 tooltip: this.nextText,
24185 html : ' <i class="fa fa-step-forward">',
24187 preventDefault: true,
24188 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24190 this.last = this.navgroup.addItem({
24191 tooltip: this.lastText,
24192 icon : 'fa fa-forward',
24195 preventDefault: true,
24196 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24198 //this.addSeparator();
24199 this.loading = this.navgroup.addItem({
24200 tooltip: this.refreshText,
24201 icon: 'fa fa-refresh',
24202 preventDefault: true,
24203 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24209 updateInfo : function(){
24210 if(this.displayEl){
24211 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24212 var msg = count == 0 ?
24216 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24218 this.displayEl.update(msg);
24223 onLoad : function(ds, r, o)
24225 this.cursor = o.params ? o.params.start : 0;
24226 var d = this.getPageData(),
24231 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24232 this.field.dom.value = ap;
24233 this.first.setDisabled(ap == 1);
24234 this.prev.setDisabled(ap == 1);
24235 this.next.setDisabled(ap == ps);
24236 this.last.setDisabled(ap == ps);
24237 this.loading.enable();
24242 getPageData : function(){
24243 var total = this.ds.getTotalCount();
24246 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24247 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24252 onLoadError : function(){
24253 this.loading.enable();
24257 onPagingKeydown : function(e){
24258 var k = e.getKey();
24259 var d = this.getPageData();
24261 var v = this.field.dom.value, pageNum;
24262 if(!v || isNaN(pageNum = parseInt(v, 10))){
24263 this.field.dom.value = d.activePage;
24266 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24267 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24270 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))
24272 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24273 this.field.dom.value = pageNum;
24274 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24277 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24279 var v = this.field.dom.value, pageNum;
24280 var increment = (e.shiftKey) ? 10 : 1;
24281 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24284 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24285 this.field.dom.value = d.activePage;
24288 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24290 this.field.dom.value = parseInt(v, 10) + increment;
24291 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24292 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24299 beforeLoad : function(){
24301 this.loading.disable();
24306 onClick : function(which){
24315 ds.load({params:{start: 0, limit: this.pageSize}});
24318 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24321 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24324 var total = ds.getTotalCount();
24325 var extra = total % this.pageSize;
24326 var lastStart = extra ? (total - extra) : total-this.pageSize;
24327 ds.load({params:{start: lastStart, limit: this.pageSize}});
24330 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24336 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24337 * @param {Roo.data.Store} store The data store to unbind
24339 unbind : function(ds){
24340 ds.un("beforeload", this.beforeLoad, this);
24341 ds.un("load", this.onLoad, this);
24342 ds.un("loadexception", this.onLoadError, this);
24343 ds.un("remove", this.updateInfo, this);
24344 ds.un("add", this.updateInfo, this);
24345 this.ds = undefined;
24349 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24350 * @param {Roo.data.Store} store The data store to bind
24352 bind : function(ds){
24353 ds.on("beforeload", this.beforeLoad, this);
24354 ds.on("load", this.onLoad, this);
24355 ds.on("loadexception", this.onLoadError, this);
24356 ds.on("remove", this.updateInfo, this);
24357 ds.on("add", this.updateInfo, this);
24368 * @class Roo.bootstrap.MessageBar
24369 * @extends Roo.bootstrap.Component
24370 * Bootstrap MessageBar class
24371 * @cfg {String} html contents of the MessageBar
24372 * @cfg {String} weight (info | success | warning | danger) default info
24373 * @cfg {String} beforeClass insert the bar before the given class
24374 * @cfg {Boolean} closable (true | false) default false
24375 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24378 * Create a new Element
24379 * @param {Object} config The config object
24382 Roo.bootstrap.MessageBar = function(config){
24383 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24386 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24392 beforeClass: 'bootstrap-sticky-wrap',
24394 getAutoCreate : function(){
24398 cls: 'alert alert-dismissable alert-' + this.weight,
24403 html: this.html || ''
24409 cfg.cls += ' alert-messages-fixed';
24423 onRender : function(ct, position)
24425 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24428 var cfg = Roo.apply({}, this.getAutoCreate());
24432 cfg.cls += ' ' + this.cls;
24435 cfg.style = this.style;
24437 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24439 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24442 this.el.select('>button.close').on('click', this.hide, this);
24448 if (!this.rendered) {
24454 this.fireEvent('show', this);
24460 if (!this.rendered) {
24466 this.fireEvent('hide', this);
24469 update : function()
24471 // var e = this.el.dom.firstChild;
24473 // if(this.closable){
24474 // e = e.nextSibling;
24477 // e.data = this.html || '';
24479 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24495 * @class Roo.bootstrap.Graph
24496 * @extends Roo.bootstrap.Component
24497 * Bootstrap Graph class
24501 @cfg {String} graphtype bar | vbar | pie
24502 @cfg {number} g_x coodinator | centre x (pie)
24503 @cfg {number} g_y coodinator | centre y (pie)
24504 @cfg {number} g_r radius (pie)
24505 @cfg {number} g_height height of the chart (respected by all elements in the set)
24506 @cfg {number} g_width width of the chart (respected by all elements in the set)
24507 @cfg {Object} title The title of the chart
24510 -opts (object) options for the chart
24512 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24513 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24515 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.
24516 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24518 o stretch (boolean)
24520 -opts (object) options for the pie
24523 o startAngle (number)
24524 o endAngle (number)
24528 * Create a new Input
24529 * @param {Object} config The config object
24532 Roo.bootstrap.Graph = function(config){
24533 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24539 * The img click event for the img.
24540 * @param {Roo.EventObject} e
24546 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24557 //g_colors: this.colors,
24564 getAutoCreate : function(){
24575 onRender : function(ct,position){
24578 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24580 if (typeof(Raphael) == 'undefined') {
24581 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24585 this.raphael = Raphael(this.el.dom);
24587 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24588 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24589 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24590 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24592 r.text(160, 10, "Single Series Chart").attr(txtattr);
24593 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24594 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24595 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24597 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24598 r.barchart(330, 10, 300, 220, data1);
24599 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24600 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24603 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24604 // r.barchart(30, 30, 560, 250, xdata, {
24605 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24606 // axis : "0 0 1 1",
24607 // axisxlabels : xdata
24608 // //yvalues : cols,
24611 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24613 // this.load(null,xdata,{
24614 // axis : "0 0 1 1",
24615 // axisxlabels : xdata
24620 load : function(graphtype,xdata,opts)
24622 this.raphael.clear();
24624 graphtype = this.graphtype;
24629 var r = this.raphael,
24630 fin = function () {
24631 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24633 fout = function () {
24634 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24636 pfin = function() {
24637 this.sector.stop();
24638 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24641 this.label[0].stop();
24642 this.label[0].attr({ r: 7.5 });
24643 this.label[1].attr({ "font-weight": 800 });
24646 pfout = function() {
24647 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24650 this.label[0].animate({ r: 5 }, 500, "bounce");
24651 this.label[1].attr({ "font-weight": 400 });
24657 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24660 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24663 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24664 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24666 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24673 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24678 setTitle: function(o)
24683 initEvents: function() {
24686 this.el.on('click', this.onClick, this);
24690 onClick : function(e)
24692 Roo.log('img onclick');
24693 this.fireEvent('click', this, e);
24705 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24708 * @class Roo.bootstrap.dash.NumberBox
24709 * @extends Roo.bootstrap.Component
24710 * Bootstrap NumberBox class
24711 * @cfg {String} headline Box headline
24712 * @cfg {String} content Box content
24713 * @cfg {String} icon Box icon
24714 * @cfg {String} footer Footer text
24715 * @cfg {String} fhref Footer href
24718 * Create a new NumberBox
24719 * @param {Object} config The config object
24723 Roo.bootstrap.dash.NumberBox = function(config){
24724 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24728 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24737 getAutoCreate : function(){
24741 cls : 'small-box ',
24749 cls : 'roo-headline',
24750 html : this.headline
24754 cls : 'roo-content',
24755 html : this.content
24769 cls : 'ion ' + this.icon
24778 cls : 'small-box-footer',
24779 href : this.fhref || '#',
24783 cfg.cn.push(footer);
24790 onRender : function(ct,position){
24791 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24798 setHeadline: function (value)
24800 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24803 setFooter: function (value, href)
24805 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24808 this.el.select('a.small-box-footer',true).first().attr('href', href);
24813 setContent: function (value)
24815 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24818 initEvents: function()
24832 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24835 * @class Roo.bootstrap.dash.TabBox
24836 * @extends Roo.bootstrap.Component
24837 * Bootstrap TabBox class
24838 * @cfg {String} title Title of the TabBox
24839 * @cfg {String} icon Icon of the TabBox
24840 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24841 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24844 * Create a new TabBox
24845 * @param {Object} config The config object
24849 Roo.bootstrap.dash.TabBox = function(config){
24850 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24855 * When a pane is added
24856 * @param {Roo.bootstrap.dash.TabPane} pane
24860 * @event activatepane
24861 * When a pane is activated
24862 * @param {Roo.bootstrap.dash.TabPane} pane
24864 "activatepane" : true
24872 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24877 tabScrollable : false,
24879 getChildContainer : function()
24881 return this.el.select('.tab-content', true).first();
24884 getAutoCreate : function(){
24888 cls: 'pull-left header',
24896 cls: 'fa ' + this.icon
24902 cls: 'nav nav-tabs pull-right',
24908 if(this.tabScrollable){
24915 cls: 'nav nav-tabs pull-right',
24926 cls: 'nav-tabs-custom',
24931 cls: 'tab-content no-padding',
24939 initEvents : function()
24941 //Roo.log('add add pane handler');
24942 this.on('addpane', this.onAddPane, this);
24945 * Updates the box title
24946 * @param {String} html to set the title to.
24948 setTitle : function(value)
24950 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24952 onAddPane : function(pane)
24954 this.panes.push(pane);
24955 //Roo.log('addpane');
24957 // tabs are rendere left to right..
24958 if(!this.showtabs){
24962 var ctr = this.el.select('.nav-tabs', true).first();
24965 var existing = ctr.select('.nav-tab',true);
24966 var qty = existing.getCount();;
24969 var tab = ctr.createChild({
24971 cls : 'nav-tab' + (qty ? '' : ' active'),
24979 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24982 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24984 pane.el.addClass('active');
24989 onTabClick : function(ev,un,ob,pane)
24991 //Roo.log('tab - prev default');
24992 ev.preventDefault();
24995 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24996 pane.tab.addClass('active');
24997 //Roo.log(pane.title);
24998 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24999 // technically we should have a deactivate event.. but maybe add later.
25000 // and it should not de-activate the selected tab...
25001 this.fireEvent('activatepane', pane);
25002 pane.el.addClass('active');
25003 pane.fireEvent('activate');
25008 getActivePane : function()
25011 Roo.each(this.panes, function(p) {
25012 if(p.el.hasClass('active')){
25033 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25035 * @class Roo.bootstrap.TabPane
25036 * @extends Roo.bootstrap.Component
25037 * Bootstrap TabPane class
25038 * @cfg {Boolean} active (false | true) Default false
25039 * @cfg {String} title title of panel
25043 * Create a new TabPane
25044 * @param {Object} config The config object
25047 Roo.bootstrap.dash.TabPane = function(config){
25048 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25054 * When a pane is activated
25055 * @param {Roo.bootstrap.dash.TabPane} pane
25062 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25067 // the tabBox that this is attached to.
25070 getAutoCreate : function()
25078 cfg.cls += ' active';
25083 initEvents : function()
25085 //Roo.log('trigger add pane handler');
25086 this.parent().fireEvent('addpane', this)
25090 * Updates the tab title
25091 * @param {String} html to set the title to.
25093 setTitle: function(str)
25099 this.tab.select('a', true).first().dom.innerHTML = str;
25116 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25119 * @class Roo.bootstrap.menu.Menu
25120 * @extends Roo.bootstrap.Component
25121 * Bootstrap Menu class - container for Menu
25122 * @cfg {String} html Text of the menu
25123 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25124 * @cfg {String} icon Font awesome icon
25125 * @cfg {String} pos Menu align to (top | bottom) default bottom
25129 * Create a new Menu
25130 * @param {Object} config The config object
25134 Roo.bootstrap.menu.Menu = function(config){
25135 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25139 * @event beforeshow
25140 * Fires before this menu is displayed
25141 * @param {Roo.bootstrap.menu.Menu} this
25145 * @event beforehide
25146 * Fires before this menu is hidden
25147 * @param {Roo.bootstrap.menu.Menu} this
25152 * Fires after this menu is displayed
25153 * @param {Roo.bootstrap.menu.Menu} this
25158 * Fires after this menu is hidden
25159 * @param {Roo.bootstrap.menu.Menu} this
25164 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25165 * @param {Roo.bootstrap.menu.Menu} this
25166 * @param {Roo.EventObject} e
25173 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25177 weight : 'default',
25182 getChildContainer : function() {
25183 if(this.isSubMenu){
25187 return this.el.select('ul.dropdown-menu', true).first();
25190 getAutoCreate : function()
25195 cls : 'roo-menu-text',
25203 cls : 'fa ' + this.icon
25214 cls : 'dropdown-button btn btn-' + this.weight,
25219 cls : 'dropdown-toggle btn btn-' + this.weight,
25229 cls : 'dropdown-menu'
25235 if(this.pos == 'top'){
25236 cfg.cls += ' dropup';
25239 if(this.isSubMenu){
25242 cls : 'dropdown-menu'
25249 onRender : function(ct, position)
25251 this.isSubMenu = ct.hasClass('dropdown-submenu');
25253 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25256 initEvents : function()
25258 if(this.isSubMenu){
25262 this.hidden = true;
25264 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25265 this.triggerEl.on('click', this.onTriggerPress, this);
25267 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25268 this.buttonEl.on('click', this.onClick, this);
25274 if(this.isSubMenu){
25278 return this.el.select('ul.dropdown-menu', true).first();
25281 onClick : function(e)
25283 this.fireEvent("click", this, e);
25286 onTriggerPress : function(e)
25288 if (this.isVisible()) {
25295 isVisible : function(){
25296 return !this.hidden;
25301 this.fireEvent("beforeshow", this);
25303 this.hidden = false;
25304 this.el.addClass('open');
25306 Roo.get(document).on("mouseup", this.onMouseUp, this);
25308 this.fireEvent("show", this);
25315 this.fireEvent("beforehide", this);
25317 this.hidden = true;
25318 this.el.removeClass('open');
25320 Roo.get(document).un("mouseup", this.onMouseUp);
25322 this.fireEvent("hide", this);
25325 onMouseUp : function()
25339 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25342 * @class Roo.bootstrap.menu.Item
25343 * @extends Roo.bootstrap.Component
25344 * Bootstrap MenuItem class
25345 * @cfg {Boolean} submenu (true | false) default false
25346 * @cfg {String} html text of the item
25347 * @cfg {String} href the link
25348 * @cfg {Boolean} disable (true | false) default false
25349 * @cfg {Boolean} preventDefault (true | false) default true
25350 * @cfg {String} icon Font awesome icon
25351 * @cfg {String} pos Submenu align to (left | right) default right
25355 * Create a new Item
25356 * @param {Object} config The config object
25360 Roo.bootstrap.menu.Item = function(config){
25361 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25365 * Fires when the mouse is hovering over this menu
25366 * @param {Roo.bootstrap.menu.Item} this
25367 * @param {Roo.EventObject} e
25372 * Fires when the mouse exits this menu
25373 * @param {Roo.bootstrap.menu.Item} this
25374 * @param {Roo.EventObject} e
25380 * The raw click event for the entire grid.
25381 * @param {Roo.EventObject} e
25387 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25392 preventDefault: true,
25397 getAutoCreate : function()
25402 cls : 'roo-menu-item-text',
25410 cls : 'fa ' + this.icon
25419 href : this.href || '#',
25426 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25430 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25432 if(this.pos == 'left'){
25433 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25440 initEvents : function()
25442 this.el.on('mouseover', this.onMouseOver, this);
25443 this.el.on('mouseout', this.onMouseOut, this);
25445 this.el.select('a', true).first().on('click', this.onClick, this);
25449 onClick : function(e)
25451 if(this.preventDefault){
25452 e.preventDefault();
25455 this.fireEvent("click", this, e);
25458 onMouseOver : function(e)
25460 if(this.submenu && this.pos == 'left'){
25461 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25464 this.fireEvent("mouseover", this, e);
25467 onMouseOut : function(e)
25469 this.fireEvent("mouseout", this, e);
25481 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25484 * @class Roo.bootstrap.menu.Separator
25485 * @extends Roo.bootstrap.Component
25486 * Bootstrap Separator class
25489 * Create a new Separator
25490 * @param {Object} config The config object
25494 Roo.bootstrap.menu.Separator = function(config){
25495 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25498 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25500 getAutoCreate : function(){
25521 * @class Roo.bootstrap.Tooltip
25522 * Bootstrap Tooltip class
25523 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25524 * to determine which dom element triggers the tooltip.
25526 * It needs to add support for additional attributes like tooltip-position
25529 * Create a new Toolti
25530 * @param {Object} config The config object
25533 Roo.bootstrap.Tooltip = function(config){
25534 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25536 this.alignment = Roo.bootstrap.Tooltip.alignment;
25538 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25539 this.alignment = config.alignment;
25544 Roo.apply(Roo.bootstrap.Tooltip, {
25546 * @function init initialize tooltip monitoring.
25550 currentTip : false,
25551 currentRegion : false,
25557 Roo.get(document).on('mouseover', this.enter ,this);
25558 Roo.get(document).on('mouseout', this.leave, this);
25561 this.currentTip = new Roo.bootstrap.Tooltip();
25564 enter : function(ev)
25566 var dom = ev.getTarget();
25568 //Roo.log(['enter',dom]);
25569 var el = Roo.fly(dom);
25570 if (this.currentEl) {
25572 //Roo.log(this.currentEl);
25573 //Roo.log(this.currentEl.contains(dom));
25574 if (this.currentEl == el) {
25577 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25583 if (this.currentTip.el) {
25584 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25588 if(!el || el.dom == document){
25594 // you can not look for children, as if el is the body.. then everythign is the child..
25595 if (!el.attr('tooltip')) { //
25596 if (!el.select("[tooltip]").elements.length) {
25599 // is the mouse over this child...?
25600 bindEl = el.select("[tooltip]").first();
25601 var xy = ev.getXY();
25602 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25603 //Roo.log("not in region.");
25606 //Roo.log("child element over..");
25609 this.currentEl = bindEl;
25610 this.currentTip.bind(bindEl);
25611 this.currentRegion = Roo.lib.Region.getRegion(dom);
25612 this.currentTip.enter();
25615 leave : function(ev)
25617 var dom = ev.getTarget();
25618 //Roo.log(['leave',dom]);
25619 if (!this.currentEl) {
25624 if (dom != this.currentEl.dom) {
25627 var xy = ev.getXY();
25628 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25631 // only activate leave if mouse cursor is outside... bounding box..
25636 if (this.currentTip) {
25637 this.currentTip.leave();
25639 //Roo.log('clear currentEl');
25640 this.currentEl = false;
25645 'left' : ['r-l', [-2,0], 'right'],
25646 'right' : ['l-r', [2,0], 'left'],
25647 'bottom' : ['t-b', [0,2], 'top'],
25648 'top' : [ 'b-t', [0,-2], 'bottom']
25654 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25659 delay : null, // can be { show : 300 , hide: 500}
25663 hoverState : null, //???
25665 placement : 'bottom',
25669 getAutoCreate : function(){
25676 cls : 'tooltip-arrow'
25679 cls : 'tooltip-inner'
25686 bind : function(el)
25692 enter : function () {
25694 if (this.timeout != null) {
25695 clearTimeout(this.timeout);
25698 this.hoverState = 'in';
25699 //Roo.log("enter - show");
25700 if (!this.delay || !this.delay.show) {
25705 this.timeout = setTimeout(function () {
25706 if (_t.hoverState == 'in') {
25709 }, this.delay.show);
25713 clearTimeout(this.timeout);
25715 this.hoverState = 'out';
25716 if (!this.delay || !this.delay.hide) {
25722 this.timeout = setTimeout(function () {
25723 //Roo.log("leave - timeout");
25725 if (_t.hoverState == 'out') {
25727 Roo.bootstrap.Tooltip.currentEl = false;
25732 show : function (msg)
25735 this.render(document.body);
25738 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25740 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25742 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25744 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25746 var placement = typeof this.placement == 'function' ?
25747 this.placement.call(this, this.el, on_el) :
25750 var autoToken = /\s?auto?\s?/i;
25751 var autoPlace = autoToken.test(placement);
25753 placement = placement.replace(autoToken, '') || 'top';
25757 //this.el.setXY([0,0]);
25759 //this.el.dom.style.display='block';
25761 //this.el.appendTo(on_el);
25763 var p = this.getPosition();
25764 var box = this.el.getBox();
25770 var align = this.alignment[placement];
25772 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25774 if(placement == 'top' || placement == 'bottom'){
25776 placement = 'right';
25779 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25780 placement = 'left';
25783 var scroll = Roo.select('body', true).first().getScroll();
25785 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25791 this.el.alignTo(this.bindEl, align[0],align[1]);
25792 //var arrow = this.el.select('.arrow',true).first();
25793 //arrow.set(align[2],
25795 this.el.addClass(placement);
25797 this.el.addClass('in fade');
25799 this.hoverState = null;
25801 if (this.el.hasClass('fade')) {
25812 //this.el.setXY([0,0]);
25813 this.el.removeClass('in');
25829 * @class Roo.bootstrap.LocationPicker
25830 * @extends Roo.bootstrap.Component
25831 * Bootstrap LocationPicker class
25832 * @cfg {Number} latitude Position when init default 0
25833 * @cfg {Number} longitude Position when init default 0
25834 * @cfg {Number} zoom default 15
25835 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25836 * @cfg {Boolean} mapTypeControl default false
25837 * @cfg {Boolean} disableDoubleClickZoom default false
25838 * @cfg {Boolean} scrollwheel default true
25839 * @cfg {Boolean} streetViewControl default false
25840 * @cfg {Number} radius default 0
25841 * @cfg {String} locationName
25842 * @cfg {Boolean} draggable default true
25843 * @cfg {Boolean} enableAutocomplete default false
25844 * @cfg {Boolean} enableReverseGeocode default true
25845 * @cfg {String} markerTitle
25848 * Create a new LocationPicker
25849 * @param {Object} config The config object
25853 Roo.bootstrap.LocationPicker = function(config){
25855 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25860 * Fires when the picker initialized.
25861 * @param {Roo.bootstrap.LocationPicker} this
25862 * @param {Google Location} location
25866 * @event positionchanged
25867 * Fires when the picker position changed.
25868 * @param {Roo.bootstrap.LocationPicker} this
25869 * @param {Google Location} location
25871 positionchanged : true,
25874 * Fires when the map resize.
25875 * @param {Roo.bootstrap.LocationPicker} this
25880 * Fires when the map show.
25881 * @param {Roo.bootstrap.LocationPicker} this
25886 * Fires when the map hide.
25887 * @param {Roo.bootstrap.LocationPicker} this
25892 * Fires when click the map.
25893 * @param {Roo.bootstrap.LocationPicker} this
25894 * @param {Map event} e
25898 * @event mapRightClick
25899 * Fires when right click the map.
25900 * @param {Roo.bootstrap.LocationPicker} this
25901 * @param {Map event} e
25903 mapRightClick : true,
25905 * @event markerClick
25906 * Fires when click the marker.
25907 * @param {Roo.bootstrap.LocationPicker} this
25908 * @param {Map event} e
25910 markerClick : true,
25912 * @event markerRightClick
25913 * Fires when right click the marker.
25914 * @param {Roo.bootstrap.LocationPicker} this
25915 * @param {Map event} e
25917 markerRightClick : true,
25919 * @event OverlayViewDraw
25920 * Fires when OverlayView Draw
25921 * @param {Roo.bootstrap.LocationPicker} this
25923 OverlayViewDraw : true,
25925 * @event OverlayViewOnAdd
25926 * Fires when OverlayView Draw
25927 * @param {Roo.bootstrap.LocationPicker} this
25929 OverlayViewOnAdd : true,
25931 * @event OverlayViewOnRemove
25932 * Fires when OverlayView Draw
25933 * @param {Roo.bootstrap.LocationPicker} this
25935 OverlayViewOnRemove : true,
25937 * @event OverlayViewShow
25938 * Fires when OverlayView Draw
25939 * @param {Roo.bootstrap.LocationPicker} this
25940 * @param {Pixel} cpx
25942 OverlayViewShow : true,
25944 * @event OverlayViewHide
25945 * Fires when OverlayView Draw
25946 * @param {Roo.bootstrap.LocationPicker} this
25948 OverlayViewHide : true,
25950 * @event loadexception
25951 * Fires when load google lib failed.
25952 * @param {Roo.bootstrap.LocationPicker} this
25954 loadexception : true
25959 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25961 gMapContext: false,
25967 mapTypeControl: false,
25968 disableDoubleClickZoom: false,
25970 streetViewControl: false,
25974 enableAutocomplete: false,
25975 enableReverseGeocode: true,
25978 getAutoCreate: function()
25983 cls: 'roo-location-picker'
25989 initEvents: function(ct, position)
25991 if(!this.el.getWidth() || this.isApplied()){
25995 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26000 initial: function()
26002 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26003 this.fireEvent('loadexception', this);
26007 if(!this.mapTypeId){
26008 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26011 this.gMapContext = this.GMapContext();
26013 this.initOverlayView();
26015 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26019 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26020 _this.setPosition(_this.gMapContext.marker.position);
26023 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26024 _this.fireEvent('mapClick', this, event);
26028 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26029 _this.fireEvent('mapRightClick', this, event);
26033 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26034 _this.fireEvent('markerClick', this, event);
26038 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26039 _this.fireEvent('markerRightClick', this, event);
26043 this.setPosition(this.gMapContext.location);
26045 this.fireEvent('initial', this, this.gMapContext.location);
26048 initOverlayView: function()
26052 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26056 _this.fireEvent('OverlayViewDraw', _this);
26061 _this.fireEvent('OverlayViewOnAdd', _this);
26064 onRemove: function()
26066 _this.fireEvent('OverlayViewOnRemove', _this);
26069 show: function(cpx)
26071 _this.fireEvent('OverlayViewShow', _this, cpx);
26076 _this.fireEvent('OverlayViewHide', _this);
26082 fromLatLngToContainerPixel: function(event)
26084 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26087 isApplied: function()
26089 return this.getGmapContext() == false ? false : true;
26092 getGmapContext: function()
26094 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26097 GMapContext: function()
26099 var position = new google.maps.LatLng(this.latitude, this.longitude);
26101 var _map = new google.maps.Map(this.el.dom, {
26104 mapTypeId: this.mapTypeId,
26105 mapTypeControl: this.mapTypeControl,
26106 disableDoubleClickZoom: this.disableDoubleClickZoom,
26107 scrollwheel: this.scrollwheel,
26108 streetViewControl: this.streetViewControl,
26109 locationName: this.locationName,
26110 draggable: this.draggable,
26111 enableAutocomplete: this.enableAutocomplete,
26112 enableReverseGeocode: this.enableReverseGeocode
26115 var _marker = new google.maps.Marker({
26116 position: position,
26118 title: this.markerTitle,
26119 draggable: this.draggable
26126 location: position,
26127 radius: this.radius,
26128 locationName: this.locationName,
26129 addressComponents: {
26130 formatted_address: null,
26131 addressLine1: null,
26132 addressLine2: null,
26134 streetNumber: null,
26138 stateOrProvince: null
26141 domContainer: this.el.dom,
26142 geodecoder: new google.maps.Geocoder()
26146 drawCircle: function(center, radius, options)
26148 if (this.gMapContext.circle != null) {
26149 this.gMapContext.circle.setMap(null);
26153 options = Roo.apply({}, options, {
26154 strokeColor: "#0000FF",
26155 strokeOpacity: .35,
26157 fillColor: "#0000FF",
26161 options.map = this.gMapContext.map;
26162 options.radius = radius;
26163 options.center = center;
26164 this.gMapContext.circle = new google.maps.Circle(options);
26165 return this.gMapContext.circle;
26171 setPosition: function(location)
26173 this.gMapContext.location = location;
26174 this.gMapContext.marker.setPosition(location);
26175 this.gMapContext.map.panTo(location);
26176 this.drawCircle(location, this.gMapContext.radius, {});
26180 if (this.gMapContext.settings.enableReverseGeocode) {
26181 this.gMapContext.geodecoder.geocode({
26182 latLng: this.gMapContext.location
26183 }, function(results, status) {
26185 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26186 _this.gMapContext.locationName = results[0].formatted_address;
26187 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26189 _this.fireEvent('positionchanged', this, location);
26196 this.fireEvent('positionchanged', this, location);
26201 google.maps.event.trigger(this.gMapContext.map, "resize");
26203 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26205 this.fireEvent('resize', this);
26208 setPositionByLatLng: function(latitude, longitude)
26210 this.setPosition(new google.maps.LatLng(latitude, longitude));
26213 getCurrentPosition: function()
26216 latitude: this.gMapContext.location.lat(),
26217 longitude: this.gMapContext.location.lng()
26221 getAddressName: function()
26223 return this.gMapContext.locationName;
26226 getAddressComponents: function()
26228 return this.gMapContext.addressComponents;
26231 address_component_from_google_geocode: function(address_components)
26235 for (var i = 0; i < address_components.length; i++) {
26236 var component = address_components[i];
26237 if (component.types.indexOf("postal_code") >= 0) {
26238 result.postalCode = component.short_name;
26239 } else if (component.types.indexOf("street_number") >= 0) {
26240 result.streetNumber = component.short_name;
26241 } else if (component.types.indexOf("route") >= 0) {
26242 result.streetName = component.short_name;
26243 } else if (component.types.indexOf("neighborhood") >= 0) {
26244 result.city = component.short_name;
26245 } else if (component.types.indexOf("locality") >= 0) {
26246 result.city = component.short_name;
26247 } else if (component.types.indexOf("sublocality") >= 0) {
26248 result.district = component.short_name;
26249 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26250 result.stateOrProvince = component.short_name;
26251 } else if (component.types.indexOf("country") >= 0) {
26252 result.country = component.short_name;
26256 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26257 result.addressLine2 = "";
26261 setZoomLevel: function(zoom)
26263 this.gMapContext.map.setZoom(zoom);
26276 this.fireEvent('show', this);
26287 this.fireEvent('hide', this);
26292 Roo.apply(Roo.bootstrap.LocationPicker, {
26294 OverlayView : function(map, options)
26296 options = options || {};
26310 * @class Roo.bootstrap.Alert
26311 * @extends Roo.bootstrap.Component
26312 * Bootstrap Alert class
26313 * @cfg {String} title The title of alert
26314 * @cfg {String} html The content of alert
26315 * @cfg {String} weight ( success | info | warning | danger )
26316 * @cfg {String} faicon font-awesomeicon
26319 * Create a new alert
26320 * @param {Object} config The config object
26324 Roo.bootstrap.Alert = function(config){
26325 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26329 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26336 getAutoCreate : function()
26345 cls : 'roo-alert-icon'
26350 cls : 'roo-alert-title',
26355 cls : 'roo-alert-text',
26362 cfg.cn[0].cls += ' fa ' + this.faicon;
26366 cfg.cls += ' alert-' + this.weight;
26372 initEvents: function()
26374 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26377 setTitle : function(str)
26379 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26382 setText : function(str)
26384 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26387 setWeight : function(weight)
26390 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26393 this.weight = weight;
26395 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26398 setIcon : function(icon)
26401 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26404 this.faicon = icon;
26406 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26427 * @class Roo.bootstrap.UploadCropbox
26428 * @extends Roo.bootstrap.Component
26429 * Bootstrap UploadCropbox class
26430 * @cfg {String} emptyText show when image has been loaded
26431 * @cfg {String} rotateNotify show when image too small to rotate
26432 * @cfg {Number} errorTimeout default 3000
26433 * @cfg {Number} minWidth default 300
26434 * @cfg {Number} minHeight default 300
26435 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26436 * @cfg {Boolean} isDocument (true|false) default false
26437 * @cfg {String} url action url
26438 * @cfg {String} paramName default 'imageUpload'
26439 * @cfg {String} method default POST
26440 * @cfg {Boolean} loadMask (true|false) default true
26441 * @cfg {Boolean} loadingText default 'Loading...'
26444 * Create a new UploadCropbox
26445 * @param {Object} config The config object
26448 Roo.bootstrap.UploadCropbox = function(config){
26449 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26453 * @event beforeselectfile
26454 * Fire before select file
26455 * @param {Roo.bootstrap.UploadCropbox} this
26457 "beforeselectfile" : true,
26460 * Fire after initEvent
26461 * @param {Roo.bootstrap.UploadCropbox} this
26466 * Fire after initEvent
26467 * @param {Roo.bootstrap.UploadCropbox} this
26468 * @param {String} data
26473 * Fire when preparing the file data
26474 * @param {Roo.bootstrap.UploadCropbox} this
26475 * @param {Object} file
26480 * Fire when get exception
26481 * @param {Roo.bootstrap.UploadCropbox} this
26482 * @param {XMLHttpRequest} xhr
26484 "exception" : true,
26486 * @event beforeloadcanvas
26487 * Fire before load the canvas
26488 * @param {Roo.bootstrap.UploadCropbox} this
26489 * @param {String} src
26491 "beforeloadcanvas" : true,
26494 * Fire when trash image
26495 * @param {Roo.bootstrap.UploadCropbox} this
26500 * Fire when download the image
26501 * @param {Roo.bootstrap.UploadCropbox} this
26505 * @event footerbuttonclick
26506 * Fire when footerbuttonclick
26507 * @param {Roo.bootstrap.UploadCropbox} this
26508 * @param {String} type
26510 "footerbuttonclick" : true,
26514 * @param {Roo.bootstrap.UploadCropbox} this
26519 * Fire when rotate the image
26520 * @param {Roo.bootstrap.UploadCropbox} this
26521 * @param {String} pos
26526 * Fire when inspect the file
26527 * @param {Roo.bootstrap.UploadCropbox} this
26528 * @param {Object} file
26533 * Fire when xhr upload the file
26534 * @param {Roo.bootstrap.UploadCropbox} this
26535 * @param {Object} data
26540 * Fire when arrange the file data
26541 * @param {Roo.bootstrap.UploadCropbox} this
26542 * @param {Object} formData
26547 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26550 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26552 emptyText : 'Click to upload image',
26553 rotateNotify : 'Image is too small to rotate',
26554 errorTimeout : 3000,
26568 cropType : 'image/jpeg',
26570 canvasLoaded : false,
26571 isDocument : false,
26573 paramName : 'imageUpload',
26575 loadingText : 'Loading...',
26578 getAutoCreate : function()
26582 cls : 'roo-upload-cropbox',
26586 cls : 'roo-upload-cropbox-selector',
26591 cls : 'roo-upload-cropbox-body',
26592 style : 'cursor:pointer',
26596 cls : 'roo-upload-cropbox-preview'
26600 cls : 'roo-upload-cropbox-thumb'
26604 cls : 'roo-upload-cropbox-empty-notify',
26605 html : this.emptyText
26609 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26610 html : this.rotateNotify
26616 cls : 'roo-upload-cropbox-footer',
26619 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26629 onRender : function(ct, position)
26631 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26633 if (this.buttons.length) {
26635 Roo.each(this.buttons, function(bb) {
26637 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26639 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26645 this.maskEl = this.el;
26649 initEvents : function()
26651 this.urlAPI = (window.createObjectURL && window) ||
26652 (window.URL && URL.revokeObjectURL && URL) ||
26653 (window.webkitURL && webkitURL);
26655 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26656 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26658 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26659 this.selectorEl.hide();
26661 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26662 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26664 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26665 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26666 this.thumbEl.hide();
26668 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26669 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26671 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26672 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26673 this.errorEl.hide();
26675 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26676 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26677 this.footerEl.hide();
26679 this.setThumbBoxSize();
26685 this.fireEvent('initial', this);
26692 window.addEventListener("resize", function() { _this.resize(); } );
26694 this.bodyEl.on('click', this.beforeSelectFile, this);
26697 this.bodyEl.on('touchstart', this.onTouchStart, this);
26698 this.bodyEl.on('touchmove', this.onTouchMove, this);
26699 this.bodyEl.on('touchend', this.onTouchEnd, this);
26703 this.bodyEl.on('mousedown', this.onMouseDown, this);
26704 this.bodyEl.on('mousemove', this.onMouseMove, this);
26705 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26706 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26707 Roo.get(document).on('mouseup', this.onMouseUp, this);
26710 this.selectorEl.on('change', this.onFileSelected, this);
26716 this.baseScale = 1;
26718 this.baseRotate = 1;
26719 this.dragable = false;
26720 this.pinching = false;
26723 this.cropData = false;
26724 this.notifyEl.dom.innerHTML = this.emptyText;
26726 this.selectorEl.dom.value = '';
26730 resize : function()
26732 if(this.fireEvent('resize', this) != false){
26733 this.setThumbBoxPosition();
26734 this.setCanvasPosition();
26738 onFooterButtonClick : function(e, el, o, type)
26741 case 'rotate-left' :
26742 this.onRotateLeft(e);
26744 case 'rotate-right' :
26745 this.onRotateRight(e);
26748 this.beforeSelectFile(e);
26763 this.fireEvent('footerbuttonclick', this, type);
26766 beforeSelectFile : function(e)
26768 e.preventDefault();
26770 if(this.fireEvent('beforeselectfile', this) != false){
26771 this.selectorEl.dom.click();
26775 onFileSelected : function(e)
26777 e.preventDefault();
26779 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26783 var file = this.selectorEl.dom.files[0];
26785 if(this.fireEvent('inspect', this, file) != false){
26786 this.prepare(file);
26791 trash : function(e)
26793 this.fireEvent('trash', this);
26796 download : function(e)
26798 this.fireEvent('download', this);
26801 loadCanvas : function(src)
26803 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26807 this.imageEl = document.createElement('img');
26811 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26813 this.imageEl.src = src;
26817 onLoadCanvas : function()
26819 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26820 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26822 this.bodyEl.un('click', this.beforeSelectFile, this);
26824 this.notifyEl.hide();
26825 this.thumbEl.show();
26826 this.footerEl.show();
26828 this.baseRotateLevel();
26830 if(this.isDocument){
26831 this.setThumbBoxSize();
26834 this.setThumbBoxPosition();
26836 this.baseScaleLevel();
26842 this.canvasLoaded = true;
26845 this.maskEl.unmask();
26850 setCanvasPosition : function()
26852 if(!this.canvasEl){
26856 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26857 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26859 this.previewEl.setLeft(pw);
26860 this.previewEl.setTop(ph);
26864 onMouseDown : function(e)
26868 this.dragable = true;
26869 this.pinching = false;
26871 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26872 this.dragable = false;
26876 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26877 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26881 onMouseMove : function(e)
26885 if(!this.canvasLoaded){
26889 if (!this.dragable){
26893 var minX = Math.ceil(this.thumbEl.getLeft(true));
26894 var minY = Math.ceil(this.thumbEl.getTop(true));
26896 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26897 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26899 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26900 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26902 x = x - this.mouseX;
26903 y = y - this.mouseY;
26905 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26906 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26908 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26909 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26911 this.previewEl.setLeft(bgX);
26912 this.previewEl.setTop(bgY);
26914 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26915 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26918 onMouseUp : function(e)
26922 this.dragable = false;
26925 onMouseWheel : function(e)
26929 this.startScale = this.scale;
26931 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26933 if(!this.zoomable()){
26934 this.scale = this.startScale;
26943 zoomable : function()
26945 var minScale = this.thumbEl.getWidth() / this.minWidth;
26947 if(this.minWidth < this.minHeight){
26948 minScale = this.thumbEl.getHeight() / this.minHeight;
26951 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26952 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26956 (this.rotate == 0 || this.rotate == 180) &&
26958 width > this.imageEl.OriginWidth ||
26959 height > this.imageEl.OriginHeight ||
26960 (width < this.minWidth && height < this.minHeight)
26968 (this.rotate == 90 || this.rotate == 270) &&
26970 width > this.imageEl.OriginWidth ||
26971 height > this.imageEl.OriginHeight ||
26972 (width < this.minHeight && height < this.minWidth)
26979 !this.isDocument &&
26980 (this.rotate == 0 || this.rotate == 180) &&
26982 width < this.minWidth ||
26983 width > this.imageEl.OriginWidth ||
26984 height < this.minHeight ||
26985 height > this.imageEl.OriginHeight
26992 !this.isDocument &&
26993 (this.rotate == 90 || this.rotate == 270) &&
26995 width < this.minHeight ||
26996 width > this.imageEl.OriginWidth ||
26997 height < this.minWidth ||
26998 height > this.imageEl.OriginHeight
27008 onRotateLeft : function(e)
27010 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27012 var minScale = this.thumbEl.getWidth() / this.minWidth;
27014 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27015 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27017 this.startScale = this.scale;
27019 while (this.getScaleLevel() < minScale){
27021 this.scale = this.scale + 1;
27023 if(!this.zoomable()){
27028 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27029 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27034 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27041 this.scale = this.startScale;
27043 this.onRotateFail();
27048 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27050 if(this.isDocument){
27051 this.setThumbBoxSize();
27052 this.setThumbBoxPosition();
27053 this.setCanvasPosition();
27058 this.fireEvent('rotate', this, 'left');
27062 onRotateRight : function(e)
27064 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27066 var minScale = this.thumbEl.getWidth() / this.minWidth;
27068 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27069 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27071 this.startScale = this.scale;
27073 while (this.getScaleLevel() < minScale){
27075 this.scale = this.scale + 1;
27077 if(!this.zoomable()){
27082 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27083 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27088 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27095 this.scale = this.startScale;
27097 this.onRotateFail();
27102 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27104 if(this.isDocument){
27105 this.setThumbBoxSize();
27106 this.setThumbBoxPosition();
27107 this.setCanvasPosition();
27112 this.fireEvent('rotate', this, 'right');
27115 onRotateFail : function()
27117 this.errorEl.show(true);
27121 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27126 this.previewEl.dom.innerHTML = '';
27128 var canvasEl = document.createElement("canvas");
27130 var contextEl = canvasEl.getContext("2d");
27132 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27133 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27134 var center = this.imageEl.OriginWidth / 2;
27136 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27137 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27138 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27139 center = this.imageEl.OriginHeight / 2;
27142 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27144 contextEl.translate(center, center);
27145 contextEl.rotate(this.rotate * Math.PI / 180);
27147 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27149 this.canvasEl = document.createElement("canvas");
27151 this.contextEl = this.canvasEl.getContext("2d");
27153 switch (this.rotate) {
27156 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27157 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27159 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27164 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27165 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27167 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27168 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);
27172 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27177 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27178 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27180 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27181 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);
27185 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);
27190 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27191 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27193 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27194 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27198 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);
27205 this.previewEl.appendChild(this.canvasEl);
27207 this.setCanvasPosition();
27212 if(!this.canvasLoaded){
27216 var imageCanvas = document.createElement("canvas");
27218 var imageContext = imageCanvas.getContext("2d");
27220 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27221 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27223 var center = imageCanvas.width / 2;
27225 imageContext.translate(center, center);
27227 imageContext.rotate(this.rotate * Math.PI / 180);
27229 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27231 var canvas = document.createElement("canvas");
27233 var context = canvas.getContext("2d");
27235 canvas.width = this.minWidth;
27236 canvas.height = this.minHeight;
27238 switch (this.rotate) {
27241 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27242 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27244 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27245 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27247 var targetWidth = this.minWidth - 2 * x;
27248 var targetHeight = this.minHeight - 2 * y;
27252 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27253 scale = targetWidth / width;
27256 if(x > 0 && y == 0){
27257 scale = targetHeight / height;
27260 if(x > 0 && y > 0){
27261 scale = targetWidth / width;
27263 if(width < height){
27264 scale = targetHeight / height;
27268 context.scale(scale, scale);
27270 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27271 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27273 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27274 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27276 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27281 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27282 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27284 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27285 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27287 var targetWidth = this.minWidth - 2 * x;
27288 var targetHeight = this.minHeight - 2 * y;
27292 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27293 scale = targetWidth / width;
27296 if(x > 0 && y == 0){
27297 scale = targetHeight / height;
27300 if(x > 0 && y > 0){
27301 scale = targetWidth / width;
27303 if(width < height){
27304 scale = targetHeight / height;
27308 context.scale(scale, scale);
27310 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27311 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27313 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27314 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27316 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27318 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27323 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27324 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27326 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27327 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27329 var targetWidth = this.minWidth - 2 * x;
27330 var targetHeight = this.minHeight - 2 * y;
27334 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27335 scale = targetWidth / width;
27338 if(x > 0 && y == 0){
27339 scale = targetHeight / height;
27342 if(x > 0 && y > 0){
27343 scale = targetWidth / width;
27345 if(width < height){
27346 scale = targetHeight / height;
27350 context.scale(scale, scale);
27352 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27353 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27355 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27356 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27358 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27359 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27361 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27366 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27367 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27369 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27370 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27372 var targetWidth = this.minWidth - 2 * x;
27373 var targetHeight = this.minHeight - 2 * y;
27377 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27378 scale = targetWidth / width;
27381 if(x > 0 && y == 0){
27382 scale = targetHeight / height;
27385 if(x > 0 && y > 0){
27386 scale = targetWidth / width;
27388 if(width < height){
27389 scale = targetHeight / height;
27393 context.scale(scale, scale);
27395 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27396 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27398 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27399 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27401 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27403 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27410 this.cropData = canvas.toDataURL(this.cropType);
27412 if(this.fireEvent('crop', this, this.cropData) !== false){
27413 this.process(this.file, this.cropData);
27420 setThumbBoxSize : function()
27424 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27425 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27426 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27428 this.minWidth = width;
27429 this.minHeight = height;
27431 if(this.rotate == 90 || this.rotate == 270){
27432 this.minWidth = height;
27433 this.minHeight = width;
27438 width = Math.ceil(this.minWidth * height / this.minHeight);
27440 if(this.minWidth > this.minHeight){
27442 height = Math.ceil(this.minHeight * width / this.minWidth);
27445 this.thumbEl.setStyle({
27446 width : width + 'px',
27447 height : height + 'px'
27454 setThumbBoxPosition : function()
27456 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27457 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27459 this.thumbEl.setLeft(x);
27460 this.thumbEl.setTop(y);
27464 baseRotateLevel : function()
27466 this.baseRotate = 1;
27469 typeof(this.exif) != 'undefined' &&
27470 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27471 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27473 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27476 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27480 baseScaleLevel : function()
27484 if(this.isDocument){
27486 if(this.baseRotate == 6 || this.baseRotate == 8){
27488 height = this.thumbEl.getHeight();
27489 this.baseScale = height / this.imageEl.OriginWidth;
27491 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27492 width = this.thumbEl.getWidth();
27493 this.baseScale = width / this.imageEl.OriginHeight;
27499 height = this.thumbEl.getHeight();
27500 this.baseScale = height / this.imageEl.OriginHeight;
27502 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27503 width = this.thumbEl.getWidth();
27504 this.baseScale = width / this.imageEl.OriginWidth;
27510 if(this.baseRotate == 6 || this.baseRotate == 8){
27512 width = this.thumbEl.getHeight();
27513 this.baseScale = width / this.imageEl.OriginHeight;
27515 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27516 height = this.thumbEl.getWidth();
27517 this.baseScale = height / this.imageEl.OriginHeight;
27520 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27521 height = this.thumbEl.getWidth();
27522 this.baseScale = height / this.imageEl.OriginHeight;
27524 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27525 width = this.thumbEl.getHeight();
27526 this.baseScale = width / this.imageEl.OriginWidth;
27533 width = this.thumbEl.getWidth();
27534 this.baseScale = width / this.imageEl.OriginWidth;
27536 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27537 height = this.thumbEl.getHeight();
27538 this.baseScale = height / this.imageEl.OriginHeight;
27541 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27543 height = this.thumbEl.getHeight();
27544 this.baseScale = height / this.imageEl.OriginHeight;
27546 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27547 width = this.thumbEl.getWidth();
27548 this.baseScale = width / this.imageEl.OriginWidth;
27556 getScaleLevel : function()
27558 return this.baseScale * Math.pow(1.1, this.scale);
27561 onTouchStart : function(e)
27563 if(!this.canvasLoaded){
27564 this.beforeSelectFile(e);
27568 var touches = e.browserEvent.touches;
27574 if(touches.length == 1){
27575 this.onMouseDown(e);
27579 if(touches.length != 2){
27585 for(var i = 0, finger; finger = touches[i]; i++){
27586 coords.push(finger.pageX, finger.pageY);
27589 var x = Math.pow(coords[0] - coords[2], 2);
27590 var y = Math.pow(coords[1] - coords[3], 2);
27592 this.startDistance = Math.sqrt(x + y);
27594 this.startScale = this.scale;
27596 this.pinching = true;
27597 this.dragable = false;
27601 onTouchMove : function(e)
27603 if(!this.pinching && !this.dragable){
27607 var touches = e.browserEvent.touches;
27614 this.onMouseMove(e);
27620 for(var i = 0, finger; finger = touches[i]; i++){
27621 coords.push(finger.pageX, finger.pageY);
27624 var x = Math.pow(coords[0] - coords[2], 2);
27625 var y = Math.pow(coords[1] - coords[3], 2);
27627 this.endDistance = Math.sqrt(x + y);
27629 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27631 if(!this.zoomable()){
27632 this.scale = this.startScale;
27640 onTouchEnd : function(e)
27642 this.pinching = false;
27643 this.dragable = false;
27647 process : function(file, crop)
27650 this.maskEl.mask(this.loadingText);
27653 this.xhr = new XMLHttpRequest();
27655 file.xhr = this.xhr;
27657 this.xhr.open(this.method, this.url, true);
27660 "Accept": "application/json",
27661 "Cache-Control": "no-cache",
27662 "X-Requested-With": "XMLHttpRequest"
27665 for (var headerName in headers) {
27666 var headerValue = headers[headerName];
27668 this.xhr.setRequestHeader(headerName, headerValue);
27674 this.xhr.onload = function()
27676 _this.xhrOnLoad(_this.xhr);
27679 this.xhr.onerror = function()
27681 _this.xhrOnError(_this.xhr);
27684 var formData = new FormData();
27686 formData.append('returnHTML', 'NO');
27689 formData.append('crop', crop);
27692 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27693 formData.append(this.paramName, file, file.name);
27696 if(typeof(file.filename) != 'undefined'){
27697 formData.append('filename', file.filename);
27700 if(typeof(file.mimetype) != 'undefined'){
27701 formData.append('mimetype', file.mimetype);
27704 if(this.fireEvent('arrange', this, formData) != false){
27705 this.xhr.send(formData);
27709 xhrOnLoad : function(xhr)
27712 this.maskEl.unmask();
27715 if (xhr.readyState !== 4) {
27716 this.fireEvent('exception', this, xhr);
27720 var response = Roo.decode(xhr.responseText);
27722 if(!response.success){
27723 this.fireEvent('exception', this, xhr);
27727 var response = Roo.decode(xhr.responseText);
27729 this.fireEvent('upload', this, response);
27733 xhrOnError : function()
27736 this.maskEl.unmask();
27739 Roo.log('xhr on error');
27741 var response = Roo.decode(xhr.responseText);
27747 prepare : function(file)
27750 this.maskEl.mask(this.loadingText);
27756 if(typeof(file) === 'string'){
27757 this.loadCanvas(file);
27761 if(!file || !this.urlAPI){
27766 this.cropType = file.type;
27770 if(this.fireEvent('prepare', this, this.file) != false){
27772 var reader = new FileReader();
27774 reader.onload = function (e) {
27775 if (e.target.error) {
27776 Roo.log(e.target.error);
27780 var buffer = e.target.result,
27781 dataView = new DataView(buffer),
27783 maxOffset = dataView.byteLength - 4,
27787 if (dataView.getUint16(0) === 0xffd8) {
27788 while (offset < maxOffset) {
27789 markerBytes = dataView.getUint16(offset);
27791 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27792 markerLength = dataView.getUint16(offset + 2) + 2;
27793 if (offset + markerLength > dataView.byteLength) {
27794 Roo.log('Invalid meta data: Invalid segment size.');
27798 if(markerBytes == 0xffe1){
27799 _this.parseExifData(
27806 offset += markerLength;
27816 var url = _this.urlAPI.createObjectURL(_this.file);
27818 _this.loadCanvas(url);
27823 reader.readAsArrayBuffer(this.file);
27829 parseExifData : function(dataView, offset, length)
27831 var tiffOffset = offset + 10,
27835 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27836 // No Exif data, might be XMP data instead
27840 // Check for the ASCII code for "Exif" (0x45786966):
27841 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27842 // No Exif data, might be XMP data instead
27845 if (tiffOffset + 8 > dataView.byteLength) {
27846 Roo.log('Invalid Exif data: Invalid segment size.');
27849 // Check for the two null bytes:
27850 if (dataView.getUint16(offset + 8) !== 0x0000) {
27851 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27854 // Check the byte alignment:
27855 switch (dataView.getUint16(tiffOffset)) {
27857 littleEndian = true;
27860 littleEndian = false;
27863 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27866 // Check for the TIFF tag marker (0x002A):
27867 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27868 Roo.log('Invalid Exif data: Missing TIFF marker.');
27871 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27872 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27874 this.parseExifTags(
27877 tiffOffset + dirOffset,
27882 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27887 if (dirOffset + 6 > dataView.byteLength) {
27888 Roo.log('Invalid Exif data: Invalid directory offset.');
27891 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27892 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27893 if (dirEndOffset + 4 > dataView.byteLength) {
27894 Roo.log('Invalid Exif data: Invalid directory size.');
27897 for (i = 0; i < tagsNumber; i += 1) {
27901 dirOffset + 2 + 12 * i, // tag offset
27905 // Return the offset to the next directory:
27906 return dataView.getUint32(dirEndOffset, littleEndian);
27909 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27911 var tag = dataView.getUint16(offset, littleEndian);
27913 this.exif[tag] = this.getExifValue(
27917 dataView.getUint16(offset + 2, littleEndian), // tag type
27918 dataView.getUint32(offset + 4, littleEndian), // tag length
27923 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27925 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27934 Roo.log('Invalid Exif data: Invalid tag type.');
27938 tagSize = tagType.size * length;
27939 // Determine if the value is contained in the dataOffset bytes,
27940 // or if the value at the dataOffset is a pointer to the actual data:
27941 dataOffset = tagSize > 4 ?
27942 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27943 if (dataOffset + tagSize > dataView.byteLength) {
27944 Roo.log('Invalid Exif data: Invalid data offset.');
27947 if (length === 1) {
27948 return tagType.getValue(dataView, dataOffset, littleEndian);
27951 for (i = 0; i < length; i += 1) {
27952 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27955 if (tagType.ascii) {
27957 // Concatenate the chars:
27958 for (i = 0; i < values.length; i += 1) {
27960 // Ignore the terminating NULL byte(s):
27961 if (c === '\u0000') {
27973 Roo.apply(Roo.bootstrap.UploadCropbox, {
27975 'Orientation': 0x0112
27979 1: 0, //'top-left',
27981 3: 180, //'bottom-right',
27982 // 4: 'bottom-left',
27984 6: 90, //'right-top',
27985 // 7: 'right-bottom',
27986 8: 270 //'left-bottom'
27990 // byte, 8-bit unsigned int:
27992 getValue: function (dataView, dataOffset) {
27993 return dataView.getUint8(dataOffset);
27997 // ascii, 8-bit byte:
27999 getValue: function (dataView, dataOffset) {
28000 return String.fromCharCode(dataView.getUint8(dataOffset));
28005 // short, 16 bit int:
28007 getValue: function (dataView, dataOffset, littleEndian) {
28008 return dataView.getUint16(dataOffset, littleEndian);
28012 // long, 32 bit int:
28014 getValue: function (dataView, dataOffset, littleEndian) {
28015 return dataView.getUint32(dataOffset, littleEndian);
28019 // rational = two long values, first is numerator, second is denominator:
28021 getValue: function (dataView, dataOffset, littleEndian) {
28022 return dataView.getUint32(dataOffset, littleEndian) /
28023 dataView.getUint32(dataOffset + 4, littleEndian);
28027 // slong, 32 bit signed int:
28029 getValue: function (dataView, dataOffset, littleEndian) {
28030 return dataView.getInt32(dataOffset, littleEndian);
28034 // srational, two slongs, first is numerator, second is denominator:
28036 getValue: function (dataView, dataOffset, littleEndian) {
28037 return dataView.getInt32(dataOffset, littleEndian) /
28038 dataView.getInt32(dataOffset + 4, littleEndian);
28048 cls : 'btn-group roo-upload-cropbox-rotate-left',
28049 action : 'rotate-left',
28053 cls : 'btn btn-default',
28054 html : '<i class="fa fa-undo"></i>'
28060 cls : 'btn-group roo-upload-cropbox-picture',
28061 action : 'picture',
28065 cls : 'btn btn-default',
28066 html : '<i class="fa fa-picture-o"></i>'
28072 cls : 'btn-group roo-upload-cropbox-rotate-right',
28073 action : 'rotate-right',
28077 cls : 'btn btn-default',
28078 html : '<i class="fa fa-repeat"></i>'
28086 cls : 'btn-group roo-upload-cropbox-rotate-left',
28087 action : 'rotate-left',
28091 cls : 'btn btn-default',
28092 html : '<i class="fa fa-undo"></i>'
28098 cls : 'btn-group roo-upload-cropbox-download',
28099 action : 'download',
28103 cls : 'btn btn-default',
28104 html : '<i class="fa fa-download"></i>'
28110 cls : 'btn-group roo-upload-cropbox-crop',
28115 cls : 'btn btn-default',
28116 html : '<i class="fa fa-crop"></i>'
28122 cls : 'btn-group roo-upload-cropbox-trash',
28127 cls : 'btn btn-default',
28128 html : '<i class="fa fa-trash"></i>'
28134 cls : 'btn-group roo-upload-cropbox-rotate-right',
28135 action : 'rotate-right',
28139 cls : 'btn btn-default',
28140 html : '<i class="fa fa-repeat"></i>'
28148 cls : 'btn-group roo-upload-cropbox-rotate-left',
28149 action : 'rotate-left',
28153 cls : 'btn btn-default',
28154 html : '<i class="fa fa-undo"></i>'
28160 cls : 'btn-group roo-upload-cropbox-rotate-right',
28161 action : 'rotate-right',
28165 cls : 'btn btn-default',
28166 html : '<i class="fa fa-repeat"></i>'
28179 * @class Roo.bootstrap.DocumentManager
28180 * @extends Roo.bootstrap.Component
28181 * Bootstrap DocumentManager class
28182 * @cfg {String} paramName default 'imageUpload'
28183 * @cfg {String} toolTipName default 'filename'
28184 * @cfg {String} method default POST
28185 * @cfg {String} url action url
28186 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28187 * @cfg {Boolean} multiple multiple upload default true
28188 * @cfg {Number} thumbSize default 300
28189 * @cfg {String} fieldLabel
28190 * @cfg {Number} labelWidth default 4
28191 * @cfg {String} labelAlign (left|top) default left
28192 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28193 * @cfg {Number} labellg set the width of label (1-12)
28194 * @cfg {Number} labelmd set the width of label (1-12)
28195 * @cfg {Number} labelsm set the width of label (1-12)
28196 * @cfg {Number} labelxs set the width of label (1-12)
28199 * Create a new DocumentManager
28200 * @param {Object} config The config object
28203 Roo.bootstrap.DocumentManager = function(config){
28204 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28207 this.delegates = [];
28212 * Fire when initial the DocumentManager
28213 * @param {Roo.bootstrap.DocumentManager} this
28218 * inspect selected file
28219 * @param {Roo.bootstrap.DocumentManager} this
28220 * @param {File} file
28225 * Fire when xhr load exception
28226 * @param {Roo.bootstrap.DocumentManager} this
28227 * @param {XMLHttpRequest} xhr
28229 "exception" : true,
28231 * @event afterupload
28232 * Fire when xhr load exception
28233 * @param {Roo.bootstrap.DocumentManager} this
28234 * @param {XMLHttpRequest} xhr
28236 "afterupload" : true,
28239 * prepare the form data
28240 * @param {Roo.bootstrap.DocumentManager} this
28241 * @param {Object} formData
28246 * Fire when remove the file
28247 * @param {Roo.bootstrap.DocumentManager} this
28248 * @param {Object} file
28253 * Fire after refresh the file
28254 * @param {Roo.bootstrap.DocumentManager} this
28259 * Fire after click the image
28260 * @param {Roo.bootstrap.DocumentManager} this
28261 * @param {Object} file
28266 * Fire when upload a image and editable set to true
28267 * @param {Roo.bootstrap.DocumentManager} this
28268 * @param {Object} file
28272 * @event beforeselectfile
28273 * Fire before select file
28274 * @param {Roo.bootstrap.DocumentManager} this
28276 "beforeselectfile" : true,
28279 * Fire before process file
28280 * @param {Roo.bootstrap.DocumentManager} this
28281 * @param {Object} file
28288 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28297 paramName : 'imageUpload',
28298 toolTipName : 'filename',
28301 labelAlign : 'left',
28311 getAutoCreate : function()
28313 var managerWidget = {
28315 cls : 'roo-document-manager',
28319 cls : 'roo-document-manager-selector',
28324 cls : 'roo-document-manager-uploader',
28328 cls : 'roo-document-manager-upload-btn',
28329 html : '<i class="fa fa-plus"></i>'
28340 cls : 'column col-md-12',
28345 if(this.fieldLabel.length){
28350 cls : 'column col-md-12',
28351 html : this.fieldLabel
28355 cls : 'column col-md-12',
28360 if(this.labelAlign == 'left'){
28365 html : this.fieldLabel
28374 if(this.labelWidth > 12){
28375 content[0].style = "width: " + this.labelWidth + 'px';
28378 if(this.labelWidth < 13 && this.labelmd == 0){
28379 this.labelmd = this.labelWidth;
28382 if(this.labellg > 0){
28383 content[0].cls += ' col-lg-' + this.labellg;
28384 content[1].cls += ' col-lg-' + (12 - this.labellg);
28387 if(this.labelmd > 0){
28388 content[0].cls += ' col-md-' + this.labelmd;
28389 content[1].cls += ' col-md-' + (12 - this.labelmd);
28392 if(this.labelsm > 0){
28393 content[0].cls += ' col-sm-' + this.labelsm;
28394 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28397 if(this.labelxs > 0){
28398 content[0].cls += ' col-xs-' + this.labelxs;
28399 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28407 cls : 'row clearfix',
28415 initEvents : function()
28417 this.managerEl = this.el.select('.roo-document-manager', true).first();
28418 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28420 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28421 this.selectorEl.hide();
28424 this.selectorEl.attr('multiple', 'multiple');
28427 this.selectorEl.on('change', this.onFileSelected, this);
28429 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28430 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28432 this.uploader.on('click', this.onUploaderClick, this);
28434 this.renderProgressDialog();
28438 window.addEventListener("resize", function() { _this.refresh(); } );
28440 this.fireEvent('initial', this);
28443 renderProgressDialog : function()
28447 this.progressDialog = new Roo.bootstrap.Modal({
28448 cls : 'roo-document-manager-progress-dialog',
28449 allow_close : false,
28459 btnclick : function() {
28460 _this.uploadCancel();
28466 this.progressDialog.render(Roo.get(document.body));
28468 this.progress = new Roo.bootstrap.Progress({
28469 cls : 'roo-document-manager-progress',
28474 this.progress.render(this.progressDialog.getChildContainer());
28476 this.progressBar = new Roo.bootstrap.ProgressBar({
28477 cls : 'roo-document-manager-progress-bar',
28480 aria_valuemax : 12,
28484 this.progressBar.render(this.progress.getChildContainer());
28487 onUploaderClick : function(e)
28489 e.preventDefault();
28491 if(this.fireEvent('beforeselectfile', this) != false){
28492 this.selectorEl.dom.click();
28497 onFileSelected : function(e)
28499 e.preventDefault();
28501 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28505 Roo.each(this.selectorEl.dom.files, function(file){
28506 if(this.fireEvent('inspect', this, file) != false){
28507 this.files.push(file);
28517 this.selectorEl.dom.value = '';
28519 if(!this.files.length){
28523 if(this.boxes > 0 && this.files.length > this.boxes){
28524 this.files = this.files.slice(0, this.boxes);
28527 this.uploader.show();
28529 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28530 this.uploader.hide();
28539 Roo.each(this.files, function(file){
28541 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28542 var f = this.renderPreview(file);
28547 if(file.type.indexOf('image') != -1){
28548 this.delegates.push(
28550 _this.process(file);
28551 }).createDelegate(this)
28559 _this.process(file);
28560 }).createDelegate(this)
28565 this.files = files;
28567 this.delegates = this.delegates.concat(docs);
28569 if(!this.delegates.length){
28574 this.progressBar.aria_valuemax = this.delegates.length;
28581 arrange : function()
28583 if(!this.delegates.length){
28584 this.progressDialog.hide();
28589 var delegate = this.delegates.shift();
28591 this.progressDialog.show();
28593 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28595 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28600 refresh : function()
28602 this.uploader.show();
28604 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28605 this.uploader.hide();
28608 Roo.isTouch ? this.closable(false) : this.closable(true);
28610 this.fireEvent('refresh', this);
28613 onRemove : function(e, el, o)
28615 e.preventDefault();
28617 this.fireEvent('remove', this, o);
28621 remove : function(o)
28625 Roo.each(this.files, function(file){
28626 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28635 this.files = files;
28642 Roo.each(this.files, function(file){
28647 file.target.remove();
28656 onClick : function(e, el, o)
28658 e.preventDefault();
28660 this.fireEvent('click', this, o);
28664 closable : function(closable)
28666 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28668 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28680 xhrOnLoad : function(xhr)
28682 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28686 if (xhr.readyState !== 4) {
28688 this.fireEvent('exception', this, xhr);
28692 var response = Roo.decode(xhr.responseText);
28694 if(!response.success){
28696 this.fireEvent('exception', this, xhr);
28700 var file = this.renderPreview(response.data);
28702 this.files.push(file);
28706 this.fireEvent('afterupload', this, xhr);
28710 xhrOnError : function(xhr)
28712 Roo.log('xhr on error');
28714 var response = Roo.decode(xhr.responseText);
28721 process : function(file)
28723 if(this.fireEvent('process', this, file) !== false){
28724 if(this.editable && file.type.indexOf('image') != -1){
28725 this.fireEvent('edit', this, file);
28729 this.uploadStart(file, false);
28736 uploadStart : function(file, crop)
28738 this.xhr = new XMLHttpRequest();
28740 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28745 file.xhr = this.xhr;
28747 this.managerEl.createChild({
28749 cls : 'roo-document-manager-loading',
28753 tooltip : file.name,
28754 cls : 'roo-document-manager-thumb',
28755 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28761 this.xhr.open(this.method, this.url, true);
28764 "Accept": "application/json",
28765 "Cache-Control": "no-cache",
28766 "X-Requested-With": "XMLHttpRequest"
28769 for (var headerName in headers) {
28770 var headerValue = headers[headerName];
28772 this.xhr.setRequestHeader(headerName, headerValue);
28778 this.xhr.onload = function()
28780 _this.xhrOnLoad(_this.xhr);
28783 this.xhr.onerror = function()
28785 _this.xhrOnError(_this.xhr);
28788 var formData = new FormData();
28790 formData.append('returnHTML', 'NO');
28793 formData.append('crop', crop);
28796 formData.append(this.paramName, file, file.name);
28803 if(this.fireEvent('prepare', this, formData, options) != false){
28805 if(options.manually){
28809 this.xhr.send(formData);
28813 this.uploadCancel();
28816 uploadCancel : function()
28822 this.delegates = [];
28824 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28831 renderPreview : function(file)
28833 if(typeof(file.target) != 'undefined' && file.target){
28837 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
28839 var previewEl = this.managerEl.createChild({
28841 cls : 'roo-document-manager-preview',
28845 tooltip : file[this.toolTipName],
28846 cls : 'roo-document-manager-thumb',
28847 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
28852 html : '<i class="fa fa-times-circle"></i>'
28857 var close = previewEl.select('button.close', true).first();
28859 close.on('click', this.onRemove, this, file);
28861 file.target = previewEl;
28863 var image = previewEl.select('img', true).first();
28867 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28869 image.on('click', this.onClick, this, file);
28875 onPreviewLoad : function(file, image)
28877 if(typeof(file.target) == 'undefined' || !file.target){
28881 var width = image.dom.naturalWidth || image.dom.width;
28882 var height = image.dom.naturalHeight || image.dom.height;
28884 if(width > height){
28885 file.target.addClass('wide');
28889 file.target.addClass('tall');
28894 uploadFromSource : function(file, crop)
28896 this.xhr = new XMLHttpRequest();
28898 this.managerEl.createChild({
28900 cls : 'roo-document-manager-loading',
28904 tooltip : file.name,
28905 cls : 'roo-document-manager-thumb',
28906 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28912 this.xhr.open(this.method, this.url, true);
28915 "Accept": "application/json",
28916 "Cache-Control": "no-cache",
28917 "X-Requested-With": "XMLHttpRequest"
28920 for (var headerName in headers) {
28921 var headerValue = headers[headerName];
28923 this.xhr.setRequestHeader(headerName, headerValue);
28929 this.xhr.onload = function()
28931 _this.xhrOnLoad(_this.xhr);
28934 this.xhr.onerror = function()
28936 _this.xhrOnError(_this.xhr);
28939 var formData = new FormData();
28941 formData.append('returnHTML', 'NO');
28943 formData.append('crop', crop);
28945 if(typeof(file.filename) != 'undefined'){
28946 formData.append('filename', file.filename);
28949 if(typeof(file.mimetype) != 'undefined'){
28950 formData.append('mimetype', file.mimetype);
28955 if(this.fireEvent('prepare', this, formData) != false){
28956 this.xhr.send(formData);
28966 * @class Roo.bootstrap.DocumentViewer
28967 * @extends Roo.bootstrap.Component
28968 * Bootstrap DocumentViewer class
28969 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28970 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28973 * Create a new DocumentViewer
28974 * @param {Object} config The config object
28977 Roo.bootstrap.DocumentViewer = function(config){
28978 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28983 * Fire after initEvent
28984 * @param {Roo.bootstrap.DocumentViewer} this
28990 * @param {Roo.bootstrap.DocumentViewer} this
28995 * Fire after download button
28996 * @param {Roo.bootstrap.DocumentViewer} this
29001 * Fire after trash button
29002 * @param {Roo.bootstrap.DocumentViewer} this
29009 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29011 showDownload : true,
29015 getAutoCreate : function()
29019 cls : 'roo-document-viewer',
29023 cls : 'roo-document-viewer-body',
29027 cls : 'roo-document-viewer-thumb',
29031 cls : 'roo-document-viewer-image'
29039 cls : 'roo-document-viewer-footer',
29042 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29046 cls : 'btn-group roo-document-viewer-download',
29050 cls : 'btn btn-default',
29051 html : '<i class="fa fa-download"></i>'
29057 cls : 'btn-group roo-document-viewer-trash',
29061 cls : 'btn btn-default',
29062 html : '<i class="fa fa-trash"></i>'
29075 initEvents : function()
29077 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29078 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29080 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29081 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29083 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29084 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29086 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29087 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29089 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29090 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29092 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29093 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29095 this.bodyEl.on('click', this.onClick, this);
29096 this.downloadBtn.on('click', this.onDownload, this);
29097 this.trashBtn.on('click', this.onTrash, this);
29099 this.downloadBtn.hide();
29100 this.trashBtn.hide();
29102 if(this.showDownload){
29103 this.downloadBtn.show();
29106 if(this.showTrash){
29107 this.trashBtn.show();
29110 if(!this.showDownload && !this.showTrash) {
29111 this.footerEl.hide();
29116 initial : function()
29118 this.fireEvent('initial', this);
29122 onClick : function(e)
29124 e.preventDefault();
29126 this.fireEvent('click', this);
29129 onDownload : function(e)
29131 e.preventDefault();
29133 this.fireEvent('download', this);
29136 onTrash : function(e)
29138 e.preventDefault();
29140 this.fireEvent('trash', this);
29152 * @class Roo.bootstrap.NavProgressBar
29153 * @extends Roo.bootstrap.Component
29154 * Bootstrap NavProgressBar class
29157 * Create a new nav progress bar
29158 * @param {Object} config The config object
29161 Roo.bootstrap.NavProgressBar = function(config){
29162 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29164 this.bullets = this.bullets || [];
29166 // Roo.bootstrap.NavProgressBar.register(this);
29170 * Fires when the active item changes
29171 * @param {Roo.bootstrap.NavProgressBar} this
29172 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29173 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29180 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29185 getAutoCreate : function()
29187 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29191 cls : 'roo-navigation-bar-group',
29195 cls : 'roo-navigation-top-bar'
29199 cls : 'roo-navigation-bullets-bar',
29203 cls : 'roo-navigation-bar'
29210 cls : 'roo-navigation-bottom-bar'
29220 initEvents: function()
29225 onRender : function(ct, position)
29227 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29229 if(this.bullets.length){
29230 Roo.each(this.bullets, function(b){
29239 addItem : function(cfg)
29241 var item = new Roo.bootstrap.NavProgressItem(cfg);
29243 item.parentId = this.id;
29244 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29247 var top = new Roo.bootstrap.Element({
29249 cls : 'roo-navigation-bar-text'
29252 var bottom = new Roo.bootstrap.Element({
29254 cls : 'roo-navigation-bar-text'
29257 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29258 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29260 var topText = new Roo.bootstrap.Element({
29262 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29265 var bottomText = new Roo.bootstrap.Element({
29267 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29270 topText.onRender(top.el, null);
29271 bottomText.onRender(bottom.el, null);
29274 item.bottomEl = bottom;
29277 this.barItems.push(item);
29282 getActive : function()
29284 var active = false;
29286 Roo.each(this.barItems, function(v){
29288 if (!v.isActive()) {
29300 setActiveItem : function(item)
29304 Roo.each(this.barItems, function(v){
29305 if (v.rid == item.rid) {
29309 if (v.isActive()) {
29310 v.setActive(false);
29315 item.setActive(true);
29317 this.fireEvent('changed', this, item, prev);
29320 getBarItem: function(rid)
29324 Roo.each(this.barItems, function(e) {
29325 if (e.rid != rid) {
29336 indexOfItem : function(item)
29340 Roo.each(this.barItems, function(v, i){
29342 if (v.rid != item.rid) {
29353 setActiveNext : function()
29355 var i = this.indexOfItem(this.getActive());
29357 if (i > this.barItems.length) {
29361 this.setActiveItem(this.barItems[i+1]);
29364 setActivePrev : function()
29366 var i = this.indexOfItem(this.getActive());
29372 this.setActiveItem(this.barItems[i-1]);
29375 format : function()
29377 if(!this.barItems.length){
29381 var width = 100 / this.barItems.length;
29383 Roo.each(this.barItems, function(i){
29384 i.el.setStyle('width', width + '%');
29385 i.topEl.el.setStyle('width', width + '%');
29386 i.bottomEl.el.setStyle('width', width + '%');
29395 * Nav Progress Item
29400 * @class Roo.bootstrap.NavProgressItem
29401 * @extends Roo.bootstrap.Component
29402 * Bootstrap NavProgressItem class
29403 * @cfg {String} rid the reference id
29404 * @cfg {Boolean} active (true|false) Is item active default false
29405 * @cfg {Boolean} disabled (true|false) Is item active default false
29406 * @cfg {String} html
29407 * @cfg {String} position (top|bottom) text position default bottom
29408 * @cfg {String} icon show icon instead of number
29411 * Create a new NavProgressItem
29412 * @param {Object} config The config object
29414 Roo.bootstrap.NavProgressItem = function(config){
29415 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29420 * The raw click event for the entire grid.
29421 * @param {Roo.bootstrap.NavProgressItem} this
29422 * @param {Roo.EventObject} e
29429 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29435 position : 'bottom',
29438 getAutoCreate : function()
29440 var iconCls = 'roo-navigation-bar-item-icon';
29442 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29446 cls: 'roo-navigation-bar-item',
29456 cfg.cls += ' active';
29459 cfg.cls += ' disabled';
29465 disable : function()
29467 this.setDisabled(true);
29470 enable : function()
29472 this.setDisabled(false);
29475 initEvents: function()
29477 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29479 this.iconEl.on('click', this.onClick, this);
29482 onClick : function(e)
29484 e.preventDefault();
29490 if(this.fireEvent('click', this, e) === false){
29494 this.parent().setActiveItem(this);
29497 isActive: function ()
29499 return this.active;
29502 setActive : function(state)
29504 if(this.active == state){
29508 this.active = state;
29511 this.el.addClass('active');
29515 this.el.removeClass('active');
29520 setDisabled : function(state)
29522 if(this.disabled == state){
29526 this.disabled = state;
29529 this.el.addClass('disabled');
29533 this.el.removeClass('disabled');
29536 tooltipEl : function()
29538 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29551 * @class Roo.bootstrap.FieldLabel
29552 * @extends Roo.bootstrap.Component
29553 * Bootstrap FieldLabel class
29554 * @cfg {String} html contents of the element
29555 * @cfg {String} tag tag of the element default label
29556 * @cfg {String} cls class of the element
29557 * @cfg {String} target label target
29558 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29559 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29560 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29561 * @cfg {String} iconTooltip default "This field is required"
29564 * Create a new FieldLabel
29565 * @param {Object} config The config object
29568 Roo.bootstrap.FieldLabel = function(config){
29569 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29574 * Fires after the field has been marked as invalid.
29575 * @param {Roo.form.FieldLabel} this
29576 * @param {String} msg The validation message
29581 * Fires after the field has been validated with no errors.
29582 * @param {Roo.form.FieldLabel} this
29588 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29595 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29596 validClass : 'text-success fa fa-lg fa-check',
29597 iconTooltip : 'This field is required',
29599 getAutoCreate : function(){
29603 cls : 'roo-bootstrap-field-label ' + this.cls,
29609 tooltip : this.iconTooltip
29621 initEvents: function()
29623 Roo.bootstrap.Element.superclass.initEvents.call(this);
29625 this.iconEl = this.el.select('i', true).first();
29627 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29629 Roo.bootstrap.FieldLabel.register(this);
29633 * Mark this field as valid
29635 markValid : function()
29637 this.iconEl.show();
29639 this.iconEl.removeClass(this.invalidClass);
29641 this.iconEl.addClass(this.validClass);
29643 this.fireEvent('valid', this);
29647 * Mark this field as invalid
29648 * @param {String} msg The validation message
29650 markInvalid : function(msg)
29652 this.iconEl.show();
29654 this.iconEl.removeClass(this.validClass);
29656 this.iconEl.addClass(this.invalidClass);
29658 this.fireEvent('invalid', this, msg);
29664 Roo.apply(Roo.bootstrap.FieldLabel, {
29669 * register a FieldLabel Group
29670 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29672 register : function(label)
29674 if(this.groups.hasOwnProperty(label.target)){
29678 this.groups[label.target] = label;
29682 * fetch a FieldLabel Group based on the target
29683 * @param {string} target
29684 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29686 get: function(target) {
29687 if (typeof(this.groups[target]) == 'undefined') {
29691 return this.groups[target] ;
29700 * page DateSplitField.
29706 * @class Roo.bootstrap.DateSplitField
29707 * @extends Roo.bootstrap.Component
29708 * Bootstrap DateSplitField class
29709 * @cfg {string} fieldLabel - the label associated
29710 * @cfg {Number} labelWidth set the width of label (0-12)
29711 * @cfg {String} labelAlign (top|left)
29712 * @cfg {Boolean} dayAllowBlank (true|false) default false
29713 * @cfg {Boolean} monthAllowBlank (true|false) default false
29714 * @cfg {Boolean} yearAllowBlank (true|false) default false
29715 * @cfg {string} dayPlaceholder
29716 * @cfg {string} monthPlaceholder
29717 * @cfg {string} yearPlaceholder
29718 * @cfg {string} dayFormat default 'd'
29719 * @cfg {string} monthFormat default 'm'
29720 * @cfg {string} yearFormat default 'Y'
29721 * @cfg {Number} labellg set the width of label (1-12)
29722 * @cfg {Number} labelmd set the width of label (1-12)
29723 * @cfg {Number} labelsm set the width of label (1-12)
29724 * @cfg {Number} labelxs set the width of label (1-12)
29728 * Create a new DateSplitField
29729 * @param {Object} config The config object
29732 Roo.bootstrap.DateSplitField = function(config){
29733 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29739 * getting the data of years
29740 * @param {Roo.bootstrap.DateSplitField} this
29741 * @param {Object} years
29746 * getting the data of days
29747 * @param {Roo.bootstrap.DateSplitField} this
29748 * @param {Object} days
29753 * Fires after the field has been marked as invalid.
29754 * @param {Roo.form.Field} this
29755 * @param {String} msg The validation message
29760 * Fires after the field has been validated with no errors.
29761 * @param {Roo.form.Field} this
29767 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29770 labelAlign : 'top',
29772 dayAllowBlank : false,
29773 monthAllowBlank : false,
29774 yearAllowBlank : false,
29775 dayPlaceholder : '',
29776 monthPlaceholder : '',
29777 yearPlaceholder : '',
29781 isFormField : true,
29787 getAutoCreate : function()
29791 cls : 'row roo-date-split-field-group',
29796 cls : 'form-hidden-field roo-date-split-field-group-value',
29802 var labelCls = 'col-md-12';
29803 var contentCls = 'col-md-4';
29805 if(this.fieldLabel){
29809 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29813 html : this.fieldLabel
29818 if(this.labelAlign == 'left'){
29820 if(this.labelWidth > 12){
29821 label.style = "width: " + this.labelWidth + 'px';
29824 if(this.labelWidth < 13 && this.labelmd == 0){
29825 this.labelmd = this.labelWidth;
29828 if(this.labellg > 0){
29829 labelCls = ' col-lg-' + this.labellg;
29830 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29833 if(this.labelmd > 0){
29834 labelCls = ' col-md-' + this.labelmd;
29835 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29838 if(this.labelsm > 0){
29839 labelCls = ' col-sm-' + this.labelsm;
29840 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29843 if(this.labelxs > 0){
29844 labelCls = ' col-xs-' + this.labelxs;
29845 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29849 label.cls += ' ' + labelCls;
29851 cfg.cn.push(label);
29854 Roo.each(['day', 'month', 'year'], function(t){
29857 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29864 inputEl: function ()
29866 return this.el.select('.roo-date-split-field-group-value', true).first();
29869 onRender : function(ct, position)
29873 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29875 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29877 this.dayField = new Roo.bootstrap.ComboBox({
29878 allowBlank : this.dayAllowBlank,
29879 alwaysQuery : true,
29880 displayField : 'value',
29883 forceSelection : true,
29885 placeholder : this.dayPlaceholder,
29886 selectOnFocus : true,
29887 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29888 triggerAction : 'all',
29890 valueField : 'value',
29891 store : new Roo.data.SimpleStore({
29892 data : (function() {
29894 _this.fireEvent('days', _this, days);
29897 fields : [ 'value' ]
29900 select : function (_self, record, index)
29902 _this.setValue(_this.getValue());
29907 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29909 this.monthField = new Roo.bootstrap.MonthField({
29910 after : '<i class=\"fa fa-calendar\"></i>',
29911 allowBlank : this.monthAllowBlank,
29912 placeholder : this.monthPlaceholder,
29915 render : function (_self)
29917 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29918 e.preventDefault();
29922 select : function (_self, oldvalue, newvalue)
29924 _this.setValue(_this.getValue());
29929 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29931 this.yearField = new Roo.bootstrap.ComboBox({
29932 allowBlank : this.yearAllowBlank,
29933 alwaysQuery : true,
29934 displayField : 'value',
29937 forceSelection : true,
29939 placeholder : this.yearPlaceholder,
29940 selectOnFocus : true,
29941 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29942 triggerAction : 'all',
29944 valueField : 'value',
29945 store : new Roo.data.SimpleStore({
29946 data : (function() {
29948 _this.fireEvent('years', _this, years);
29951 fields : [ 'value' ]
29954 select : function (_self, record, index)
29956 _this.setValue(_this.getValue());
29961 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29964 setValue : function(v, format)
29966 this.inputEl.dom.value = v;
29968 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29970 var d = Date.parseDate(v, f);
29977 this.setDay(d.format(this.dayFormat));
29978 this.setMonth(d.format(this.monthFormat));
29979 this.setYear(d.format(this.yearFormat));
29986 setDay : function(v)
29988 this.dayField.setValue(v);
29989 this.inputEl.dom.value = this.getValue();
29994 setMonth : function(v)
29996 this.monthField.setValue(v, true);
29997 this.inputEl.dom.value = this.getValue();
30002 setYear : function(v)
30004 this.yearField.setValue(v);
30005 this.inputEl.dom.value = this.getValue();
30010 getDay : function()
30012 return this.dayField.getValue();
30015 getMonth : function()
30017 return this.monthField.getValue();
30020 getYear : function()
30022 return this.yearField.getValue();
30025 getValue : function()
30027 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30029 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30039 this.inputEl.dom.value = '';
30044 validate : function()
30046 var d = this.dayField.validate();
30047 var m = this.monthField.validate();
30048 var y = this.yearField.validate();
30053 (!this.dayAllowBlank && !d) ||
30054 (!this.monthAllowBlank && !m) ||
30055 (!this.yearAllowBlank && !y)
30060 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30069 this.markInvalid();
30074 markValid : function()
30077 var label = this.el.select('label', true).first();
30078 var icon = this.el.select('i.fa-star', true).first();
30084 this.fireEvent('valid', this);
30088 * Mark this field as invalid
30089 * @param {String} msg The validation message
30091 markInvalid : function(msg)
30094 var label = this.el.select('label', true).first();
30095 var icon = this.el.select('i.fa-star', true).first();
30097 if(label && !icon){
30098 this.el.select('.roo-date-split-field-label', true).createChild({
30100 cls : 'text-danger fa fa-lg fa-star',
30101 tooltip : 'This field is required',
30102 style : 'margin-right:5px;'
30106 this.fireEvent('invalid', this, msg);
30109 clearInvalid : function()
30111 var label = this.el.select('label', true).first();
30112 var icon = this.el.select('i.fa-star', true).first();
30118 this.fireEvent('valid', this);
30121 getName: function()
30131 * http://masonry.desandro.com
30133 * The idea is to render all the bricks based on vertical width...
30135 * The original code extends 'outlayer' - we might need to use that....
30141 * @class Roo.bootstrap.LayoutMasonry
30142 * @extends Roo.bootstrap.Component
30143 * Bootstrap Layout Masonry class
30146 * Create a new Element
30147 * @param {Object} config The config object
30150 Roo.bootstrap.LayoutMasonry = function(config){
30152 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30156 Roo.bootstrap.LayoutMasonry.register(this);
30162 * Fire after layout the items
30163 * @param {Roo.bootstrap.LayoutMasonry} this
30164 * @param {Roo.EventObject} e
30171 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30174 * @cfg {Boolean} isLayoutInstant = no animation?
30176 isLayoutInstant : false, // needed?
30179 * @cfg {Number} boxWidth width of the columns
30184 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30189 * @cfg {Number} padWidth padding below box..
30194 * @cfg {Number} gutter gutter width..
30199 * @cfg {Number} maxCols maximum number of columns
30205 * @cfg {Boolean} isAutoInitial defalut true
30207 isAutoInitial : true,
30212 * @cfg {Boolean} isHorizontal defalut false
30214 isHorizontal : false,
30216 currentSize : null,
30222 bricks: null, //CompositeElement
30226 _isLayoutInited : false,
30228 // isAlternative : false, // only use for vertical layout...
30231 * @cfg {Number} alternativePadWidth padding below box..
30233 alternativePadWidth : 50,
30235 selectedBrick : [],
30237 getAutoCreate : function(){
30239 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30243 cls: 'blog-masonary-wrapper ' + this.cls,
30245 cls : 'mas-boxes masonary'
30252 getChildContainer: function( )
30254 if (this.boxesEl) {
30255 return this.boxesEl;
30258 this.boxesEl = this.el.select('.mas-boxes').first();
30260 return this.boxesEl;
30264 initEvents : function()
30268 if(this.isAutoInitial){
30269 Roo.log('hook children rendered');
30270 this.on('childrenrendered', function() {
30271 Roo.log('children rendered');
30277 initial : function()
30279 this.selectedBrick = [];
30281 this.currentSize = this.el.getBox(true);
30283 Roo.EventManager.onWindowResize(this.resize, this);
30285 if(!this.isAutoInitial){
30293 //this.layout.defer(500,this);
30297 resize : function()
30299 var cs = this.el.getBox(true);
30302 this.currentSize.width == cs.width &&
30303 this.currentSize.x == cs.x &&
30304 this.currentSize.height == cs.height &&
30305 this.currentSize.y == cs.y
30307 Roo.log("no change in with or X or Y");
30311 this.currentSize = cs;
30317 layout : function()
30319 this._resetLayout();
30321 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30323 this.layoutItems( isInstant );
30325 this._isLayoutInited = true;
30327 this.fireEvent('layout', this);
30331 _resetLayout : function()
30333 if(this.isHorizontal){
30334 this.horizontalMeasureColumns();
30338 this.verticalMeasureColumns();
30342 verticalMeasureColumns : function()
30344 this.getContainerWidth();
30346 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30347 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30351 var boxWidth = this.boxWidth + this.padWidth;
30353 if(this.containerWidth < this.boxWidth){
30354 boxWidth = this.containerWidth
30357 var containerWidth = this.containerWidth;
30359 var cols = Math.floor(containerWidth / boxWidth);
30361 this.cols = Math.max( cols, 1 );
30363 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30365 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30367 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30369 this.colWidth = boxWidth + avail - this.padWidth;
30371 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30372 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30375 horizontalMeasureColumns : function()
30377 this.getContainerWidth();
30379 var boxWidth = this.boxWidth;
30381 if(this.containerWidth < boxWidth){
30382 boxWidth = this.containerWidth;
30385 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30387 this.el.setHeight(boxWidth);
30391 getContainerWidth : function()
30393 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30396 layoutItems : function( isInstant )
30398 Roo.log(this.bricks);
30400 var items = Roo.apply([], this.bricks);
30402 if(this.isHorizontal){
30403 this._horizontalLayoutItems( items , isInstant );
30407 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30408 // this._verticalAlternativeLayoutItems( items , isInstant );
30412 this._verticalLayoutItems( items , isInstant );
30416 _verticalLayoutItems : function ( items , isInstant)
30418 if ( !items || !items.length ) {
30423 ['xs', 'xs', 'xs', 'tall'],
30424 ['xs', 'xs', 'tall'],
30425 ['xs', 'xs', 'sm'],
30426 ['xs', 'xs', 'xs'],
30432 ['sm', 'xs', 'xs'],
30436 ['tall', 'xs', 'xs', 'xs'],
30437 ['tall', 'xs', 'xs'],
30449 Roo.each(items, function(item, k){
30451 switch (item.size) {
30452 // these layouts take up a full box,
30463 boxes.push([item]);
30486 var filterPattern = function(box, length)
30494 var pattern = box.slice(0, length);
30498 Roo.each(pattern, function(i){
30499 format.push(i.size);
30502 Roo.each(standard, function(s){
30504 if(String(s) != String(format)){
30513 if(!match && length == 1){
30518 filterPattern(box, length - 1);
30522 queue.push(pattern);
30524 box = box.slice(length, box.length);
30526 filterPattern(box, 4);
30532 Roo.each(boxes, function(box, k){
30538 if(box.length == 1){
30543 filterPattern(box, 4);
30547 this._processVerticalLayoutQueue( queue, isInstant );
30551 // _verticalAlternativeLayoutItems : function( items , isInstant )
30553 // if ( !items || !items.length ) {
30557 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30561 _horizontalLayoutItems : function ( items , isInstant)
30563 if ( !items || !items.length || items.length < 3) {
30569 var eItems = items.slice(0, 3);
30571 items = items.slice(3, items.length);
30574 ['xs', 'xs', 'xs', 'wide'],
30575 ['xs', 'xs', 'wide'],
30576 ['xs', 'xs', 'sm'],
30577 ['xs', 'xs', 'xs'],
30583 ['sm', 'xs', 'xs'],
30587 ['wide', 'xs', 'xs', 'xs'],
30588 ['wide', 'xs', 'xs'],
30601 Roo.each(items, function(item, k){
30603 switch (item.size) {
30614 boxes.push([item]);
30638 var filterPattern = function(box, length)
30646 var pattern = box.slice(0, length);
30650 Roo.each(pattern, function(i){
30651 format.push(i.size);
30654 Roo.each(standard, function(s){
30656 if(String(s) != String(format)){
30665 if(!match && length == 1){
30670 filterPattern(box, length - 1);
30674 queue.push(pattern);
30676 box = box.slice(length, box.length);
30678 filterPattern(box, 4);
30684 Roo.each(boxes, function(box, k){
30690 if(box.length == 1){
30695 filterPattern(box, 4);
30702 var pos = this.el.getBox(true);
30706 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30708 var hit_end = false;
30710 Roo.each(queue, function(box){
30714 Roo.each(box, function(b){
30716 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30726 Roo.each(box, function(b){
30728 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30731 mx = Math.max(mx, b.x);
30735 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30739 Roo.each(box, function(b){
30741 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30755 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30758 /** Sets position of item in DOM
30759 * @param {Element} item
30760 * @param {Number} x - horizontal position
30761 * @param {Number} y - vertical position
30762 * @param {Boolean} isInstant - disables transitions
30764 _processVerticalLayoutQueue : function( queue, isInstant )
30766 var pos = this.el.getBox(true);
30771 for (var i = 0; i < this.cols; i++){
30775 Roo.each(queue, function(box, k){
30777 var col = k % this.cols;
30779 Roo.each(box, function(b,kk){
30781 b.el.position('absolute');
30783 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30784 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30786 if(b.size == 'md-left' || b.size == 'md-right'){
30787 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30788 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30791 b.el.setWidth(width);
30792 b.el.setHeight(height);
30794 b.el.select('iframe',true).setSize(width,height);
30798 for (var i = 0; i < this.cols; i++){
30800 if(maxY[i] < maxY[col]){
30805 col = Math.min(col, i);
30809 x = pos.x + col * (this.colWidth + this.padWidth);
30813 var positions = [];
30815 switch (box.length){
30817 positions = this.getVerticalOneBoxColPositions(x, y, box);
30820 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30823 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30826 positions = this.getVerticalFourBoxColPositions(x, y, box);
30832 Roo.each(box, function(b,kk){
30834 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30836 var sz = b.el.getSize();
30838 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30846 for (var i = 0; i < this.cols; i++){
30847 mY = Math.max(mY, maxY[i]);
30850 this.el.setHeight(mY - pos.y);
30854 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30856 // var pos = this.el.getBox(true);
30859 // var maxX = pos.right;
30861 // var maxHeight = 0;
30863 // Roo.each(items, function(item, k){
30867 // item.el.position('absolute');
30869 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30871 // item.el.setWidth(width);
30873 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30875 // item.el.setHeight(height);
30878 // item.el.setXY([x, y], isInstant ? false : true);
30880 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30883 // y = y + height + this.alternativePadWidth;
30885 // maxHeight = maxHeight + height + this.alternativePadWidth;
30889 // this.el.setHeight(maxHeight);
30893 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30895 var pos = this.el.getBox(true);
30900 var maxX = pos.right;
30902 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30904 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30906 Roo.each(queue, function(box, k){
30908 Roo.each(box, function(b, kk){
30910 b.el.position('absolute');
30912 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30913 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30915 if(b.size == 'md-left' || b.size == 'md-right'){
30916 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30917 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30920 b.el.setWidth(width);
30921 b.el.setHeight(height);
30929 var positions = [];
30931 switch (box.length){
30933 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30936 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30939 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30942 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30948 Roo.each(box, function(b,kk){
30950 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30952 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30960 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30962 Roo.each(eItems, function(b,k){
30964 b.size = (k == 0) ? 'sm' : 'xs';
30965 b.x = (k == 0) ? 2 : 1;
30966 b.y = (k == 0) ? 2 : 1;
30968 b.el.position('absolute');
30970 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30972 b.el.setWidth(width);
30974 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30976 b.el.setHeight(height);
30980 var positions = [];
30983 x : maxX - this.unitWidth * 2 - this.gutter,
30988 x : maxX - this.unitWidth,
30989 y : minY + (this.unitWidth + this.gutter) * 2
30993 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30997 Roo.each(eItems, function(b,k){
30999 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31005 getVerticalOneBoxColPositions : function(x, y, box)
31009 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31011 if(box[0].size == 'md-left'){
31015 if(box[0].size == 'md-right'){
31020 x : x + (this.unitWidth + this.gutter) * rand,
31027 getVerticalTwoBoxColPositions : function(x, y, box)
31031 if(box[0].size == 'xs'){
31035 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31039 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31053 x : x + (this.unitWidth + this.gutter) * 2,
31054 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31061 getVerticalThreeBoxColPositions : function(x, y, box)
31065 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31073 x : x + (this.unitWidth + this.gutter) * 1,
31078 x : x + (this.unitWidth + this.gutter) * 2,
31086 if(box[0].size == 'xs' && box[1].size == 'xs'){
31095 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31099 x : x + (this.unitWidth + this.gutter) * 1,
31113 x : x + (this.unitWidth + this.gutter) * 2,
31118 x : x + (this.unitWidth + this.gutter) * 2,
31119 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31126 getVerticalFourBoxColPositions : function(x, y, box)
31130 if(box[0].size == 'xs'){
31139 y : y + (this.unitHeight + this.gutter) * 1
31144 y : y + (this.unitHeight + this.gutter) * 2
31148 x : x + (this.unitWidth + this.gutter) * 1,
31162 x : x + (this.unitWidth + this.gutter) * 2,
31167 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31168 y : y + (this.unitHeight + this.gutter) * 1
31172 x : x + (this.unitWidth + this.gutter) * 2,
31173 y : y + (this.unitWidth + this.gutter) * 2
31180 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31184 if(box[0].size == 'md-left'){
31186 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31193 if(box[0].size == 'md-right'){
31195 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31196 y : minY + (this.unitWidth + this.gutter) * 1
31202 var rand = Math.floor(Math.random() * (4 - box[0].y));
31205 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31206 y : minY + (this.unitWidth + this.gutter) * rand
31213 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31217 if(box[0].size == 'xs'){
31220 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31225 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31226 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31234 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31239 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31240 y : minY + (this.unitWidth + this.gutter) * 2
31247 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31251 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31254 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31259 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31260 y : minY + (this.unitWidth + this.gutter) * 1
31264 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31265 y : minY + (this.unitWidth + this.gutter) * 2
31272 if(box[0].size == 'xs' && box[1].size == 'xs'){
31275 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31280 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31285 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31286 y : minY + (this.unitWidth + this.gutter) * 1
31294 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31299 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31300 y : minY + (this.unitWidth + this.gutter) * 2
31304 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31305 y : minY + (this.unitWidth + this.gutter) * 2
31312 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31316 if(box[0].size == 'xs'){
31319 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31324 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31329 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),
31334 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31335 y : minY + (this.unitWidth + this.gutter) * 1
31343 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31348 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31349 y : minY + (this.unitWidth + this.gutter) * 2
31353 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31354 y : minY + (this.unitWidth + this.gutter) * 2
31358 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),
31359 y : minY + (this.unitWidth + this.gutter) * 2
31367 * remove a Masonry Brick
31368 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31370 removeBrick : function(brick_id)
31376 for (var i = 0; i<this.bricks.length; i++) {
31377 if (this.bricks[i].id == brick_id) {
31378 this.bricks.splice(i,1);
31379 this.el.dom.removeChild(Roo.get(brick_id).dom);
31386 * adds a Masonry Brick
31387 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31389 addBrick : function(cfg)
31391 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31392 //this.register(cn);
31393 cn.parentId = this.id;
31394 cn.onRender(this.el, null);
31399 * register a Masonry Brick
31400 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31403 register : function(brick)
31405 this.bricks.push(brick);
31406 brick.masonryId = this.id;
31410 * clear all the Masonry Brick
31412 clearAll : function()
31415 //this.getChildContainer().dom.innerHTML = "";
31416 this.el.dom.innerHTML = '';
31419 getSelected : function()
31421 if (!this.selectedBrick) {
31425 return this.selectedBrick;
31429 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31433 * register a Masonry Layout
31434 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31437 register : function(layout)
31439 this.groups[layout.id] = layout;
31442 * fetch a Masonry Layout based on the masonry layout ID
31443 * @param {string} the masonry layout to add
31444 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31447 get: function(layout_id) {
31448 if (typeof(this.groups[layout_id]) == 'undefined') {
31451 return this.groups[layout_id] ;
31463 * http://masonry.desandro.com
31465 * The idea is to render all the bricks based on vertical width...
31467 * The original code extends 'outlayer' - we might need to use that....
31473 * @class Roo.bootstrap.LayoutMasonryAuto
31474 * @extends Roo.bootstrap.Component
31475 * Bootstrap Layout Masonry class
31478 * Create a new Element
31479 * @param {Object} config The config object
31482 Roo.bootstrap.LayoutMasonryAuto = function(config){
31483 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31486 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31489 * @cfg {Boolean} isFitWidth - resize the width..
31491 isFitWidth : false, // options..
31493 * @cfg {Boolean} isOriginLeft = left align?
31495 isOriginLeft : true,
31497 * @cfg {Boolean} isOriginTop = top align?
31499 isOriginTop : false,
31501 * @cfg {Boolean} isLayoutInstant = no animation?
31503 isLayoutInstant : false, // needed?
31505 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31507 isResizingContainer : true,
31509 * @cfg {Number} columnWidth width of the columns
31515 * @cfg {Number} maxCols maximum number of columns
31520 * @cfg {Number} padHeight padding below box..
31526 * @cfg {Boolean} isAutoInitial defalut true
31529 isAutoInitial : true,
31535 initialColumnWidth : 0,
31536 currentSize : null,
31538 colYs : null, // array.
31545 bricks: null, //CompositeElement
31546 cols : 0, // array?
31547 // element : null, // wrapped now this.el
31548 _isLayoutInited : null,
31551 getAutoCreate : function(){
31555 cls: 'blog-masonary-wrapper ' + this.cls,
31557 cls : 'mas-boxes masonary'
31564 getChildContainer: function( )
31566 if (this.boxesEl) {
31567 return this.boxesEl;
31570 this.boxesEl = this.el.select('.mas-boxes').first();
31572 return this.boxesEl;
31576 initEvents : function()
31580 if(this.isAutoInitial){
31581 Roo.log('hook children rendered');
31582 this.on('childrenrendered', function() {
31583 Roo.log('children rendered');
31590 initial : function()
31592 this.reloadItems();
31594 this.currentSize = this.el.getBox(true);
31596 /// was window resize... - let's see if this works..
31597 Roo.EventManager.onWindowResize(this.resize, this);
31599 if(!this.isAutoInitial){
31604 this.layout.defer(500,this);
31607 reloadItems: function()
31609 this.bricks = this.el.select('.masonry-brick', true);
31611 this.bricks.each(function(b) {
31612 //Roo.log(b.getSize());
31613 if (!b.attr('originalwidth')) {
31614 b.attr('originalwidth', b.getSize().width);
31619 Roo.log(this.bricks.elements.length);
31622 resize : function()
31625 var cs = this.el.getBox(true);
31627 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31628 Roo.log("no change in with or X");
31631 this.currentSize = cs;
31635 layout : function()
31638 this._resetLayout();
31639 //this._manageStamps();
31641 // don't animate first layout
31642 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31643 this.layoutItems( isInstant );
31645 // flag for initalized
31646 this._isLayoutInited = true;
31649 layoutItems : function( isInstant )
31651 //var items = this._getItemsForLayout( this.items );
31652 // original code supports filtering layout items.. we just ignore it..
31654 this._layoutItems( this.bricks , isInstant );
31656 this._postLayout();
31658 _layoutItems : function ( items , isInstant)
31660 //this.fireEvent( 'layout', this, items );
31663 if ( !items || !items.elements.length ) {
31664 // no items, emit event with empty array
31669 items.each(function(item) {
31670 Roo.log("layout item");
31672 // get x/y object from method
31673 var position = this._getItemLayoutPosition( item );
31675 position.item = item;
31676 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31677 queue.push( position );
31680 this._processLayoutQueue( queue );
31682 /** Sets position of item in DOM
31683 * @param {Element} item
31684 * @param {Number} x - horizontal position
31685 * @param {Number} y - vertical position
31686 * @param {Boolean} isInstant - disables transitions
31688 _processLayoutQueue : function( queue )
31690 for ( var i=0, len = queue.length; i < len; i++ ) {
31691 var obj = queue[i];
31692 obj.item.position('absolute');
31693 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31699 * Any logic you want to do after each layout,
31700 * i.e. size the container
31702 _postLayout : function()
31704 this.resizeContainer();
31707 resizeContainer : function()
31709 if ( !this.isResizingContainer ) {
31712 var size = this._getContainerSize();
31714 this.el.setSize(size.width,size.height);
31715 this.boxesEl.setSize(size.width,size.height);
31721 _resetLayout : function()
31723 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31724 this.colWidth = this.el.getWidth();
31725 //this.gutter = this.el.getWidth();
31727 this.measureColumns();
31733 this.colYs.push( 0 );
31739 measureColumns : function()
31741 this.getContainerWidth();
31742 // if columnWidth is 0, default to outerWidth of first item
31743 if ( !this.columnWidth ) {
31744 var firstItem = this.bricks.first();
31745 Roo.log(firstItem);
31746 this.columnWidth = this.containerWidth;
31747 if (firstItem && firstItem.attr('originalwidth') ) {
31748 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31750 // columnWidth fall back to item of first element
31751 Roo.log("set column width?");
31752 this.initialColumnWidth = this.columnWidth ;
31754 // if first elem has no width, default to size of container
31759 if (this.initialColumnWidth) {
31760 this.columnWidth = this.initialColumnWidth;
31765 // column width is fixed at the top - however if container width get's smaller we should
31768 // this bit calcs how man columns..
31770 var columnWidth = this.columnWidth += this.gutter;
31772 // calculate columns
31773 var containerWidth = this.containerWidth + this.gutter;
31775 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31776 // fix rounding errors, typically with gutters
31777 var excess = columnWidth - containerWidth % columnWidth;
31780 // if overshoot is less than a pixel, round up, otherwise floor it
31781 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31782 cols = Math[ mathMethod ]( cols );
31783 this.cols = Math.max( cols, 1 );
31784 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31786 // padding positioning..
31787 var totalColWidth = this.cols * this.columnWidth;
31788 var padavail = this.containerWidth - totalColWidth;
31789 // so for 2 columns - we need 3 'pads'
31791 var padNeeded = (1+this.cols) * this.padWidth;
31793 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31795 this.columnWidth += padExtra
31796 //this.padWidth = Math.floor(padavail / ( this.cols));
31798 // adjust colum width so that padding is fixed??
31800 // we have 3 columns ... total = width * 3
31801 // we have X left over... that should be used by
31803 //if (this.expandC) {
31811 getContainerWidth : function()
31813 /* // container is parent if fit width
31814 var container = this.isFitWidth ? this.element.parentNode : this.element;
31815 // check that this.size and size are there
31816 // IE8 triggers resize on body size change, so they might not be
31818 var size = getSize( container ); //FIXME
31819 this.containerWidth = size && size.innerWidth; //FIXME
31822 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31826 _getItemLayoutPosition : function( item ) // what is item?
31828 // we resize the item to our columnWidth..
31830 item.setWidth(this.columnWidth);
31831 item.autoBoxAdjust = false;
31833 var sz = item.getSize();
31835 // how many columns does this brick span
31836 var remainder = this.containerWidth % this.columnWidth;
31838 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31839 // round if off by 1 pixel, otherwise use ceil
31840 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31841 colSpan = Math.min( colSpan, this.cols );
31843 // normally this should be '1' as we dont' currently allow multi width columns..
31845 var colGroup = this._getColGroup( colSpan );
31846 // get the minimum Y value from the columns
31847 var minimumY = Math.min.apply( Math, colGroup );
31848 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31850 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31852 // position the brick
31854 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31855 y: this.currentSize.y + minimumY + this.padHeight
31859 // apply setHeight to necessary columns
31860 var setHeight = minimumY + sz.height + this.padHeight;
31861 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31863 var setSpan = this.cols + 1 - colGroup.length;
31864 for ( var i = 0; i < setSpan; i++ ) {
31865 this.colYs[ shortColIndex + i ] = setHeight ;
31872 * @param {Number} colSpan - number of columns the element spans
31873 * @returns {Array} colGroup
31875 _getColGroup : function( colSpan )
31877 if ( colSpan < 2 ) {
31878 // if brick spans only one column, use all the column Ys
31883 // how many different places could this brick fit horizontally
31884 var groupCount = this.cols + 1 - colSpan;
31885 // for each group potential horizontal position
31886 for ( var i = 0; i < groupCount; i++ ) {
31887 // make an array of colY values for that one group
31888 var groupColYs = this.colYs.slice( i, i + colSpan );
31889 // and get the max value of the array
31890 colGroup[i] = Math.max.apply( Math, groupColYs );
31895 _manageStamp : function( stamp )
31897 var stampSize = stamp.getSize();
31898 var offset = stamp.getBox();
31899 // get the columns that this stamp affects
31900 var firstX = this.isOriginLeft ? offset.x : offset.right;
31901 var lastX = firstX + stampSize.width;
31902 var firstCol = Math.floor( firstX / this.columnWidth );
31903 firstCol = Math.max( 0, firstCol );
31905 var lastCol = Math.floor( lastX / this.columnWidth );
31906 // lastCol should not go over if multiple of columnWidth #425
31907 lastCol -= lastX % this.columnWidth ? 0 : 1;
31908 lastCol = Math.min( this.cols - 1, lastCol );
31910 // set colYs to bottom of the stamp
31911 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31914 for ( var i = firstCol; i <= lastCol; i++ ) {
31915 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31920 _getContainerSize : function()
31922 this.maxY = Math.max.apply( Math, this.colYs );
31927 if ( this.isFitWidth ) {
31928 size.width = this._getContainerFitWidth();
31934 _getContainerFitWidth : function()
31936 var unusedCols = 0;
31937 // count unused columns
31940 if ( this.colYs[i] !== 0 ) {
31945 // fit container to columns that have been used
31946 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31949 needsResizeLayout : function()
31951 var previousWidth = this.containerWidth;
31952 this.getContainerWidth();
31953 return previousWidth !== this.containerWidth;
31968 * @class Roo.bootstrap.MasonryBrick
31969 * @extends Roo.bootstrap.Component
31970 * Bootstrap MasonryBrick class
31973 * Create a new MasonryBrick
31974 * @param {Object} config The config object
31977 Roo.bootstrap.MasonryBrick = function(config){
31979 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31981 Roo.bootstrap.MasonryBrick.register(this);
31987 * When a MasonryBrick is clcik
31988 * @param {Roo.bootstrap.MasonryBrick} this
31989 * @param {Roo.EventObject} e
31995 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31998 * @cfg {String} title
32002 * @cfg {String} html
32006 * @cfg {String} bgimage
32010 * @cfg {String} videourl
32014 * @cfg {String} cls
32018 * @cfg {String} href
32022 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32027 * @cfg {String} placetitle (center|bottom)
32032 * @cfg {Boolean} isFitContainer defalut true
32034 isFitContainer : true,
32037 * @cfg {Boolean} preventDefault defalut false
32039 preventDefault : false,
32042 * @cfg {Boolean} inverse defalut false
32044 maskInverse : false,
32046 getAutoCreate : function()
32048 if(!this.isFitContainer){
32049 return this.getSplitAutoCreate();
32052 var cls = 'masonry-brick masonry-brick-full';
32054 if(this.href.length){
32055 cls += ' masonry-brick-link';
32058 if(this.bgimage.length){
32059 cls += ' masonry-brick-image';
32062 if(this.maskInverse){
32063 cls += ' mask-inverse';
32066 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32067 cls += ' enable-mask';
32071 cls += ' masonry-' + this.size + '-brick';
32074 if(this.placetitle.length){
32076 switch (this.placetitle) {
32078 cls += ' masonry-center-title';
32081 cls += ' masonry-bottom-title';
32088 if(!this.html.length && !this.bgimage.length){
32089 cls += ' masonry-center-title';
32092 if(!this.html.length && this.bgimage.length){
32093 cls += ' masonry-bottom-title';
32098 cls += ' ' + this.cls;
32102 tag: (this.href.length) ? 'a' : 'div',
32107 cls: 'masonry-brick-mask'
32111 cls: 'masonry-brick-paragraph',
32117 if(this.href.length){
32118 cfg.href = this.href;
32121 var cn = cfg.cn[1].cn;
32123 if(this.title.length){
32126 cls: 'masonry-brick-title',
32131 if(this.html.length){
32134 cls: 'masonry-brick-text',
32139 if (!this.title.length && !this.html.length) {
32140 cfg.cn[1].cls += ' hide';
32143 if(this.bgimage.length){
32146 cls: 'masonry-brick-image-view',
32151 if(this.videourl.length){
32152 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32153 // youtube support only?
32156 cls: 'masonry-brick-image-view',
32159 allowfullscreen : true
32167 getSplitAutoCreate : function()
32169 var cls = 'masonry-brick masonry-brick-split';
32171 if(this.href.length){
32172 cls += ' masonry-brick-link';
32175 if(this.bgimage.length){
32176 cls += ' masonry-brick-image';
32180 cls += ' masonry-' + this.size + '-brick';
32183 switch (this.placetitle) {
32185 cls += ' masonry-center-title';
32188 cls += ' masonry-bottom-title';
32191 if(!this.bgimage.length){
32192 cls += ' masonry-center-title';
32195 if(this.bgimage.length){
32196 cls += ' masonry-bottom-title';
32202 cls += ' ' + this.cls;
32206 tag: (this.href.length) ? 'a' : 'div',
32211 cls: 'masonry-brick-split-head',
32215 cls: 'masonry-brick-paragraph',
32222 cls: 'masonry-brick-split-body',
32228 if(this.href.length){
32229 cfg.href = this.href;
32232 if(this.title.length){
32233 cfg.cn[0].cn[0].cn.push({
32235 cls: 'masonry-brick-title',
32240 if(this.html.length){
32241 cfg.cn[1].cn.push({
32243 cls: 'masonry-brick-text',
32248 if(this.bgimage.length){
32249 cfg.cn[0].cn.push({
32251 cls: 'masonry-brick-image-view',
32256 if(this.videourl.length){
32257 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32258 // youtube support only?
32259 cfg.cn[0].cn.cn.push({
32261 cls: 'masonry-brick-image-view',
32264 allowfullscreen : true
32271 initEvents: function()
32273 switch (this.size) {
32306 this.el.on('touchstart', this.onTouchStart, this);
32307 this.el.on('touchmove', this.onTouchMove, this);
32308 this.el.on('touchend', this.onTouchEnd, this);
32309 this.el.on('contextmenu', this.onContextMenu, this);
32311 this.el.on('mouseenter' ,this.enter, this);
32312 this.el.on('mouseleave', this.leave, this);
32313 this.el.on('click', this.onClick, this);
32316 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32317 this.parent().bricks.push(this);
32322 onClick: function(e, el)
32324 var time = this.endTimer - this.startTimer;
32325 // Roo.log(e.preventDefault());
32328 e.preventDefault();
32333 if(!this.preventDefault){
32337 e.preventDefault();
32339 if (this.activcClass != '') {
32340 this.selectBrick();
32343 this.fireEvent('click', this);
32346 enter: function(e, el)
32348 e.preventDefault();
32350 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32354 if(this.bgimage.length && this.html.length){
32355 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32359 leave: function(e, el)
32361 e.preventDefault();
32363 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32367 if(this.bgimage.length && this.html.length){
32368 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32372 onTouchStart: function(e, el)
32374 // e.preventDefault();
32376 this.touchmoved = false;
32378 if(!this.isFitContainer){
32382 if(!this.bgimage.length || !this.html.length){
32386 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32388 this.timer = new Date().getTime();
32392 onTouchMove: function(e, el)
32394 this.touchmoved = true;
32397 onContextMenu : function(e,el)
32399 e.preventDefault();
32400 e.stopPropagation();
32404 onTouchEnd: function(e, el)
32406 // e.preventDefault();
32408 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32415 if(!this.bgimage.length || !this.html.length){
32417 if(this.href.length){
32418 window.location.href = this.href;
32424 if(!this.isFitContainer){
32428 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32430 window.location.href = this.href;
32433 //selection on single brick only
32434 selectBrick : function() {
32436 if (!this.parentId) {
32440 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32441 var index = m.selectedBrick.indexOf(this.id);
32444 m.selectedBrick.splice(index,1);
32445 this.el.removeClass(this.activeClass);
32449 for(var i = 0; i < m.selectedBrick.length; i++) {
32450 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32451 b.el.removeClass(b.activeClass);
32454 m.selectedBrick = [];
32456 m.selectedBrick.push(this.id);
32457 this.el.addClass(this.activeClass);
32463 Roo.apply(Roo.bootstrap.MasonryBrick, {
32466 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32468 * register a Masonry Brick
32469 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32472 register : function(brick)
32474 //this.groups[brick.id] = brick;
32475 this.groups.add(brick.id, brick);
32478 * fetch a masonry brick based on the masonry brick ID
32479 * @param {string} the masonry brick to add
32480 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32483 get: function(brick_id)
32485 // if (typeof(this.groups[brick_id]) == 'undefined') {
32488 // return this.groups[brick_id] ;
32490 if(this.groups.key(brick_id)) {
32491 return this.groups.key(brick_id);
32509 * @class Roo.bootstrap.Brick
32510 * @extends Roo.bootstrap.Component
32511 * Bootstrap Brick class
32514 * Create a new Brick
32515 * @param {Object} config The config object
32518 Roo.bootstrap.Brick = function(config){
32519 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32525 * When a Brick is click
32526 * @param {Roo.bootstrap.Brick} this
32527 * @param {Roo.EventObject} e
32533 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32536 * @cfg {String} title
32540 * @cfg {String} html
32544 * @cfg {String} bgimage
32548 * @cfg {String} cls
32552 * @cfg {String} href
32556 * @cfg {String} video
32560 * @cfg {Boolean} square
32564 getAutoCreate : function()
32566 var cls = 'roo-brick';
32568 if(this.href.length){
32569 cls += ' roo-brick-link';
32572 if(this.bgimage.length){
32573 cls += ' roo-brick-image';
32576 if(!this.html.length && !this.bgimage.length){
32577 cls += ' roo-brick-center-title';
32580 if(!this.html.length && this.bgimage.length){
32581 cls += ' roo-brick-bottom-title';
32585 cls += ' ' + this.cls;
32589 tag: (this.href.length) ? 'a' : 'div',
32594 cls: 'roo-brick-paragraph',
32600 if(this.href.length){
32601 cfg.href = this.href;
32604 var cn = cfg.cn[0].cn;
32606 if(this.title.length){
32609 cls: 'roo-brick-title',
32614 if(this.html.length){
32617 cls: 'roo-brick-text',
32624 if(this.bgimage.length){
32627 cls: 'roo-brick-image-view',
32635 initEvents: function()
32637 if(this.title.length || this.html.length){
32638 this.el.on('mouseenter' ,this.enter, this);
32639 this.el.on('mouseleave', this.leave, this);
32642 Roo.EventManager.onWindowResize(this.resize, this);
32644 if(this.bgimage.length){
32645 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32646 this.imageEl.on('load', this.onImageLoad, this);
32653 onImageLoad : function()
32658 resize : function()
32660 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32662 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32664 if(this.bgimage.length){
32665 var image = this.el.select('.roo-brick-image-view', true).first();
32667 image.setWidth(paragraph.getWidth());
32670 image.setHeight(paragraph.getWidth());
32673 this.el.setHeight(image.getHeight());
32674 paragraph.setHeight(image.getHeight());
32680 enter: function(e, el)
32682 e.preventDefault();
32684 if(this.bgimage.length){
32685 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32686 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32690 leave: function(e, el)
32692 e.preventDefault();
32694 if(this.bgimage.length){
32695 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32696 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32712 * @class Roo.bootstrap.NumberField
32713 * @extends Roo.bootstrap.Input
32714 * Bootstrap NumberField class
32720 * Create a new NumberField
32721 * @param {Object} config The config object
32724 Roo.bootstrap.NumberField = function(config){
32725 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32728 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32731 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32733 allowDecimals : true,
32735 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32737 decimalSeparator : ".",
32739 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32741 decimalPrecision : 2,
32743 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32745 allowNegative : true,
32747 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32749 minValue : Number.NEGATIVE_INFINITY,
32751 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32753 maxValue : Number.MAX_VALUE,
32755 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32757 minText : "The minimum value for this field is {0}",
32759 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32761 maxText : "The maximum value for this field is {0}",
32763 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32764 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32766 nanText : "{0} is not a valid number",
32768 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32773 initEvents : function()
32775 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32777 var allowed = "0123456789";
32779 if(this.allowDecimals){
32780 allowed += this.decimalSeparator;
32783 if(this.allowNegative){
32787 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32789 var keyPress = function(e){
32791 var k = e.getKey();
32793 var c = e.getCharCode();
32796 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32797 allowed.indexOf(String.fromCharCode(c)) === -1
32803 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32807 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32812 this.el.on("keypress", keyPress, this);
32815 validateValue : function(value)
32818 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32822 var num = this.parseValue(value);
32825 this.markInvalid(String.format(this.nanText, value));
32829 if(num < this.minValue){
32830 this.markInvalid(String.format(this.minText, this.minValue));
32834 if(num > this.maxValue){
32835 this.markInvalid(String.format(this.maxText, this.maxValue));
32842 getValue : function()
32844 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32847 parseValue : function(value)
32849 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32850 return isNaN(value) ? '' : value;
32853 fixPrecision : function(value)
32855 var nan = isNaN(value);
32857 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32858 return nan ? '' : value;
32860 return parseFloat(value).toFixed(this.decimalPrecision);
32863 setValue : function(v)
32865 v = this.fixPrecision(v);
32866 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32869 decimalPrecisionFcn : function(v)
32871 return Math.floor(v);
32874 beforeBlur : function()
32880 var v = this.parseValue(this.getRawValue());
32895 * @class Roo.bootstrap.DocumentSlider
32896 * @extends Roo.bootstrap.Component
32897 * Bootstrap DocumentSlider class
32900 * Create a new DocumentViewer
32901 * @param {Object} config The config object
32904 Roo.bootstrap.DocumentSlider = function(config){
32905 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32912 * Fire after initEvent
32913 * @param {Roo.bootstrap.DocumentSlider} this
32918 * Fire after update
32919 * @param {Roo.bootstrap.DocumentSlider} this
32925 * @param {Roo.bootstrap.DocumentSlider} this
32931 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32937 getAutoCreate : function()
32941 cls : 'roo-document-slider',
32945 cls : 'roo-document-slider-header',
32949 cls : 'roo-document-slider-header-title'
32955 cls : 'roo-document-slider-body',
32959 cls : 'roo-document-slider-prev',
32963 cls : 'fa fa-chevron-left'
32969 cls : 'roo-document-slider-thumb',
32973 cls : 'roo-document-slider-image'
32979 cls : 'roo-document-slider-next',
32983 cls : 'fa fa-chevron-right'
32995 initEvents : function()
32997 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32998 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33000 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33001 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33003 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33004 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33006 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33007 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33009 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33010 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33012 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33013 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33015 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33016 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33018 this.thumbEl.on('click', this.onClick, this);
33020 this.prevIndicator.on('click', this.prev, this);
33022 this.nextIndicator.on('click', this.next, this);
33026 initial : function()
33028 if(this.files.length){
33029 this.indicator = 1;
33033 this.fireEvent('initial', this);
33036 update : function()
33038 this.imageEl.attr('src', this.files[this.indicator - 1]);
33040 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33042 this.prevIndicator.show();
33044 if(this.indicator == 1){
33045 this.prevIndicator.hide();
33048 this.nextIndicator.show();
33050 if(this.indicator == this.files.length){
33051 this.nextIndicator.hide();
33054 this.thumbEl.scrollTo('top');
33056 this.fireEvent('update', this);
33059 onClick : function(e)
33061 e.preventDefault();
33063 this.fireEvent('click', this);
33068 e.preventDefault();
33070 this.indicator = Math.max(1, this.indicator - 1);
33077 e.preventDefault();
33079 this.indicator = Math.min(this.files.length, this.indicator + 1);
33093 * @class Roo.bootstrap.RadioSet
33094 * @extends Roo.bootstrap.Input
33095 * Bootstrap RadioSet class
33096 * @cfg {String} indicatorpos (left|right) default left
33097 * @cfg {Boolean} inline (true|false) inline the element (default true)
33098 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33100 * Create a new RadioSet
33101 * @param {Object} config The config object
33104 Roo.bootstrap.RadioSet = function(config){
33106 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33110 Roo.bootstrap.RadioSet.register(this);
33115 * Fires when the element is checked or unchecked.
33116 * @param {Roo.bootstrap.RadioSet} this This radio
33117 * @param {Roo.bootstrap.Radio} item The checked item
33124 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33132 indicatorpos : 'left',
33134 getAutoCreate : function()
33138 cls : 'roo-radio-set-label',
33142 html : this.fieldLabel
33147 if(this.indicatorpos == 'left'){
33150 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33151 tooltip : 'This field is required'
33156 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33157 tooltip : 'This field is required'
33163 cls : 'roo-radio-set-items'
33166 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33168 if (align === 'left' && this.fieldLabel.length) {
33171 cls : "roo-radio-set-right",
33177 if(this.labelWidth > 12){
33178 label.style = "width: " + this.labelWidth + 'px';
33181 if(this.labelWidth < 13 && this.labelmd == 0){
33182 this.labelmd = this.labelWidth;
33185 if(this.labellg > 0){
33186 label.cls += ' col-lg-' + this.labellg;
33187 items.cls += ' col-lg-' + (12 - this.labellg);
33190 if(this.labelmd > 0){
33191 label.cls += ' col-md-' + this.labelmd;
33192 items.cls += ' col-md-' + (12 - this.labelmd);
33195 if(this.labelsm > 0){
33196 label.cls += ' col-sm-' + this.labelsm;
33197 items.cls += ' col-sm-' + (12 - this.labelsm);
33200 if(this.labelxs > 0){
33201 label.cls += ' col-xs-' + this.labelxs;
33202 items.cls += ' col-xs-' + (12 - this.labelxs);
33208 cls : 'roo-radio-set',
33212 cls : 'roo-radio-set-input',
33215 value : this.value ? this.value : ''
33222 if(this.weight.length){
33223 cfg.cls += ' roo-radio-' + this.weight;
33227 cfg.cls += ' roo-radio-set-inline';
33234 initEvents : function()
33236 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33237 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33239 if(!this.fieldLabel.length){
33240 this.labelEl.hide();
33243 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33244 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33246 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
33247 this.indicatorEl().hide();
33249 this.originalValue = this.getValue();
33253 inputEl: function ()
33255 return this.el.select('.roo-radio-set-input', true).first();
33258 getChildContainer : function()
33260 return this.itemsEl;
33263 register : function(item)
33265 this.radioes.push(item);
33269 validate : function()
33273 Roo.each(this.radioes, function(i){
33282 if(this.allowBlank) {
33286 if(this.disabled || valid){
33291 this.markInvalid();
33296 markValid : function()
33298 if(this.labelEl.isVisible(true)){
33299 this.indicatorEl().hide();
33302 this.el.removeClass([this.invalidClass, this.validClass]);
33303 this.el.addClass(this.validClass);
33305 this.fireEvent('valid', this);
33308 markInvalid : function(msg)
33310 if(this.allowBlank || this.disabled){
33314 if(this.labelEl.isVisible(true)){
33315 this.indicatorEl().show();
33318 this.el.removeClass([this.invalidClass, this.validClass]);
33319 this.el.addClass(this.invalidClass);
33321 this.fireEvent('invalid', this, msg);
33325 setValue : function(v, suppressEvent)
33329 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33332 Roo.each(this.radioes, function(i){
33335 i.el.removeClass('checked');
33337 if(i.value === v || i.value.toString() === v.toString()){
33339 i.el.addClass('checked');
33341 if(suppressEvent !== true){
33342 this.fireEvent('check', this, i);
33351 clearInvalid : function(){
33353 if(!this.el || this.preventMark){
33357 this.el.removeClass([this.invalidClass]);
33359 this.fireEvent('valid', this);
33364 Roo.apply(Roo.bootstrap.RadioSet, {
33368 register : function(set)
33370 this.groups[set.name] = set;
33373 get: function(name)
33375 if (typeof(this.groups[name]) == 'undefined') {
33379 return this.groups[name] ;
33385 * Ext JS Library 1.1.1
33386 * Copyright(c) 2006-2007, Ext JS, LLC.
33388 * Originally Released Under LGPL - original licence link has changed is not relivant.
33391 * <script type="text/javascript">
33396 * @class Roo.bootstrap.SplitBar
33397 * @extends Roo.util.Observable
33398 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33402 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33403 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33404 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33405 split.minSize = 100;
33406 split.maxSize = 600;
33407 split.animate = true;
33408 split.on('moved', splitterMoved);
33411 * Create a new SplitBar
33412 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33413 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33414 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33415 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33416 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33417 position of the SplitBar).
33419 Roo.bootstrap.SplitBar = function(cfg){
33424 // dragElement : elm
33425 // resizingElement: el,
33427 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33428 // placement : Roo.bootstrap.SplitBar.LEFT ,
33429 // existingProxy ???
33432 this.el = Roo.get(cfg.dragElement, true);
33433 this.el.dom.unselectable = "on";
33435 this.resizingEl = Roo.get(cfg.resizingElement, true);
33439 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33440 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33443 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33446 * The minimum size of the resizing element. (Defaults to 0)
33452 * The maximum size of the resizing element. (Defaults to 2000)
33455 this.maxSize = 2000;
33458 * Whether to animate the transition to the new size
33461 this.animate = false;
33464 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33467 this.useShim = false;
33472 if(!cfg.existingProxy){
33474 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33476 this.proxy = Roo.get(cfg.existingProxy).dom;
33479 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33482 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33485 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33488 this.dragSpecs = {};
33491 * @private The adapter to use to positon and resize elements
33493 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33494 this.adapter.init(this);
33496 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33498 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33499 this.el.addClass("roo-splitbar-h");
33502 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33503 this.el.addClass("roo-splitbar-v");
33509 * Fires when the splitter is moved (alias for {@link #event-moved})
33510 * @param {Roo.bootstrap.SplitBar} this
33511 * @param {Number} newSize the new width or height
33516 * Fires when the splitter is moved
33517 * @param {Roo.bootstrap.SplitBar} this
33518 * @param {Number} newSize the new width or height
33522 * @event beforeresize
33523 * Fires before the splitter is dragged
33524 * @param {Roo.bootstrap.SplitBar} this
33526 "beforeresize" : true,
33528 "beforeapply" : true
33531 Roo.util.Observable.call(this);
33534 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33535 onStartProxyDrag : function(x, y){
33536 this.fireEvent("beforeresize", this);
33538 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33540 o.enableDisplayMode("block");
33541 // all splitbars share the same overlay
33542 Roo.bootstrap.SplitBar.prototype.overlay = o;
33544 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33545 this.overlay.show();
33546 Roo.get(this.proxy).setDisplayed("block");
33547 var size = this.adapter.getElementSize(this);
33548 this.activeMinSize = this.getMinimumSize();;
33549 this.activeMaxSize = this.getMaximumSize();;
33550 var c1 = size - this.activeMinSize;
33551 var c2 = Math.max(this.activeMaxSize - size, 0);
33552 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33553 this.dd.resetConstraints();
33554 this.dd.setXConstraint(
33555 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33556 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33558 this.dd.setYConstraint(0, 0);
33560 this.dd.resetConstraints();
33561 this.dd.setXConstraint(0, 0);
33562 this.dd.setYConstraint(
33563 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33564 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33567 this.dragSpecs.startSize = size;
33568 this.dragSpecs.startPoint = [x, y];
33569 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33573 * @private Called after the drag operation by the DDProxy
33575 onEndProxyDrag : function(e){
33576 Roo.get(this.proxy).setDisplayed(false);
33577 var endPoint = Roo.lib.Event.getXY(e);
33579 this.overlay.hide();
33582 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33583 newSize = this.dragSpecs.startSize +
33584 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33585 endPoint[0] - this.dragSpecs.startPoint[0] :
33586 this.dragSpecs.startPoint[0] - endPoint[0]
33589 newSize = this.dragSpecs.startSize +
33590 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33591 endPoint[1] - this.dragSpecs.startPoint[1] :
33592 this.dragSpecs.startPoint[1] - endPoint[1]
33595 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33596 if(newSize != this.dragSpecs.startSize){
33597 if(this.fireEvent('beforeapply', this, newSize) !== false){
33598 this.adapter.setElementSize(this, newSize);
33599 this.fireEvent("moved", this, newSize);
33600 this.fireEvent("resize", this, newSize);
33606 * Get the adapter this SplitBar uses
33607 * @return The adapter object
33609 getAdapter : function(){
33610 return this.adapter;
33614 * Set the adapter this SplitBar uses
33615 * @param {Object} adapter A SplitBar adapter object
33617 setAdapter : function(adapter){
33618 this.adapter = adapter;
33619 this.adapter.init(this);
33623 * Gets the minimum size for the resizing element
33624 * @return {Number} The minimum size
33626 getMinimumSize : function(){
33627 return this.minSize;
33631 * Sets the minimum size for the resizing element
33632 * @param {Number} minSize The minimum size
33634 setMinimumSize : function(minSize){
33635 this.minSize = minSize;
33639 * Gets the maximum size for the resizing element
33640 * @return {Number} The maximum size
33642 getMaximumSize : function(){
33643 return this.maxSize;
33647 * Sets the maximum size for the resizing element
33648 * @param {Number} maxSize The maximum size
33650 setMaximumSize : function(maxSize){
33651 this.maxSize = maxSize;
33655 * Sets the initialize size for the resizing element
33656 * @param {Number} size The initial size
33658 setCurrentSize : function(size){
33659 var oldAnimate = this.animate;
33660 this.animate = false;
33661 this.adapter.setElementSize(this, size);
33662 this.animate = oldAnimate;
33666 * Destroy this splitbar.
33667 * @param {Boolean} removeEl True to remove the element
33669 destroy : function(removeEl){
33671 this.shim.remove();
33674 this.proxy.parentNode.removeChild(this.proxy);
33682 * @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.
33684 Roo.bootstrap.SplitBar.createProxy = function(dir){
33685 var proxy = new Roo.Element(document.createElement("div"));
33686 proxy.unselectable();
33687 var cls = 'roo-splitbar-proxy';
33688 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33689 document.body.appendChild(proxy.dom);
33694 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33695 * Default Adapter. It assumes the splitter and resizing element are not positioned
33696 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33698 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33701 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33702 // do nothing for now
33703 init : function(s){
33707 * Called before drag operations to get the current size of the resizing element.
33708 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33710 getElementSize : function(s){
33711 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33712 return s.resizingEl.getWidth();
33714 return s.resizingEl.getHeight();
33719 * Called after drag operations to set the size of the resizing element.
33720 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33721 * @param {Number} newSize The new size to set
33722 * @param {Function} onComplete A function to be invoked when resizing is complete
33724 setElementSize : function(s, newSize, onComplete){
33725 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33727 s.resizingEl.setWidth(newSize);
33729 onComplete(s, newSize);
33732 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33737 s.resizingEl.setHeight(newSize);
33739 onComplete(s, newSize);
33742 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33749 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33750 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33751 * Adapter that moves the splitter element to align with the resized sizing element.
33752 * Used with an absolute positioned SplitBar.
33753 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33754 * document.body, make sure you assign an id to the body element.
33756 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33757 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33758 this.container = Roo.get(container);
33761 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33762 init : function(s){
33763 this.basic.init(s);
33766 getElementSize : function(s){
33767 return this.basic.getElementSize(s);
33770 setElementSize : function(s, newSize, onComplete){
33771 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33774 moveSplitter : function(s){
33775 var yes = Roo.bootstrap.SplitBar;
33776 switch(s.placement){
33778 s.el.setX(s.resizingEl.getRight());
33781 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33784 s.el.setY(s.resizingEl.getBottom());
33787 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33794 * Orientation constant - Create a vertical SplitBar
33798 Roo.bootstrap.SplitBar.VERTICAL = 1;
33801 * Orientation constant - Create a horizontal SplitBar
33805 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33808 * Placement constant - The resizing element is to the left of the splitter element
33812 Roo.bootstrap.SplitBar.LEFT = 1;
33815 * Placement constant - The resizing element is to the right of the splitter element
33819 Roo.bootstrap.SplitBar.RIGHT = 2;
33822 * Placement constant - The resizing element is positioned above the splitter element
33826 Roo.bootstrap.SplitBar.TOP = 3;
33829 * Placement constant - The resizing element is positioned under splitter element
33833 Roo.bootstrap.SplitBar.BOTTOM = 4;
33834 Roo.namespace("Roo.bootstrap.layout");/*
33836 * Ext JS Library 1.1.1
33837 * Copyright(c) 2006-2007, Ext JS, LLC.
33839 * Originally Released Under LGPL - original licence link has changed is not relivant.
33842 * <script type="text/javascript">
33846 * @class Roo.bootstrap.layout.Manager
33847 * @extends Roo.bootstrap.Component
33848 * Base class for layout managers.
33850 Roo.bootstrap.layout.Manager = function(config)
33852 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33858 /** false to disable window resize monitoring @type Boolean */
33859 this.monitorWindowResize = true;
33864 * Fires when a layout is performed.
33865 * @param {Roo.LayoutManager} this
33869 * @event regionresized
33870 * Fires when the user resizes a region.
33871 * @param {Roo.LayoutRegion} region The resized region
33872 * @param {Number} newSize The new size (width for east/west, height for north/south)
33874 "regionresized" : true,
33876 * @event regioncollapsed
33877 * Fires when a region is collapsed.
33878 * @param {Roo.LayoutRegion} region The collapsed region
33880 "regioncollapsed" : true,
33882 * @event regionexpanded
33883 * Fires when a region is expanded.
33884 * @param {Roo.LayoutRegion} region The expanded region
33886 "regionexpanded" : true
33888 this.updating = false;
33891 this.el = Roo.get(config.el);
33897 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33902 monitorWindowResize : true,
33908 onRender : function(ct, position)
33911 this.el = Roo.get(ct);
33914 //this.fireEvent('render',this);
33918 initEvents: function()
33922 // ie scrollbar fix
33923 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33924 document.body.scroll = "no";
33925 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33926 this.el.position('relative');
33928 this.id = this.el.id;
33929 this.el.addClass("roo-layout-container");
33930 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33931 if(this.el.dom != document.body ) {
33932 this.el.on('resize', this.layout,this);
33933 this.el.on('show', this.layout,this);
33939 * Returns true if this layout is currently being updated
33940 * @return {Boolean}
33942 isUpdating : function(){
33943 return this.updating;
33947 * Suspend the LayoutManager from doing auto-layouts while
33948 * making multiple add or remove calls
33950 beginUpdate : function(){
33951 this.updating = true;
33955 * Restore auto-layouts and optionally disable the manager from performing a layout
33956 * @param {Boolean} noLayout true to disable a layout update
33958 endUpdate : function(noLayout){
33959 this.updating = false;
33965 layout: function(){
33969 onRegionResized : function(region, newSize){
33970 this.fireEvent("regionresized", region, newSize);
33974 onRegionCollapsed : function(region){
33975 this.fireEvent("regioncollapsed", region);
33978 onRegionExpanded : function(region){
33979 this.fireEvent("regionexpanded", region);
33983 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33984 * performs box-model adjustments.
33985 * @return {Object} The size as an object {width: (the width), height: (the height)}
33987 getViewSize : function()
33990 if(this.el.dom != document.body){
33991 size = this.el.getSize();
33993 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33995 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33996 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34001 * Returns the Element this layout is bound to.
34002 * @return {Roo.Element}
34004 getEl : function(){
34009 * Returns the specified region.
34010 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34011 * @return {Roo.LayoutRegion}
34013 getRegion : function(target){
34014 return this.regions[target.toLowerCase()];
34017 onWindowResize : function(){
34018 if(this.monitorWindowResize){
34025 * Ext JS Library 1.1.1
34026 * Copyright(c) 2006-2007, Ext JS, LLC.
34028 * Originally Released Under LGPL - original licence link has changed is not relivant.
34031 * <script type="text/javascript">
34034 * @class Roo.bootstrap.layout.Border
34035 * @extends Roo.bootstrap.layout.Manager
34036 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34037 * please see: examples/bootstrap/nested.html<br><br>
34039 <b>The container the layout is rendered into can be either the body element or any other element.
34040 If it is not the body element, the container needs to either be an absolute positioned element,
34041 or you will need to add "position:relative" to the css of the container. You will also need to specify
34042 the container size if it is not the body element.</b>
34045 * Create a new Border
34046 * @param {Object} config Configuration options
34048 Roo.bootstrap.layout.Border = function(config){
34049 config = config || {};
34050 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34054 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34055 if(config[region]){
34056 config[region].region = region;
34057 this.addRegion(config[region]);
34063 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34065 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34067 * Creates and adds a new region if it doesn't already exist.
34068 * @param {String} target The target region key (north, south, east, west or center).
34069 * @param {Object} config The regions config object
34070 * @return {BorderLayoutRegion} The new region
34072 addRegion : function(config)
34074 if(!this.regions[config.region]){
34075 var r = this.factory(config);
34076 this.bindRegion(r);
34078 return this.regions[config.region];
34082 bindRegion : function(r){
34083 this.regions[r.config.region] = r;
34085 r.on("visibilitychange", this.layout, this);
34086 r.on("paneladded", this.layout, this);
34087 r.on("panelremoved", this.layout, this);
34088 r.on("invalidated", this.layout, this);
34089 r.on("resized", this.onRegionResized, this);
34090 r.on("collapsed", this.onRegionCollapsed, this);
34091 r.on("expanded", this.onRegionExpanded, this);
34095 * Performs a layout update.
34097 layout : function()
34099 if(this.updating) {
34103 // render all the rebions if they have not been done alreayd?
34104 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34105 if(this.regions[region] && !this.regions[region].bodyEl){
34106 this.regions[region].onRender(this.el)
34110 var size = this.getViewSize();
34111 var w = size.width;
34112 var h = size.height;
34117 //var x = 0, y = 0;
34119 var rs = this.regions;
34120 var north = rs["north"];
34121 var south = rs["south"];
34122 var west = rs["west"];
34123 var east = rs["east"];
34124 var center = rs["center"];
34125 //if(this.hideOnLayout){ // not supported anymore
34126 //c.el.setStyle("display", "none");
34128 if(north && north.isVisible()){
34129 var b = north.getBox();
34130 var m = north.getMargins();
34131 b.width = w - (m.left+m.right);
34134 centerY = b.height + b.y + m.bottom;
34135 centerH -= centerY;
34136 north.updateBox(this.safeBox(b));
34138 if(south && south.isVisible()){
34139 var b = south.getBox();
34140 var m = south.getMargins();
34141 b.width = w - (m.left+m.right);
34143 var totalHeight = (b.height + m.top + m.bottom);
34144 b.y = h - totalHeight + m.top;
34145 centerH -= totalHeight;
34146 south.updateBox(this.safeBox(b));
34148 if(west && west.isVisible()){
34149 var b = west.getBox();
34150 var m = west.getMargins();
34151 b.height = centerH - (m.top+m.bottom);
34153 b.y = centerY + m.top;
34154 var totalWidth = (b.width + m.left + m.right);
34155 centerX += totalWidth;
34156 centerW -= totalWidth;
34157 west.updateBox(this.safeBox(b));
34159 if(east && east.isVisible()){
34160 var b = east.getBox();
34161 var m = east.getMargins();
34162 b.height = centerH - (m.top+m.bottom);
34163 var totalWidth = (b.width + m.left + m.right);
34164 b.x = w - totalWidth + m.left;
34165 b.y = centerY + m.top;
34166 centerW -= totalWidth;
34167 east.updateBox(this.safeBox(b));
34170 var m = center.getMargins();
34172 x: centerX + m.left,
34173 y: centerY + m.top,
34174 width: centerW - (m.left+m.right),
34175 height: centerH - (m.top+m.bottom)
34177 //if(this.hideOnLayout){
34178 //center.el.setStyle("display", "block");
34180 center.updateBox(this.safeBox(centerBox));
34183 this.fireEvent("layout", this);
34187 safeBox : function(box){
34188 box.width = Math.max(0, box.width);
34189 box.height = Math.max(0, box.height);
34194 * Adds a ContentPanel (or subclass) to this layout.
34195 * @param {String} target The target region key (north, south, east, west or center).
34196 * @param {Roo.ContentPanel} panel The panel to add
34197 * @return {Roo.ContentPanel} The added panel
34199 add : function(target, panel){
34201 target = target.toLowerCase();
34202 return this.regions[target].add(panel);
34206 * Remove a ContentPanel (or subclass) to this layout.
34207 * @param {String} target The target region key (north, south, east, west or center).
34208 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34209 * @return {Roo.ContentPanel} The removed panel
34211 remove : function(target, panel){
34212 target = target.toLowerCase();
34213 return this.regions[target].remove(panel);
34217 * Searches all regions for a panel with the specified id
34218 * @param {String} panelId
34219 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34221 findPanel : function(panelId){
34222 var rs = this.regions;
34223 for(var target in rs){
34224 if(typeof rs[target] != "function"){
34225 var p = rs[target].getPanel(panelId);
34235 * Searches all regions for a panel with the specified id and activates (shows) it.
34236 * @param {String/ContentPanel} panelId The panels id or the panel itself
34237 * @return {Roo.ContentPanel} The shown panel or null
34239 showPanel : function(panelId) {
34240 var rs = this.regions;
34241 for(var target in rs){
34242 var r = rs[target];
34243 if(typeof r != "function"){
34244 if(r.hasPanel(panelId)){
34245 return r.showPanel(panelId);
34253 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34254 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34257 restoreState : function(provider){
34259 provider = Roo.state.Manager;
34261 var sm = new Roo.LayoutStateManager();
34262 sm.init(this, provider);
34268 * Adds a xtype elements to the layout.
34272 xtype : 'ContentPanel',
34279 xtype : 'NestedLayoutPanel',
34285 items : [ ... list of content panels or nested layout panels.. ]
34289 * @param {Object} cfg Xtype definition of item to add.
34291 addxtype : function(cfg)
34293 // basically accepts a pannel...
34294 // can accept a layout region..!?!?
34295 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34298 // theory? children can only be panels??
34300 //if (!cfg.xtype.match(/Panel$/)) {
34305 if (typeof(cfg.region) == 'undefined') {
34306 Roo.log("Failed to add Panel, region was not set");
34310 var region = cfg.region;
34316 xitems = cfg.items;
34323 case 'Content': // ContentPanel (el, cfg)
34324 case 'Scroll': // ContentPanel (el, cfg)
34326 cfg.autoCreate = true;
34327 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34329 // var el = this.el.createChild();
34330 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34333 this.add(region, ret);
34337 case 'TreePanel': // our new panel!
34338 cfg.el = this.el.createChild();
34339 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34340 this.add(region, ret);
34345 // create a new Layout (which is a Border Layout...
34347 var clayout = cfg.layout;
34348 clayout.el = this.el.createChild();
34349 clayout.items = clayout.items || [];
34353 // replace this exitems with the clayout ones..
34354 xitems = clayout.items;
34356 // force background off if it's in center...
34357 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34358 cfg.background = false;
34360 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34363 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34364 //console.log('adding nested layout panel ' + cfg.toSource());
34365 this.add(region, ret);
34366 nb = {}; /// find first...
34371 // needs grid and region
34373 //var el = this.getRegion(region).el.createChild();
34375 *var el = this.el.createChild();
34376 // create the grid first...
34377 cfg.grid.container = el;
34378 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34381 if (region == 'center' && this.active ) {
34382 cfg.background = false;
34385 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34387 this.add(region, ret);
34389 if (cfg.background) {
34390 // render grid on panel activation (if panel background)
34391 ret.on('activate', function(gp) {
34392 if (!gp.grid.rendered) {
34393 // gp.grid.render(el);
34397 // cfg.grid.render(el);
34403 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34404 // it was the old xcomponent building that caused this before.
34405 // espeically if border is the top element in the tree.
34415 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34417 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34418 this.add(region, ret);
34422 throw "Can not add '" + cfg.xtype + "' to Border";
34428 this.beginUpdate();
34432 Roo.each(xitems, function(i) {
34433 region = nb && i.region ? i.region : false;
34435 var add = ret.addxtype(i);
34438 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34439 if (!i.background) {
34440 abn[region] = nb[region] ;
34447 // make the last non-background panel active..
34448 //if (nb) { Roo.log(abn); }
34451 for(var r in abn) {
34452 region = this.getRegion(r);
34454 // tried using nb[r], but it does not work..
34456 region.showPanel(abn[r]);
34467 factory : function(cfg)
34470 var validRegions = Roo.bootstrap.layout.Border.regions;
34472 var target = cfg.region;
34475 var r = Roo.bootstrap.layout;
34479 return new r.North(cfg);
34481 return new r.South(cfg);
34483 return new r.East(cfg);
34485 return new r.West(cfg);
34487 return new r.Center(cfg);
34489 throw 'Layout region "'+target+'" not supported.';
34496 * Ext JS Library 1.1.1
34497 * Copyright(c) 2006-2007, Ext JS, LLC.
34499 * Originally Released Under LGPL - original licence link has changed is not relivant.
34502 * <script type="text/javascript">
34506 * @class Roo.bootstrap.layout.Basic
34507 * @extends Roo.util.Observable
34508 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34509 * and does not have a titlebar, tabs or any other features. All it does is size and position
34510 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34511 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34512 * @cfg {string} region the region that it inhabits..
34513 * @cfg {bool} skipConfig skip config?
34517 Roo.bootstrap.layout.Basic = function(config){
34519 this.mgr = config.mgr;
34521 this.position = config.region;
34523 var skipConfig = config.skipConfig;
34527 * @scope Roo.BasicLayoutRegion
34531 * @event beforeremove
34532 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34533 * @param {Roo.LayoutRegion} this
34534 * @param {Roo.ContentPanel} panel The panel
34535 * @param {Object} e The cancel event object
34537 "beforeremove" : true,
34539 * @event invalidated
34540 * Fires when the layout for this region is changed.
34541 * @param {Roo.LayoutRegion} this
34543 "invalidated" : true,
34545 * @event visibilitychange
34546 * Fires when this region is shown or hidden
34547 * @param {Roo.LayoutRegion} this
34548 * @param {Boolean} visibility true or false
34550 "visibilitychange" : true,
34552 * @event paneladded
34553 * Fires when a panel is added.
34554 * @param {Roo.LayoutRegion} this
34555 * @param {Roo.ContentPanel} panel The panel
34557 "paneladded" : true,
34559 * @event panelremoved
34560 * Fires when a panel is removed.
34561 * @param {Roo.LayoutRegion} this
34562 * @param {Roo.ContentPanel} panel The panel
34564 "panelremoved" : true,
34566 * @event beforecollapse
34567 * Fires when this region before collapse.
34568 * @param {Roo.LayoutRegion} this
34570 "beforecollapse" : true,
34573 * Fires when this region is collapsed.
34574 * @param {Roo.LayoutRegion} this
34576 "collapsed" : true,
34579 * Fires when this region is expanded.
34580 * @param {Roo.LayoutRegion} this
34585 * Fires when this region is slid into view.
34586 * @param {Roo.LayoutRegion} this
34588 "slideshow" : true,
34591 * Fires when this region slides out of view.
34592 * @param {Roo.LayoutRegion} this
34594 "slidehide" : true,
34596 * @event panelactivated
34597 * Fires when a panel is activated.
34598 * @param {Roo.LayoutRegion} this
34599 * @param {Roo.ContentPanel} panel The activated panel
34601 "panelactivated" : true,
34604 * Fires when the user resizes this region.
34605 * @param {Roo.LayoutRegion} this
34606 * @param {Number} newSize The new size (width for east/west, height for north/south)
34610 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34611 this.panels = new Roo.util.MixedCollection();
34612 this.panels.getKey = this.getPanelId.createDelegate(this);
34614 this.activePanel = null;
34615 // ensure listeners are added...
34617 if (config.listeners || config.events) {
34618 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34619 listeners : config.listeners || {},
34620 events : config.events || {}
34624 if(skipConfig !== true){
34625 this.applyConfig(config);
34629 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34631 getPanelId : function(p){
34635 applyConfig : function(config){
34636 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34637 this.config = config;
34642 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34643 * the width, for horizontal (north, south) the height.
34644 * @param {Number} newSize The new width or height
34646 resizeTo : function(newSize){
34647 var el = this.el ? this.el :
34648 (this.activePanel ? this.activePanel.getEl() : null);
34650 switch(this.position){
34653 el.setWidth(newSize);
34654 this.fireEvent("resized", this, newSize);
34658 el.setHeight(newSize);
34659 this.fireEvent("resized", this, newSize);
34665 getBox : function(){
34666 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34669 getMargins : function(){
34670 return this.margins;
34673 updateBox : function(box){
34675 var el = this.activePanel.getEl();
34676 el.dom.style.left = box.x + "px";
34677 el.dom.style.top = box.y + "px";
34678 this.activePanel.setSize(box.width, box.height);
34682 * Returns the container element for this region.
34683 * @return {Roo.Element}
34685 getEl : function(){
34686 return this.activePanel;
34690 * Returns true if this region is currently visible.
34691 * @return {Boolean}
34693 isVisible : function(){
34694 return this.activePanel ? true : false;
34697 setActivePanel : function(panel){
34698 panel = this.getPanel(panel);
34699 if(this.activePanel && this.activePanel != panel){
34700 this.activePanel.setActiveState(false);
34701 this.activePanel.getEl().setLeftTop(-10000,-10000);
34703 this.activePanel = panel;
34704 panel.setActiveState(true);
34706 panel.setSize(this.box.width, this.box.height);
34708 this.fireEvent("panelactivated", this, panel);
34709 this.fireEvent("invalidated");
34713 * Show the specified panel.
34714 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34715 * @return {Roo.ContentPanel} The shown panel or null
34717 showPanel : function(panel){
34718 panel = this.getPanel(panel);
34720 this.setActivePanel(panel);
34726 * Get the active panel for this region.
34727 * @return {Roo.ContentPanel} The active panel or null
34729 getActivePanel : function(){
34730 return this.activePanel;
34734 * Add the passed ContentPanel(s)
34735 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34736 * @return {Roo.ContentPanel} The panel added (if only one was added)
34738 add : function(panel){
34739 if(arguments.length > 1){
34740 for(var i = 0, len = arguments.length; i < len; i++) {
34741 this.add(arguments[i]);
34745 if(this.hasPanel(panel)){
34746 this.showPanel(panel);
34749 var el = panel.getEl();
34750 if(el.dom.parentNode != this.mgr.el.dom){
34751 this.mgr.el.dom.appendChild(el.dom);
34753 if(panel.setRegion){
34754 panel.setRegion(this);
34756 this.panels.add(panel);
34757 el.setStyle("position", "absolute");
34758 if(!panel.background){
34759 this.setActivePanel(panel);
34760 if(this.config.initialSize && this.panels.getCount()==1){
34761 this.resizeTo(this.config.initialSize);
34764 this.fireEvent("paneladded", this, panel);
34769 * Returns true if the panel is in this region.
34770 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34771 * @return {Boolean}
34773 hasPanel : function(panel){
34774 if(typeof panel == "object"){ // must be panel obj
34775 panel = panel.getId();
34777 return this.getPanel(panel) ? true : false;
34781 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34782 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34783 * @param {Boolean} preservePanel Overrides the config preservePanel option
34784 * @return {Roo.ContentPanel} The panel that was removed
34786 remove : function(panel, preservePanel){
34787 panel = this.getPanel(panel);
34792 this.fireEvent("beforeremove", this, panel, e);
34793 if(e.cancel === true){
34796 var panelId = panel.getId();
34797 this.panels.removeKey(panelId);
34802 * Returns the panel specified or null if it's not in this region.
34803 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34804 * @return {Roo.ContentPanel}
34806 getPanel : function(id){
34807 if(typeof id == "object"){ // must be panel obj
34810 return this.panels.get(id);
34814 * Returns this regions position (north/south/east/west/center).
34817 getPosition: function(){
34818 return this.position;
34822 * Ext JS Library 1.1.1
34823 * Copyright(c) 2006-2007, Ext JS, LLC.
34825 * Originally Released Under LGPL - original licence link has changed is not relivant.
34828 * <script type="text/javascript">
34832 * @class Roo.bootstrap.layout.Region
34833 * @extends Roo.bootstrap.layout.Basic
34834 * This class represents a region in a layout manager.
34836 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34837 * @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})
34838 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34839 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34840 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34841 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34842 * @cfg {String} title The title for the region (overrides panel titles)
34843 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34844 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34845 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34846 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34847 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34848 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34849 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34850 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34851 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34852 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34854 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34855 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34856 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34857 * @cfg {Number} width For East/West panels
34858 * @cfg {Number} height For North/South panels
34859 * @cfg {Boolean} split To show the splitter
34860 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34862 * @cfg {string} cls Extra CSS classes to add to region
34864 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34865 * @cfg {string} region the region that it inhabits..
34868 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34869 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34871 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34872 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34873 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34875 Roo.bootstrap.layout.Region = function(config)
34877 this.applyConfig(config);
34879 var mgr = config.mgr;
34880 var pos = config.region;
34881 config.skipConfig = true;
34882 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34885 this.onRender(mgr.el);
34888 this.visible = true;
34889 this.collapsed = false;
34890 this.unrendered_panels = [];
34893 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34895 position: '', // set by wrapper (eg. north/south etc..)
34896 unrendered_panels : null, // unrendered panels.
34897 createBody : function(){
34898 /** This region's body element
34899 * @type Roo.Element */
34900 this.bodyEl = this.el.createChild({
34902 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34906 onRender: function(ctr, pos)
34908 var dh = Roo.DomHelper;
34909 /** This region's container element
34910 * @type Roo.Element */
34911 this.el = dh.append(ctr.dom, {
34913 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34915 /** This region's title element
34916 * @type Roo.Element */
34918 this.titleEl = dh.append(this.el.dom,
34921 unselectable: "on",
34922 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34924 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34925 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34928 this.titleEl.enableDisplayMode();
34929 /** This region's title text element
34930 * @type HTMLElement */
34931 this.titleTextEl = this.titleEl.dom.firstChild;
34932 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34934 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34935 this.closeBtn.enableDisplayMode();
34936 this.closeBtn.on("click", this.closeClicked, this);
34937 this.closeBtn.hide();
34939 this.createBody(this.config);
34940 if(this.config.hideWhenEmpty){
34942 this.on("paneladded", this.validateVisibility, this);
34943 this.on("panelremoved", this.validateVisibility, this);
34945 if(this.autoScroll){
34946 this.bodyEl.setStyle("overflow", "auto");
34948 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34950 //if(c.titlebar !== false){
34951 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34952 this.titleEl.hide();
34954 this.titleEl.show();
34955 if(this.config.title){
34956 this.titleTextEl.innerHTML = this.config.title;
34960 if(this.config.collapsed){
34961 this.collapse(true);
34963 if(this.config.hidden){
34967 if (this.unrendered_panels && this.unrendered_panels.length) {
34968 for (var i =0;i< this.unrendered_panels.length; i++) {
34969 this.add(this.unrendered_panels[i]);
34971 this.unrendered_panels = null;
34977 applyConfig : function(c)
34980 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34981 var dh = Roo.DomHelper;
34982 if(c.titlebar !== false){
34983 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34984 this.collapseBtn.on("click", this.collapse, this);
34985 this.collapseBtn.enableDisplayMode();
34987 if(c.showPin === true || this.showPin){
34988 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34989 this.stickBtn.enableDisplayMode();
34990 this.stickBtn.on("click", this.expand, this);
34991 this.stickBtn.hide();
34996 /** This region's collapsed element
34997 * @type Roo.Element */
35000 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35001 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35004 if(c.floatable !== false){
35005 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35006 this.collapsedEl.on("click", this.collapseClick, this);
35009 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35010 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35011 id: "message", unselectable: "on", style:{"float":"left"}});
35012 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35014 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35015 this.expandBtn.on("click", this.expand, this);
35019 if(this.collapseBtn){
35020 this.collapseBtn.setVisible(c.collapsible == true);
35023 this.cmargins = c.cmargins || this.cmargins ||
35024 (this.position == "west" || this.position == "east" ?
35025 {top: 0, left: 2, right:2, bottom: 0} :
35026 {top: 2, left: 0, right:0, bottom: 2});
35028 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35031 this.bottomTabs = c.tabPosition != "top";
35033 this.autoScroll = c.autoScroll || false;
35038 this.duration = c.duration || .30;
35039 this.slideDuration = c.slideDuration || .45;
35044 * Returns true if this region is currently visible.
35045 * @return {Boolean}
35047 isVisible : function(){
35048 return this.visible;
35052 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35053 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35055 //setCollapsedTitle : function(title){
35056 // title = title || " ";
35057 // if(this.collapsedTitleTextEl){
35058 // this.collapsedTitleTextEl.innerHTML = title;
35062 getBox : function(){
35064 // if(!this.collapsed){
35065 b = this.el.getBox(false, true);
35067 // b = this.collapsedEl.getBox(false, true);
35072 getMargins : function(){
35073 return this.margins;
35074 //return this.collapsed ? this.cmargins : this.margins;
35077 highlight : function(){
35078 this.el.addClass("x-layout-panel-dragover");
35081 unhighlight : function(){
35082 this.el.removeClass("x-layout-panel-dragover");
35085 updateBox : function(box)
35087 if (!this.bodyEl) {
35088 return; // not rendered yet..
35092 if(!this.collapsed){
35093 this.el.dom.style.left = box.x + "px";
35094 this.el.dom.style.top = box.y + "px";
35095 this.updateBody(box.width, box.height);
35097 this.collapsedEl.dom.style.left = box.x + "px";
35098 this.collapsedEl.dom.style.top = box.y + "px";
35099 this.collapsedEl.setSize(box.width, box.height);
35102 this.tabs.autoSizeTabs();
35106 updateBody : function(w, h)
35109 this.el.setWidth(w);
35110 w -= this.el.getBorderWidth("rl");
35111 if(this.config.adjustments){
35112 w += this.config.adjustments[0];
35115 if(h !== null && h > 0){
35116 this.el.setHeight(h);
35117 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35118 h -= this.el.getBorderWidth("tb");
35119 if(this.config.adjustments){
35120 h += this.config.adjustments[1];
35122 this.bodyEl.setHeight(h);
35124 h = this.tabs.syncHeight(h);
35127 if(this.panelSize){
35128 w = w !== null ? w : this.panelSize.width;
35129 h = h !== null ? h : this.panelSize.height;
35131 if(this.activePanel){
35132 var el = this.activePanel.getEl();
35133 w = w !== null ? w : el.getWidth();
35134 h = h !== null ? h : el.getHeight();
35135 this.panelSize = {width: w, height: h};
35136 this.activePanel.setSize(w, h);
35138 if(Roo.isIE && this.tabs){
35139 this.tabs.el.repaint();
35144 * Returns the container element for this region.
35145 * @return {Roo.Element}
35147 getEl : function(){
35152 * Hides this region.
35155 //if(!this.collapsed){
35156 this.el.dom.style.left = "-2000px";
35159 // this.collapsedEl.dom.style.left = "-2000px";
35160 // this.collapsedEl.hide();
35162 this.visible = false;
35163 this.fireEvent("visibilitychange", this, false);
35167 * Shows this region if it was previously hidden.
35170 //if(!this.collapsed){
35173 // this.collapsedEl.show();
35175 this.visible = true;
35176 this.fireEvent("visibilitychange", this, true);
35179 closeClicked : function(){
35180 if(this.activePanel){
35181 this.remove(this.activePanel);
35185 collapseClick : function(e){
35187 e.stopPropagation();
35190 e.stopPropagation();
35196 * Collapses this region.
35197 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35200 collapse : function(skipAnim, skipCheck = false){
35201 if(this.collapsed) {
35205 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35207 this.collapsed = true;
35209 this.split.el.hide();
35211 if(this.config.animate && skipAnim !== true){
35212 this.fireEvent("invalidated", this);
35213 this.animateCollapse();
35215 this.el.setLocation(-20000,-20000);
35217 this.collapsedEl.show();
35218 this.fireEvent("collapsed", this);
35219 this.fireEvent("invalidated", this);
35225 animateCollapse : function(){
35230 * Expands this region if it was previously collapsed.
35231 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35232 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35235 expand : function(e, skipAnim){
35237 e.stopPropagation();
35239 if(!this.collapsed || this.el.hasActiveFx()) {
35243 this.afterSlideIn();
35246 this.collapsed = false;
35247 if(this.config.animate && skipAnim !== true){
35248 this.animateExpand();
35252 this.split.el.show();
35254 this.collapsedEl.setLocation(-2000,-2000);
35255 this.collapsedEl.hide();
35256 this.fireEvent("invalidated", this);
35257 this.fireEvent("expanded", this);
35261 animateExpand : function(){
35265 initTabs : function()
35267 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35269 var ts = new Roo.bootstrap.panel.Tabs({
35270 el: this.bodyEl.dom,
35271 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35272 disableTooltips: this.config.disableTabTips,
35273 toolbar : this.config.toolbar
35276 if(this.config.hideTabs){
35277 ts.stripWrap.setDisplayed(false);
35280 ts.resizeTabs = this.config.resizeTabs === true;
35281 ts.minTabWidth = this.config.minTabWidth || 40;
35282 ts.maxTabWidth = this.config.maxTabWidth || 250;
35283 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35284 ts.monitorResize = false;
35285 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35286 ts.bodyEl.addClass('roo-layout-tabs-body');
35287 this.panels.each(this.initPanelAsTab, this);
35290 initPanelAsTab : function(panel){
35291 var ti = this.tabs.addTab(
35295 this.config.closeOnTab && panel.isClosable(),
35298 if(panel.tabTip !== undefined){
35299 ti.setTooltip(panel.tabTip);
35301 ti.on("activate", function(){
35302 this.setActivePanel(panel);
35305 if(this.config.closeOnTab){
35306 ti.on("beforeclose", function(t, e){
35308 this.remove(panel);
35312 panel.tabItem = ti;
35317 updatePanelTitle : function(panel, title)
35319 if(this.activePanel == panel){
35320 this.updateTitle(title);
35323 var ti = this.tabs.getTab(panel.getEl().id);
35325 if(panel.tabTip !== undefined){
35326 ti.setTooltip(panel.tabTip);
35331 updateTitle : function(title){
35332 if(this.titleTextEl && !this.config.title){
35333 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35337 setActivePanel : function(panel)
35339 panel = this.getPanel(panel);
35340 if(this.activePanel && this.activePanel != panel){
35341 this.activePanel.setActiveState(false);
35343 this.activePanel = panel;
35344 panel.setActiveState(true);
35345 if(this.panelSize){
35346 panel.setSize(this.panelSize.width, this.panelSize.height);
35349 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35351 this.updateTitle(panel.getTitle());
35353 this.fireEvent("invalidated", this);
35355 this.fireEvent("panelactivated", this, panel);
35359 * Shows the specified panel.
35360 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35361 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35363 showPanel : function(panel)
35365 panel = this.getPanel(panel);
35368 var tab = this.tabs.getTab(panel.getEl().id);
35369 if(tab.isHidden()){
35370 this.tabs.unhideTab(tab.id);
35374 this.setActivePanel(panel);
35381 * Get the active panel for this region.
35382 * @return {Roo.ContentPanel} The active panel or null
35384 getActivePanel : function(){
35385 return this.activePanel;
35388 validateVisibility : function(){
35389 if(this.panels.getCount() < 1){
35390 this.updateTitle(" ");
35391 this.closeBtn.hide();
35394 if(!this.isVisible()){
35401 * Adds the passed ContentPanel(s) to this region.
35402 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35403 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35405 add : function(panel)
35407 if(arguments.length > 1){
35408 for(var i = 0, len = arguments.length; i < len; i++) {
35409 this.add(arguments[i]);
35414 // if we have not been rendered yet, then we can not really do much of this..
35415 if (!this.bodyEl) {
35416 this.unrendered_panels.push(panel);
35423 if(this.hasPanel(panel)){
35424 this.showPanel(panel);
35427 panel.setRegion(this);
35428 this.panels.add(panel);
35429 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35430 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35431 // and hide them... ???
35432 this.bodyEl.dom.appendChild(panel.getEl().dom);
35433 if(panel.background !== true){
35434 this.setActivePanel(panel);
35436 this.fireEvent("paneladded", this, panel);
35443 this.initPanelAsTab(panel);
35447 if(panel.background !== true){
35448 this.tabs.activate(panel.getEl().id);
35450 this.fireEvent("paneladded", this, panel);
35455 * Hides the tab for the specified panel.
35456 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35458 hidePanel : function(panel){
35459 if(this.tabs && (panel = this.getPanel(panel))){
35460 this.tabs.hideTab(panel.getEl().id);
35465 * Unhides the tab for a previously hidden panel.
35466 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35468 unhidePanel : function(panel){
35469 if(this.tabs && (panel = this.getPanel(panel))){
35470 this.tabs.unhideTab(panel.getEl().id);
35474 clearPanels : function(){
35475 while(this.panels.getCount() > 0){
35476 this.remove(this.panels.first());
35481 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35482 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35483 * @param {Boolean} preservePanel Overrides the config preservePanel option
35484 * @return {Roo.ContentPanel} The panel that was removed
35486 remove : function(panel, preservePanel)
35488 panel = this.getPanel(panel);
35493 this.fireEvent("beforeremove", this, panel, e);
35494 if(e.cancel === true){
35497 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35498 var panelId = panel.getId();
35499 this.panels.removeKey(panelId);
35501 document.body.appendChild(panel.getEl().dom);
35504 this.tabs.removeTab(panel.getEl().id);
35505 }else if (!preservePanel){
35506 this.bodyEl.dom.removeChild(panel.getEl().dom);
35508 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35509 var p = this.panels.first();
35510 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35511 tempEl.appendChild(p.getEl().dom);
35512 this.bodyEl.update("");
35513 this.bodyEl.dom.appendChild(p.getEl().dom);
35515 this.updateTitle(p.getTitle());
35517 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35518 this.setActivePanel(p);
35520 panel.setRegion(null);
35521 if(this.activePanel == panel){
35522 this.activePanel = null;
35524 if(this.config.autoDestroy !== false && preservePanel !== true){
35525 try{panel.destroy();}catch(e){}
35527 this.fireEvent("panelremoved", this, panel);
35532 * Returns the TabPanel component used by this region
35533 * @return {Roo.TabPanel}
35535 getTabs : function(){
35539 createTool : function(parentEl, className){
35540 var btn = Roo.DomHelper.append(parentEl, {
35542 cls: "x-layout-tools-button",
35545 cls: "roo-layout-tools-button-inner " + className,
35549 btn.addClassOnOver("roo-layout-tools-button-over");
35554 * Ext JS Library 1.1.1
35555 * Copyright(c) 2006-2007, Ext JS, LLC.
35557 * Originally Released Under LGPL - original licence link has changed is not relivant.
35560 * <script type="text/javascript">
35566 * @class Roo.SplitLayoutRegion
35567 * @extends Roo.LayoutRegion
35568 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35570 Roo.bootstrap.layout.Split = function(config){
35571 this.cursor = config.cursor;
35572 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35575 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35577 splitTip : "Drag to resize.",
35578 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35579 useSplitTips : false,
35581 applyConfig : function(config){
35582 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35585 onRender : function(ctr,pos) {
35587 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35588 if(!this.config.split){
35593 var splitEl = Roo.DomHelper.append(ctr.dom, {
35595 id: this.el.id + "-split",
35596 cls: "roo-layout-split roo-layout-split-"+this.position,
35599 /** The SplitBar for this region
35600 * @type Roo.SplitBar */
35601 // does not exist yet...
35602 Roo.log([this.position, this.orientation]);
35604 this.split = new Roo.bootstrap.SplitBar({
35605 dragElement : splitEl,
35606 resizingElement: this.el,
35607 orientation : this.orientation
35610 this.split.on("moved", this.onSplitMove, this);
35611 this.split.useShim = this.config.useShim === true;
35612 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35613 if(this.useSplitTips){
35614 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35616 //if(config.collapsible){
35617 // this.split.el.on("dblclick", this.collapse, this);
35620 if(typeof this.config.minSize != "undefined"){
35621 this.split.minSize = this.config.minSize;
35623 if(typeof this.config.maxSize != "undefined"){
35624 this.split.maxSize = this.config.maxSize;
35626 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35627 this.hideSplitter();
35632 getHMaxSize : function(){
35633 var cmax = this.config.maxSize || 10000;
35634 var center = this.mgr.getRegion("center");
35635 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35638 getVMaxSize : function(){
35639 var cmax = this.config.maxSize || 10000;
35640 var center = this.mgr.getRegion("center");
35641 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35644 onSplitMove : function(split, newSize){
35645 this.fireEvent("resized", this, newSize);
35649 * Returns the {@link Roo.SplitBar} for this region.
35650 * @return {Roo.SplitBar}
35652 getSplitBar : function(){
35657 this.hideSplitter();
35658 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35661 hideSplitter : function(){
35663 this.split.el.setLocation(-2000,-2000);
35664 this.split.el.hide();
35670 this.split.el.show();
35672 Roo.bootstrap.layout.Split.superclass.show.call(this);
35675 beforeSlide: function(){
35676 if(Roo.isGecko){// firefox overflow auto bug workaround
35677 this.bodyEl.clip();
35679 this.tabs.bodyEl.clip();
35681 if(this.activePanel){
35682 this.activePanel.getEl().clip();
35684 if(this.activePanel.beforeSlide){
35685 this.activePanel.beforeSlide();
35691 afterSlide : function(){
35692 if(Roo.isGecko){// firefox overflow auto bug workaround
35693 this.bodyEl.unclip();
35695 this.tabs.bodyEl.unclip();
35697 if(this.activePanel){
35698 this.activePanel.getEl().unclip();
35699 if(this.activePanel.afterSlide){
35700 this.activePanel.afterSlide();
35706 initAutoHide : function(){
35707 if(this.autoHide !== false){
35708 if(!this.autoHideHd){
35709 var st = new Roo.util.DelayedTask(this.slideIn, this);
35710 this.autoHideHd = {
35711 "mouseout": function(e){
35712 if(!e.within(this.el, true)){
35716 "mouseover" : function(e){
35722 this.el.on(this.autoHideHd);
35726 clearAutoHide : function(){
35727 if(this.autoHide !== false){
35728 this.el.un("mouseout", this.autoHideHd.mouseout);
35729 this.el.un("mouseover", this.autoHideHd.mouseover);
35733 clearMonitor : function(){
35734 Roo.get(document).un("click", this.slideInIf, this);
35737 // these names are backwards but not changed for compat
35738 slideOut : function(){
35739 if(this.isSlid || this.el.hasActiveFx()){
35742 this.isSlid = true;
35743 if(this.collapseBtn){
35744 this.collapseBtn.hide();
35746 this.closeBtnState = this.closeBtn.getStyle('display');
35747 this.closeBtn.hide();
35749 this.stickBtn.show();
35752 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35753 this.beforeSlide();
35754 this.el.setStyle("z-index", 10001);
35755 this.el.slideIn(this.getSlideAnchor(), {
35756 callback: function(){
35758 this.initAutoHide();
35759 Roo.get(document).on("click", this.slideInIf, this);
35760 this.fireEvent("slideshow", this);
35767 afterSlideIn : function(){
35768 this.clearAutoHide();
35769 this.isSlid = false;
35770 this.clearMonitor();
35771 this.el.setStyle("z-index", "");
35772 if(this.collapseBtn){
35773 this.collapseBtn.show();
35775 this.closeBtn.setStyle('display', this.closeBtnState);
35777 this.stickBtn.hide();
35779 this.fireEvent("slidehide", this);
35782 slideIn : function(cb){
35783 if(!this.isSlid || this.el.hasActiveFx()){
35787 this.isSlid = false;
35788 this.beforeSlide();
35789 this.el.slideOut(this.getSlideAnchor(), {
35790 callback: function(){
35791 this.el.setLeftTop(-10000, -10000);
35793 this.afterSlideIn();
35801 slideInIf : function(e){
35802 if(!e.within(this.el)){
35807 animateCollapse : function(){
35808 this.beforeSlide();
35809 this.el.setStyle("z-index", 20000);
35810 var anchor = this.getSlideAnchor();
35811 this.el.slideOut(anchor, {
35812 callback : function(){
35813 this.el.setStyle("z-index", "");
35814 this.collapsedEl.slideIn(anchor, {duration:.3});
35816 this.el.setLocation(-10000,-10000);
35818 this.fireEvent("collapsed", this);
35825 animateExpand : function(){
35826 this.beforeSlide();
35827 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35828 this.el.setStyle("z-index", 20000);
35829 this.collapsedEl.hide({
35832 this.el.slideIn(this.getSlideAnchor(), {
35833 callback : function(){
35834 this.el.setStyle("z-index", "");
35837 this.split.el.show();
35839 this.fireEvent("invalidated", this);
35840 this.fireEvent("expanded", this);
35868 getAnchor : function(){
35869 return this.anchors[this.position];
35872 getCollapseAnchor : function(){
35873 return this.canchors[this.position];
35876 getSlideAnchor : function(){
35877 return this.sanchors[this.position];
35880 getAlignAdj : function(){
35881 var cm = this.cmargins;
35882 switch(this.position){
35898 getExpandAdj : function(){
35899 var c = this.collapsedEl, cm = this.cmargins;
35900 switch(this.position){
35902 return [-(cm.right+c.getWidth()+cm.left), 0];
35905 return [cm.right+c.getWidth()+cm.left, 0];
35908 return [0, -(cm.top+cm.bottom+c.getHeight())];
35911 return [0, cm.top+cm.bottom+c.getHeight()];
35917 * Ext JS Library 1.1.1
35918 * Copyright(c) 2006-2007, Ext JS, LLC.
35920 * Originally Released Under LGPL - original licence link has changed is not relivant.
35923 * <script type="text/javascript">
35926 * These classes are private internal classes
35928 Roo.bootstrap.layout.Center = function(config){
35929 config.region = "center";
35930 Roo.bootstrap.layout.Region.call(this, config);
35931 this.visible = true;
35932 this.minWidth = config.minWidth || 20;
35933 this.minHeight = config.minHeight || 20;
35936 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35938 // center panel can't be hidden
35942 // center panel can't be hidden
35945 getMinWidth: function(){
35946 return this.minWidth;
35949 getMinHeight: function(){
35950 return this.minHeight;
35963 Roo.bootstrap.layout.North = function(config)
35965 config.region = 'north';
35966 config.cursor = 'n-resize';
35968 Roo.bootstrap.layout.Split.call(this, config);
35972 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35973 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35974 this.split.el.addClass("roo-layout-split-v");
35976 var size = config.initialSize || config.height;
35977 if(typeof size != "undefined"){
35978 this.el.setHeight(size);
35981 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35983 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35987 getBox : function(){
35988 if(this.collapsed){
35989 return this.collapsedEl.getBox();
35991 var box = this.el.getBox();
35993 box.height += this.split.el.getHeight();
35998 updateBox : function(box){
35999 if(this.split && !this.collapsed){
36000 box.height -= this.split.el.getHeight();
36001 this.split.el.setLeft(box.x);
36002 this.split.el.setTop(box.y+box.height);
36003 this.split.el.setWidth(box.width);
36005 if(this.collapsed){
36006 this.updateBody(box.width, null);
36008 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36016 Roo.bootstrap.layout.South = function(config){
36017 config.region = 'south';
36018 config.cursor = 's-resize';
36019 Roo.bootstrap.layout.Split.call(this, config);
36021 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36022 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36023 this.split.el.addClass("roo-layout-split-v");
36025 var size = config.initialSize || config.height;
36026 if(typeof size != "undefined"){
36027 this.el.setHeight(size);
36031 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36032 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36033 getBox : function(){
36034 if(this.collapsed){
36035 return this.collapsedEl.getBox();
36037 var box = this.el.getBox();
36039 var sh = this.split.el.getHeight();
36046 updateBox : function(box){
36047 if(this.split && !this.collapsed){
36048 var sh = this.split.el.getHeight();
36051 this.split.el.setLeft(box.x);
36052 this.split.el.setTop(box.y-sh);
36053 this.split.el.setWidth(box.width);
36055 if(this.collapsed){
36056 this.updateBody(box.width, null);
36058 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36062 Roo.bootstrap.layout.East = function(config){
36063 config.region = "east";
36064 config.cursor = "e-resize";
36065 Roo.bootstrap.layout.Split.call(this, config);
36067 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36068 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36069 this.split.el.addClass("roo-layout-split-h");
36071 var size = config.initialSize || config.width;
36072 if(typeof size != "undefined"){
36073 this.el.setWidth(size);
36076 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36077 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36078 getBox : function(){
36079 if(this.collapsed){
36080 return this.collapsedEl.getBox();
36082 var box = this.el.getBox();
36084 var sw = this.split.el.getWidth();
36091 updateBox : function(box){
36092 if(this.split && !this.collapsed){
36093 var sw = this.split.el.getWidth();
36095 this.split.el.setLeft(box.x);
36096 this.split.el.setTop(box.y);
36097 this.split.el.setHeight(box.height);
36100 if(this.collapsed){
36101 this.updateBody(null, box.height);
36103 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36107 Roo.bootstrap.layout.West = function(config){
36108 config.region = "west";
36109 config.cursor = "w-resize";
36111 Roo.bootstrap.layout.Split.call(this, config);
36113 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36114 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36115 this.split.el.addClass("roo-layout-split-h");
36119 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36120 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36122 onRender: function(ctr, pos)
36124 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36125 var size = this.config.initialSize || this.config.width;
36126 if(typeof size != "undefined"){
36127 this.el.setWidth(size);
36131 getBox : function(){
36132 if(this.collapsed){
36133 return this.collapsedEl.getBox();
36135 var box = this.el.getBox();
36137 box.width += this.split.el.getWidth();
36142 updateBox : function(box){
36143 if(this.split && !this.collapsed){
36144 var sw = this.split.el.getWidth();
36146 this.split.el.setLeft(box.x+box.width);
36147 this.split.el.setTop(box.y);
36148 this.split.el.setHeight(box.height);
36150 if(this.collapsed){
36151 this.updateBody(null, box.height);
36153 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36156 Roo.namespace("Roo.bootstrap.panel");/*
36158 * Ext JS Library 1.1.1
36159 * Copyright(c) 2006-2007, Ext JS, LLC.
36161 * Originally Released Under LGPL - original licence link has changed is not relivant.
36164 * <script type="text/javascript">
36167 * @class Roo.ContentPanel
36168 * @extends Roo.util.Observable
36169 * A basic ContentPanel element.
36170 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36171 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36172 * @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
36173 * @cfg {Boolean} closable True if the panel can be closed/removed
36174 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36175 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36176 * @cfg {Toolbar} toolbar A toolbar for this panel
36177 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36178 * @cfg {String} title The title for this panel
36179 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36180 * @cfg {String} url Calls {@link #setUrl} with this value
36181 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36182 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36183 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36184 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36185 * @cfg {Boolean} badges render the badges
36188 * Create a new ContentPanel.
36189 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36190 * @param {String/Object} config A string to set only the title or a config object
36191 * @param {String} content (optional) Set the HTML content for this panel
36192 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36194 Roo.bootstrap.panel.Content = function( config){
36196 this.tpl = config.tpl || false;
36198 var el = config.el;
36199 var content = config.content;
36201 if(config.autoCreate){ // xtype is available if this is called from factory
36204 this.el = Roo.get(el);
36205 if(!this.el && config && config.autoCreate){
36206 if(typeof config.autoCreate == "object"){
36207 if(!config.autoCreate.id){
36208 config.autoCreate.id = config.id||el;
36210 this.el = Roo.DomHelper.append(document.body,
36211 config.autoCreate, true);
36213 var elcfg = { tag: "div",
36214 cls: "roo-layout-inactive-content",
36218 elcfg.html = config.html;
36222 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36225 this.closable = false;
36226 this.loaded = false;
36227 this.active = false;
36230 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36232 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36234 this.wrapEl = this.el; //this.el.wrap();
36236 if (config.toolbar.items) {
36237 ti = config.toolbar.items ;
36238 delete config.toolbar.items ;
36242 this.toolbar.render(this.wrapEl, 'before');
36243 for(var i =0;i < ti.length;i++) {
36244 // Roo.log(['add child', items[i]]);
36245 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36247 this.toolbar.items = nitems;
36248 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36249 delete config.toolbar;
36253 // xtype created footer. - not sure if will work as we normally have to render first..
36254 if (this.footer && !this.footer.el && this.footer.xtype) {
36255 if (!this.wrapEl) {
36256 this.wrapEl = this.el.wrap();
36259 this.footer.container = this.wrapEl.createChild();
36261 this.footer = Roo.factory(this.footer, Roo);
36266 if(typeof config == "string"){
36267 this.title = config;
36269 Roo.apply(this, config);
36273 this.resizeEl = Roo.get(this.resizeEl, true);
36275 this.resizeEl = this.el;
36277 // handle view.xtype
36285 * Fires when this panel is activated.
36286 * @param {Roo.ContentPanel} this
36290 * @event deactivate
36291 * Fires when this panel is activated.
36292 * @param {Roo.ContentPanel} this
36294 "deactivate" : true,
36298 * Fires when this panel is resized if fitToFrame is true.
36299 * @param {Roo.ContentPanel} this
36300 * @param {Number} width The width after any component adjustments
36301 * @param {Number} height The height after any component adjustments
36307 * Fires when this tab is created
36308 * @param {Roo.ContentPanel} this
36319 if(this.autoScroll){
36320 this.resizeEl.setStyle("overflow", "auto");
36322 // fix randome scrolling
36323 //this.el.on('scroll', function() {
36324 // Roo.log('fix random scolling');
36325 // this.scrollTo('top',0);
36328 content = content || this.content;
36330 this.setContent(content);
36332 if(config && config.url){
36333 this.setUrl(this.url, this.params, this.loadOnce);
36338 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36340 if (this.view && typeof(this.view.xtype) != 'undefined') {
36341 this.view.el = this.el.appendChild(document.createElement("div"));
36342 this.view = Roo.factory(this.view);
36343 this.view.render && this.view.render(false, '');
36347 this.fireEvent('render', this);
36350 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36354 setRegion : function(region){
36355 this.region = region;
36356 this.setActiveClass(region && !this.background);
36360 setActiveClass: function(state)
36363 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36364 this.el.setStyle('position','relative');
36366 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36367 this.el.setStyle('position', 'absolute');
36372 * Returns the toolbar for this Panel if one was configured.
36373 * @return {Roo.Toolbar}
36375 getToolbar : function(){
36376 return this.toolbar;
36379 setActiveState : function(active)
36381 this.active = active;
36382 this.setActiveClass(active);
36384 this.fireEvent("deactivate", this);
36386 this.fireEvent("activate", this);
36390 * Updates this panel's element
36391 * @param {String} content The new content
36392 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36394 setContent : function(content, loadScripts){
36395 this.el.update(content, loadScripts);
36398 ignoreResize : function(w, h){
36399 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36402 this.lastSize = {width: w, height: h};
36407 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36408 * @return {Roo.UpdateManager} The UpdateManager
36410 getUpdateManager : function(){
36411 return this.el.getUpdateManager();
36414 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36415 * @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:
36418 url: "your-url.php",
36419 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36420 callback: yourFunction,
36421 scope: yourObject, //(optional scope)
36424 text: "Loading...",
36429 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36430 * 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.
36431 * @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}
36432 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36433 * @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.
36434 * @return {Roo.ContentPanel} this
36437 var um = this.el.getUpdateManager();
36438 um.update.apply(um, arguments);
36444 * 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.
36445 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36446 * @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)
36447 * @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)
36448 * @return {Roo.UpdateManager} The UpdateManager
36450 setUrl : function(url, params, loadOnce){
36451 if(this.refreshDelegate){
36452 this.removeListener("activate", this.refreshDelegate);
36454 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36455 this.on("activate", this.refreshDelegate);
36456 return this.el.getUpdateManager();
36459 _handleRefresh : function(url, params, loadOnce){
36460 if(!loadOnce || !this.loaded){
36461 var updater = this.el.getUpdateManager();
36462 updater.update(url, params, this._setLoaded.createDelegate(this));
36466 _setLoaded : function(){
36467 this.loaded = true;
36471 * Returns this panel's id
36474 getId : function(){
36479 * Returns this panel's element - used by regiosn to add.
36480 * @return {Roo.Element}
36482 getEl : function(){
36483 return this.wrapEl || this.el;
36488 adjustForComponents : function(width, height)
36490 //Roo.log('adjustForComponents ');
36491 if(this.resizeEl != this.el){
36492 width -= this.el.getFrameWidth('lr');
36493 height -= this.el.getFrameWidth('tb');
36496 var te = this.toolbar.getEl();
36497 te.setWidth(width);
36498 height -= te.getHeight();
36501 var te = this.footer.getEl();
36502 te.setWidth(width);
36503 height -= te.getHeight();
36507 if(this.adjustments){
36508 width += this.adjustments[0];
36509 height += this.adjustments[1];
36511 return {"width": width, "height": height};
36514 setSize : function(width, height){
36515 if(this.fitToFrame && !this.ignoreResize(width, height)){
36516 if(this.fitContainer && this.resizeEl != this.el){
36517 this.el.setSize(width, height);
36519 var size = this.adjustForComponents(width, height);
36520 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36521 this.fireEvent('resize', this, size.width, size.height);
36526 * Returns this panel's title
36529 getTitle : function(){
36531 if (typeof(this.title) != 'object') {
36536 for (var k in this.title) {
36537 if (!this.title.hasOwnProperty(k)) {
36541 if (k.indexOf('-') >= 0) {
36542 var s = k.split('-');
36543 for (var i = 0; i<s.length; i++) {
36544 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36547 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36554 * Set this panel's title
36555 * @param {String} title
36557 setTitle : function(title){
36558 this.title = title;
36560 this.region.updatePanelTitle(this, title);
36565 * Returns true is this panel was configured to be closable
36566 * @return {Boolean}
36568 isClosable : function(){
36569 return this.closable;
36572 beforeSlide : function(){
36574 this.resizeEl.clip();
36577 afterSlide : function(){
36579 this.resizeEl.unclip();
36583 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36584 * Will fail silently if the {@link #setUrl} method has not been called.
36585 * This does not activate the panel, just updates its content.
36587 refresh : function(){
36588 if(this.refreshDelegate){
36589 this.loaded = false;
36590 this.refreshDelegate();
36595 * Destroys this panel
36597 destroy : function(){
36598 this.el.removeAllListeners();
36599 var tempEl = document.createElement("span");
36600 tempEl.appendChild(this.el.dom);
36601 tempEl.innerHTML = "";
36607 * form - if the content panel contains a form - this is a reference to it.
36608 * @type {Roo.form.Form}
36612 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36613 * This contains a reference to it.
36619 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36629 * @param {Object} cfg Xtype definition of item to add.
36633 getChildContainer: function () {
36634 return this.getEl();
36639 var ret = new Roo.factory(cfg);
36644 if (cfg.xtype.match(/^Form$/)) {
36647 //if (this.footer) {
36648 // el = this.footer.container.insertSibling(false, 'before');
36650 el = this.el.createChild();
36653 this.form = new Roo.form.Form(cfg);
36656 if ( this.form.allItems.length) {
36657 this.form.render(el.dom);
36661 // should only have one of theses..
36662 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36663 // views.. should not be just added - used named prop 'view''
36665 cfg.el = this.el.appendChild(document.createElement("div"));
36668 var ret = new Roo.factory(cfg);
36670 ret.render && ret.render(false, ''); // render blank..
36680 * @class Roo.bootstrap.panel.Grid
36681 * @extends Roo.bootstrap.panel.Content
36683 * Create a new GridPanel.
36684 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36685 * @param {Object} config A the config object
36691 Roo.bootstrap.panel.Grid = function(config)
36695 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36696 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36698 config.el = this.wrapper;
36699 //this.el = this.wrapper;
36701 if (config.container) {
36702 // ctor'ed from a Border/panel.grid
36705 this.wrapper.setStyle("overflow", "hidden");
36706 this.wrapper.addClass('roo-grid-container');
36711 if(config.toolbar){
36712 var tool_el = this.wrapper.createChild();
36713 this.toolbar = Roo.factory(config.toolbar);
36715 if (config.toolbar.items) {
36716 ti = config.toolbar.items ;
36717 delete config.toolbar.items ;
36721 this.toolbar.render(tool_el);
36722 for(var i =0;i < ti.length;i++) {
36723 // Roo.log(['add child', items[i]]);
36724 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36726 this.toolbar.items = nitems;
36728 delete config.toolbar;
36731 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36732 config.grid.scrollBody = true;;
36733 config.grid.monitorWindowResize = false; // turn off autosizing
36734 config.grid.autoHeight = false;
36735 config.grid.autoWidth = false;
36737 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36739 if (config.background) {
36740 // render grid on panel activation (if panel background)
36741 this.on('activate', function(gp) {
36742 if (!gp.grid.rendered) {
36743 gp.grid.render(this.wrapper);
36744 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36749 this.grid.render(this.wrapper);
36750 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36753 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36754 // ??? needed ??? config.el = this.wrapper;
36759 // xtype created footer. - not sure if will work as we normally have to render first..
36760 if (this.footer && !this.footer.el && this.footer.xtype) {
36762 var ctr = this.grid.getView().getFooterPanel(true);
36763 this.footer.dataSource = this.grid.dataSource;
36764 this.footer = Roo.factory(this.footer, Roo);
36765 this.footer.render(ctr);
36775 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36776 getId : function(){
36777 return this.grid.id;
36781 * Returns the grid for this panel
36782 * @return {Roo.bootstrap.Table}
36784 getGrid : function(){
36788 setSize : function(width, height){
36789 if(!this.ignoreResize(width, height)){
36790 var grid = this.grid;
36791 var size = this.adjustForComponents(width, height);
36792 var gridel = grid.getGridEl();
36793 gridel.setSize(size.width, size.height);
36795 var thd = grid.getGridEl().select('thead',true).first();
36796 var tbd = grid.getGridEl().select('tbody', true).first();
36798 tbd.setSize(width, height - thd.getHeight());
36807 beforeSlide : function(){
36808 this.grid.getView().scroller.clip();
36811 afterSlide : function(){
36812 this.grid.getView().scroller.unclip();
36815 destroy : function(){
36816 this.grid.destroy();
36818 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36823 * @class Roo.bootstrap.panel.Nest
36824 * @extends Roo.bootstrap.panel.Content
36826 * Create a new Panel, that can contain a layout.Border.
36829 * @param {Roo.BorderLayout} layout The layout for this panel
36830 * @param {String/Object} config A string to set only the title or a config object
36832 Roo.bootstrap.panel.Nest = function(config)
36834 // construct with only one argument..
36835 /* FIXME - implement nicer consturctors
36836 if (layout.layout) {
36838 layout = config.layout;
36839 delete config.layout;
36841 if (layout.xtype && !layout.getEl) {
36842 // then layout needs constructing..
36843 layout = Roo.factory(layout, Roo);
36847 config.el = config.layout.getEl();
36849 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36851 config.layout.monitorWindowResize = false; // turn off autosizing
36852 this.layout = config.layout;
36853 this.layout.getEl().addClass("roo-layout-nested-layout");
36860 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36862 setSize : function(width, height){
36863 if(!this.ignoreResize(width, height)){
36864 var size = this.adjustForComponents(width, height);
36865 var el = this.layout.getEl();
36866 if (size.height < 1) {
36867 el.setWidth(size.width);
36869 el.setSize(size.width, size.height);
36871 var touch = el.dom.offsetWidth;
36872 this.layout.layout();
36873 // ie requires a double layout on the first pass
36874 if(Roo.isIE && !this.initialized){
36875 this.initialized = true;
36876 this.layout.layout();
36881 // activate all subpanels if not currently active..
36883 setActiveState : function(active){
36884 this.active = active;
36885 this.setActiveClass(active);
36888 this.fireEvent("deactivate", this);
36892 this.fireEvent("activate", this);
36893 // not sure if this should happen before or after..
36894 if (!this.layout) {
36895 return; // should not happen..
36898 for (var r in this.layout.regions) {
36899 reg = this.layout.getRegion(r);
36900 if (reg.getActivePanel()) {
36901 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36902 reg.setActivePanel(reg.getActivePanel());
36905 if (!reg.panels.length) {
36908 reg.showPanel(reg.getPanel(0));
36917 * Returns the nested BorderLayout for this panel
36918 * @return {Roo.BorderLayout}
36920 getLayout : function(){
36921 return this.layout;
36925 * Adds a xtype elements to the layout of the nested panel
36929 xtype : 'ContentPanel',
36936 xtype : 'NestedLayoutPanel',
36942 items : [ ... list of content panels or nested layout panels.. ]
36946 * @param {Object} cfg Xtype definition of item to add.
36948 addxtype : function(cfg) {
36949 return this.layout.addxtype(cfg);
36954 * Ext JS Library 1.1.1
36955 * Copyright(c) 2006-2007, Ext JS, LLC.
36957 * Originally Released Under LGPL - original licence link has changed is not relivant.
36960 * <script type="text/javascript">
36963 * @class Roo.TabPanel
36964 * @extends Roo.util.Observable
36965 * A lightweight tab container.
36969 // basic tabs 1, built from existing content
36970 var tabs = new Roo.TabPanel("tabs1");
36971 tabs.addTab("script", "View Script");
36972 tabs.addTab("markup", "View Markup");
36973 tabs.activate("script");
36975 // more advanced tabs, built from javascript
36976 var jtabs = new Roo.TabPanel("jtabs");
36977 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36979 // set up the UpdateManager
36980 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36981 var updater = tab2.getUpdateManager();
36982 updater.setDefaultUrl("ajax1.htm");
36983 tab2.on('activate', updater.refresh, updater, true);
36985 // Use setUrl for Ajax loading
36986 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36987 tab3.setUrl("ajax2.htm", null, true);
36990 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36993 jtabs.activate("jtabs-1");
36996 * Create a new TabPanel.
36997 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36998 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37000 Roo.bootstrap.panel.Tabs = function(config){
37002 * The container element for this TabPanel.
37003 * @type Roo.Element
37005 this.el = Roo.get(config.el);
37008 if(typeof config == "boolean"){
37009 this.tabPosition = config ? "bottom" : "top";
37011 Roo.apply(this, config);
37015 if(this.tabPosition == "bottom"){
37016 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37017 this.el.addClass("roo-tabs-bottom");
37019 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37020 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37021 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37023 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37025 if(this.tabPosition != "bottom"){
37026 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37027 * @type Roo.Element
37029 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37030 this.el.addClass("roo-tabs-top");
37034 this.bodyEl.setStyle("position", "relative");
37036 this.active = null;
37037 this.activateDelegate = this.activate.createDelegate(this);
37042 * Fires when the active tab changes
37043 * @param {Roo.TabPanel} this
37044 * @param {Roo.TabPanelItem} activePanel The new active tab
37048 * @event beforetabchange
37049 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37050 * @param {Roo.TabPanel} this
37051 * @param {Object} e Set cancel to true on this object to cancel the tab change
37052 * @param {Roo.TabPanelItem} tab The tab being changed to
37054 "beforetabchange" : true
37057 Roo.EventManager.onWindowResize(this.onResize, this);
37058 this.cpad = this.el.getPadding("lr");
37059 this.hiddenCount = 0;
37062 // toolbar on the tabbar support...
37063 if (this.toolbar) {
37064 alert("no toolbar support yet");
37065 this.toolbar = false;
37067 var tcfg = this.toolbar;
37068 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37069 this.toolbar = new Roo.Toolbar(tcfg);
37070 if (Roo.isSafari) {
37071 var tbl = tcfg.container.child('table', true);
37072 tbl.setAttribute('width', '100%');
37080 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37083 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37085 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37087 tabPosition : "top",
37089 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37091 currentTabWidth : 0,
37093 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37097 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37101 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37103 preferredTabWidth : 175,
37105 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37107 resizeTabs : false,
37109 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37111 monitorResize : true,
37113 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37118 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37119 * @param {String} id The id of the div to use <b>or create</b>
37120 * @param {String} text The text for the tab
37121 * @param {String} content (optional) Content to put in the TabPanelItem body
37122 * @param {Boolean} closable (optional) True to create a close icon on the tab
37123 * @return {Roo.TabPanelItem} The created TabPanelItem
37125 addTab : function(id, text, content, closable, tpl)
37127 var item = new Roo.bootstrap.panel.TabItem({
37131 closable : closable,
37134 this.addTabItem(item);
37136 item.setContent(content);
37142 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37143 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37144 * @return {Roo.TabPanelItem}
37146 getTab : function(id){
37147 return this.items[id];
37151 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37152 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37154 hideTab : function(id){
37155 var t = this.items[id];
37158 this.hiddenCount++;
37159 this.autoSizeTabs();
37164 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37165 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37167 unhideTab : function(id){
37168 var t = this.items[id];
37170 t.setHidden(false);
37171 this.hiddenCount--;
37172 this.autoSizeTabs();
37177 * Adds an existing {@link Roo.TabPanelItem}.
37178 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37180 addTabItem : function(item){
37181 this.items[item.id] = item;
37182 this.items.push(item);
37183 // if(this.resizeTabs){
37184 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37185 // this.autoSizeTabs();
37187 // item.autoSize();
37192 * Removes a {@link Roo.TabPanelItem}.
37193 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37195 removeTab : function(id){
37196 var items = this.items;
37197 var tab = items[id];
37198 if(!tab) { return; }
37199 var index = items.indexOf(tab);
37200 if(this.active == tab && items.length > 1){
37201 var newTab = this.getNextAvailable(index);
37206 this.stripEl.dom.removeChild(tab.pnode.dom);
37207 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37208 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37210 items.splice(index, 1);
37211 delete this.items[tab.id];
37212 tab.fireEvent("close", tab);
37213 tab.purgeListeners();
37214 this.autoSizeTabs();
37217 getNextAvailable : function(start){
37218 var items = this.items;
37220 // look for a next tab that will slide over to
37221 // replace the one being removed
37222 while(index < items.length){
37223 var item = items[++index];
37224 if(item && !item.isHidden()){
37228 // if one isn't found select the previous tab (on the left)
37231 var item = items[--index];
37232 if(item && !item.isHidden()){
37240 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37241 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37243 disableTab : function(id){
37244 var tab = this.items[id];
37245 if(tab && this.active != tab){
37251 * Enables a {@link Roo.TabPanelItem} that is disabled.
37252 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37254 enableTab : function(id){
37255 var tab = this.items[id];
37260 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37261 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37262 * @return {Roo.TabPanelItem} The TabPanelItem.
37264 activate : function(id){
37265 var tab = this.items[id];
37269 if(tab == this.active || tab.disabled){
37273 this.fireEvent("beforetabchange", this, e, tab);
37274 if(e.cancel !== true && !tab.disabled){
37276 this.active.hide();
37278 this.active = this.items[id];
37279 this.active.show();
37280 this.fireEvent("tabchange", this, this.active);
37286 * Gets the active {@link Roo.TabPanelItem}.
37287 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37289 getActiveTab : function(){
37290 return this.active;
37294 * Updates the tab body element to fit the height of the container element
37295 * for overflow scrolling
37296 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37298 syncHeight : function(targetHeight){
37299 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37300 var bm = this.bodyEl.getMargins();
37301 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37302 this.bodyEl.setHeight(newHeight);
37306 onResize : function(){
37307 if(this.monitorResize){
37308 this.autoSizeTabs();
37313 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37315 beginUpdate : function(){
37316 this.updating = true;
37320 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37322 endUpdate : function(){
37323 this.updating = false;
37324 this.autoSizeTabs();
37328 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37330 autoSizeTabs : function(){
37331 var count = this.items.length;
37332 var vcount = count - this.hiddenCount;
37333 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37336 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37337 var availWidth = Math.floor(w / vcount);
37338 var b = this.stripBody;
37339 if(b.getWidth() > w){
37340 var tabs = this.items;
37341 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37342 if(availWidth < this.minTabWidth){
37343 /*if(!this.sleft){ // incomplete scrolling code
37344 this.createScrollButtons();
37347 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37350 if(this.currentTabWidth < this.preferredTabWidth){
37351 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37357 * Returns the number of tabs in this TabPanel.
37360 getCount : function(){
37361 return this.items.length;
37365 * Resizes all the tabs to the passed width
37366 * @param {Number} The new width
37368 setTabWidth : function(width){
37369 this.currentTabWidth = width;
37370 for(var i = 0, len = this.items.length; i < len; i++) {
37371 if(!this.items[i].isHidden()) {
37372 this.items[i].setWidth(width);
37378 * Destroys this TabPanel
37379 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37381 destroy : function(removeEl){
37382 Roo.EventManager.removeResizeListener(this.onResize, this);
37383 for(var i = 0, len = this.items.length; i < len; i++){
37384 this.items[i].purgeListeners();
37386 if(removeEl === true){
37387 this.el.update("");
37392 createStrip : function(container)
37394 var strip = document.createElement("nav");
37395 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37396 container.appendChild(strip);
37400 createStripList : function(strip)
37402 // div wrapper for retard IE
37403 // returns the "tr" element.
37404 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37405 //'<div class="x-tabs-strip-wrap">'+
37406 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37407 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37408 return strip.firstChild; //.firstChild.firstChild.firstChild;
37410 createBody : function(container)
37412 var body = document.createElement("div");
37413 Roo.id(body, "tab-body");
37414 //Roo.fly(body).addClass("x-tabs-body");
37415 Roo.fly(body).addClass("tab-content");
37416 container.appendChild(body);
37419 createItemBody :function(bodyEl, id){
37420 var body = Roo.getDom(id);
37422 body = document.createElement("div");
37425 //Roo.fly(body).addClass("x-tabs-item-body");
37426 Roo.fly(body).addClass("tab-pane");
37427 bodyEl.insertBefore(body, bodyEl.firstChild);
37431 createStripElements : function(stripEl, text, closable, tpl)
37433 var td = document.createElement("li"); // was td..
37436 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37439 stripEl.appendChild(td);
37441 td.className = "x-tabs-closable";
37442 if(!this.closeTpl){
37443 this.closeTpl = new Roo.Template(
37444 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37445 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37446 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37449 var el = this.closeTpl.overwrite(td, {"text": text});
37450 var close = el.getElementsByTagName("div")[0];
37451 var inner = el.getElementsByTagName("em")[0];
37452 return {"el": el, "close": close, "inner": inner};
37455 // not sure what this is..
37456 // if(!this.tabTpl){
37457 //this.tabTpl = new Roo.Template(
37458 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37459 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37461 // this.tabTpl = new Roo.Template(
37462 // '<a href="#">' +
37463 // '<span unselectable="on"' +
37464 // (this.disableTooltips ? '' : ' title="{text}"') +
37465 // ' >{text}</span></a>'
37471 var template = tpl || this.tabTpl || false;
37475 template = new Roo.Template(
37477 '<span unselectable="on"' +
37478 (this.disableTooltips ? '' : ' title="{text}"') +
37479 ' >{text}</span></a>'
37483 switch (typeof(template)) {
37487 template = new Roo.Template(template);
37493 var el = template.overwrite(td, {"text": text});
37495 var inner = el.getElementsByTagName("span")[0];
37497 return {"el": el, "inner": inner};
37505 * @class Roo.TabPanelItem
37506 * @extends Roo.util.Observable
37507 * Represents an individual item (tab plus body) in a TabPanel.
37508 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37509 * @param {String} id The id of this TabPanelItem
37510 * @param {String} text The text for the tab of this TabPanelItem
37511 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37513 Roo.bootstrap.panel.TabItem = function(config){
37515 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37516 * @type Roo.TabPanel
37518 this.tabPanel = config.panel;
37520 * The id for this TabPanelItem
37523 this.id = config.id;
37525 this.disabled = false;
37527 this.text = config.text;
37529 this.loaded = false;
37530 this.closable = config.closable;
37533 * The body element for this TabPanelItem.
37534 * @type Roo.Element
37536 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37537 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37538 this.bodyEl.setStyle("display", "block");
37539 this.bodyEl.setStyle("zoom", "1");
37540 //this.hideAction();
37542 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37544 this.el = Roo.get(els.el);
37545 this.inner = Roo.get(els.inner, true);
37546 this.textEl = Roo.get(this.el.dom.firstChild, true);
37547 this.pnode = Roo.get(els.el.parentNode, true);
37548 this.el.on("mousedown", this.onTabMouseDown, this);
37549 this.el.on("click", this.onTabClick, this);
37551 if(config.closable){
37552 var c = Roo.get(els.close, true);
37553 c.dom.title = this.closeText;
37554 c.addClassOnOver("close-over");
37555 c.on("click", this.closeClick, this);
37561 * Fires when this tab becomes the active tab.
37562 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37563 * @param {Roo.TabPanelItem} this
37567 * @event beforeclose
37568 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37569 * @param {Roo.TabPanelItem} this
37570 * @param {Object} e Set cancel to true on this object to cancel the close.
37572 "beforeclose": true,
37575 * Fires when this tab is closed.
37576 * @param {Roo.TabPanelItem} this
37580 * @event deactivate
37581 * Fires when this tab is no longer the active tab.
37582 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37583 * @param {Roo.TabPanelItem} this
37585 "deactivate" : true
37587 this.hidden = false;
37589 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37592 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37594 purgeListeners : function(){
37595 Roo.util.Observable.prototype.purgeListeners.call(this);
37596 this.el.removeAllListeners();
37599 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37602 this.pnode.addClass("active");
37605 this.tabPanel.stripWrap.repaint();
37607 this.fireEvent("activate", this.tabPanel, this);
37611 * Returns true if this tab is the active tab.
37612 * @return {Boolean}
37614 isActive : function(){
37615 return this.tabPanel.getActiveTab() == this;
37619 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37622 this.pnode.removeClass("active");
37624 this.fireEvent("deactivate", this.tabPanel, this);
37627 hideAction : function(){
37628 this.bodyEl.hide();
37629 this.bodyEl.setStyle("position", "absolute");
37630 this.bodyEl.setLeft("-20000px");
37631 this.bodyEl.setTop("-20000px");
37634 showAction : function(){
37635 this.bodyEl.setStyle("position", "relative");
37636 this.bodyEl.setTop("");
37637 this.bodyEl.setLeft("");
37638 this.bodyEl.show();
37642 * Set the tooltip for the tab.
37643 * @param {String} tooltip The tab's tooltip
37645 setTooltip : function(text){
37646 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37647 this.textEl.dom.qtip = text;
37648 this.textEl.dom.removeAttribute('title');
37650 this.textEl.dom.title = text;
37654 onTabClick : function(e){
37655 e.preventDefault();
37656 this.tabPanel.activate(this.id);
37659 onTabMouseDown : function(e){
37660 e.preventDefault();
37661 this.tabPanel.activate(this.id);
37664 getWidth : function(){
37665 return this.inner.getWidth();
37668 setWidth : function(width){
37669 var iwidth = width - this.pnode.getPadding("lr");
37670 this.inner.setWidth(iwidth);
37671 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37672 this.pnode.setWidth(width);
37676 * Show or hide the tab
37677 * @param {Boolean} hidden True to hide or false to show.
37679 setHidden : function(hidden){
37680 this.hidden = hidden;
37681 this.pnode.setStyle("display", hidden ? "none" : "");
37685 * Returns true if this tab is "hidden"
37686 * @return {Boolean}
37688 isHidden : function(){
37689 return this.hidden;
37693 * Returns the text for this tab
37696 getText : function(){
37700 autoSize : function(){
37701 //this.el.beginMeasure();
37702 this.textEl.setWidth(1);
37704 * #2804 [new] Tabs in Roojs
37705 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37707 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37708 //this.el.endMeasure();
37712 * Sets the text for the tab (Note: this also sets the tooltip text)
37713 * @param {String} text The tab's text and tooltip
37715 setText : function(text){
37717 this.textEl.update(text);
37718 this.setTooltip(text);
37719 //if(!this.tabPanel.resizeTabs){
37720 // this.autoSize();
37724 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37726 activate : function(){
37727 this.tabPanel.activate(this.id);
37731 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37733 disable : function(){
37734 if(this.tabPanel.active != this){
37735 this.disabled = true;
37736 this.pnode.addClass("disabled");
37741 * Enables this TabPanelItem if it was previously disabled.
37743 enable : function(){
37744 this.disabled = false;
37745 this.pnode.removeClass("disabled");
37749 * Sets the content for this TabPanelItem.
37750 * @param {String} content The content
37751 * @param {Boolean} loadScripts true to look for and load scripts
37753 setContent : function(content, loadScripts){
37754 this.bodyEl.update(content, loadScripts);
37758 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37759 * @return {Roo.UpdateManager} The UpdateManager
37761 getUpdateManager : function(){
37762 return this.bodyEl.getUpdateManager();
37766 * Set a URL to be used to load the content for this TabPanelItem.
37767 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37768 * @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)
37769 * @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)
37770 * @return {Roo.UpdateManager} The UpdateManager
37772 setUrl : function(url, params, loadOnce){
37773 if(this.refreshDelegate){
37774 this.un('activate', this.refreshDelegate);
37776 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37777 this.on("activate", this.refreshDelegate);
37778 return this.bodyEl.getUpdateManager();
37782 _handleRefresh : function(url, params, loadOnce){
37783 if(!loadOnce || !this.loaded){
37784 var updater = this.bodyEl.getUpdateManager();
37785 updater.update(url, params, this._setLoaded.createDelegate(this));
37790 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37791 * Will fail silently if the setUrl method has not been called.
37792 * This does not activate the panel, just updates its content.
37794 refresh : function(){
37795 if(this.refreshDelegate){
37796 this.loaded = false;
37797 this.refreshDelegate();
37802 _setLoaded : function(){
37803 this.loaded = true;
37807 closeClick : function(e){
37810 this.fireEvent("beforeclose", this, o);
37811 if(o.cancel !== true){
37812 this.tabPanel.removeTab(this.id);
37816 * The text displayed in the tooltip for the close icon.
37819 closeText : "Close this tab"
37829 * @class Roo.bootstrap.PhoneInput
37830 * @extends Roo.bootstrap.TriggerField
37831 * Bootstrap PhoneInput class
37834 * Create a new PhoneInput
37835 * @param {Object} config The config object
37838 Roo.bootstrap.PhoneInput = function(config){
37840 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
37843 'touchviewdisplay' : true
37846 this.country = []; //fetch country JSON
37849 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
37851 listWidth: undefined,
37855 selectedClass: 'active',
37861 validClass : "has-success",
37863 invalidClass: "has-warning",
37866 defaultCountry: 'hk',
37868 preferedCountries: undefined, //array
37870 filterCountries: undefined, //array
37872 displayMode: undefined, //string
37874 getAutoCreate : function(){
37876 this.list = Roo.bootstrap.PhoneInput.List;
37878 if(this.filterCountries) {
37879 for(var i = 0; i < this.filterCountries.length; i++) {
37880 delete this.list[this.filterCountries[i]];
37884 if (this.preferedCountries) {
37888 var align = this.labelAlign || this.parentLabelAlign();
37890 var id = Roo.id(); //all el??
37899 type : this.inputType,
37900 cls : 'form-control',
37901 style: 'padding-left: 60px;',
37902 placeholder : this.placeholder || ''
37906 input.name = this.name;
37909 input.cls += ' input-' + this.size;
37912 if (this.disabled) {
37913 input.disabled=true;
37916 var inputblock = input;
37918 if(this.hasFeedback && !this.allowBlank){
37921 cls: 'glyphicon form-control-feedback'
37929 inputblock.cn.push(input);
37931 if(this.hasFeedback && !this.allowBlank){
37932 inputblock.cls += 'has-feedback';
37933 inputblock.cn.push(feedback);
37942 cls: 'form-hidden-field'
37951 style: 'margin-right:5px',
37952 cls: 'roo-selected-region',
37953 cn: [] //flag position ... (iti-flag-us)
37961 if (this.caret != false) {
37964 cls: 'fa fa-' + this.caret
37969 cls: 'roo-select2-container input-group',
37975 cls : 'input-group-addon btn dropdown-toggle',
37976 style : 'position: absolute; z-index: 4;background: none;border: none; margin-top: 4px; margin-left: 3px; margin-right: 3px;',
37982 cls: 'combobox-clear',
37993 combobox.cn.push(box);
37995 if (align ==='left' && this.fieldLabel.length) {
37997 cfg.cls += ' roo-form-group-label-left';
38002 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
38003 tooltip : 'This field is required'
38008 cls : 'control-label',
38009 html : this.fieldLabel
38020 var labelCfg = cfg.cn[1];
38021 var contentCfg = cfg.cn[2];
38023 if(this.indicatorpos == 'right'){
38028 cls : 'control-label',
38032 html : this.fieldLabel
38036 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
38037 tooltip : 'This field is required'
38050 labelCfg = cfg.cn[0];
38051 contentCfg = cfg.cn[1];
38054 if(this.labelWidth > 12){
38055 labelCfg.style = "width: " + this.labelWidth + 'px';
38058 if(this.labelWidth < 13 && this.labelmd == 0){
38059 this.labelmd = this.labelWidth;
38062 if(this.labellg > 0){
38063 labelCfg.cls += ' col-lg-' + this.labellg;
38064 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
38067 if(this.labelmd > 0){
38068 labelCfg.cls += ' col-md-' + this.labelmd;
38069 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
38072 if(this.labelsm > 0){
38073 labelCfg.cls += ' col-sm-' + this.labelsm;
38074 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
38077 if(this.labelxs > 0){
38078 labelCfg.cls += ' col-xs-' + this.labelxs;
38079 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
38082 } else if ( this.fieldLabel.length) {
38083 // Roo.log(" label");
38087 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
38088 tooltip : 'This field is required'
38092 //cls : 'input-group-addon',
38093 html : this.fieldLabel
38101 if(this.indicatorpos == 'right'){
38109 html : this.fieldLabel
38113 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
38114 tooltip : 'This field is required'
38126 ['xs','sm','md','lg'].map(function(size){
38127 if (settings[size]) {
38128 cfg.cls += ' col-' + size + '-' + settings[size];
38135 _initEventsCalled : false,
38137 initEvents: function()
38139 if (this._initEventsCalled) {
38143 this._initEventsCalled = true;
38145 this.store = new Roo.data.SimpleStore({
38147 fields : ['name','iso','dial_code','order','area_code']
38150 this.store = Roo.factory(this.store, Roo.data);
38151 this.store.parent = this;
38153 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
38158 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
38159 _this.list.setWidth(lw);
38162 this.list.on('mouseover', this.onViewOver, this);
38163 this.list.on('mousemove', this.onViewMove, this);
38164 this.list.on('scroll', this.onViewScroll, this);
38167 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
38170 this.view = new Roo.View(this.list, this.tpl, {
38171 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38173 this.view.on('click', this.onViewClick, this);
38175 this.store.on('beforeload', this.onBeforeLoad, this);
38176 this.store.on('load', this.onLoad, this);
38177 this.store.on('loadexception', this.onLoadException, this);
38179 this.keyNav = new Roo.KeyNav(this.inputEl(), {
38180 "up" : function(e){
38181 this.inKeyMode = true;
38185 "down" : function(e){
38186 if(!this.isExpanded()){
38187 this.onTriggerClick();
38189 this.inKeyMode = true;
38194 "enter" : function(e){
38195 // this.onViewClick();
38199 if(this.fireEvent("specialkey", this, e)){
38200 this.onViewClick(false);
38206 "esc" : function(e){
38210 "tab" : function(e){
38213 if(this.fireEvent("specialkey", this, e)){
38214 this.onViewClick(false);
38222 doRelay : function(foo, bar, hname){
38223 if(hname == 'down' || this.scope.isExpanded()){
38224 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38234 onViewOver : function(e, t){
38235 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38238 var item = this.view.findItemFromChild(t);
38241 var index = this.view.indexOf(item);
38242 this.select(index, false);
38246 onViewMove : function(e, t){
38247 this.inKeyMode = false;
38250 onViewScroll : function(e, t){
38252 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){
38256 this.hasQuery = true;
38258 this.loading = this.list.select('.loading', true).first();
38260 if(this.loading === null){
38261 this.list.createChild({
38263 cls: 'loading roo-select2-more-results roo-select2-active',
38264 html: 'Loading more results...'
38267 this.loading = this.list.select('.loading', true).first();
38269 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
38271 this.loading.hide();
38274 this.loading.show();
38279 this.loadNext = true;
38281 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
38288 Roo.apply(Roo.bootstrap.PhoneInput, {
38291 * iso2 and abbr for all countries
38295 ["Afghanistan (افغانستان)", "af", "93"],
38296 ["Albania (Shqipëri)", "al", "355"],
38297 ["Algeria (الجزائر)", "dz", "213"],
38298 ["American Samoa", "as", "1684"],
38299 ["Andorra", "ad", "376"],
38300 ["Angola", "ao", "244"],
38301 ["Anguilla", "ai", "1264"],
38302 ["Antigua and Barbuda", "ag", "1268"],
38303 ["Argentina", "ar", "54"],
38304 ["Armenia (Հայաստան)", "am", "374"],
38305 ["Aruba", "aw", "297"],
38306 ["Australia", "au", "61", 0],
38307 ["Austria (Österreich)", "at", "43"],
38308 ["Azerbaijan (Azərbaycan)", "az", "994"],
38309 ["Bahamas", "bs", "1242"],
38310 ["Bahrain (البحرين)", "bh", "973"],
38311 ["Bangladesh (বাংলাদেশ)", "bd", "880"],
38312 ["Barbados", "bb", "1246"],
38313 ["Belarus (Беларусь)", "by", "375"],
38314 ["Belgium (België)", "be", "32"],
38315 ["Belize", "bz", "501"],
38316 ["Benin (Bénin)", "bj", "229"],
38317 ["Bermuda", "bm", "1441"],
38318 ["Bhutan (འབྲུག)", "bt", "975"],
38319 ["Bolivia", "bo", "591"],
38320 ["Bosnia and Herzegovina (Босна и Херцеговина)", "ba", "387"],
38321 ["Botswana", "bw", "267"],
38322 ["Brazil (Brasil)", "br", "55"],
38323 ["British Indian Ocean Territory", "io", "246"],
38324 ["British Virgin Islands", "vg", "1284"],
38325 ["Brunei", "bn", "673"],
38326 ["Bulgaria (България)", "bg", "359"],
38327 ["Burkina Faso", "bf", "226"],
38328 ["Burundi (Uburundi)", "bi", "257"],
38329 ["Cambodia (កម្ពុជា)", "kh", "855"],
38330 ["Cameroon (Cameroun)", "cm", "237"],
38331 ["Canada", "ca", "1", 1, ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]],
38332 ["Cape Verde (Kabu Verdi)", "cv", "238"],
38333 ["Caribbean Netherlands", "bq", "599", 1],
38334 ["Cayman Islands", "ky", "1345"],
38335 ["Central African Republic (République centrafricaine)", "cf", "236"],
38336 ["Chad (Tchad)", "td", "235"],
38337 ["Chile", "cl", "56"],
38338 ["China (中国)", "cn", "86"],
38339 ["Christmas Island", "cx", "61", 2],
38340 ["Cocos (Keeling) Islands", "cc", "61", 1],
38341 ["Colombia", "co", "57"],
38342 ["Comoros (جزر القمر)", "km", "269"],
38343 ["Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)", "cd", "243"],
38344 ["Congo (Republic) (Congo-Brazzaville)", "cg", "242"],
38345 ["Cook Islands", "ck", "682"],
38346 ["Costa Rica", "cr", "506"],
38347 ["Côte d’Ivoire", "ci", "225"],
38348 ["Croatia (Hrvatska)", "hr", "385"],
38349 ["Cuba", "cu", "53"],
38350 ["Curaçao", "cw", "599", 0],
38351 ["Cyprus (Κύπρος)", "cy", "357"],
38352 ["Czech Republic (Česká republika)", "cz", "420"],
38353 ["Denmark (Danmark)", "dk", "45"],
38354 ["Djibouti", "dj", "253"],
38355 ["Dominica", "dm", "1767"],
38356 ["Dominican Republic (República Dominicana)", "do", "1", 2, ["809", "829", "849"]],
38357 ["Ecuador", "ec", "593"],
38358 ["Egypt (مصر)", "eg", "20"],
38359 ["El Salvador", "sv", "503"],
38360 ["Equatorial Guinea (Guinea Ecuatorial)", "gq", "240"],
38361 ["Eritrea", "er", "291"],
38362 ["Estonia (Eesti)", "ee", "372"],
38363 ["Ethiopia", "et", "251"],
38364 ["Falkland Islands (Islas Malvinas)", "fk", "500"],
38365 ["Faroe Islands (Føroyar)", "fo", "298"],
38366 ["Fiji", "fj", "679"],
38367 ["Finland (Suomi)", "fi", "358", 0],
38368 ["France", "fr", "33"],
38369 ["French Guiana (Guyane française)", "gf", "594"],
38370 ["French Polynesia (Polynésie française)", "pf", "689"],
38371 ["Gabon", "ga", "241"],
38372 ["Gambia", "gm", "220"],
38373 ["Georgia (საქართველო)", "ge", "995"],
38374 ["Germany (Deutschland)", "de", "49"],
38375 ["Ghana (Gaana)", "gh", "233"],
38376 ["Gibraltar", "gi", "350"],
38377 ["Greece (Ελλάδα)", "gr", "30"],
38378 ["Greenland (Kalaallit Nunaat)", "gl", "299"],
38379 ["Grenada", "gd", "1473"],
38380 ["Guadeloupe", "gp", "590", 0],
38381 ["Guam", "gu", "1671"],
38382 ["Guatemala", "gt", "502"],
38383 ["Guernsey", "gg", "44", 1],
38384 ["Guinea (Guinée)", "gn", "224"],
38385 ["Guinea-Bissau (Guiné Bissau)", "gw", "245"],
38386 ["Guyana", "gy", "592"],
38387 ["Haiti", "ht", "509"],
38388 ["Honduras", "hn", "504"],
38389 ["Hong Kong (香港)", "hk", "852"],
38390 ["Hungary (Magyarország)", "hu", "36"],
38391 ["Iceland (Ísland)", "is", "354"],
38392 ["India (भारत)", "in", "91"],
38393 ["Indonesia", "id", "62"],
38394 ["Iran (ایران)", "ir", "98"],
38395 ["Iraq (العراق)", "iq", "964"],
38396 ["Ireland", "ie", "353"],
38397 ["Isle of Man", "im", "44", 2],
38398 ["Israel (ישראל)", "il", "972"],
38399 ["Italy (Italia)", "it", "39", 0],
38400 ["Jamaica", "jm", "1876"],
38401 ["Japan (日本)", "jp", "81"],
38402 ["Jersey", "je", "44", 3],
38403 ["Jordan (الأردن)", "jo", "962"],
38404 ["Kazakhstan (Казахстан)", "kz", "7", 1],
38405 ["Kenya", "ke", "254"],
38406 ["Kiribati", "ki", "686"],
38407 ["Kosovo", "xk", "383"],
38408 ["Kuwait (الكويت)", "kw", "965"],
38409 ["Kyrgyzstan (Кыргызстан)", "kg", "996"],
38410 ["Laos (ລາວ)", "la", "856"],
38411 ["Latvia (Latvija)", "lv", "371"],
38412 ["Lebanon (لبنان)", "lb", "961"],
38413 ["Lesotho", "ls", "266"],
38414 ["Liberia", "lr", "231"],
38415 ["Libya (ليبيا)", "ly", "218"],
38416 ["Liechtenstein", "li", "423"],
38417 ["Lithuania (Lietuva)", "lt", "370"],
38418 ["Luxembourg", "lu", "352"],
38419 ["Macau (澳門)", "mo", "853"],
38420 ["Macedonia (FYROM) (Македонија)", "mk", "389"],
38421 ["Madagascar (Madagasikara)", "mg", "261"],
38422 ["Malawi", "mw", "265"],
38423 ["Malaysia", "my", "60"],
38424 ["Maldives", "mv", "960"],
38425 ["Mali", "ml", "223"],
38426 ["Malta", "mt", "356"],
38427 ["Marshall Islands", "mh", "692"],
38428 ["Martinique", "mq", "596"],
38429 ["Mauritania (موريتانيا)", "mr", "222"],
38430 ["Mauritius (Moris)", "mu", "230"],
38431 ["Mayotte", "yt", "262", 1],
38432 ["Mexico (México)", "mx", "52"],
38433 ["Micronesia", "fm", "691"],
38434 ["Moldova (Republica Moldova)", "md", "373"],
38435 ["Monaco", "mc", "377"],
38436 ["Mongolia (Монгол)", "mn", "976"],
38437 ["Montenegro (Crna Gora)", "me", "382"],
38438 ["Montserrat", "ms", "1664"],
38439 ["Morocco (المغرب)", "ma", "212", 0],
38440 ["Mozambique (Moçambique)", "mz", "258"],
38441 ["Myanmar (Burma) (မြန်မာ)", "mm", "95"],
38442 ["Namibia (Namibië)", "na", "264"],
38443 ["Nauru", "nr", "674"],
38444 ["Nepal (नेपाल)", "np", "977"],
38445 ["Netherlands (Nederland)", "nl", "31"],
38446 ["New Caledonia (Nouvelle-Calédonie)", "nc", "687"],
38447 ["New Zealand", "nz", "64"],
38448 ["Nicaragua", "ni", "505"],
38449 ["Niger (Nijar)", "ne", "227"],
38450 ["Nigeria", "ng", "234"],
38451 ["Niue", "nu", "683"],
38452 ["Norfolk Island", "nf", "672"],
38453 ["North Korea (조선 민주주의 인민 공화국)", "kp", "850"],
38454 ["Northern Mariana Islands", "mp", "1670"],
38455 ["Norway (Norge)", "no", "47", 0],
38456 ["Oman (عُمان)", "om", "968"],
38457 ["Pakistan (پاکستان)", "pk", "92"],
38458 ["Palau", "pw", "680"],
38459 ["Palestine (فلسطين)", "ps", "970"],
38460 ["Panama (Panamá)", "pa", "507"],
38461 ["Papua New Guinea", "pg", "675"],
38462 ["Paraguay", "py", "595"],
38463 ["Peru (Perú)", "pe", "51"],
38464 ["Philippines", "ph", "63"],
38465 ["Poland (Polska)", "pl", "48"],
38466 ["Portugal", "pt", "351"],
38467 ["Puerto Rico", "pr", "1", 3, ["787", "939"]],
38468 ["Qatar (قطر)", "qa", "974"],
38469 ["Réunion (La Réunion)", "re", "262", 0],
38470 ["Romania (România)", "ro", "40"],
38471 ["Russia (Россия)", "ru", "7", 0],
38472 ["Rwanda", "rw", "250"],
38473 ["Saint Barthélemy", "bl", "590", 1],
38474 ["Saint Helena", "sh", "290"],
38475 ["Saint Kitts and Nevis", "kn", "1869"],
38476 ["Saint Lucia", "lc", "1758"],
38477 ["Saint Martin (Saint-Martin (partie française))", "mf", "590", 2],
38478 ["Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)", "pm", "508"],
38479 ["Saint Vincent and the Grenadines", "vc", "1784"],
38480 ["Samoa", "ws", "685"],
38481 ["San Marino", "sm", "378"],
38482 ["São Tomé and Príncipe (São Tomé e Príncipe)", "st", "239"],
38483 ["Saudi Arabia (المملكة العربية السعودية)", "sa", "966"],
38484 ["Senegal (Sénégal)", "sn", "221"],
38485 ["Serbia (Србија)", "rs", "381"],
38486 ["Seychelles", "sc", "248"],
38487 ["Sierra Leone", "sl", "232"],
38488 ["Singapore", "sg", "65"],
38489 ["Sint Maarten", "sx", "1721"],
38490 ["Slovakia (Slovensko)", "sk", "421"],
38491 ["Slovenia (Slovenija)", "si", "386"],
38492 ["Solomon Islands", "sb", "677"],
38493 ["Somalia (Soomaaliya)", "so", "252"],
38494 ["South Africa", "za", "27"],
38495 ["South Korea (대한민국)", "kr", "82"],
38496 ["South Sudan (جنوب السودان)", "ss", "211"],
38497 ["Spain (España)", "es", "34"],
38498 ["Sri Lanka (ශ්රී ලංකාව)", "lk", "94"],
38499 ["Sudan (السودان)", "sd", "249"],
38500 ["Suriname", "sr", "597"],
38501 ["Svalbard and Jan Mayen", "sj", "47", 1],
38502 ["Swaziland", "sz", "268"],
38503 ["Sweden (Sverige)", "se", "46"],
38504 ["Switzerland (Schweiz)", "ch", "41"],
38505 ["Syria (سوريا)", "sy", "963"],
38506 ["Taiwan (台灣)", "tw", "886"],
38507 ["Tajikistan", "tj", "992"],
38508 ["Tanzania", "tz", "255"],
38509 ["Thailand (ไทย)", "th", "66"],
38510 ["Timor-Leste", "tl", "670"],
38511 ["Togo", "tg", "228"],
38512 ["Tokelau", "tk", "690"],
38513 ["Tonga", "to", "676"],
38514 ["Trinidad and Tobago", "tt", "1868"],
38515 ["Tunisia (تونس)", "tn", "216"],
38516 ["Turkey (Türkiye)", "tr", "90"],
38517 ["Turkmenistan", "tm", "993"],
38518 ["Turks and Caicos Islands", "tc", "1649"],
38519 ["Tuvalu", "tv", "688"],
38520 ["U.S. Virgin Islands", "vi", "1340"],
38521 ["Uganda", "ug", "256"],
38522 ["Ukraine (Україна)", "ua", "380"],
38523 ["United Arab Emirates (الإمارات العربية المتحدة)", "ae", "971"],
38524 ["United Kingdom", "gb", "44", 0],
38525 ["United States", "us", "1", 0],
38526 ["Uruguay", "uy", "598"],
38527 ["Uzbekistan (Oʻzbekiston)", "uz", "998"],
38528 ["Vanuatu", "vu", "678"],
38529 ["Vatican City (Città del Vaticano)", "va", "39", 1],
38530 ["Venezuela", "ve", "58"],
38531 ["Vietnam (Việt Nam)", "vn", "84"],
38532 ["Wallis and Futuna (Wallis-et-Futuna)", "wf", "681"],
38533 ["Western Sahara (الصحراء الغربية)", "eh", "212", 1],
38534 ["Yemen (اليمن)", "ye", "967"],
38535 ["Zambia", "zm", "260"],
38536 ["Zimbabwe", "zw", "263"],
38537 ["Åland Islands", "ax", "358", 1]