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++;
8121 this.maskEl.top.setStyle('position', 'fixed');
8122 this.maskEl.top.setStyle('z-index', zIndex);
8123 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8124 this.maskEl.top.setXY([0, 0]);
8125 this.maskEl.top.show();
8127 this.maskEl.left.setStyle('position', 'fixed');
8128 this.maskEl.left.setStyle('z-index', zIndex);
8129 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8130 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8131 this.maskEl.left.show();
8133 this.maskEl.bottom.setStyle('position', 'fixed');
8134 this.maskEl.bottom.setStyle('z-index', zIndex);
8135 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8136 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8137 this.maskEl.bottom.show();
8139 this.maskEl.right.setStyle('position', 'fixed');
8140 this.maskEl.right.setStyle('z-index', zIndex);
8141 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8142 this.maskEl.right.setXY([0, box.y - this.padding]);
8143 this.maskEl.right.show();
8146 this.toolTip.bindEl = this.target.el;
8148 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8150 var tip = this.target.blankText;
8152 if(this.target.getValue() !== '' && this.target.regexText.length){
8153 tip = this.target.regexText;
8156 this.toolTip.show(tip);
8158 this.intervalID = window.setInterval(function() {
8159 Roo.bootstrap.Form.popover.unmask();
8162 window.onwheel = function(){ return false;};
8164 (function(){ this.isMasked = true; }).defer(500, this);
8172 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8176 this.maskEl.top.setStyle('position', 'absolute');
8177 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8178 this.maskEl.top.hide();
8180 this.maskEl.left.setStyle('position', 'absolute');
8181 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8182 this.maskEl.left.hide();
8184 this.maskEl.bottom.setStyle('position', 'absolute');
8185 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8186 this.maskEl.bottom.hide();
8188 this.maskEl.right.setStyle('position', 'absolute');
8189 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8190 this.maskEl.right.hide();
8192 this.toolTip.hide();
8194 this.toolTip.el.hide();
8196 window.onwheel = function(){ return true;};
8198 if(this.intervalID){
8199 window.clearInterval(this.intervalID);
8200 this.intervalID = false;
8203 this.isMasked = false;
8213 * Ext JS Library 1.1.1
8214 * Copyright(c) 2006-2007, Ext JS, LLC.
8216 * Originally Released Under LGPL - original licence link has changed is not relivant.
8219 * <script type="text/javascript">
8222 * @class Roo.form.VTypes
8223 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8226 Roo.form.VTypes = function(){
8227 // closure these in so they are only created once.
8228 var alpha = /^[a-zA-Z_]+$/;
8229 var alphanum = /^[a-zA-Z0-9_]+$/;
8230 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8231 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8233 // All these messages and functions are configurable
8236 * The function used to validate email addresses
8237 * @param {String} value The email address
8239 'email' : function(v){
8240 return email.test(v);
8243 * The error text to display when the email validation function returns false
8246 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8248 * The keystroke filter mask to be applied on email input
8251 'emailMask' : /[a-z0-9_\.\-@]/i,
8254 * The function used to validate URLs
8255 * @param {String} value The URL
8257 'url' : function(v){
8261 * The error text to display when the url validation function returns false
8264 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8267 * The function used to validate alpha values
8268 * @param {String} value The value
8270 'alpha' : function(v){
8271 return alpha.test(v);
8274 * The error text to display when the alpha validation function returns false
8277 'alphaText' : 'This field should only contain letters and _',
8279 * The keystroke filter mask to be applied on alpha input
8282 'alphaMask' : /[a-z_]/i,
8285 * The function used to validate alphanumeric values
8286 * @param {String} value The value
8288 'alphanum' : function(v){
8289 return alphanum.test(v);
8292 * The error text to display when the alphanumeric validation function returns false
8295 'alphanumText' : 'This field should only contain letters, numbers and _',
8297 * The keystroke filter mask to be applied on alphanumeric input
8300 'alphanumMask' : /[a-z0-9_]/i
8310 * @class Roo.bootstrap.Input
8311 * @extends Roo.bootstrap.Component
8312 * Bootstrap Input class
8313 * @cfg {Boolean} disabled is it disabled
8314 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8315 * @cfg {String} name name of the input
8316 * @cfg {string} fieldLabel - the label associated
8317 * @cfg {string} placeholder - placeholder to put in text.
8318 * @cfg {string} before - input group add on before
8319 * @cfg {string} after - input group add on after
8320 * @cfg {string} size - (lg|sm) or leave empty..
8321 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8322 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8323 * @cfg {Number} md colspan out of 12 for computer-sized screens
8324 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8325 * @cfg {string} value default value of the input
8326 * @cfg {Number} labelWidth set the width of label
8327 * @cfg {Number} labellg set the width of label (1-12)
8328 * @cfg {Number} labelmd set the width of label (1-12)
8329 * @cfg {Number} labelsm set the width of label (1-12)
8330 * @cfg {Number} labelxs set the width of label (1-12)
8331 * @cfg {String} labelAlign (top|left)
8332 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8333 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8334 * @cfg {String} indicatorpos (left|right) default left
8336 * @cfg {String} align (left|center|right) Default left
8337 * @cfg {Boolean} forceFeedback (true|false) Default false
8343 * Create a new Input
8344 * @param {Object} config The config object
8347 Roo.bootstrap.Input = function(config){
8349 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8354 * Fires when this field receives input focus.
8355 * @param {Roo.form.Field} this
8360 * Fires when this field loses input focus.
8361 * @param {Roo.form.Field} this
8366 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8367 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8368 * @param {Roo.form.Field} this
8369 * @param {Roo.EventObject} e The event object
8374 * Fires just before the field blurs if the field value has changed.
8375 * @param {Roo.form.Field} this
8376 * @param {Mixed} newValue The new value
8377 * @param {Mixed} oldValue The original value
8382 * Fires after the field has been marked as invalid.
8383 * @param {Roo.form.Field} this
8384 * @param {String} msg The validation message
8389 * Fires after the field has been validated with no errors.
8390 * @param {Roo.form.Field} this
8395 * Fires after the key up
8396 * @param {Roo.form.Field} this
8397 * @param {Roo.EventObject} e The event Object
8403 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8405 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8406 automatic validation (defaults to "keyup").
8408 validationEvent : "keyup",
8410 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8412 validateOnBlur : true,
8414 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8416 validationDelay : 250,
8418 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8420 focusClass : "x-form-focus", // not needed???
8424 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8426 invalidClass : "has-warning",
8429 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8431 validClass : "has-success",
8434 * @cfg {Boolean} hasFeedback (true|false) default true
8439 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8441 invalidFeedbackClass : "glyphicon-warning-sign",
8444 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8446 validFeedbackClass : "glyphicon-ok",
8449 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8451 selectOnFocus : false,
8454 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8458 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8463 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8465 disableKeyFilter : false,
8468 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8472 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8476 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8478 blankText : "Please complete this mandatory field",
8481 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8485 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8487 maxLength : Number.MAX_VALUE,
8489 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8491 minLengthText : "The minimum length for this field is {0}",
8493 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8495 maxLengthText : "The maximum length for this field is {0}",
8499 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8500 * If available, this function will be called only after the basic validators all return true, and will be passed the
8501 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8505 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8506 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8507 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8511 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8515 autocomplete: false,
8534 formatedValue : false,
8535 forceFeedback : false,
8537 indicatorpos : 'left',
8544 parentLabelAlign : function()
8547 while (parent.parent()) {
8548 parent = parent.parent();
8549 if (typeof(parent.labelAlign) !='undefined') {
8550 return parent.labelAlign;
8557 getAutoCreate : function()
8559 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8565 if(this.inputType != 'hidden'){
8566 cfg.cls = 'form-group' //input-group
8572 type : this.inputType,
8574 cls : 'form-control',
8575 placeholder : this.placeholder || '',
8576 autocomplete : this.autocomplete || 'new-password'
8580 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8583 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8584 input.maxLength = this.maxLength;
8587 if (this.disabled) {
8588 input.disabled=true;
8591 if (this.readOnly) {
8592 input.readonly=true;
8596 input.name = this.name;
8600 input.cls += ' input-' + this.size;
8604 ['xs','sm','md','lg'].map(function(size){
8605 if (settings[size]) {
8606 cfg.cls += ' col-' + size + '-' + settings[size];
8610 var inputblock = input;
8614 cls: 'glyphicon form-control-feedback'
8617 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8620 cls : 'has-feedback',
8628 if (this.before || this.after) {
8631 cls : 'input-group',
8635 if (this.before && typeof(this.before) == 'string') {
8637 inputblock.cn.push({
8639 cls : 'roo-input-before input-group-addon',
8643 if (this.before && typeof(this.before) == 'object') {
8644 this.before = Roo.factory(this.before);
8646 inputblock.cn.push({
8648 cls : 'roo-input-before input-group-' +
8649 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8653 inputblock.cn.push(input);
8655 if (this.after && typeof(this.after) == 'string') {
8656 inputblock.cn.push({
8658 cls : 'roo-input-after input-group-addon',
8662 if (this.after && typeof(this.after) == 'object') {
8663 this.after = Roo.factory(this.after);
8665 inputblock.cn.push({
8667 cls : 'roo-input-after input-group-' +
8668 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8672 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8673 inputblock.cls += ' has-feedback';
8674 inputblock.cn.push(feedback);
8678 if (align ==='left' && this.fieldLabel.length) {
8680 cfg.cls += ' roo-form-group-label-left';
8685 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8686 tooltip : 'This field is required'
8691 cls : 'control-label',
8692 html : this.fieldLabel
8703 var labelCfg = cfg.cn[1];
8704 var contentCfg = cfg.cn[2];
8706 if(this.indicatorpos == 'right'){
8711 cls : 'control-label',
8712 html : this.fieldLabel
8717 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8718 tooltip : 'This field is required'
8729 labelCfg = cfg.cn[0];
8730 contentCfg = cfg.cn[2];
8734 if(this.labelWidth > 12){
8735 labelCfg.style = "width: " + this.labelWidth + 'px';
8738 if(this.labelWidth < 13 && this.labelmd == 0){
8739 this.labelmd = this.labelWidth;
8742 if(this.labellg > 0){
8743 labelCfg.cls += ' col-lg-' + this.labellg;
8744 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8747 if(this.labelmd > 0){
8748 labelCfg.cls += ' col-md-' + this.labelmd;
8749 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8752 if(this.labelsm > 0){
8753 labelCfg.cls += ' col-sm-' + this.labelsm;
8754 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8757 if(this.labelxs > 0){
8758 labelCfg.cls += ' col-xs-' + this.labelxs;
8759 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8763 } else if ( this.fieldLabel.length) {
8768 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8769 tooltip : 'This field is required'
8773 //cls : 'input-group-addon',
8774 html : this.fieldLabel
8782 if(this.indicatorpos == 'right'){
8787 //cls : 'input-group-addon',
8788 html : this.fieldLabel
8793 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8794 tooltip : 'This field is required'
8814 if (this.parentType === 'Navbar' && this.parent().bar) {
8815 cfg.cls += ' navbar-form';
8818 if (this.parentType === 'NavGroup') {
8819 cfg.cls += ' navbar-form';
8827 * return the real input element.
8829 inputEl: function ()
8831 return this.el.select('input.form-control',true).first();
8834 tooltipEl : function()
8836 return this.inputEl();
8839 indicatorEl : function()
8841 var indicator = this.el.select('i.roo-required-indicator',true).first();
8851 setDisabled : function(v)
8853 var i = this.inputEl().dom;
8855 i.removeAttribute('disabled');
8859 i.setAttribute('disabled','true');
8861 initEvents : function()
8864 this.inputEl().on("keydown" , this.fireKey, this);
8865 this.inputEl().on("focus", this.onFocus, this);
8866 this.inputEl().on("blur", this.onBlur, this);
8868 this.inputEl().relayEvent('keyup', this);
8870 this.indicator = this.indicatorEl();
8873 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8874 this.indicator.hide();
8877 // reference to original value for reset
8878 this.originalValue = this.getValue();
8879 //Roo.form.TextField.superclass.initEvents.call(this);
8880 if(this.validationEvent == 'keyup'){
8881 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8882 this.inputEl().on('keyup', this.filterValidation, this);
8884 else if(this.validationEvent !== false){
8885 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8888 if(this.selectOnFocus){
8889 this.on("focus", this.preFocus, this);
8892 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8893 this.inputEl().on("keypress", this.filterKeys, this);
8895 this.inputEl().relayEvent('keypress', this);
8898 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8899 this.el.on("click", this.autoSize, this);
8902 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8903 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8906 if (typeof(this.before) == 'object') {
8907 this.before.render(this.el.select('.roo-input-before',true).first());
8909 if (typeof(this.after) == 'object') {
8910 this.after.render(this.el.select('.roo-input-after',true).first());
8915 filterValidation : function(e){
8916 if(!e.isNavKeyPress()){
8917 this.validationTask.delay(this.validationDelay);
8921 * Validates the field value
8922 * @return {Boolean} True if the value is valid, else false
8924 validate : function(){
8925 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8926 if(this.disabled || this.validateValue(this.getRawValue())){
8937 * Validates a value according to the field's validation rules and marks the field as invalid
8938 * if the validation fails
8939 * @param {Mixed} value The value to validate
8940 * @return {Boolean} True if the value is valid, else false
8942 validateValue : function(value){
8943 if(value.length < 1) { // if it's blank
8944 if(this.allowBlank){
8947 return this.inputEl().hasClass('hide') ? true : false;
8950 if(value.length < this.minLength){
8953 if(value.length > this.maxLength){
8957 var vt = Roo.form.VTypes;
8958 if(!vt[this.vtype](value, this)){
8962 if(typeof this.validator == "function"){
8963 var msg = this.validator(value);
8969 if(this.regex && !this.regex.test(value)){
8979 fireKey : function(e){
8980 //Roo.log('field ' + e.getKey());
8981 if(e.isNavKeyPress()){
8982 this.fireEvent("specialkey", this, e);
8985 focus : function (selectText){
8987 this.inputEl().focus();
8988 if(selectText === true){
8989 this.inputEl().dom.select();
8995 onFocus : function(){
8996 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8997 // this.el.addClass(this.focusClass);
9000 this.hasFocus = true;
9001 this.startValue = this.getValue();
9002 this.fireEvent("focus", this);
9006 beforeBlur : Roo.emptyFn,
9010 onBlur : function(){
9012 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9013 //this.el.removeClass(this.focusClass);
9015 this.hasFocus = false;
9016 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9019 var v = this.getValue();
9020 if(String(v) !== String(this.startValue)){
9021 this.fireEvent('change', this, v, this.startValue);
9023 this.fireEvent("blur", this);
9027 * Resets the current field value to the originally loaded value and clears any validation messages
9030 this.setValue(this.originalValue);
9034 * Returns the name of the field
9035 * @return {Mixed} name The name field
9037 getName: function(){
9041 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9042 * @return {Mixed} value The field value
9044 getValue : function(){
9046 var v = this.inputEl().getValue();
9051 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9052 * @return {Mixed} value The field value
9054 getRawValue : function(){
9055 var v = this.inputEl().getValue();
9061 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9062 * @param {Mixed} value The value to set
9064 setRawValue : function(v){
9065 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9068 selectText : function(start, end){
9069 var v = this.getRawValue();
9071 start = start === undefined ? 0 : start;
9072 end = end === undefined ? v.length : end;
9073 var d = this.inputEl().dom;
9074 if(d.setSelectionRange){
9075 d.setSelectionRange(start, end);
9076 }else if(d.createTextRange){
9077 var range = d.createTextRange();
9078 range.moveStart("character", start);
9079 range.moveEnd("character", v.length-end);
9086 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9087 * @param {Mixed} value The value to set
9089 setValue : function(v){
9092 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9098 processValue : function(value){
9099 if(this.stripCharsRe){
9100 var newValue = value.replace(this.stripCharsRe, '');
9101 if(newValue !== value){
9102 this.setRawValue(newValue);
9109 preFocus : function(){
9111 if(this.selectOnFocus){
9112 this.inputEl().dom.select();
9115 filterKeys : function(e){
9117 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9120 var c = e.getCharCode(), cc = String.fromCharCode(c);
9121 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9124 if(!this.maskRe.test(cc)){
9129 * Clear any invalid styles/messages for this field
9131 clearInvalid : function(){
9133 if(!this.el || this.preventMark){ // not rendered
9138 this.el.removeClass(this.invalidClass);
9140 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9142 var feedback = this.el.select('.form-control-feedback', true).first();
9145 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9150 this.fireEvent('valid', this);
9154 * Mark this field as valid
9156 markValid : function()
9158 if(!this.el || this.preventMark){ // not rendered...
9162 this.el.removeClass([this.invalidClass, this.validClass]);
9164 var feedback = this.el.select('.form-control-feedback', true).first();
9167 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9174 if(this.allowBlank && !this.getRawValue().length){
9179 this.indicator.hide();
9182 this.el.addClass(this.validClass);
9184 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9186 var feedback = this.el.select('.form-control-feedback', true).first();
9189 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9190 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9195 this.fireEvent('valid', this);
9199 * Mark this field as invalid
9200 * @param {String} msg The validation message
9202 markInvalid : function(msg)
9204 if(!this.el || this.preventMark){ // not rendered
9208 this.el.removeClass([this.invalidClass, this.validClass]);
9210 var feedback = this.el.select('.form-control-feedback', true).first();
9213 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9220 if(this.allowBlank && !this.getRawValue().length){
9225 this.indicator.show();
9228 this.el.addClass(this.invalidClass);
9230 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9232 var feedback = this.el.select('.form-control-feedback', true).first();
9235 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9237 if(this.getValue().length || this.forceFeedback){
9238 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9245 this.fireEvent('invalid', this, msg);
9248 SafariOnKeyDown : function(event)
9250 // this is a workaround for a password hang bug on chrome/ webkit.
9251 if (this.inputEl().dom.type != 'password') {
9255 var isSelectAll = false;
9257 if(this.inputEl().dom.selectionEnd > 0){
9258 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9260 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9261 event.preventDefault();
9266 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9268 event.preventDefault();
9269 // this is very hacky as keydown always get's upper case.
9271 var cc = String.fromCharCode(event.getCharCode());
9272 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9276 adjustWidth : function(tag, w){
9277 tag = tag.toLowerCase();
9278 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9279 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9283 if(tag == 'textarea'){
9286 }else if(Roo.isOpera){
9290 if(tag == 'textarea'){
9309 * @class Roo.bootstrap.TextArea
9310 * @extends Roo.bootstrap.Input
9311 * Bootstrap TextArea class
9312 * @cfg {Number} cols Specifies the visible width of a text area
9313 * @cfg {Number} rows Specifies the visible number of lines in a text area
9314 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9315 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9316 * @cfg {string} html text
9319 * Create a new TextArea
9320 * @param {Object} config The config object
9323 Roo.bootstrap.TextArea = function(config){
9324 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9328 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9338 getAutoCreate : function(){
9340 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9351 value : this.value || '',
9352 html: this.html || '',
9353 cls : 'form-control',
9354 placeholder : this.placeholder || ''
9358 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9359 input.maxLength = this.maxLength;
9363 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9367 input.cols = this.cols;
9370 if (this.readOnly) {
9371 input.readonly = true;
9375 input.name = this.name;
9379 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9383 ['xs','sm','md','lg'].map(function(size){
9384 if (settings[size]) {
9385 cfg.cls += ' col-' + size + '-' + settings[size];
9389 var inputblock = input;
9391 if(this.hasFeedback && !this.allowBlank){
9395 cls: 'glyphicon form-control-feedback'
9399 cls : 'has-feedback',
9408 if (this.before || this.after) {
9411 cls : 'input-group',
9415 inputblock.cn.push({
9417 cls : 'input-group-addon',
9422 inputblock.cn.push(input);
9424 if(this.hasFeedback && !this.allowBlank){
9425 inputblock.cls += ' has-feedback';
9426 inputblock.cn.push(feedback);
9430 inputblock.cn.push({
9432 cls : 'input-group-addon',
9439 if (align ==='left' && this.fieldLabel.length) {
9444 cls : 'control-label',
9445 html : this.fieldLabel
9456 if(this.labelWidth > 12){
9457 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9460 if(this.labelWidth < 13 && this.labelmd == 0){
9461 this.labelmd = this.labelWidth;
9464 if(this.labellg > 0){
9465 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9466 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9469 if(this.labelmd > 0){
9470 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9471 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9474 if(this.labelsm > 0){
9475 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9476 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9479 if(this.labelxs > 0){
9480 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9481 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9484 } else if ( this.fieldLabel.length) {
9489 //cls : 'input-group-addon',
9490 html : this.fieldLabel
9508 if (this.disabled) {
9509 input.disabled=true;
9516 * return the real textarea element.
9518 inputEl: function ()
9520 return this.el.select('textarea.form-control',true).first();
9524 * Clear any invalid styles/messages for this field
9526 clearInvalid : function()
9529 if(!this.el || this.preventMark){ // not rendered
9533 var label = this.el.select('label', true).first();
9534 var icon = this.el.select('i.fa-star', true).first();
9540 this.el.removeClass(this.invalidClass);
9542 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9544 var feedback = this.el.select('.form-control-feedback', true).first();
9547 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9552 this.fireEvent('valid', this);
9556 * Mark this field as valid
9558 markValid : function()
9560 if(!this.el || this.preventMark){ // not rendered
9564 this.el.removeClass([this.invalidClass, this.validClass]);
9566 var feedback = this.el.select('.form-control-feedback', true).first();
9569 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9572 if(this.disabled || this.allowBlank){
9576 var label = this.el.select('label', true).first();
9577 var icon = this.el.select('i.fa-star', true).first();
9583 this.el.addClass(this.validClass);
9585 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9587 var feedback = this.el.select('.form-control-feedback', true).first();
9590 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9591 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9596 this.fireEvent('valid', this);
9600 * Mark this field as invalid
9601 * @param {String} msg The validation message
9603 markInvalid : function(msg)
9605 if(!this.el || this.preventMark){ // not rendered
9609 this.el.removeClass([this.invalidClass, this.validClass]);
9611 var feedback = this.el.select('.form-control-feedback', true).first();
9614 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9617 if(this.disabled || this.allowBlank){
9621 var label = this.el.select('label', true).first();
9622 var icon = this.el.select('i.fa-star', true).first();
9624 if(!this.getValue().length && label && !icon){
9625 this.el.createChild({
9627 cls : 'text-danger fa fa-lg fa-star',
9628 tooltip : 'This field is required',
9629 style : 'margin-right:5px;'
9633 this.el.addClass(this.invalidClass);
9635 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9637 var feedback = this.el.select('.form-control-feedback', true).first();
9640 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9642 if(this.getValue().length || this.forceFeedback){
9643 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9650 this.fireEvent('invalid', this, msg);
9658 * trigger field - base class for combo..
9663 * @class Roo.bootstrap.TriggerField
9664 * @extends Roo.bootstrap.Input
9665 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9666 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9667 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9668 * for which you can provide a custom implementation. For example:
9670 var trigger = new Roo.bootstrap.TriggerField();
9671 trigger.onTriggerClick = myTriggerFn;
9672 trigger.applyTo('my-field');
9675 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9676 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9677 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9678 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9679 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9682 * Create a new TriggerField.
9683 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9684 * to the base TextField)
9686 Roo.bootstrap.TriggerField = function(config){
9687 this.mimicing = false;
9688 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9691 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9693 * @cfg {String} triggerClass A CSS class to apply to the trigger
9696 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9701 * @cfg {Boolean} removable (true|false) special filter default false
9705 /** @cfg {Boolean} grow @hide */
9706 /** @cfg {Number} growMin @hide */
9707 /** @cfg {Number} growMax @hide */
9713 autoSize: Roo.emptyFn,
9720 actionMode : 'wrap',
9725 getAutoCreate : function(){
9727 var align = this.labelAlign || this.parentLabelAlign();
9732 cls: 'form-group' //input-group
9739 type : this.inputType,
9740 cls : 'form-control',
9741 autocomplete: 'new-password',
9742 placeholder : this.placeholder || ''
9746 input.name = this.name;
9749 input.cls += ' input-' + this.size;
9752 if (this.disabled) {
9753 input.disabled=true;
9756 var inputblock = input;
9758 if(this.hasFeedback && !this.allowBlank){
9762 cls: 'glyphicon form-control-feedback'
9765 if(this.removable && !this.editable && !this.tickable){
9767 cls : 'has-feedback',
9773 cls : 'roo-combo-removable-btn close'
9780 cls : 'has-feedback',
9789 if(this.removable && !this.editable && !this.tickable){
9791 cls : 'roo-removable',
9797 cls : 'roo-combo-removable-btn close'
9804 if (this.before || this.after) {
9807 cls : 'input-group',
9811 inputblock.cn.push({
9813 cls : 'input-group-addon',
9818 inputblock.cn.push(input);
9820 if(this.hasFeedback && !this.allowBlank){
9821 inputblock.cls += ' has-feedback';
9822 inputblock.cn.push(feedback);
9826 inputblock.cn.push({
9828 cls : 'input-group-addon',
9841 cls: 'form-hidden-field'
9855 cls: 'form-hidden-field'
9859 cls: 'roo-select2-choices',
9863 cls: 'roo-select2-search-field',
9876 cls: 'roo-select2-container input-group',
9881 // cls: 'typeahead typeahead-long dropdown-menu',
9882 // style: 'display:none'
9887 if(!this.multiple && this.showToggleBtn){
9893 if (this.caret != false) {
9896 cls: 'fa fa-' + this.caret
9903 cls : 'input-group-addon btn dropdown-toggle',
9908 cls: 'combobox-clear',
9922 combobox.cls += ' roo-select2-container-multi';
9925 if (align ==='left' && this.fieldLabel.length) {
9927 cfg.cls += ' roo-form-group-label-left';
9932 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9933 tooltip : 'This field is required'
9938 cls : 'control-label',
9939 html : this.fieldLabel
9951 var labelCfg = cfg.cn[1];
9952 var contentCfg = cfg.cn[2];
9954 if(this.indicatorpos == 'right'){
9959 cls : 'control-label',
9963 html : this.fieldLabel
9967 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9968 tooltip : 'This field is required'
9981 labelCfg = cfg.cn[0];
9982 contentCfg = cfg.cn[1];
9985 if(this.labelWidth > 12){
9986 labelCfg.style = "width: " + this.labelWidth + 'px';
9989 if(this.labelWidth < 13 && this.labelmd == 0){
9990 this.labelmd = this.labelWidth;
9993 if(this.labellg > 0){
9994 labelCfg.cls += ' col-lg-' + this.labellg;
9995 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9998 if(this.labelmd > 0){
9999 labelCfg.cls += ' col-md-' + this.labelmd;
10000 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10003 if(this.labelsm > 0){
10004 labelCfg.cls += ' col-sm-' + this.labelsm;
10005 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10008 if(this.labelxs > 0){
10009 labelCfg.cls += ' col-xs-' + this.labelxs;
10010 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10013 } else if ( this.fieldLabel.length) {
10014 // Roo.log(" label");
10018 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10019 tooltip : 'This field is required'
10023 //cls : 'input-group-addon',
10024 html : this.fieldLabel
10032 if(this.indicatorpos == 'right'){
10040 html : this.fieldLabel
10044 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10045 tooltip : 'This field is required'
10058 // Roo.log(" no label && no align");
10065 ['xs','sm','md','lg'].map(function(size){
10066 if (settings[size]) {
10067 cfg.cls += ' col-' + size + '-' + settings[size];
10078 onResize : function(w, h){
10079 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10080 // if(typeof w == 'number'){
10081 // var x = w - this.trigger.getWidth();
10082 // this.inputEl().setWidth(this.adjustWidth('input', x));
10083 // this.trigger.setStyle('left', x+'px');
10088 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10091 getResizeEl : function(){
10092 return this.inputEl();
10096 getPositionEl : function(){
10097 return this.inputEl();
10101 alignErrorIcon : function(){
10102 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10106 initEvents : function(){
10110 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10111 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10112 if(!this.multiple && this.showToggleBtn){
10113 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10114 if(this.hideTrigger){
10115 this.trigger.setDisplayed(false);
10117 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10121 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10124 if(this.removable && !this.editable && !this.tickable){
10125 var close = this.closeTriggerEl();
10128 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10129 close.on('click', this.removeBtnClick, this, close);
10133 //this.trigger.addClassOnOver('x-form-trigger-over');
10134 //this.trigger.addClassOnClick('x-form-trigger-click');
10137 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10141 closeTriggerEl : function()
10143 var close = this.el.select('.roo-combo-removable-btn', true).first();
10144 return close ? close : false;
10147 removeBtnClick : function(e, h, el)
10149 e.preventDefault();
10151 if(this.fireEvent("remove", this) !== false){
10153 this.fireEvent("afterremove", this)
10157 createList : function()
10159 this.list = Roo.get(document.body).createChild({
10161 cls: 'typeahead typeahead-long dropdown-menu',
10162 style: 'display:none'
10165 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10170 initTrigger : function(){
10175 onDestroy : function(){
10177 this.trigger.removeAllListeners();
10178 // this.trigger.remove();
10181 // this.wrap.remove();
10183 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10187 onFocus : function(){
10188 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10190 if(!this.mimicing){
10191 this.wrap.addClass('x-trigger-wrap-focus');
10192 this.mimicing = true;
10193 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10194 if(this.monitorTab){
10195 this.el.on("keydown", this.checkTab, this);
10202 checkTab : function(e){
10203 if(e.getKey() == e.TAB){
10204 this.triggerBlur();
10209 onBlur : function(){
10214 mimicBlur : function(e, t){
10216 if(!this.wrap.contains(t) && this.validateBlur()){
10217 this.triggerBlur();
10223 triggerBlur : function(){
10224 this.mimicing = false;
10225 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10226 if(this.monitorTab){
10227 this.el.un("keydown", this.checkTab, this);
10229 //this.wrap.removeClass('x-trigger-wrap-focus');
10230 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10234 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10235 validateBlur : function(e, t){
10240 onDisable : function(){
10241 this.inputEl().dom.disabled = true;
10242 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10244 // this.wrap.addClass('x-item-disabled');
10249 onEnable : function(){
10250 this.inputEl().dom.disabled = false;
10251 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10253 // this.el.removeClass('x-item-disabled');
10258 onShow : function(){
10259 var ae = this.getActionEl();
10262 ae.dom.style.display = '';
10263 ae.dom.style.visibility = 'visible';
10269 onHide : function(){
10270 var ae = this.getActionEl();
10271 ae.dom.style.display = 'none';
10275 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10276 * by an implementing function.
10278 * @param {EventObject} e
10280 onTriggerClick : Roo.emptyFn
10284 * Ext JS Library 1.1.1
10285 * Copyright(c) 2006-2007, Ext JS, LLC.
10287 * Originally Released Under LGPL - original licence link has changed is not relivant.
10290 * <script type="text/javascript">
10295 * @class Roo.data.SortTypes
10297 * Defines the default sorting (casting?) comparison functions used when sorting data.
10299 Roo.data.SortTypes = {
10301 * Default sort that does nothing
10302 * @param {Mixed} s The value being converted
10303 * @return {Mixed} The comparison value
10305 none : function(s){
10310 * The regular expression used to strip tags
10314 stripTagsRE : /<\/?[^>]+>/gi,
10317 * Strips all HTML tags to sort on text only
10318 * @param {Mixed} s The value being converted
10319 * @return {String} The comparison value
10321 asText : function(s){
10322 return String(s).replace(this.stripTagsRE, "");
10326 * Strips all HTML tags to sort on text only - Case insensitive
10327 * @param {Mixed} s The value being converted
10328 * @return {String} The comparison value
10330 asUCText : function(s){
10331 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10335 * Case insensitive string
10336 * @param {Mixed} s The value being converted
10337 * @return {String} The comparison value
10339 asUCString : function(s) {
10340 return String(s).toUpperCase();
10345 * @param {Mixed} s The value being converted
10346 * @return {Number} The comparison value
10348 asDate : function(s) {
10352 if(s instanceof Date){
10353 return s.getTime();
10355 return Date.parse(String(s));
10360 * @param {Mixed} s The value being converted
10361 * @return {Float} The comparison value
10363 asFloat : function(s) {
10364 var val = parseFloat(String(s).replace(/,/g, ""));
10373 * @param {Mixed} s The value being converted
10374 * @return {Number} The comparison value
10376 asInt : function(s) {
10377 var val = parseInt(String(s).replace(/,/g, ""));
10385 * Ext JS Library 1.1.1
10386 * Copyright(c) 2006-2007, Ext JS, LLC.
10388 * Originally Released Under LGPL - original licence link has changed is not relivant.
10391 * <script type="text/javascript">
10395 * @class Roo.data.Record
10396 * Instances of this class encapsulate both record <em>definition</em> information, and record
10397 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10398 * to access Records cached in an {@link Roo.data.Store} object.<br>
10400 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10401 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10404 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10406 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10407 * {@link #create}. The parameters are the same.
10408 * @param {Array} data An associative Array of data values keyed by the field name.
10409 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10410 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10411 * not specified an integer id is generated.
10413 Roo.data.Record = function(data, id){
10414 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10419 * Generate a constructor for a specific record layout.
10420 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10421 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10422 * Each field definition object may contain the following properties: <ul>
10423 * <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,
10424 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10425 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10426 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10427 * is being used, then this is a string containing the javascript expression to reference the data relative to
10428 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10429 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10430 * this may be omitted.</p></li>
10431 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10432 * <ul><li>auto (Default, implies no conversion)</li>
10437 * <li>date</li></ul></p></li>
10438 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10439 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10440 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10441 * by the Reader into an object that will be stored in the Record. It is passed the
10442 * following parameters:<ul>
10443 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10445 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10447 * <br>usage:<br><pre><code>
10448 var TopicRecord = Roo.data.Record.create(
10449 {name: 'title', mapping: 'topic_title'},
10450 {name: 'author', mapping: 'username'},
10451 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10452 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10453 {name: 'lastPoster', mapping: 'user2'},
10454 {name: 'excerpt', mapping: 'post_text'}
10457 var myNewRecord = new TopicRecord({
10458 title: 'Do my job please',
10461 lastPost: new Date(),
10462 lastPoster: 'Animal',
10463 excerpt: 'No way dude!'
10465 myStore.add(myNewRecord);
10470 Roo.data.Record.create = function(o){
10471 var f = function(){
10472 f.superclass.constructor.apply(this, arguments);
10474 Roo.extend(f, Roo.data.Record);
10475 var p = f.prototype;
10476 p.fields = new Roo.util.MixedCollection(false, function(field){
10479 for(var i = 0, len = o.length; i < len; i++){
10480 p.fields.add(new Roo.data.Field(o[i]));
10482 f.getField = function(name){
10483 return p.fields.get(name);
10488 Roo.data.Record.AUTO_ID = 1000;
10489 Roo.data.Record.EDIT = 'edit';
10490 Roo.data.Record.REJECT = 'reject';
10491 Roo.data.Record.COMMIT = 'commit';
10493 Roo.data.Record.prototype = {
10495 * Readonly flag - true if this record has been modified.
10504 join : function(store){
10505 this.store = store;
10509 * Set the named field to the specified value.
10510 * @param {String} name The name of the field to set.
10511 * @param {Object} value The value to set the field to.
10513 set : function(name, value){
10514 if(this.data[name] == value){
10518 if(!this.modified){
10519 this.modified = {};
10521 if(typeof this.modified[name] == 'undefined'){
10522 this.modified[name] = this.data[name];
10524 this.data[name] = value;
10525 if(!this.editing && this.store){
10526 this.store.afterEdit(this);
10531 * Get the value of the named field.
10532 * @param {String} name The name of the field to get the value of.
10533 * @return {Object} The value of the field.
10535 get : function(name){
10536 return this.data[name];
10540 beginEdit : function(){
10541 this.editing = true;
10542 this.modified = {};
10546 cancelEdit : function(){
10547 this.editing = false;
10548 delete this.modified;
10552 endEdit : function(){
10553 this.editing = false;
10554 if(this.dirty && this.store){
10555 this.store.afterEdit(this);
10560 * Usually called by the {@link Roo.data.Store} which owns the Record.
10561 * Rejects all changes made to the Record since either creation, or the last commit operation.
10562 * Modified fields are reverted to their original values.
10564 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10565 * of reject operations.
10567 reject : function(){
10568 var m = this.modified;
10570 if(typeof m[n] != "function"){
10571 this.data[n] = m[n];
10574 this.dirty = false;
10575 delete this.modified;
10576 this.editing = false;
10578 this.store.afterReject(this);
10583 * Usually called by the {@link Roo.data.Store} which owns the Record.
10584 * Commits all changes made to the Record since either creation, or the last commit operation.
10586 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10587 * of commit operations.
10589 commit : function(){
10590 this.dirty = false;
10591 delete this.modified;
10592 this.editing = false;
10594 this.store.afterCommit(this);
10599 hasError : function(){
10600 return this.error != null;
10604 clearError : function(){
10609 * Creates a copy of this record.
10610 * @param {String} id (optional) A new record id if you don't want to use this record's id
10613 copy : function(newId) {
10614 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10618 * Ext JS Library 1.1.1
10619 * Copyright(c) 2006-2007, Ext JS, LLC.
10621 * Originally Released Under LGPL - original licence link has changed is not relivant.
10624 * <script type="text/javascript">
10630 * @class Roo.data.Store
10631 * @extends Roo.util.Observable
10632 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10633 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10635 * 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
10636 * has no knowledge of the format of the data returned by the Proxy.<br>
10638 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10639 * instances from the data object. These records are cached and made available through accessor functions.
10641 * Creates a new Store.
10642 * @param {Object} config A config object containing the objects needed for the Store to access data,
10643 * and read the data into Records.
10645 Roo.data.Store = function(config){
10646 this.data = new Roo.util.MixedCollection(false);
10647 this.data.getKey = function(o){
10650 this.baseParams = {};
10652 this.paramNames = {
10657 "multisort" : "_multisort"
10660 if(config && config.data){
10661 this.inlineData = config.data;
10662 delete config.data;
10665 Roo.apply(this, config);
10667 if(this.reader){ // reader passed
10668 this.reader = Roo.factory(this.reader, Roo.data);
10669 this.reader.xmodule = this.xmodule || false;
10670 if(!this.recordType){
10671 this.recordType = this.reader.recordType;
10673 if(this.reader.onMetaChange){
10674 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10678 if(this.recordType){
10679 this.fields = this.recordType.prototype.fields;
10681 this.modified = [];
10685 * @event datachanged
10686 * Fires when the data cache has changed, and a widget which is using this Store
10687 * as a Record cache should refresh its view.
10688 * @param {Store} this
10690 datachanged : true,
10692 * @event metachange
10693 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10694 * @param {Store} this
10695 * @param {Object} meta The JSON metadata
10700 * Fires when Records have been added to the Store
10701 * @param {Store} this
10702 * @param {Roo.data.Record[]} records The array of Records added
10703 * @param {Number} index The index at which the record(s) were added
10708 * Fires when a Record has been removed from the Store
10709 * @param {Store} this
10710 * @param {Roo.data.Record} record The Record that was removed
10711 * @param {Number} index The index at which the record was removed
10716 * Fires when a Record has been updated
10717 * @param {Store} this
10718 * @param {Roo.data.Record} record The Record that was updated
10719 * @param {String} operation The update operation being performed. Value may be one of:
10721 Roo.data.Record.EDIT
10722 Roo.data.Record.REJECT
10723 Roo.data.Record.COMMIT
10729 * Fires when the data cache has been cleared.
10730 * @param {Store} this
10734 * @event beforeload
10735 * Fires before a request is made for a new data object. If the beforeload handler returns false
10736 * the load action will be canceled.
10737 * @param {Store} this
10738 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10742 * @event beforeloadadd
10743 * Fires after a new set of Records has been loaded.
10744 * @param {Store} this
10745 * @param {Roo.data.Record[]} records The Records that were loaded
10746 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10748 beforeloadadd : true,
10751 * Fires after a new set of Records has been loaded, before they are added to the store.
10752 * @param {Store} this
10753 * @param {Roo.data.Record[]} records The Records that were loaded
10754 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10755 * @params {Object} return from reader
10759 * @event loadexception
10760 * Fires if an exception occurs in the Proxy during loading.
10761 * Called with the signature of the Proxy's "loadexception" event.
10762 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10765 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10766 * @param {Object} load options
10767 * @param {Object} jsonData from your request (normally this contains the Exception)
10769 loadexception : true
10773 this.proxy = Roo.factory(this.proxy, Roo.data);
10774 this.proxy.xmodule = this.xmodule || false;
10775 this.relayEvents(this.proxy, ["loadexception"]);
10777 this.sortToggle = {};
10778 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10780 Roo.data.Store.superclass.constructor.call(this);
10782 if(this.inlineData){
10783 this.loadData(this.inlineData);
10784 delete this.inlineData;
10788 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10790 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10791 * without a remote query - used by combo/forms at present.
10795 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10798 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10801 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10802 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10805 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10806 * on any HTTP request
10809 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10812 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10816 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10817 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10819 remoteSort : false,
10822 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10823 * loaded or when a record is removed. (defaults to false).
10825 pruneModifiedRecords : false,
10828 lastOptions : null,
10831 * Add Records to the Store and fires the add event.
10832 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10834 add : function(records){
10835 records = [].concat(records);
10836 for(var i = 0, len = records.length; i < len; i++){
10837 records[i].join(this);
10839 var index = this.data.length;
10840 this.data.addAll(records);
10841 this.fireEvent("add", this, records, index);
10845 * Remove a Record from the Store and fires the remove event.
10846 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10848 remove : function(record){
10849 var index = this.data.indexOf(record);
10850 this.data.removeAt(index);
10851 if(this.pruneModifiedRecords){
10852 this.modified.remove(record);
10854 this.fireEvent("remove", this, record, index);
10858 * Remove all Records from the Store and fires the clear event.
10860 removeAll : function(){
10862 if(this.pruneModifiedRecords){
10863 this.modified = [];
10865 this.fireEvent("clear", this);
10869 * Inserts Records to the Store at the given index and fires the add event.
10870 * @param {Number} index The start index at which to insert the passed Records.
10871 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10873 insert : function(index, records){
10874 records = [].concat(records);
10875 for(var i = 0, len = records.length; i < len; i++){
10876 this.data.insert(index, records[i]);
10877 records[i].join(this);
10879 this.fireEvent("add", this, records, index);
10883 * Get the index within the cache of the passed Record.
10884 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10885 * @return {Number} The index of the passed Record. Returns -1 if not found.
10887 indexOf : function(record){
10888 return this.data.indexOf(record);
10892 * Get the index within the cache of the Record with the passed id.
10893 * @param {String} id The id of the Record to find.
10894 * @return {Number} The index of the Record. Returns -1 if not found.
10896 indexOfId : function(id){
10897 return this.data.indexOfKey(id);
10901 * Get the Record with the specified id.
10902 * @param {String} id The id of the Record to find.
10903 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10905 getById : function(id){
10906 return this.data.key(id);
10910 * Get the Record at the specified index.
10911 * @param {Number} index The index of the Record to find.
10912 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10914 getAt : function(index){
10915 return this.data.itemAt(index);
10919 * Returns a range of Records between specified indices.
10920 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10921 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10922 * @return {Roo.data.Record[]} An array of Records
10924 getRange : function(start, end){
10925 return this.data.getRange(start, end);
10929 storeOptions : function(o){
10930 o = Roo.apply({}, o);
10933 this.lastOptions = o;
10937 * Loads the Record cache from the configured Proxy using the configured Reader.
10939 * If using remote paging, then the first load call must specify the <em>start</em>
10940 * and <em>limit</em> properties in the options.params property to establish the initial
10941 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10943 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10944 * and this call will return before the new data has been loaded. Perform any post-processing
10945 * in a callback function, or in a "load" event handler.</strong>
10947 * @param {Object} options An object containing properties which control loading options:<ul>
10948 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10949 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10950 * passed the following arguments:<ul>
10951 * <li>r : Roo.data.Record[]</li>
10952 * <li>options: Options object from the load call</li>
10953 * <li>success: Boolean success indicator</li></ul></li>
10954 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10955 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10958 load : function(options){
10959 options = options || {};
10960 if(this.fireEvent("beforeload", this, options) !== false){
10961 this.storeOptions(options);
10962 var p = Roo.apply(options.params || {}, this.baseParams);
10963 // if meta was not loaded from remote source.. try requesting it.
10964 if (!this.reader.metaFromRemote) {
10965 p._requestMeta = 1;
10967 if(this.sortInfo && this.remoteSort){
10968 var pn = this.paramNames;
10969 p[pn["sort"]] = this.sortInfo.field;
10970 p[pn["dir"]] = this.sortInfo.direction;
10972 if (this.multiSort) {
10973 var pn = this.paramNames;
10974 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10977 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10982 * Reloads the Record cache from the configured Proxy using the configured Reader and
10983 * the options from the last load operation performed.
10984 * @param {Object} options (optional) An object containing properties which may override the options
10985 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10986 * the most recently used options are reused).
10988 reload : function(options){
10989 this.load(Roo.applyIf(options||{}, this.lastOptions));
10993 // Called as a callback by the Reader during a load operation.
10994 loadRecords : function(o, options, success){
10995 if(!o || success === false){
10996 if(success !== false){
10997 this.fireEvent("load", this, [], options, o);
10999 if(options.callback){
11000 options.callback.call(options.scope || this, [], options, false);
11004 // if data returned failure - throw an exception.
11005 if (o.success === false) {
11006 // show a message if no listener is registered.
11007 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11008 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11010 // loadmask wil be hooked into this..
11011 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11014 var r = o.records, t = o.totalRecords || r.length;
11016 this.fireEvent("beforeloadadd", this, r, options, o);
11018 if(!options || options.add !== true){
11019 if(this.pruneModifiedRecords){
11020 this.modified = [];
11022 for(var i = 0, len = r.length; i < len; i++){
11026 this.data = this.snapshot;
11027 delete this.snapshot;
11030 this.data.addAll(r);
11031 this.totalLength = t;
11033 this.fireEvent("datachanged", this);
11035 this.totalLength = Math.max(t, this.data.length+r.length);
11039 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11041 var e = new Roo.data.Record({});
11043 e.set(this.parent.displayField, this.parent.emptyTitle);
11044 e.set(this.parent.valueField, '');
11049 this.fireEvent("load", this, r, options, o);
11050 if(options.callback){
11051 options.callback.call(options.scope || this, r, options, true);
11057 * Loads data from a passed data block. A Reader which understands the format of the data
11058 * must have been configured in the constructor.
11059 * @param {Object} data The data block from which to read the Records. The format of the data expected
11060 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11061 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11063 loadData : function(o, append){
11064 var r = this.reader.readRecords(o);
11065 this.loadRecords(r, {add: append}, true);
11069 * Gets the number of cached records.
11071 * <em>If using paging, this may not be the total size of the dataset. If the data object
11072 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11073 * the data set size</em>
11075 getCount : function(){
11076 return this.data.length || 0;
11080 * Gets the total number of records in the dataset as returned by the server.
11082 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11083 * the dataset size</em>
11085 getTotalCount : function(){
11086 return this.totalLength || 0;
11090 * Returns the sort state of the Store as an object with two properties:
11092 field {String} The name of the field by which the Records are sorted
11093 direction {String} The sort order, "ASC" or "DESC"
11096 getSortState : function(){
11097 return this.sortInfo;
11101 applySort : function(){
11102 if(this.sortInfo && !this.remoteSort){
11103 var s = this.sortInfo, f = s.field;
11104 var st = this.fields.get(f).sortType;
11105 var fn = function(r1, r2){
11106 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11107 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11109 this.data.sort(s.direction, fn);
11110 if(this.snapshot && this.snapshot != this.data){
11111 this.snapshot.sort(s.direction, fn);
11117 * Sets the default sort column and order to be used by the next load operation.
11118 * @param {String} fieldName The name of the field to sort by.
11119 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11121 setDefaultSort : function(field, dir){
11122 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11126 * Sort the Records.
11127 * If remote sorting is used, the sort is performed on the server, and the cache is
11128 * reloaded. If local sorting is used, the cache is sorted internally.
11129 * @param {String} fieldName The name of the field to sort by.
11130 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11132 sort : function(fieldName, dir){
11133 var f = this.fields.get(fieldName);
11135 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11137 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11138 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11143 this.sortToggle[f.name] = dir;
11144 this.sortInfo = {field: f.name, direction: dir};
11145 if(!this.remoteSort){
11147 this.fireEvent("datachanged", this);
11149 this.load(this.lastOptions);
11154 * Calls the specified function for each of the Records in the cache.
11155 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11156 * Returning <em>false</em> aborts and exits the iteration.
11157 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11159 each : function(fn, scope){
11160 this.data.each(fn, scope);
11164 * Gets all records modified since the last commit. Modified records are persisted across load operations
11165 * (e.g., during paging).
11166 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11168 getModifiedRecords : function(){
11169 return this.modified;
11173 createFilterFn : function(property, value, anyMatch){
11174 if(!value.exec){ // not a regex
11175 value = String(value);
11176 if(value.length == 0){
11179 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11181 return function(r){
11182 return value.test(r.data[property]);
11187 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11188 * @param {String} property A field on your records
11189 * @param {Number} start The record index to start at (defaults to 0)
11190 * @param {Number} end The last record index to include (defaults to length - 1)
11191 * @return {Number} The sum
11193 sum : function(property, start, end){
11194 var rs = this.data.items, v = 0;
11195 start = start || 0;
11196 end = (end || end === 0) ? end : rs.length-1;
11198 for(var i = start; i <= end; i++){
11199 v += (rs[i].data[property] || 0);
11205 * Filter the records by a specified property.
11206 * @param {String} field A field on your records
11207 * @param {String/RegExp} value Either a string that the field
11208 * should start with or a RegExp to test against the field
11209 * @param {Boolean} anyMatch True to match any part not just the beginning
11211 filter : function(property, value, anyMatch){
11212 var fn = this.createFilterFn(property, value, anyMatch);
11213 return fn ? this.filterBy(fn) : this.clearFilter();
11217 * Filter by a function. The specified function will be called with each
11218 * record in this data source. If the function returns true the record is included,
11219 * otherwise it is filtered.
11220 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11221 * @param {Object} scope (optional) The scope of the function (defaults to this)
11223 filterBy : function(fn, scope){
11224 this.snapshot = this.snapshot || this.data;
11225 this.data = this.queryBy(fn, scope||this);
11226 this.fireEvent("datachanged", this);
11230 * Query the records by a specified property.
11231 * @param {String} field A field on your records
11232 * @param {String/RegExp} value Either a string that the field
11233 * should start with or a RegExp to test against the field
11234 * @param {Boolean} anyMatch True to match any part not just the beginning
11235 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11237 query : function(property, value, anyMatch){
11238 var fn = this.createFilterFn(property, value, anyMatch);
11239 return fn ? this.queryBy(fn) : this.data.clone();
11243 * Query by a function. The specified function will be called with each
11244 * record in this data source. If the function returns true the record is included
11246 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11247 * @param {Object} scope (optional) The scope of the function (defaults to this)
11248 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11250 queryBy : function(fn, scope){
11251 var data = this.snapshot || this.data;
11252 return data.filterBy(fn, scope||this);
11256 * Collects unique values for a particular dataIndex from this store.
11257 * @param {String} dataIndex The property to collect
11258 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11259 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11260 * @return {Array} An array of the unique values
11262 collect : function(dataIndex, allowNull, bypassFilter){
11263 var d = (bypassFilter === true && this.snapshot) ?
11264 this.snapshot.items : this.data.items;
11265 var v, sv, r = [], l = {};
11266 for(var i = 0, len = d.length; i < len; i++){
11267 v = d[i].data[dataIndex];
11269 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11278 * Revert to a view of the Record cache with no filtering applied.
11279 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11281 clearFilter : function(suppressEvent){
11282 if(this.snapshot && this.snapshot != this.data){
11283 this.data = this.snapshot;
11284 delete this.snapshot;
11285 if(suppressEvent !== true){
11286 this.fireEvent("datachanged", this);
11292 afterEdit : function(record){
11293 if(this.modified.indexOf(record) == -1){
11294 this.modified.push(record);
11296 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11300 afterReject : function(record){
11301 this.modified.remove(record);
11302 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11306 afterCommit : function(record){
11307 this.modified.remove(record);
11308 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11312 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11313 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11315 commitChanges : function(){
11316 var m = this.modified.slice(0);
11317 this.modified = [];
11318 for(var i = 0, len = m.length; i < len; i++){
11324 * Cancel outstanding changes on all changed records.
11326 rejectChanges : function(){
11327 var m = this.modified.slice(0);
11328 this.modified = [];
11329 for(var i = 0, len = m.length; i < len; i++){
11334 onMetaChange : function(meta, rtype, o){
11335 this.recordType = rtype;
11336 this.fields = rtype.prototype.fields;
11337 delete this.snapshot;
11338 this.sortInfo = meta.sortInfo || this.sortInfo;
11339 this.modified = [];
11340 this.fireEvent('metachange', this, this.reader.meta);
11343 moveIndex : function(data, type)
11345 var index = this.indexOf(data);
11347 var newIndex = index + type;
11351 this.insert(newIndex, data);
11356 * Ext JS Library 1.1.1
11357 * Copyright(c) 2006-2007, Ext JS, LLC.
11359 * Originally Released Under LGPL - original licence link has changed is not relivant.
11362 * <script type="text/javascript">
11366 * @class Roo.data.SimpleStore
11367 * @extends Roo.data.Store
11368 * Small helper class to make creating Stores from Array data easier.
11369 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11370 * @cfg {Array} fields An array of field definition objects, or field name strings.
11371 * @cfg {Array} data The multi-dimensional array of data
11373 * @param {Object} config
11375 Roo.data.SimpleStore = function(config){
11376 Roo.data.SimpleStore.superclass.constructor.call(this, {
11378 reader: new Roo.data.ArrayReader({
11381 Roo.data.Record.create(config.fields)
11383 proxy : new Roo.data.MemoryProxy(config.data)
11387 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11389 * Ext JS Library 1.1.1
11390 * Copyright(c) 2006-2007, Ext JS, LLC.
11392 * Originally Released Under LGPL - original licence link has changed is not relivant.
11395 * <script type="text/javascript">
11400 * @extends Roo.data.Store
11401 * @class Roo.data.JsonStore
11402 * Small helper class to make creating Stores for JSON data easier. <br/>
11404 var store = new Roo.data.JsonStore({
11405 url: 'get-images.php',
11407 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11410 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11411 * JsonReader and HttpProxy (unless inline data is provided).</b>
11412 * @cfg {Array} fields An array of field definition objects, or field name strings.
11414 * @param {Object} config
11416 Roo.data.JsonStore = function(c){
11417 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11418 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11419 reader: new Roo.data.JsonReader(c, c.fields)
11422 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11424 * Ext JS Library 1.1.1
11425 * Copyright(c) 2006-2007, Ext JS, LLC.
11427 * Originally Released Under LGPL - original licence link has changed is not relivant.
11430 * <script type="text/javascript">
11434 Roo.data.Field = function(config){
11435 if(typeof config == "string"){
11436 config = {name: config};
11438 Roo.apply(this, config);
11441 this.type = "auto";
11444 var st = Roo.data.SortTypes;
11445 // named sortTypes are supported, here we look them up
11446 if(typeof this.sortType == "string"){
11447 this.sortType = st[this.sortType];
11450 // set default sortType for strings and dates
11451 if(!this.sortType){
11454 this.sortType = st.asUCString;
11457 this.sortType = st.asDate;
11460 this.sortType = st.none;
11465 var stripRe = /[\$,%]/g;
11467 // prebuilt conversion function for this field, instead of
11468 // switching every time we're reading a value
11470 var cv, dateFormat = this.dateFormat;
11475 cv = function(v){ return v; };
11478 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11482 return v !== undefined && v !== null && v !== '' ?
11483 parseInt(String(v).replace(stripRe, ""), 10) : '';
11488 return v !== undefined && v !== null && v !== '' ?
11489 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11494 cv = function(v){ return v === true || v === "true" || v == 1; };
11501 if(v instanceof Date){
11505 if(dateFormat == "timestamp"){
11506 return new Date(v*1000);
11508 return Date.parseDate(v, dateFormat);
11510 var parsed = Date.parse(v);
11511 return parsed ? new Date(parsed) : null;
11520 Roo.data.Field.prototype = {
11528 * Ext JS Library 1.1.1
11529 * Copyright(c) 2006-2007, Ext JS, LLC.
11531 * Originally Released Under LGPL - original licence link has changed is not relivant.
11534 * <script type="text/javascript">
11537 // Base class for reading structured data from a data source. This class is intended to be
11538 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11541 * @class Roo.data.DataReader
11542 * Base class for reading structured data from a data source. This class is intended to be
11543 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11546 Roo.data.DataReader = function(meta, recordType){
11550 this.recordType = recordType instanceof Array ?
11551 Roo.data.Record.create(recordType) : recordType;
11554 Roo.data.DataReader.prototype = {
11556 * Create an empty record
11557 * @param {Object} data (optional) - overlay some values
11558 * @return {Roo.data.Record} record created.
11560 newRow : function(d) {
11562 this.recordType.prototype.fields.each(function(c) {
11564 case 'int' : da[c.name] = 0; break;
11565 case 'date' : da[c.name] = new Date(); break;
11566 case 'float' : da[c.name] = 0.0; break;
11567 case 'boolean' : da[c.name] = false; break;
11568 default : da[c.name] = ""; break;
11572 return new this.recordType(Roo.apply(da, d));
11577 * Ext JS Library 1.1.1
11578 * Copyright(c) 2006-2007, Ext JS, LLC.
11580 * Originally Released Under LGPL - original licence link has changed is not relivant.
11583 * <script type="text/javascript">
11587 * @class Roo.data.DataProxy
11588 * @extends Roo.data.Observable
11589 * This class is an abstract base class for implementations which provide retrieval of
11590 * unformatted data objects.<br>
11592 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11593 * (of the appropriate type which knows how to parse the data object) to provide a block of
11594 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11596 * Custom implementations must implement the load method as described in
11597 * {@link Roo.data.HttpProxy#load}.
11599 Roo.data.DataProxy = function(){
11602 * @event beforeload
11603 * Fires before a network request is made to retrieve a data object.
11604 * @param {Object} This DataProxy object.
11605 * @param {Object} params The params parameter to the load function.
11610 * Fires before the load method's callback is called.
11611 * @param {Object} This DataProxy object.
11612 * @param {Object} o The data object.
11613 * @param {Object} arg The callback argument object passed to the load function.
11617 * @event loadexception
11618 * Fires if an Exception occurs during data retrieval.
11619 * @param {Object} This DataProxy object.
11620 * @param {Object} o The data object.
11621 * @param {Object} arg The callback argument object passed to the load function.
11622 * @param {Object} e The Exception.
11624 loadexception : true
11626 Roo.data.DataProxy.superclass.constructor.call(this);
11629 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11632 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11636 * Ext JS Library 1.1.1
11637 * Copyright(c) 2006-2007, Ext JS, LLC.
11639 * Originally Released Under LGPL - original licence link has changed is not relivant.
11642 * <script type="text/javascript">
11645 * @class Roo.data.MemoryProxy
11646 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11647 * to the Reader when its load method is called.
11649 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11651 Roo.data.MemoryProxy = function(data){
11655 Roo.data.MemoryProxy.superclass.constructor.call(this);
11659 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11662 * Load data from the requested source (in this case an in-memory
11663 * data object passed to the constructor), read the data object into
11664 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11665 * process that block using the passed callback.
11666 * @param {Object} params This parameter is not used by the MemoryProxy class.
11667 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11668 * object into a block of Roo.data.Records.
11669 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11670 * The function must be passed <ul>
11671 * <li>The Record block object</li>
11672 * <li>The "arg" argument from the load function</li>
11673 * <li>A boolean success indicator</li>
11675 * @param {Object} scope The scope in which to call the callback
11676 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11678 load : function(params, reader, callback, scope, arg){
11679 params = params || {};
11682 result = reader.readRecords(this.data);
11684 this.fireEvent("loadexception", this, arg, null, e);
11685 callback.call(scope, null, arg, false);
11688 callback.call(scope, result, arg, true);
11692 update : function(params, records){
11697 * Ext JS Library 1.1.1
11698 * Copyright(c) 2006-2007, Ext JS, LLC.
11700 * Originally Released Under LGPL - original licence link has changed is not relivant.
11703 * <script type="text/javascript">
11706 * @class Roo.data.HttpProxy
11707 * @extends Roo.data.DataProxy
11708 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11709 * configured to reference a certain URL.<br><br>
11711 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11712 * from which the running page was served.<br><br>
11714 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11716 * Be aware that to enable the browser to parse an XML document, the server must set
11717 * the Content-Type header in the HTTP response to "text/xml".
11719 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11720 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11721 * will be used to make the request.
11723 Roo.data.HttpProxy = function(conn){
11724 Roo.data.HttpProxy.superclass.constructor.call(this);
11725 // is conn a conn config or a real conn?
11727 this.useAjax = !conn || !conn.events;
11731 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11732 // thse are take from connection...
11735 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11738 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11739 * extra parameters to each request made by this object. (defaults to undefined)
11742 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11743 * to each request made by this object. (defaults to undefined)
11746 * @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)
11749 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11752 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11758 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11762 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11763 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11764 * a finer-grained basis than the DataProxy events.
11766 getConnection : function(){
11767 return this.useAjax ? Roo.Ajax : this.conn;
11771 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11772 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11773 * process that block using the passed callback.
11774 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11775 * for the request to the remote server.
11776 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11777 * object into a block of Roo.data.Records.
11778 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11779 * The function must be passed <ul>
11780 * <li>The Record block object</li>
11781 * <li>The "arg" argument from the load function</li>
11782 * <li>A boolean success indicator</li>
11784 * @param {Object} scope The scope in which to call the callback
11785 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11787 load : function(params, reader, callback, scope, arg){
11788 if(this.fireEvent("beforeload", this, params) !== false){
11790 params : params || {},
11792 callback : callback,
11797 callback : this.loadResponse,
11801 Roo.applyIf(o, this.conn);
11802 if(this.activeRequest){
11803 Roo.Ajax.abort(this.activeRequest);
11805 this.activeRequest = Roo.Ajax.request(o);
11807 this.conn.request(o);
11810 callback.call(scope||this, null, arg, false);
11815 loadResponse : function(o, success, response){
11816 delete this.activeRequest;
11818 this.fireEvent("loadexception", this, o, response);
11819 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11824 result = o.reader.read(response);
11826 this.fireEvent("loadexception", this, o, response, e);
11827 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11831 this.fireEvent("load", this, o, o.request.arg);
11832 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11836 update : function(dataSet){
11841 updateResponse : function(dataSet){
11846 * Ext JS Library 1.1.1
11847 * Copyright(c) 2006-2007, Ext JS, LLC.
11849 * Originally Released Under LGPL - original licence link has changed is not relivant.
11852 * <script type="text/javascript">
11856 * @class Roo.data.ScriptTagProxy
11857 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11858 * other than the originating domain of the running page.<br><br>
11860 * <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
11861 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11863 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11864 * source code that is used as the source inside a <script> tag.<br><br>
11866 * In order for the browser to process the returned data, the server must wrap the data object
11867 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11868 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11869 * depending on whether the callback name was passed:
11872 boolean scriptTag = false;
11873 String cb = request.getParameter("callback");
11876 response.setContentType("text/javascript");
11878 response.setContentType("application/x-json");
11880 Writer out = response.getWriter();
11882 out.write(cb + "(");
11884 out.print(dataBlock.toJsonString());
11891 * @param {Object} config A configuration object.
11893 Roo.data.ScriptTagProxy = function(config){
11894 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11895 Roo.apply(this, config);
11896 this.head = document.getElementsByTagName("head")[0];
11899 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11901 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11903 * @cfg {String} url The URL from which to request the data object.
11906 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11910 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11911 * the server the name of the callback function set up by the load call to process the returned data object.
11912 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11913 * javascript output which calls this named function passing the data object as its only parameter.
11915 callbackParam : "callback",
11917 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11918 * name to the request.
11923 * Load data from the configured URL, read the data object into
11924 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11925 * process that block using the passed callback.
11926 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11927 * for the request to the remote server.
11928 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11929 * object into a block of Roo.data.Records.
11930 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11931 * The function must be passed <ul>
11932 * <li>The Record block object</li>
11933 * <li>The "arg" argument from the load function</li>
11934 * <li>A boolean success indicator</li>
11936 * @param {Object} scope The scope in which to call the callback
11937 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11939 load : function(params, reader, callback, scope, arg){
11940 if(this.fireEvent("beforeload", this, params) !== false){
11942 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11944 var url = this.url;
11945 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11947 url += "&_dc=" + (new Date().getTime());
11949 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11952 cb : "stcCallback"+transId,
11953 scriptId : "stcScript"+transId,
11957 callback : callback,
11963 window[trans.cb] = function(o){
11964 conn.handleResponse(o, trans);
11967 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11969 if(this.autoAbort !== false){
11973 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11975 var script = document.createElement("script");
11976 script.setAttribute("src", url);
11977 script.setAttribute("type", "text/javascript");
11978 script.setAttribute("id", trans.scriptId);
11979 this.head.appendChild(script);
11981 this.trans = trans;
11983 callback.call(scope||this, null, arg, false);
11988 isLoading : function(){
11989 return this.trans ? true : false;
11993 * Abort the current server request.
11995 abort : function(){
11996 if(this.isLoading()){
11997 this.destroyTrans(this.trans);
12002 destroyTrans : function(trans, isLoaded){
12003 this.head.removeChild(document.getElementById(trans.scriptId));
12004 clearTimeout(trans.timeoutId);
12006 window[trans.cb] = undefined;
12008 delete window[trans.cb];
12011 // if hasn't been loaded, wait for load to remove it to prevent script error
12012 window[trans.cb] = function(){
12013 window[trans.cb] = undefined;
12015 delete window[trans.cb];
12022 handleResponse : function(o, trans){
12023 this.trans = false;
12024 this.destroyTrans(trans, true);
12027 result = trans.reader.readRecords(o);
12029 this.fireEvent("loadexception", this, o, trans.arg, e);
12030 trans.callback.call(trans.scope||window, null, trans.arg, false);
12033 this.fireEvent("load", this, o, trans.arg);
12034 trans.callback.call(trans.scope||window, result, trans.arg, true);
12038 handleFailure : function(trans){
12039 this.trans = false;
12040 this.destroyTrans(trans, false);
12041 this.fireEvent("loadexception", this, null, trans.arg);
12042 trans.callback.call(trans.scope||window, null, trans.arg, false);
12046 * Ext JS Library 1.1.1
12047 * Copyright(c) 2006-2007, Ext JS, LLC.
12049 * Originally Released Under LGPL - original licence link has changed is not relivant.
12052 * <script type="text/javascript">
12056 * @class Roo.data.JsonReader
12057 * @extends Roo.data.DataReader
12058 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12059 * based on mappings in a provided Roo.data.Record constructor.
12061 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12062 * in the reply previously.
12067 var RecordDef = Roo.data.Record.create([
12068 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12069 {name: 'occupation'} // This field will use "occupation" as the mapping.
12071 var myReader = new Roo.data.JsonReader({
12072 totalProperty: "results", // The property which contains the total dataset size (optional)
12073 root: "rows", // The property which contains an Array of row objects
12074 id: "id" // The property within each row object that provides an ID for the record (optional)
12078 * This would consume a JSON file like this:
12080 { 'results': 2, 'rows': [
12081 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12082 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12085 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12086 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12087 * paged from the remote server.
12088 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12089 * @cfg {String} root name of the property which contains the Array of row objects.
12090 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12091 * @cfg {Array} fields Array of field definition objects
12093 * Create a new JsonReader
12094 * @param {Object} meta Metadata configuration options
12095 * @param {Object} recordType Either an Array of field definition objects,
12096 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12098 Roo.data.JsonReader = function(meta, recordType){
12101 // set some defaults:
12102 Roo.applyIf(meta, {
12103 totalProperty: 'total',
12104 successProperty : 'success',
12109 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12111 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12114 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12115 * Used by Store query builder to append _requestMeta to params.
12118 metaFromRemote : false,
12120 * This method is only used by a DataProxy which has retrieved data from a remote server.
12121 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12122 * @return {Object} data A data block which is used by an Roo.data.Store object as
12123 * a cache of Roo.data.Records.
12125 read : function(response){
12126 var json = response.responseText;
12128 var o = /* eval:var:o */ eval("("+json+")");
12130 throw {message: "JsonReader.read: Json object not found"};
12136 this.metaFromRemote = true;
12137 this.meta = o.metaData;
12138 this.recordType = Roo.data.Record.create(o.metaData.fields);
12139 this.onMetaChange(this.meta, this.recordType, o);
12141 return this.readRecords(o);
12144 // private function a store will implement
12145 onMetaChange : function(meta, recordType, o){
12152 simpleAccess: function(obj, subsc) {
12159 getJsonAccessor: function(){
12161 return function(expr) {
12163 return(re.test(expr))
12164 ? new Function("obj", "return obj." + expr)
12169 return Roo.emptyFn;
12174 * Create a data block containing Roo.data.Records from an XML document.
12175 * @param {Object} o An object which contains an Array of row objects in the property specified
12176 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12177 * which contains the total size of the dataset.
12178 * @return {Object} data A data block which is used by an Roo.data.Store object as
12179 * a cache of Roo.data.Records.
12181 readRecords : function(o){
12183 * After any data loads, the raw JSON data is available for further custom processing.
12187 var s = this.meta, Record = this.recordType,
12188 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12190 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12192 if(s.totalProperty) {
12193 this.getTotal = this.getJsonAccessor(s.totalProperty);
12195 if(s.successProperty) {
12196 this.getSuccess = this.getJsonAccessor(s.successProperty);
12198 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12200 var g = this.getJsonAccessor(s.id);
12201 this.getId = function(rec) {
12203 return (r === undefined || r === "") ? null : r;
12206 this.getId = function(){return null;};
12209 for(var jj = 0; jj < fl; jj++){
12211 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12212 this.ef[jj] = this.getJsonAccessor(map);
12216 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12217 if(s.totalProperty){
12218 var vt = parseInt(this.getTotal(o), 10);
12223 if(s.successProperty){
12224 var vs = this.getSuccess(o);
12225 if(vs === false || vs === 'false'){
12230 for(var i = 0; i < c; i++){
12233 var id = this.getId(n);
12234 for(var j = 0; j < fl; j++){
12236 var v = this.ef[j](n);
12238 Roo.log('missing convert for ' + f.name);
12242 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12244 var record = new Record(values, id);
12246 records[i] = record;
12252 totalRecords : totalRecords
12257 * Ext JS Library 1.1.1
12258 * Copyright(c) 2006-2007, Ext JS, LLC.
12260 * Originally Released Under LGPL - original licence link has changed is not relivant.
12263 * <script type="text/javascript">
12267 * @class Roo.data.ArrayReader
12268 * @extends Roo.data.DataReader
12269 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12270 * Each element of that Array represents a row of data fields. The
12271 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12272 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12276 var RecordDef = Roo.data.Record.create([
12277 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12278 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12280 var myReader = new Roo.data.ArrayReader({
12281 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12285 * This would consume an Array like this:
12287 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12289 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12291 * Create a new JsonReader
12292 * @param {Object} meta Metadata configuration options.
12293 * @param {Object} recordType Either an Array of field definition objects
12294 * as specified to {@link Roo.data.Record#create},
12295 * or an {@link Roo.data.Record} object
12296 * created using {@link Roo.data.Record#create}.
12298 Roo.data.ArrayReader = function(meta, recordType){
12299 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12302 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12304 * Create a data block containing Roo.data.Records from an XML document.
12305 * @param {Object} o An Array of row objects which represents the dataset.
12306 * @return {Object} data A data block which is used by an Roo.data.Store object as
12307 * a cache of Roo.data.Records.
12309 readRecords : function(o){
12310 var sid = this.meta ? this.meta.id : null;
12311 var recordType = this.recordType, fields = recordType.prototype.fields;
12314 for(var i = 0; i < root.length; i++){
12317 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12318 for(var j = 0, jlen = fields.length; j < jlen; j++){
12319 var f = fields.items[j];
12320 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12321 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12323 values[f.name] = v;
12325 var record = new recordType(values, id);
12327 records[records.length] = record;
12331 totalRecords : records.length
12340 * @class Roo.bootstrap.ComboBox
12341 * @extends Roo.bootstrap.TriggerField
12342 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12343 * @cfg {Boolean} append (true|false) default false
12344 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12345 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12346 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12347 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12348 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12349 * @cfg {Boolean} animate default true
12350 * @cfg {Boolean} emptyResultText only for touch device
12351 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12352 * @cfg {String} emptyTitle default ''
12354 * Create a new ComboBox.
12355 * @param {Object} config Configuration options
12357 Roo.bootstrap.ComboBox = function(config){
12358 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12362 * Fires when the dropdown list is expanded
12363 * @param {Roo.bootstrap.ComboBox} combo This combo box
12368 * Fires when the dropdown list is collapsed
12369 * @param {Roo.bootstrap.ComboBox} combo This combo box
12373 * @event beforeselect
12374 * Fires before a list item is selected. Return false to cancel the selection.
12375 * @param {Roo.bootstrap.ComboBox} combo This combo box
12376 * @param {Roo.data.Record} record The data record returned from the underlying store
12377 * @param {Number} index The index of the selected item in the dropdown list
12379 'beforeselect' : true,
12382 * Fires when a list item is selected
12383 * @param {Roo.bootstrap.ComboBox} combo This combo box
12384 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12385 * @param {Number} index The index of the selected item in the dropdown list
12389 * @event beforequery
12390 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12391 * The event object passed has these properties:
12392 * @param {Roo.bootstrap.ComboBox} combo This combo box
12393 * @param {String} query The query
12394 * @param {Boolean} forceAll true to force "all" query
12395 * @param {Boolean} cancel true to cancel the query
12396 * @param {Object} e The query event object
12398 'beforequery': true,
12401 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12402 * @param {Roo.bootstrap.ComboBox} combo This combo box
12407 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12408 * @param {Roo.bootstrap.ComboBox} combo This combo box
12409 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12414 * Fires when the remove value from the combobox array
12415 * @param {Roo.bootstrap.ComboBox} combo This combo box
12419 * @event afterremove
12420 * Fires when the remove value from the combobox array
12421 * @param {Roo.bootstrap.ComboBox} combo This combo box
12423 'afterremove' : true,
12425 * @event specialfilter
12426 * Fires when specialfilter
12427 * @param {Roo.bootstrap.ComboBox} combo This combo box
12429 'specialfilter' : true,
12432 * Fires when tick the element
12433 * @param {Roo.bootstrap.ComboBox} combo This combo box
12437 * @event touchviewdisplay
12438 * Fires when touch view require special display (default is using displayField)
12439 * @param {Roo.bootstrap.ComboBox} combo This combo box
12440 * @param {Object} cfg set html .
12442 'touchviewdisplay' : true
12447 this.tickItems = [];
12449 this.selectedIndex = -1;
12450 if(this.mode == 'local'){
12451 if(config.queryDelay === undefined){
12452 this.queryDelay = 10;
12454 if(config.minChars === undefined){
12460 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12463 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12464 * rendering into an Roo.Editor, defaults to false)
12467 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12468 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12471 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12474 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12475 * the dropdown list (defaults to undefined, with no header element)
12479 * @cfg {String/Roo.Template} tpl The template to use to render the output
12483 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12485 listWidth: undefined,
12487 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12488 * mode = 'remote' or 'text' if mode = 'local')
12490 displayField: undefined,
12493 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12494 * mode = 'remote' or 'value' if mode = 'local').
12495 * Note: use of a valueField requires the user make a selection
12496 * in order for a value to be mapped.
12498 valueField: undefined,
12500 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12505 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12506 * field's data value (defaults to the underlying DOM element's name)
12508 hiddenName: undefined,
12510 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12514 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12516 selectedClass: 'active',
12519 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12523 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12524 * anchor positions (defaults to 'tl-bl')
12526 listAlign: 'tl-bl?',
12528 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12532 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12533 * query specified by the allQuery config option (defaults to 'query')
12535 triggerAction: 'query',
12537 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12538 * (defaults to 4, does not apply if editable = false)
12542 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12543 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12547 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12548 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12552 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12553 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12557 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12558 * when editable = true (defaults to false)
12560 selectOnFocus:false,
12562 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12564 queryParam: 'query',
12566 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12567 * when mode = 'remote' (defaults to 'Loading...')
12569 loadingText: 'Loading...',
12571 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12575 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12579 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12580 * traditional select (defaults to true)
12584 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12588 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12592 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12593 * listWidth has a higher value)
12597 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12598 * allow the user to set arbitrary text into the field (defaults to false)
12600 forceSelection:false,
12602 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12603 * if typeAhead = true (defaults to 250)
12605 typeAheadDelay : 250,
12607 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12608 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12610 valueNotFoundText : undefined,
12612 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12614 blockFocus : false,
12617 * @cfg {Boolean} disableClear Disable showing of clear button.
12619 disableClear : false,
12621 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12623 alwaysQuery : false,
12626 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12631 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12633 invalidClass : "has-warning",
12636 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12638 validClass : "has-success",
12641 * @cfg {Boolean} specialFilter (true|false) special filter default false
12643 specialFilter : false,
12646 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12648 mobileTouchView : true,
12651 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12653 useNativeIOS : false,
12655 ios_options : false,
12667 btnPosition : 'right',
12668 triggerList : true,
12669 showToggleBtn : true,
12671 emptyResultText: 'Empty',
12672 triggerText : 'Select',
12675 // element that contains real text value.. (when hidden is used..)
12677 getAutoCreate : function()
12682 * Render classic select for iso
12685 if(Roo.isIOS && this.useNativeIOS){
12686 cfg = this.getAutoCreateNativeIOS();
12694 if(Roo.isTouch && this.mobileTouchView){
12695 cfg = this.getAutoCreateTouchView();
12702 if(!this.tickable){
12703 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12708 * ComboBox with tickable selections
12711 var align = this.labelAlign || this.parentLabelAlign();
12714 cls : 'form-group roo-combobox-tickable' //input-group
12717 var btn_text_select = '';
12718 var btn_text_done = '';
12719 var btn_text_cancel = '';
12721 if (this.btn_text_show) {
12722 btn_text_select = 'Select';
12723 btn_text_done = 'Done';
12724 btn_text_cancel = 'Cancel';
12729 cls : 'tickable-buttons',
12734 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12735 //html : this.triggerText
12736 html: btn_text_select
12742 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12744 html: btn_text_done
12750 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12752 html: btn_text_cancel
12758 buttons.cn.unshift({
12760 cls: 'roo-select2-search-field-input'
12766 Roo.each(buttons.cn, function(c){
12768 c.cls += ' btn-' + _this.size;
12771 if (_this.disabled) {
12782 cls: 'form-hidden-field'
12786 cls: 'roo-select2-choices',
12790 cls: 'roo-select2-search-field',
12801 cls: 'roo-select2-container input-group roo-select2-container-multi',
12806 // cls: 'typeahead typeahead-long dropdown-menu',
12807 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12812 if(this.hasFeedback && !this.allowBlank){
12816 cls: 'glyphicon form-control-feedback'
12819 combobox.cn.push(feedback);
12823 if (align ==='left' && this.fieldLabel.length) {
12825 cfg.cls += ' roo-form-group-label-left';
12830 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12831 tooltip : 'This field is required'
12836 cls : 'control-label',
12837 html : this.fieldLabel
12849 var labelCfg = cfg.cn[1];
12850 var contentCfg = cfg.cn[2];
12853 if(this.indicatorpos == 'right'){
12859 cls : 'control-label',
12863 html : this.fieldLabel
12867 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12868 tooltip : 'This field is required'
12883 labelCfg = cfg.cn[0];
12884 contentCfg = cfg.cn[1];
12888 if(this.labelWidth > 12){
12889 labelCfg.style = "width: " + this.labelWidth + 'px';
12892 if(this.labelWidth < 13 && this.labelmd == 0){
12893 this.labelmd = this.labelWidth;
12896 if(this.labellg > 0){
12897 labelCfg.cls += ' col-lg-' + this.labellg;
12898 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12901 if(this.labelmd > 0){
12902 labelCfg.cls += ' col-md-' + this.labelmd;
12903 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12906 if(this.labelsm > 0){
12907 labelCfg.cls += ' col-sm-' + this.labelsm;
12908 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12911 if(this.labelxs > 0){
12912 labelCfg.cls += ' col-xs-' + this.labelxs;
12913 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12917 } else if ( this.fieldLabel.length) {
12918 // Roo.log(" label");
12922 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12923 tooltip : 'This field is required'
12927 //cls : 'input-group-addon',
12928 html : this.fieldLabel
12933 if(this.indicatorpos == 'right'){
12937 //cls : 'input-group-addon',
12938 html : this.fieldLabel
12942 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12943 tooltip : 'This field is required'
12952 // Roo.log(" no label && no align");
12959 ['xs','sm','md','lg'].map(function(size){
12960 if (settings[size]) {
12961 cfg.cls += ' col-' + size + '-' + settings[size];
12969 _initEventsCalled : false,
12972 initEvents: function()
12974 if (this._initEventsCalled) { // as we call render... prevent looping...
12977 this._initEventsCalled = true;
12980 throw "can not find store for combo";
12983 this.store = Roo.factory(this.store, Roo.data);
12984 this.store.parent = this;
12986 // if we are building from html. then this element is so complex, that we can not really
12987 // use the rendered HTML.
12988 // so we have to trash and replace the previous code.
12989 if (Roo.XComponent.build_from_html) {
12991 // remove this element....
12992 var e = this.el.dom, k=0;
12993 while (e ) { e = e.previousSibling; ++k;}
12998 this.rendered = false;
13000 this.render(this.parent().getChildContainer(true), k);
13006 if(Roo.isIOS && this.useNativeIOS){
13007 this.initIOSView();
13015 if(Roo.isTouch && this.mobileTouchView){
13016 this.initTouchView();
13021 this.initTickableEvents();
13025 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13027 if(this.hiddenName){
13029 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13031 this.hiddenField.dom.value =
13032 this.hiddenValue !== undefined ? this.hiddenValue :
13033 this.value !== undefined ? this.value : '';
13035 // prevent input submission
13036 this.el.dom.removeAttribute('name');
13037 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13042 // this.el.dom.setAttribute('autocomplete', 'off');
13045 var cls = 'x-combo-list';
13047 //this.list = new Roo.Layer({
13048 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13054 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13055 _this.list.setWidth(lw);
13058 this.list.on('mouseover', this.onViewOver, this);
13059 this.list.on('mousemove', this.onViewMove, this);
13061 this.list.on('scroll', this.onViewScroll, this);
13064 this.list.swallowEvent('mousewheel');
13065 this.assetHeight = 0;
13068 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13069 this.assetHeight += this.header.getHeight();
13072 this.innerList = this.list.createChild({cls:cls+'-inner'});
13073 this.innerList.on('mouseover', this.onViewOver, this);
13074 this.innerList.on('mousemove', this.onViewMove, this);
13075 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13077 if(this.allowBlank && !this.pageSize && !this.disableClear){
13078 this.footer = this.list.createChild({cls:cls+'-ft'});
13079 this.pageTb = new Roo.Toolbar(this.footer);
13083 this.footer = this.list.createChild({cls:cls+'-ft'});
13084 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13085 {pageSize: this.pageSize});
13089 if (this.pageTb && this.allowBlank && !this.disableClear) {
13091 this.pageTb.add(new Roo.Toolbar.Fill(), {
13092 cls: 'x-btn-icon x-btn-clear',
13094 handler: function()
13097 _this.clearValue();
13098 _this.onSelect(false, -1);
13103 this.assetHeight += this.footer.getHeight();
13108 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13111 this.view = new Roo.View(this.list, this.tpl, {
13112 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13114 //this.view.wrapEl.setDisplayed(false);
13115 this.view.on('click', this.onViewClick, this);
13118 this.store.on('beforeload', this.onBeforeLoad, this);
13119 this.store.on('load', this.onLoad, this);
13120 this.store.on('loadexception', this.onLoadException, this);
13122 if(this.resizable){
13123 this.resizer = new Roo.Resizable(this.list, {
13124 pinned:true, handles:'se'
13126 this.resizer.on('resize', function(r, w, h){
13127 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13128 this.listWidth = w;
13129 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13130 this.restrictHeight();
13132 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13135 if(!this.editable){
13136 this.editable = true;
13137 this.setEditable(false);
13142 if (typeof(this.events.add.listeners) != 'undefined') {
13144 this.addicon = this.wrap.createChild(
13145 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13147 this.addicon.on('click', function(e) {
13148 this.fireEvent('add', this);
13151 if (typeof(this.events.edit.listeners) != 'undefined') {
13153 this.editicon = this.wrap.createChild(
13154 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13155 if (this.addicon) {
13156 this.editicon.setStyle('margin-left', '40px');
13158 this.editicon.on('click', function(e) {
13160 // we fire even if inothing is selected..
13161 this.fireEvent('edit', this, this.lastData );
13167 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13168 "up" : function(e){
13169 this.inKeyMode = true;
13173 "down" : function(e){
13174 if(!this.isExpanded()){
13175 this.onTriggerClick();
13177 this.inKeyMode = true;
13182 "enter" : function(e){
13183 // this.onViewClick();
13187 if(this.fireEvent("specialkey", this, e)){
13188 this.onViewClick(false);
13194 "esc" : function(e){
13198 "tab" : function(e){
13201 if(this.fireEvent("specialkey", this, e)){
13202 this.onViewClick(false);
13210 doRelay : function(foo, bar, hname){
13211 if(hname == 'down' || this.scope.isExpanded()){
13212 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13221 this.queryDelay = Math.max(this.queryDelay || 10,
13222 this.mode == 'local' ? 10 : 250);
13225 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13227 if(this.typeAhead){
13228 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13230 if(this.editable !== false){
13231 this.inputEl().on("keyup", this.onKeyUp, this);
13233 if(this.forceSelection){
13234 this.inputEl().on('blur', this.doForce, this);
13238 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13239 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13243 initTickableEvents: function()
13247 if(this.hiddenName){
13249 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13251 this.hiddenField.dom.value =
13252 this.hiddenValue !== undefined ? this.hiddenValue :
13253 this.value !== undefined ? this.value : '';
13255 // prevent input submission
13256 this.el.dom.removeAttribute('name');
13257 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13262 // this.list = this.el.select('ul.dropdown-menu',true).first();
13264 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13265 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13266 if(this.triggerList){
13267 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13270 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13271 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13273 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13274 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13276 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13277 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13279 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13280 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13281 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13284 this.cancelBtn.hide();
13289 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13290 _this.list.setWidth(lw);
13293 this.list.on('mouseover', this.onViewOver, this);
13294 this.list.on('mousemove', this.onViewMove, this);
13296 this.list.on('scroll', this.onViewScroll, this);
13299 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>';
13302 this.view = new Roo.View(this.list, this.tpl, {
13303 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13306 //this.view.wrapEl.setDisplayed(false);
13307 this.view.on('click', this.onViewClick, this);
13311 this.store.on('beforeload', this.onBeforeLoad, this);
13312 this.store.on('load', this.onLoad, this);
13313 this.store.on('loadexception', this.onLoadException, this);
13316 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13317 "up" : function(e){
13318 this.inKeyMode = true;
13322 "down" : function(e){
13323 this.inKeyMode = true;
13327 "enter" : function(e){
13328 if(this.fireEvent("specialkey", this, e)){
13329 this.onViewClick(false);
13335 "esc" : function(e){
13336 this.onTickableFooterButtonClick(e, false, false);
13339 "tab" : function(e){
13340 this.fireEvent("specialkey", this, e);
13342 this.onTickableFooterButtonClick(e, false, false);
13349 doRelay : function(e, fn, key){
13350 if(this.scope.isExpanded()){
13351 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13360 this.queryDelay = Math.max(this.queryDelay || 10,
13361 this.mode == 'local' ? 10 : 250);
13364 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13366 if(this.typeAhead){
13367 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13370 if(this.editable !== false){
13371 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13374 this.indicator = this.indicatorEl();
13376 if(this.indicator){
13377 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13378 this.indicator.hide();
13383 onDestroy : function(){
13385 this.view.setStore(null);
13386 this.view.el.removeAllListeners();
13387 this.view.el.remove();
13388 this.view.purgeListeners();
13391 this.list.dom.innerHTML = '';
13395 this.store.un('beforeload', this.onBeforeLoad, this);
13396 this.store.un('load', this.onLoad, this);
13397 this.store.un('loadexception', this.onLoadException, this);
13399 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13403 fireKey : function(e){
13404 if(e.isNavKeyPress() && !this.list.isVisible()){
13405 this.fireEvent("specialkey", this, e);
13410 onResize: function(w, h){
13411 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13413 // if(typeof w != 'number'){
13414 // // we do not handle it!?!?
13417 // var tw = this.trigger.getWidth();
13418 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13419 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13421 // this.inputEl().setWidth( this.adjustWidth('input', x));
13423 // //this.trigger.setStyle('left', x+'px');
13425 // if(this.list && this.listWidth === undefined){
13426 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13427 // this.list.setWidth(lw);
13428 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13436 * Allow or prevent the user from directly editing the field text. If false is passed,
13437 * the user will only be able to select from the items defined in the dropdown list. This method
13438 * is the runtime equivalent of setting the 'editable' config option at config time.
13439 * @param {Boolean} value True to allow the user to directly edit the field text
13441 setEditable : function(value){
13442 if(value == this.editable){
13445 this.editable = value;
13447 this.inputEl().dom.setAttribute('readOnly', true);
13448 this.inputEl().on('mousedown', this.onTriggerClick, this);
13449 this.inputEl().addClass('x-combo-noedit');
13451 this.inputEl().dom.setAttribute('readOnly', false);
13452 this.inputEl().un('mousedown', this.onTriggerClick, this);
13453 this.inputEl().removeClass('x-combo-noedit');
13459 onBeforeLoad : function(combo,opts){
13460 if(!this.hasFocus){
13464 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13466 this.restrictHeight();
13467 this.selectedIndex = -1;
13471 onLoad : function(){
13473 this.hasQuery = false;
13475 if(!this.hasFocus){
13479 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13480 this.loading.hide();
13483 if(this.store.getCount() > 0){
13486 this.restrictHeight();
13487 if(this.lastQuery == this.allQuery){
13488 if(this.editable && !this.tickable){
13489 this.inputEl().dom.select();
13493 !this.selectByValue(this.value, true) &&
13496 !this.store.lastOptions ||
13497 typeof(this.store.lastOptions.add) == 'undefined' ||
13498 this.store.lastOptions.add != true
13501 this.select(0, true);
13504 if(this.autoFocus){
13507 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13508 this.taTask.delay(this.typeAheadDelay);
13512 this.onEmptyResults();
13518 onLoadException : function()
13520 this.hasQuery = false;
13522 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13523 this.loading.hide();
13526 if(this.tickable && this.editable){
13531 // only causes errors at present
13532 //Roo.log(this.store.reader.jsonData);
13533 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13535 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13541 onTypeAhead : function(){
13542 if(this.store.getCount() > 0){
13543 var r = this.store.getAt(0);
13544 var newValue = r.data[this.displayField];
13545 var len = newValue.length;
13546 var selStart = this.getRawValue().length;
13548 if(selStart != len){
13549 this.setRawValue(newValue);
13550 this.selectText(selStart, newValue.length);
13556 onSelect : function(record, index){
13558 if(this.fireEvent('beforeselect', this, record, index) !== false){
13560 this.setFromData(index > -1 ? record.data : false);
13563 this.fireEvent('select', this, record, index);
13568 * Returns the currently selected field value or empty string if no value is set.
13569 * @return {String} value The selected value
13571 getValue : function()
13573 if(Roo.isIOS && this.useNativeIOS){
13574 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13578 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13581 if(this.valueField){
13582 return typeof this.value != 'undefined' ? this.value : '';
13584 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13588 getRawValue : function()
13590 if(Roo.isIOS && this.useNativeIOS){
13591 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13594 var v = this.inputEl().getValue();
13600 * Clears any text/value currently set in the field
13602 clearValue : function(){
13604 if(this.hiddenField){
13605 this.hiddenField.dom.value = '';
13608 this.setRawValue('');
13609 this.lastSelectionText = '';
13610 this.lastData = false;
13612 var close = this.closeTriggerEl();
13623 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13624 * will be displayed in the field. If the value does not match the data value of an existing item,
13625 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13626 * Otherwise the field will be blank (although the value will still be set).
13627 * @param {String} value The value to match
13629 setValue : function(v)
13631 if(Roo.isIOS && this.useNativeIOS){
13632 this.setIOSValue(v);
13642 if(this.valueField){
13643 var r = this.findRecord(this.valueField, v);
13645 text = r.data[this.displayField];
13646 }else if(this.valueNotFoundText !== undefined){
13647 text = this.valueNotFoundText;
13650 this.lastSelectionText = text;
13651 if(this.hiddenField){
13652 this.hiddenField.dom.value = v;
13654 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13657 var close = this.closeTriggerEl();
13660 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13666 * @property {Object} the last set data for the element
13671 * Sets the value of the field based on a object which is related to the record format for the store.
13672 * @param {Object} value the value to set as. or false on reset?
13674 setFromData : function(o){
13681 var dv = ''; // display value
13682 var vv = ''; // value value..
13684 if (this.displayField) {
13685 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13687 // this is an error condition!!!
13688 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13691 if(this.valueField){
13692 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13695 var close = this.closeTriggerEl();
13698 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13701 if(this.hiddenField){
13702 this.hiddenField.dom.value = vv;
13704 this.lastSelectionText = dv;
13705 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13709 // no hidden field.. - we store the value in 'value', but still display
13710 // display field!!!!
13711 this.lastSelectionText = dv;
13712 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13719 reset : function(){
13720 // overridden so that last data is reset..
13727 this.setValue(this.originalValue);
13728 //this.clearInvalid();
13729 this.lastData = false;
13731 this.view.clearSelections();
13737 findRecord : function(prop, value){
13739 if(this.store.getCount() > 0){
13740 this.store.each(function(r){
13741 if(r.data[prop] == value){
13751 getName: function()
13753 // returns hidden if it's set..
13754 if (!this.rendered) {return ''};
13755 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13759 onViewMove : function(e, t){
13760 this.inKeyMode = false;
13764 onViewOver : function(e, t){
13765 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13768 var item = this.view.findItemFromChild(t);
13771 var index = this.view.indexOf(item);
13772 this.select(index, false);
13777 onViewClick : function(view, doFocus, el, e)
13779 var index = this.view.getSelectedIndexes()[0];
13781 var r = this.store.getAt(index);
13785 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13792 Roo.each(this.tickItems, function(v,k){
13794 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13796 _this.tickItems.splice(k, 1);
13798 if(typeof(e) == 'undefined' && view == false){
13799 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13811 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13812 this.tickItems.push(r.data);
13815 if(typeof(e) == 'undefined' && view == false){
13816 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13823 this.onSelect(r, index);
13825 if(doFocus !== false && !this.blockFocus){
13826 this.inputEl().focus();
13831 restrictHeight : function(){
13832 //this.innerList.dom.style.height = '';
13833 //var inner = this.innerList.dom;
13834 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13835 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13836 //this.list.beginUpdate();
13837 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13838 this.list.alignTo(this.inputEl(), this.listAlign);
13839 this.list.alignTo(this.inputEl(), this.listAlign);
13840 //this.list.endUpdate();
13844 onEmptyResults : function(){
13846 if(this.tickable && this.editable){
13847 this.restrictHeight();
13855 * Returns true if the dropdown list is expanded, else false.
13857 isExpanded : function(){
13858 return this.list.isVisible();
13862 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13863 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13864 * @param {String} value The data value of the item to select
13865 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13866 * selected item if it is not currently in view (defaults to true)
13867 * @return {Boolean} True if the value matched an item in the list, else false
13869 selectByValue : function(v, scrollIntoView){
13870 if(v !== undefined && v !== null){
13871 var r = this.findRecord(this.valueField || this.displayField, v);
13873 this.select(this.store.indexOf(r), scrollIntoView);
13881 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13882 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13883 * @param {Number} index The zero-based index of the list item to select
13884 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13885 * selected item if it is not currently in view (defaults to true)
13887 select : function(index, scrollIntoView){
13888 this.selectedIndex = index;
13889 this.view.select(index);
13890 if(scrollIntoView !== false){
13891 var el = this.view.getNode(index);
13893 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13896 this.list.scrollChildIntoView(el, false);
13902 selectNext : function(){
13903 var ct = this.store.getCount();
13905 if(this.selectedIndex == -1){
13907 }else if(this.selectedIndex < ct-1){
13908 this.select(this.selectedIndex+1);
13914 selectPrev : function(){
13915 var ct = this.store.getCount();
13917 if(this.selectedIndex == -1){
13919 }else if(this.selectedIndex != 0){
13920 this.select(this.selectedIndex-1);
13926 onKeyUp : function(e){
13927 if(this.editable !== false && !e.isSpecialKey()){
13928 this.lastKey = e.getKey();
13929 this.dqTask.delay(this.queryDelay);
13934 validateBlur : function(){
13935 return !this.list || !this.list.isVisible();
13939 initQuery : function(){
13941 var v = this.getRawValue();
13943 if(this.tickable && this.editable){
13944 v = this.tickableInputEl().getValue();
13951 doForce : function(){
13952 if(this.inputEl().dom.value.length > 0){
13953 this.inputEl().dom.value =
13954 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13960 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13961 * query allowing the query action to be canceled if needed.
13962 * @param {String} query The SQL query to execute
13963 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13964 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13965 * saved in the current store (defaults to false)
13967 doQuery : function(q, forceAll){
13969 if(q === undefined || q === null){
13974 forceAll: forceAll,
13978 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13983 forceAll = qe.forceAll;
13984 if(forceAll === true || (q.length >= this.minChars)){
13986 this.hasQuery = true;
13988 if(this.lastQuery != q || this.alwaysQuery){
13989 this.lastQuery = q;
13990 if(this.mode == 'local'){
13991 this.selectedIndex = -1;
13993 this.store.clearFilter();
13996 if(this.specialFilter){
13997 this.fireEvent('specialfilter', this);
14002 this.store.filter(this.displayField, q);
14005 this.store.fireEvent("datachanged", this.store);
14012 this.store.baseParams[this.queryParam] = q;
14014 var options = {params : this.getParams(q)};
14017 options.add = true;
14018 options.params.start = this.page * this.pageSize;
14021 this.store.load(options);
14024 * this code will make the page width larger, at the beginning, the list not align correctly,
14025 * we should expand the list on onLoad
14026 * so command out it
14031 this.selectedIndex = -1;
14036 this.loadNext = false;
14040 getParams : function(q){
14042 //p[this.queryParam] = q;
14046 p.limit = this.pageSize;
14052 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14054 collapse : function(){
14055 if(!this.isExpanded()){
14061 this.hasFocus = false;
14065 this.cancelBtn.hide();
14066 this.trigger.show();
14069 this.tickableInputEl().dom.value = '';
14070 this.tickableInputEl().blur();
14075 Roo.get(document).un('mousedown', this.collapseIf, this);
14076 Roo.get(document).un('mousewheel', this.collapseIf, this);
14077 if (!this.editable) {
14078 Roo.get(document).un('keydown', this.listKeyPress, this);
14080 this.fireEvent('collapse', this);
14086 collapseIf : function(e){
14087 var in_combo = e.within(this.el);
14088 var in_list = e.within(this.list);
14089 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14091 if (in_combo || in_list || is_list) {
14092 //e.stopPropagation();
14097 this.onTickableFooterButtonClick(e, false, false);
14105 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14107 expand : function(){
14109 if(this.isExpanded() || !this.hasFocus){
14113 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14114 this.list.setWidth(lw);
14120 this.restrictHeight();
14124 this.tickItems = Roo.apply([], this.item);
14127 this.cancelBtn.show();
14128 this.trigger.hide();
14131 this.tickableInputEl().focus();
14136 Roo.get(document).on('mousedown', this.collapseIf, this);
14137 Roo.get(document).on('mousewheel', this.collapseIf, this);
14138 if (!this.editable) {
14139 Roo.get(document).on('keydown', this.listKeyPress, this);
14142 this.fireEvent('expand', this);
14146 // Implements the default empty TriggerField.onTriggerClick function
14147 onTriggerClick : function(e)
14149 Roo.log('trigger click');
14151 if(this.disabled || !this.triggerList){
14156 this.loadNext = false;
14158 if(this.isExpanded()){
14160 if (!this.blockFocus) {
14161 this.inputEl().focus();
14165 this.hasFocus = true;
14166 if(this.triggerAction == 'all') {
14167 this.doQuery(this.allQuery, true);
14169 this.doQuery(this.getRawValue());
14171 if (!this.blockFocus) {
14172 this.inputEl().focus();
14177 onTickableTriggerClick : function(e)
14184 this.loadNext = false;
14185 this.hasFocus = true;
14187 if(this.triggerAction == 'all') {
14188 this.doQuery(this.allQuery, true);
14190 this.doQuery(this.getRawValue());
14194 onSearchFieldClick : function(e)
14196 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14197 this.onTickableFooterButtonClick(e, false, false);
14201 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14206 this.loadNext = false;
14207 this.hasFocus = true;
14209 if(this.triggerAction == 'all') {
14210 this.doQuery(this.allQuery, true);
14212 this.doQuery(this.getRawValue());
14216 listKeyPress : function(e)
14218 //Roo.log('listkeypress');
14219 // scroll to first matching element based on key pres..
14220 if (e.isSpecialKey()) {
14223 var k = String.fromCharCode(e.getKey()).toUpperCase();
14226 var csel = this.view.getSelectedNodes();
14227 var cselitem = false;
14229 var ix = this.view.indexOf(csel[0]);
14230 cselitem = this.store.getAt(ix);
14231 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14237 this.store.each(function(v) {
14239 // start at existing selection.
14240 if (cselitem.id == v.id) {
14246 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14247 match = this.store.indexOf(v);
14253 if (match === false) {
14254 return true; // no more action?
14257 this.view.select(match);
14258 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14259 sn.scrollIntoView(sn.dom.parentNode, false);
14262 onViewScroll : function(e, t){
14264 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){
14268 this.hasQuery = true;
14270 this.loading = this.list.select('.loading', true).first();
14272 if(this.loading === null){
14273 this.list.createChild({
14275 cls: 'loading roo-select2-more-results roo-select2-active',
14276 html: 'Loading more results...'
14279 this.loading = this.list.select('.loading', true).first();
14281 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14283 this.loading.hide();
14286 this.loading.show();
14291 this.loadNext = true;
14293 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14298 addItem : function(o)
14300 var dv = ''; // display value
14302 if (this.displayField) {
14303 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14305 // this is an error condition!!!
14306 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14313 var choice = this.choices.createChild({
14315 cls: 'roo-select2-search-choice',
14324 cls: 'roo-select2-search-choice-close fa fa-times',
14329 }, this.searchField);
14331 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14333 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14341 this.inputEl().dom.value = '';
14346 onRemoveItem : function(e, _self, o)
14348 e.preventDefault();
14350 this.lastItem = Roo.apply([], this.item);
14352 var index = this.item.indexOf(o.data) * 1;
14355 Roo.log('not this item?!');
14359 this.item.splice(index, 1);
14364 this.fireEvent('remove', this, e);
14370 syncValue : function()
14372 if(!this.item.length){
14379 Roo.each(this.item, function(i){
14380 if(_this.valueField){
14381 value.push(i[_this.valueField]);
14388 this.value = value.join(',');
14390 if(this.hiddenField){
14391 this.hiddenField.dom.value = this.value;
14394 this.store.fireEvent("datachanged", this.store);
14399 clearItem : function()
14401 if(!this.multiple){
14407 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14415 if(this.tickable && !Roo.isTouch){
14416 this.view.refresh();
14420 inputEl: function ()
14422 if(Roo.isIOS && this.useNativeIOS){
14423 return this.el.select('select.roo-ios-select', true).first();
14426 if(Roo.isTouch && this.mobileTouchView){
14427 return this.el.select('input.form-control',true).first();
14431 return this.searchField;
14434 return this.el.select('input.form-control',true).first();
14437 onTickableFooterButtonClick : function(e, btn, el)
14439 e.preventDefault();
14441 this.lastItem = Roo.apply([], this.item);
14443 if(btn && btn.name == 'cancel'){
14444 this.tickItems = Roo.apply([], this.item);
14453 Roo.each(this.tickItems, function(o){
14461 validate : function()
14463 var v = this.getRawValue();
14466 v = this.getValue();
14469 if(this.disabled || this.allowBlank || v.length){
14474 this.markInvalid();
14478 tickableInputEl : function()
14480 if(!this.tickable || !this.editable){
14481 return this.inputEl();
14484 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14488 getAutoCreateTouchView : function()
14493 cls: 'form-group' //input-group
14499 type : this.inputType,
14500 cls : 'form-control x-combo-noedit',
14501 autocomplete: 'new-password',
14502 placeholder : this.placeholder || '',
14507 input.name = this.name;
14511 input.cls += ' input-' + this.size;
14514 if (this.disabled) {
14515 input.disabled = true;
14526 inputblock.cls += ' input-group';
14528 inputblock.cn.unshift({
14530 cls : 'input-group-addon',
14535 if(this.removable && !this.multiple){
14536 inputblock.cls += ' roo-removable';
14538 inputblock.cn.push({
14541 cls : 'roo-combo-removable-btn close'
14545 if(this.hasFeedback && !this.allowBlank){
14547 inputblock.cls += ' has-feedback';
14549 inputblock.cn.push({
14551 cls: 'glyphicon form-control-feedback'
14558 inputblock.cls += (this.before) ? '' : ' input-group';
14560 inputblock.cn.push({
14562 cls : 'input-group-addon',
14573 cls: 'form-hidden-field'
14587 cls: 'form-hidden-field'
14591 cls: 'roo-select2-choices',
14595 cls: 'roo-select2-search-field',
14608 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14614 if(!this.multiple && this.showToggleBtn){
14621 if (this.caret != false) {
14624 cls: 'fa fa-' + this.caret
14631 cls : 'input-group-addon btn dropdown-toggle',
14636 cls: 'combobox-clear',
14650 combobox.cls += ' roo-select2-container-multi';
14653 var align = this.labelAlign || this.parentLabelAlign();
14655 if (align ==='left' && this.fieldLabel.length) {
14660 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14661 tooltip : 'This field is required'
14665 cls : 'control-label',
14666 html : this.fieldLabel
14677 var labelCfg = cfg.cn[1];
14678 var contentCfg = cfg.cn[2];
14681 if(this.indicatorpos == 'right'){
14685 cls : 'control-label',
14686 html : this.fieldLabel,
14690 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14691 tooltip : 'This field is required'
14704 labelCfg = cfg.cn[0];
14705 contentCfg = cfg.cn[2];
14707 if(this.labelWidth > 12){
14708 labelCfg.style = "width: " + this.labelWidth + 'px';
14711 if(this.labelWidth < 13 && this.labelmd == 0){
14712 this.labelmd = this.labelWidth;
14715 if(this.labellg > 0){
14716 labelCfg.cls += ' col-lg-' + this.labellg;
14717 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14720 if(this.labelmd > 0){
14721 labelCfg.cls += ' col-md-' + this.labelmd;
14722 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14725 if(this.labelsm > 0){
14726 labelCfg.cls += ' col-sm-' + this.labelsm;
14727 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14730 if(this.labelxs > 0){
14731 labelCfg.cls += ' col-xs-' + this.labelxs;
14732 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14736 } else if ( this.fieldLabel.length) {
14740 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14741 tooltip : 'This field is required'
14745 cls : 'control-label',
14746 html : this.fieldLabel
14757 if(this.indicatorpos == 'right'){
14761 cls : 'control-label',
14762 html : this.fieldLabel,
14766 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14767 tooltip : 'This field is required'
14784 var settings = this;
14786 ['xs','sm','md','lg'].map(function(size){
14787 if (settings[size]) {
14788 cfg.cls += ' col-' + size + '-' + settings[size];
14795 initTouchView : function()
14797 this.renderTouchView();
14799 this.touchViewEl.on('scroll', function(){
14800 this.el.dom.scrollTop = 0;
14803 this.originalValue = this.getValue();
14805 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14807 this.inputEl().on("click", this.showTouchView, this);
14808 if (this.triggerEl) {
14809 this.triggerEl.on("click", this.showTouchView, this);
14813 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14814 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14816 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14818 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14819 this.store.on('load', this.onTouchViewLoad, this);
14820 this.store.on('loadexception', this.onTouchViewLoadException, this);
14822 if(this.hiddenName){
14824 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14826 this.hiddenField.dom.value =
14827 this.hiddenValue !== undefined ? this.hiddenValue :
14828 this.value !== undefined ? this.value : '';
14830 this.el.dom.removeAttribute('name');
14831 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14835 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14836 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14839 if(this.removable && !this.multiple){
14840 var close = this.closeTriggerEl();
14842 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14843 close.on('click', this.removeBtnClick, this, close);
14847 * fix the bug in Safari iOS8
14849 this.inputEl().on("focus", function(e){
14850 document.activeElement.blur();
14858 renderTouchView : function()
14860 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14861 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14863 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14864 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14866 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14867 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14868 this.touchViewBodyEl.setStyle('overflow', 'auto');
14870 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14871 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14873 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14874 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14878 showTouchView : function()
14884 this.touchViewHeaderEl.hide();
14886 if(this.modalTitle.length){
14887 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14888 this.touchViewHeaderEl.show();
14891 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14892 this.touchViewEl.show();
14894 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14895 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14896 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14898 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14900 if(this.modalTitle.length){
14901 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14904 this.touchViewBodyEl.setHeight(bodyHeight);
14908 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14910 this.touchViewEl.addClass('in');
14913 this.doTouchViewQuery();
14917 hideTouchView : function()
14919 this.touchViewEl.removeClass('in');
14923 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14925 this.touchViewEl.setStyle('display', 'none');
14930 setTouchViewValue : function()
14937 Roo.each(this.tickItems, function(o){
14942 this.hideTouchView();
14945 doTouchViewQuery : function()
14954 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14958 if(!this.alwaysQuery || this.mode == 'local'){
14959 this.onTouchViewLoad();
14966 onTouchViewBeforeLoad : function(combo,opts)
14972 onTouchViewLoad : function()
14974 if(this.store.getCount() < 1){
14975 this.onTouchViewEmptyResults();
14979 this.clearTouchView();
14981 var rawValue = this.getRawValue();
14983 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14985 this.tickItems = [];
14987 this.store.data.each(function(d, rowIndex){
14988 var row = this.touchViewListGroup.createChild(template);
14990 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14991 row.addClass(d.data.cls);
14994 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14997 html : d.data[this.displayField]
15000 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15001 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15004 row.removeClass('selected');
15005 if(!this.multiple && this.valueField &&
15006 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15009 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15010 row.addClass('selected');
15013 if(this.multiple && this.valueField &&
15014 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15018 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15019 this.tickItems.push(d.data);
15022 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15026 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15028 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15030 if(this.modalTitle.length){
15031 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15034 var listHeight = this.touchViewListGroup.getHeight();
15038 if(firstChecked && listHeight > bodyHeight){
15039 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15044 onTouchViewLoadException : function()
15046 this.hideTouchView();
15049 onTouchViewEmptyResults : function()
15051 this.clearTouchView();
15053 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15055 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15059 clearTouchView : function()
15061 this.touchViewListGroup.dom.innerHTML = '';
15064 onTouchViewClick : function(e, el, o)
15066 e.preventDefault();
15069 var rowIndex = o.rowIndex;
15071 var r = this.store.getAt(rowIndex);
15073 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15075 if(!this.multiple){
15076 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15077 c.dom.removeAttribute('checked');
15080 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15082 this.setFromData(r.data);
15084 var close = this.closeTriggerEl();
15090 this.hideTouchView();
15092 this.fireEvent('select', this, r, rowIndex);
15097 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15098 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15099 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15103 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15104 this.addItem(r.data);
15105 this.tickItems.push(r.data);
15109 getAutoCreateNativeIOS : function()
15112 cls: 'form-group' //input-group,
15117 cls : 'roo-ios-select'
15121 combobox.name = this.name;
15124 if (this.disabled) {
15125 combobox.disabled = true;
15128 var settings = this;
15130 ['xs','sm','md','lg'].map(function(size){
15131 if (settings[size]) {
15132 cfg.cls += ' col-' + size + '-' + settings[size];
15142 initIOSView : function()
15144 this.store.on('load', this.onIOSViewLoad, this);
15149 onIOSViewLoad : function()
15151 if(this.store.getCount() < 1){
15155 this.clearIOSView();
15157 if(this.allowBlank) {
15159 var default_text = '-- SELECT --';
15161 var opt = this.inputEl().createChild({
15164 html : default_text
15168 o[this.valueField] = 0;
15169 o[this.displayField] = default_text;
15171 this.ios_options.push({
15178 this.store.data.each(function(d, rowIndex){
15182 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15183 html = d.data[this.displayField];
15188 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15189 value = d.data[this.valueField];
15198 if(this.value == d.data[this.valueField]){
15199 option['selected'] = true;
15202 var opt = this.inputEl().createChild(option);
15204 this.ios_options.push({
15211 this.inputEl().on('change', function(){
15212 this.fireEvent('select', this);
15217 clearIOSView: function()
15219 this.inputEl().dom.innerHTML = '';
15221 this.ios_options = [];
15224 setIOSValue: function(v)
15228 if(!this.ios_options){
15232 Roo.each(this.ios_options, function(opts){
15234 opts.el.dom.removeAttribute('selected');
15236 if(opts.data[this.valueField] != v){
15240 opts.el.dom.setAttribute('selected', true);
15246 * @cfg {Boolean} grow
15250 * @cfg {Number} growMin
15254 * @cfg {Number} growMax
15263 Roo.apply(Roo.bootstrap.ComboBox, {
15267 cls: 'modal-header',
15289 cls: 'list-group-item',
15293 cls: 'roo-combobox-list-group-item-value'
15297 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15311 listItemCheckbox : {
15313 cls: 'list-group-item',
15317 cls: 'roo-combobox-list-group-item-value'
15321 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15337 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15342 cls: 'modal-footer',
15350 cls: 'col-xs-6 text-left',
15353 cls: 'btn btn-danger roo-touch-view-cancel',
15359 cls: 'col-xs-6 text-right',
15362 cls: 'btn btn-success roo-touch-view-ok',
15373 Roo.apply(Roo.bootstrap.ComboBox, {
15375 touchViewTemplate : {
15377 cls: 'modal fade roo-combobox-touch-view',
15381 cls: 'modal-dialog',
15382 style : 'position:fixed', // we have to fix position....
15386 cls: 'modal-content',
15388 Roo.bootstrap.ComboBox.header,
15389 Roo.bootstrap.ComboBox.body,
15390 Roo.bootstrap.ComboBox.footer
15399 * Ext JS Library 1.1.1
15400 * Copyright(c) 2006-2007, Ext JS, LLC.
15402 * Originally Released Under LGPL - original licence link has changed is not relivant.
15405 * <script type="text/javascript">
15410 * @extends Roo.util.Observable
15411 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15412 * This class also supports single and multi selection modes. <br>
15413 * Create a data model bound view:
15415 var store = new Roo.data.Store(...);
15417 var view = new Roo.View({
15419 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15421 singleSelect: true,
15422 selectedClass: "ydataview-selected",
15426 // listen for node click?
15427 view.on("click", function(vw, index, node, e){
15428 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15432 dataModel.load("foobar.xml");
15434 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15436 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15437 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15439 * Note: old style constructor is still suported (container, template, config)
15442 * Create a new View
15443 * @param {Object} config The config object
15446 Roo.View = function(config, depreciated_tpl, depreciated_config){
15448 this.parent = false;
15450 if (typeof(depreciated_tpl) == 'undefined') {
15451 // new way.. - universal constructor.
15452 Roo.apply(this, config);
15453 this.el = Roo.get(this.el);
15456 this.el = Roo.get(config);
15457 this.tpl = depreciated_tpl;
15458 Roo.apply(this, depreciated_config);
15460 this.wrapEl = this.el.wrap().wrap();
15461 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15464 if(typeof(this.tpl) == "string"){
15465 this.tpl = new Roo.Template(this.tpl);
15467 // support xtype ctors..
15468 this.tpl = new Roo.factory(this.tpl, Roo);
15472 this.tpl.compile();
15477 * @event beforeclick
15478 * Fires before a click is processed. Returns false to cancel the default action.
15479 * @param {Roo.View} this
15480 * @param {Number} index The index of the target node
15481 * @param {HTMLElement} node The target node
15482 * @param {Roo.EventObject} e The raw event object
15484 "beforeclick" : true,
15487 * Fires when a template node is clicked.
15488 * @param {Roo.View} this
15489 * @param {Number} index The index of the target node
15490 * @param {HTMLElement} node The target node
15491 * @param {Roo.EventObject} e The raw event object
15496 * Fires when a template node is double clicked.
15497 * @param {Roo.View} this
15498 * @param {Number} index The index of the target node
15499 * @param {HTMLElement} node The target node
15500 * @param {Roo.EventObject} e The raw event object
15504 * @event contextmenu
15505 * Fires when a template node is right clicked.
15506 * @param {Roo.View} this
15507 * @param {Number} index The index of the target node
15508 * @param {HTMLElement} node The target node
15509 * @param {Roo.EventObject} e The raw event object
15511 "contextmenu" : true,
15513 * @event selectionchange
15514 * Fires when the selected nodes change.
15515 * @param {Roo.View} this
15516 * @param {Array} selections Array of the selected nodes
15518 "selectionchange" : true,
15521 * @event beforeselect
15522 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15523 * @param {Roo.View} this
15524 * @param {HTMLElement} node The node to be selected
15525 * @param {Array} selections Array of currently selected nodes
15527 "beforeselect" : true,
15529 * @event preparedata
15530 * Fires on every row to render, to allow you to change the data.
15531 * @param {Roo.View} this
15532 * @param {Object} data to be rendered (change this)
15534 "preparedata" : true
15542 "click": this.onClick,
15543 "dblclick": this.onDblClick,
15544 "contextmenu": this.onContextMenu,
15548 this.selections = [];
15550 this.cmp = new Roo.CompositeElementLite([]);
15552 this.store = Roo.factory(this.store, Roo.data);
15553 this.setStore(this.store, true);
15556 if ( this.footer && this.footer.xtype) {
15558 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15560 this.footer.dataSource = this.store;
15561 this.footer.container = fctr;
15562 this.footer = Roo.factory(this.footer, Roo);
15563 fctr.insertFirst(this.el);
15565 // this is a bit insane - as the paging toolbar seems to detach the el..
15566 // dom.parentNode.parentNode.parentNode
15567 // they get detached?
15571 Roo.View.superclass.constructor.call(this);
15576 Roo.extend(Roo.View, Roo.util.Observable, {
15579 * @cfg {Roo.data.Store} store Data store to load data from.
15584 * @cfg {String|Roo.Element} el The container element.
15589 * @cfg {String|Roo.Template} tpl The template used by this View
15593 * @cfg {String} dataName the named area of the template to use as the data area
15594 * Works with domtemplates roo-name="name"
15598 * @cfg {String} selectedClass The css class to add to selected nodes
15600 selectedClass : "x-view-selected",
15602 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15607 * @cfg {String} text to display on mask (default Loading)
15611 * @cfg {Boolean} multiSelect Allow multiple selection
15613 multiSelect : false,
15615 * @cfg {Boolean} singleSelect Allow single selection
15617 singleSelect: false,
15620 * @cfg {Boolean} toggleSelect - selecting
15622 toggleSelect : false,
15625 * @cfg {Boolean} tickable - selecting
15630 * Returns the element this view is bound to.
15631 * @return {Roo.Element}
15633 getEl : function(){
15634 return this.wrapEl;
15640 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15642 refresh : function(){
15643 //Roo.log('refresh');
15646 // if we are using something like 'domtemplate', then
15647 // the what gets used is:
15648 // t.applySubtemplate(NAME, data, wrapping data..)
15649 // the outer template then get' applied with
15650 // the store 'extra data'
15651 // and the body get's added to the
15652 // roo-name="data" node?
15653 // <span class='roo-tpl-{name}'></span> ?????
15657 this.clearSelections();
15658 this.el.update("");
15660 var records = this.store.getRange();
15661 if(records.length < 1) {
15663 // is this valid?? = should it render a template??
15665 this.el.update(this.emptyText);
15669 if (this.dataName) {
15670 this.el.update(t.apply(this.store.meta)); //????
15671 el = this.el.child('.roo-tpl-' + this.dataName);
15674 for(var i = 0, len = records.length; i < len; i++){
15675 var data = this.prepareData(records[i].data, i, records[i]);
15676 this.fireEvent("preparedata", this, data, i, records[i]);
15678 var d = Roo.apply({}, data);
15681 Roo.apply(d, {'roo-id' : Roo.id()});
15685 Roo.each(this.parent.item, function(item){
15686 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15689 Roo.apply(d, {'roo-data-checked' : 'checked'});
15693 html[html.length] = Roo.util.Format.trim(
15695 t.applySubtemplate(this.dataName, d, this.store.meta) :
15702 el.update(html.join(""));
15703 this.nodes = el.dom.childNodes;
15704 this.updateIndexes(0);
15709 * Function to override to reformat the data that is sent to
15710 * the template for each node.
15711 * DEPRICATED - use the preparedata event handler.
15712 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15713 * a JSON object for an UpdateManager bound view).
15715 prepareData : function(data, index, record)
15717 this.fireEvent("preparedata", this, data, index, record);
15721 onUpdate : function(ds, record){
15722 // Roo.log('on update');
15723 this.clearSelections();
15724 var index = this.store.indexOf(record);
15725 var n = this.nodes[index];
15726 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15727 n.parentNode.removeChild(n);
15728 this.updateIndexes(index, index);
15734 onAdd : function(ds, records, index)
15736 //Roo.log(['on Add', ds, records, index] );
15737 this.clearSelections();
15738 if(this.nodes.length == 0){
15742 var n = this.nodes[index];
15743 for(var i = 0, len = records.length; i < len; i++){
15744 var d = this.prepareData(records[i].data, i, records[i]);
15746 this.tpl.insertBefore(n, d);
15749 this.tpl.append(this.el, d);
15752 this.updateIndexes(index);
15755 onRemove : function(ds, record, index){
15756 // Roo.log('onRemove');
15757 this.clearSelections();
15758 var el = this.dataName ?
15759 this.el.child('.roo-tpl-' + this.dataName) :
15762 el.dom.removeChild(this.nodes[index]);
15763 this.updateIndexes(index);
15767 * Refresh an individual node.
15768 * @param {Number} index
15770 refreshNode : function(index){
15771 this.onUpdate(this.store, this.store.getAt(index));
15774 updateIndexes : function(startIndex, endIndex){
15775 var ns = this.nodes;
15776 startIndex = startIndex || 0;
15777 endIndex = endIndex || ns.length - 1;
15778 for(var i = startIndex; i <= endIndex; i++){
15779 ns[i].nodeIndex = i;
15784 * Changes the data store this view uses and refresh the view.
15785 * @param {Store} store
15787 setStore : function(store, initial){
15788 if(!initial && this.store){
15789 this.store.un("datachanged", this.refresh);
15790 this.store.un("add", this.onAdd);
15791 this.store.un("remove", this.onRemove);
15792 this.store.un("update", this.onUpdate);
15793 this.store.un("clear", this.refresh);
15794 this.store.un("beforeload", this.onBeforeLoad);
15795 this.store.un("load", this.onLoad);
15796 this.store.un("loadexception", this.onLoad);
15800 store.on("datachanged", this.refresh, this);
15801 store.on("add", this.onAdd, this);
15802 store.on("remove", this.onRemove, this);
15803 store.on("update", this.onUpdate, this);
15804 store.on("clear", this.refresh, this);
15805 store.on("beforeload", this.onBeforeLoad, this);
15806 store.on("load", this.onLoad, this);
15807 store.on("loadexception", this.onLoad, this);
15815 * onbeforeLoad - masks the loading area.
15818 onBeforeLoad : function(store,opts)
15820 //Roo.log('onBeforeLoad');
15822 this.el.update("");
15824 this.el.mask(this.mask ? this.mask : "Loading" );
15826 onLoad : function ()
15833 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15834 * @param {HTMLElement} node
15835 * @return {HTMLElement} The template node
15837 findItemFromChild : function(node){
15838 var el = this.dataName ?
15839 this.el.child('.roo-tpl-' + this.dataName,true) :
15842 if(!node || node.parentNode == el){
15845 var p = node.parentNode;
15846 while(p && p != el){
15847 if(p.parentNode == el){
15856 onClick : function(e){
15857 var item = this.findItemFromChild(e.getTarget());
15859 var index = this.indexOf(item);
15860 if(this.onItemClick(item, index, e) !== false){
15861 this.fireEvent("click", this, index, item, e);
15864 this.clearSelections();
15869 onContextMenu : function(e){
15870 var item = this.findItemFromChild(e.getTarget());
15872 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15877 onDblClick : function(e){
15878 var item = this.findItemFromChild(e.getTarget());
15880 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15884 onItemClick : function(item, index, e)
15886 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15889 if (this.toggleSelect) {
15890 var m = this.isSelected(item) ? 'unselect' : 'select';
15893 _t[m](item, true, false);
15896 if(this.multiSelect || this.singleSelect){
15897 if(this.multiSelect && e.shiftKey && this.lastSelection){
15898 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15900 this.select(item, this.multiSelect && e.ctrlKey);
15901 this.lastSelection = item;
15904 if(!this.tickable){
15905 e.preventDefault();
15913 * Get the number of selected nodes.
15916 getSelectionCount : function(){
15917 return this.selections.length;
15921 * Get the currently selected nodes.
15922 * @return {Array} An array of HTMLElements
15924 getSelectedNodes : function(){
15925 return this.selections;
15929 * Get the indexes of the selected nodes.
15932 getSelectedIndexes : function(){
15933 var indexes = [], s = this.selections;
15934 for(var i = 0, len = s.length; i < len; i++){
15935 indexes.push(s[i].nodeIndex);
15941 * Clear all selections
15942 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15944 clearSelections : function(suppressEvent){
15945 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15946 this.cmp.elements = this.selections;
15947 this.cmp.removeClass(this.selectedClass);
15948 this.selections = [];
15949 if(!suppressEvent){
15950 this.fireEvent("selectionchange", this, this.selections);
15956 * Returns true if the passed node is selected
15957 * @param {HTMLElement/Number} node The node or node index
15958 * @return {Boolean}
15960 isSelected : function(node){
15961 var s = this.selections;
15965 node = this.getNode(node);
15966 return s.indexOf(node) !== -1;
15971 * @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
15972 * @param {Boolean} keepExisting (optional) true to keep existing selections
15973 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15975 select : function(nodeInfo, keepExisting, suppressEvent){
15976 if(nodeInfo instanceof Array){
15978 this.clearSelections(true);
15980 for(var i = 0, len = nodeInfo.length; i < len; i++){
15981 this.select(nodeInfo[i], true, true);
15985 var node = this.getNode(nodeInfo);
15986 if(!node || this.isSelected(node)){
15987 return; // already selected.
15990 this.clearSelections(true);
15993 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15994 Roo.fly(node).addClass(this.selectedClass);
15995 this.selections.push(node);
15996 if(!suppressEvent){
15997 this.fireEvent("selectionchange", this, this.selections);
16005 * @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
16006 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16007 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16009 unselect : function(nodeInfo, keepExisting, suppressEvent)
16011 if(nodeInfo instanceof Array){
16012 Roo.each(this.selections, function(s) {
16013 this.unselect(s, nodeInfo);
16017 var node = this.getNode(nodeInfo);
16018 if(!node || !this.isSelected(node)){
16019 //Roo.log("not selected");
16020 return; // not selected.
16024 Roo.each(this.selections, function(s) {
16026 Roo.fly(node).removeClass(this.selectedClass);
16033 this.selections= ns;
16034 this.fireEvent("selectionchange", this, this.selections);
16038 * Gets a template node.
16039 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16040 * @return {HTMLElement} The node or null if it wasn't found
16042 getNode : function(nodeInfo){
16043 if(typeof nodeInfo == "string"){
16044 return document.getElementById(nodeInfo);
16045 }else if(typeof nodeInfo == "number"){
16046 return this.nodes[nodeInfo];
16052 * Gets a range template nodes.
16053 * @param {Number} startIndex
16054 * @param {Number} endIndex
16055 * @return {Array} An array of nodes
16057 getNodes : function(start, end){
16058 var ns = this.nodes;
16059 start = start || 0;
16060 end = typeof end == "undefined" ? ns.length - 1 : end;
16063 for(var i = start; i <= end; i++){
16067 for(var i = start; i >= end; i--){
16075 * Finds the index of the passed node
16076 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16077 * @return {Number} The index of the node or -1
16079 indexOf : function(node){
16080 node = this.getNode(node);
16081 if(typeof node.nodeIndex == "number"){
16082 return node.nodeIndex;
16084 var ns = this.nodes;
16085 for(var i = 0, len = ns.length; i < len; i++){
16096 * based on jquery fullcalendar
16100 Roo.bootstrap = Roo.bootstrap || {};
16102 * @class Roo.bootstrap.Calendar
16103 * @extends Roo.bootstrap.Component
16104 * Bootstrap Calendar class
16105 * @cfg {Boolean} loadMask (true|false) default false
16106 * @cfg {Object} header generate the user specific header of the calendar, default false
16109 * Create a new Container
16110 * @param {Object} config The config object
16115 Roo.bootstrap.Calendar = function(config){
16116 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16120 * Fires when a date is selected
16121 * @param {DatePicker} this
16122 * @param {Date} date The selected date
16126 * @event monthchange
16127 * Fires when the displayed month changes
16128 * @param {DatePicker} this
16129 * @param {Date} date The selected month
16131 'monthchange': true,
16133 * @event evententer
16134 * Fires when mouse over an event
16135 * @param {Calendar} this
16136 * @param {event} Event
16138 'evententer': true,
16140 * @event eventleave
16141 * Fires when the mouse leaves an
16142 * @param {Calendar} this
16145 'eventleave': true,
16147 * @event eventclick
16148 * Fires when the mouse click an
16149 * @param {Calendar} this
16158 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16161 * @cfg {Number} startDay
16162 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16170 getAutoCreate : function(){
16173 var fc_button = function(name, corner, style, content ) {
16174 return Roo.apply({},{
16176 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16178 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16181 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16192 style : 'width:100%',
16199 cls : 'fc-header-left',
16201 fc_button('prev', 'left', 'arrow', '‹' ),
16202 fc_button('next', 'right', 'arrow', '›' ),
16203 { tag: 'span', cls: 'fc-header-space' },
16204 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16212 cls : 'fc-header-center',
16216 cls: 'fc-header-title',
16219 html : 'month / year'
16227 cls : 'fc-header-right',
16229 /* fc_button('month', 'left', '', 'month' ),
16230 fc_button('week', '', '', 'week' ),
16231 fc_button('day', 'right', '', 'day' )
16243 header = this.header;
16246 var cal_heads = function() {
16248 // fixme - handle this.
16250 for (var i =0; i < Date.dayNames.length; i++) {
16251 var d = Date.dayNames[i];
16254 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16255 html : d.substring(0,3)
16259 ret[0].cls += ' fc-first';
16260 ret[6].cls += ' fc-last';
16263 var cal_cell = function(n) {
16266 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16271 cls: 'fc-day-number',
16275 cls: 'fc-day-content',
16279 style: 'position: relative;' // height: 17px;
16291 var cal_rows = function() {
16294 for (var r = 0; r < 6; r++) {
16301 for (var i =0; i < Date.dayNames.length; i++) {
16302 var d = Date.dayNames[i];
16303 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16306 row.cn[0].cls+=' fc-first';
16307 row.cn[0].cn[0].style = 'min-height:90px';
16308 row.cn[6].cls+=' fc-last';
16312 ret[0].cls += ' fc-first';
16313 ret[4].cls += ' fc-prev-last';
16314 ret[5].cls += ' fc-last';
16321 cls: 'fc-border-separate',
16322 style : 'width:100%',
16330 cls : 'fc-first fc-last',
16348 cls : 'fc-content',
16349 style : "position: relative;",
16352 cls : 'fc-view fc-view-month fc-grid',
16353 style : 'position: relative',
16354 unselectable : 'on',
16357 cls : 'fc-event-container',
16358 style : 'position:absolute;z-index:8;top:0;left:0;'
16376 initEvents : function()
16379 throw "can not find store for calendar";
16385 style: "text-align:center",
16389 style: "background-color:white;width:50%;margin:250 auto",
16393 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16404 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16406 var size = this.el.select('.fc-content', true).first().getSize();
16407 this.maskEl.setSize(size.width, size.height);
16408 this.maskEl.enableDisplayMode("block");
16409 if(!this.loadMask){
16410 this.maskEl.hide();
16413 this.store = Roo.factory(this.store, Roo.data);
16414 this.store.on('load', this.onLoad, this);
16415 this.store.on('beforeload', this.onBeforeLoad, this);
16419 this.cells = this.el.select('.fc-day',true);
16420 //Roo.log(this.cells);
16421 this.textNodes = this.el.query('.fc-day-number');
16422 this.cells.addClassOnOver('fc-state-hover');
16424 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16425 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16426 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16427 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16429 this.on('monthchange', this.onMonthChange, this);
16431 this.update(new Date().clearTime());
16434 resize : function() {
16435 var sz = this.el.getSize();
16437 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16438 this.el.select('.fc-day-content div',true).setHeight(34);
16443 showPrevMonth : function(e){
16444 this.update(this.activeDate.add("mo", -1));
16446 showToday : function(e){
16447 this.update(new Date().clearTime());
16450 showNextMonth : function(e){
16451 this.update(this.activeDate.add("mo", 1));
16455 showPrevYear : function(){
16456 this.update(this.activeDate.add("y", -1));
16460 showNextYear : function(){
16461 this.update(this.activeDate.add("y", 1));
16466 update : function(date)
16468 var vd = this.activeDate;
16469 this.activeDate = date;
16470 // if(vd && this.el){
16471 // var t = date.getTime();
16472 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16473 // Roo.log('using add remove');
16475 // this.fireEvent('monthchange', this, date);
16477 // this.cells.removeClass("fc-state-highlight");
16478 // this.cells.each(function(c){
16479 // if(c.dateValue == t){
16480 // c.addClass("fc-state-highlight");
16481 // setTimeout(function(){
16482 // try{c.dom.firstChild.focus();}catch(e){}
16492 var days = date.getDaysInMonth();
16494 var firstOfMonth = date.getFirstDateOfMonth();
16495 var startingPos = firstOfMonth.getDay()-this.startDay;
16497 if(startingPos < this.startDay){
16501 var pm = date.add(Date.MONTH, -1);
16502 var prevStart = pm.getDaysInMonth()-startingPos;
16504 this.cells = this.el.select('.fc-day',true);
16505 this.textNodes = this.el.query('.fc-day-number');
16506 this.cells.addClassOnOver('fc-state-hover');
16508 var cells = this.cells.elements;
16509 var textEls = this.textNodes;
16511 Roo.each(cells, function(cell){
16512 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16515 days += startingPos;
16517 // convert everything to numbers so it's fast
16518 var day = 86400000;
16519 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16522 //Roo.log(prevStart);
16524 var today = new Date().clearTime().getTime();
16525 var sel = date.clearTime().getTime();
16526 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16527 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16528 var ddMatch = this.disabledDatesRE;
16529 var ddText = this.disabledDatesText;
16530 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16531 var ddaysText = this.disabledDaysText;
16532 var format = this.format;
16534 var setCellClass = function(cal, cell){
16538 //Roo.log('set Cell Class');
16540 var t = d.getTime();
16544 cell.dateValue = t;
16546 cell.className += " fc-today";
16547 cell.className += " fc-state-highlight";
16548 cell.title = cal.todayText;
16551 // disable highlight in other month..
16552 //cell.className += " fc-state-highlight";
16557 cell.className = " fc-state-disabled";
16558 cell.title = cal.minText;
16562 cell.className = " fc-state-disabled";
16563 cell.title = cal.maxText;
16567 if(ddays.indexOf(d.getDay()) != -1){
16568 cell.title = ddaysText;
16569 cell.className = " fc-state-disabled";
16572 if(ddMatch && format){
16573 var fvalue = d.dateFormat(format);
16574 if(ddMatch.test(fvalue)){
16575 cell.title = ddText.replace("%0", fvalue);
16576 cell.className = " fc-state-disabled";
16580 if (!cell.initialClassName) {
16581 cell.initialClassName = cell.dom.className;
16584 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16589 for(; i < startingPos; i++) {
16590 textEls[i].innerHTML = (++prevStart);
16591 d.setDate(d.getDate()+1);
16593 cells[i].className = "fc-past fc-other-month";
16594 setCellClass(this, cells[i]);
16599 for(; i < days; i++){
16600 intDay = i - startingPos + 1;
16601 textEls[i].innerHTML = (intDay);
16602 d.setDate(d.getDate()+1);
16604 cells[i].className = ''; // "x-date-active";
16605 setCellClass(this, cells[i]);
16609 for(; i < 42; i++) {
16610 textEls[i].innerHTML = (++extraDays);
16611 d.setDate(d.getDate()+1);
16613 cells[i].className = "fc-future fc-other-month";
16614 setCellClass(this, cells[i]);
16617 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16619 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16621 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16622 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16624 if(totalRows != 6){
16625 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16626 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16629 this.fireEvent('monthchange', this, date);
16633 if(!this.internalRender){
16634 var main = this.el.dom.firstChild;
16635 var w = main.offsetWidth;
16636 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16637 Roo.fly(main).setWidth(w);
16638 this.internalRender = true;
16639 // opera does not respect the auto grow header center column
16640 // then, after it gets a width opera refuses to recalculate
16641 // without a second pass
16642 if(Roo.isOpera && !this.secondPass){
16643 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16644 this.secondPass = true;
16645 this.update.defer(10, this, [date]);
16652 findCell : function(dt) {
16653 dt = dt.clearTime().getTime();
16655 this.cells.each(function(c){
16656 //Roo.log("check " +c.dateValue + '?=' + dt);
16657 if(c.dateValue == dt){
16667 findCells : function(ev) {
16668 var s = ev.start.clone().clearTime().getTime();
16670 var e= ev.end.clone().clearTime().getTime();
16673 this.cells.each(function(c){
16674 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16676 if(c.dateValue > e){
16679 if(c.dateValue < s){
16688 // findBestRow: function(cells)
16692 // for (var i =0 ; i < cells.length;i++) {
16693 // ret = Math.max(cells[i].rows || 0,ret);
16700 addItem : function(ev)
16702 // look for vertical location slot in
16703 var cells = this.findCells(ev);
16705 // ev.row = this.findBestRow(cells);
16707 // work out the location.
16711 for(var i =0; i < cells.length; i++) {
16713 cells[i].row = cells[0].row;
16716 cells[i].row = cells[i].row + 1;
16726 if (crow.start.getY() == cells[i].getY()) {
16728 crow.end = cells[i];
16745 cells[0].events.push(ev);
16747 this.calevents.push(ev);
16750 clearEvents: function() {
16752 if(!this.calevents){
16756 Roo.each(this.cells.elements, function(c){
16762 Roo.each(this.calevents, function(e) {
16763 Roo.each(e.els, function(el) {
16764 el.un('mouseenter' ,this.onEventEnter, this);
16765 el.un('mouseleave' ,this.onEventLeave, this);
16770 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16776 renderEvents: function()
16780 this.cells.each(function(c) {
16789 if(c.row != c.events.length){
16790 r = 4 - (4 - (c.row - c.events.length));
16793 c.events = ev.slice(0, r);
16794 c.more = ev.slice(r);
16796 if(c.more.length && c.more.length == 1){
16797 c.events.push(c.more.pop());
16800 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16804 this.cells.each(function(c) {
16806 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16809 for (var e = 0; e < c.events.length; e++){
16810 var ev = c.events[e];
16811 var rows = ev.rows;
16813 for(var i = 0; i < rows.length; i++) {
16815 // how many rows should it span..
16818 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16819 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16821 unselectable : "on",
16824 cls: 'fc-event-inner',
16828 // cls: 'fc-event-time',
16829 // html : cells.length > 1 ? '' : ev.time
16833 cls: 'fc-event-title',
16834 html : String.format('{0}', ev.title)
16841 cls: 'ui-resizable-handle ui-resizable-e',
16842 html : '  '
16849 cfg.cls += ' fc-event-start';
16851 if ((i+1) == rows.length) {
16852 cfg.cls += ' fc-event-end';
16855 var ctr = _this.el.select('.fc-event-container',true).first();
16856 var cg = ctr.createChild(cfg);
16858 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16859 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16861 var r = (c.more.length) ? 1 : 0;
16862 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16863 cg.setWidth(ebox.right - sbox.x -2);
16865 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16866 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16867 cg.on('click', _this.onEventClick, _this, ev);
16878 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16879 style : 'position: absolute',
16880 unselectable : "on",
16883 cls: 'fc-event-inner',
16887 cls: 'fc-event-title',
16895 cls: 'ui-resizable-handle ui-resizable-e',
16896 html : '  '
16902 var ctr = _this.el.select('.fc-event-container',true).first();
16903 var cg = ctr.createChild(cfg);
16905 var sbox = c.select('.fc-day-content',true).first().getBox();
16906 var ebox = c.select('.fc-day-content',true).first().getBox();
16908 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16909 cg.setWidth(ebox.right - sbox.x -2);
16911 cg.on('click', _this.onMoreEventClick, _this, c.more);
16921 onEventEnter: function (e, el,event,d) {
16922 this.fireEvent('evententer', this, el, event);
16925 onEventLeave: function (e, el,event,d) {
16926 this.fireEvent('eventleave', this, el, event);
16929 onEventClick: function (e, el,event,d) {
16930 this.fireEvent('eventclick', this, el, event);
16933 onMonthChange: function () {
16937 onMoreEventClick: function(e, el, more)
16941 this.calpopover.placement = 'right';
16942 this.calpopover.setTitle('More');
16944 this.calpopover.setContent('');
16946 var ctr = this.calpopover.el.select('.popover-content', true).first();
16948 Roo.each(more, function(m){
16950 cls : 'fc-event-hori fc-event-draggable',
16953 var cg = ctr.createChild(cfg);
16955 cg.on('click', _this.onEventClick, _this, m);
16958 this.calpopover.show(el);
16963 onLoad: function ()
16965 this.calevents = [];
16968 if(this.store.getCount() > 0){
16969 this.store.data.each(function(d){
16972 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16973 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16974 time : d.data.start_time,
16975 title : d.data.title,
16976 description : d.data.description,
16977 venue : d.data.venue
16982 this.renderEvents();
16984 if(this.calevents.length && this.loadMask){
16985 this.maskEl.hide();
16989 onBeforeLoad: function()
16991 this.clearEvents();
16993 this.maskEl.show();
17007 * @class Roo.bootstrap.Popover
17008 * @extends Roo.bootstrap.Component
17009 * Bootstrap Popover class
17010 * @cfg {String} html contents of the popover (or false to use children..)
17011 * @cfg {String} title of popover (or false to hide)
17012 * @cfg {String} placement how it is placed
17013 * @cfg {String} trigger click || hover (or false to trigger manually)
17014 * @cfg {String} over what (parent or false to trigger manually.)
17015 * @cfg {Number} delay - delay before showing
17018 * Create a new Popover
17019 * @param {Object} config The config object
17022 Roo.bootstrap.Popover = function(config){
17023 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17029 * After the popover show
17031 * @param {Roo.bootstrap.Popover} this
17036 * After the popover hide
17038 * @param {Roo.bootstrap.Popover} this
17044 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17046 title: 'Fill in a title',
17049 placement : 'right',
17050 trigger : 'hover', // hover
17056 can_build_overlaid : false,
17058 getChildContainer : function()
17060 return this.el.select('.popover-content',true).first();
17063 getAutoCreate : function(){
17066 cls : 'popover roo-dynamic',
17067 style: 'display:block',
17073 cls : 'popover-inner',
17077 cls: 'popover-title',
17081 cls : 'popover-content',
17092 setTitle: function(str)
17095 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17097 setContent: function(str)
17100 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17102 // as it get's added to the bottom of the page.
17103 onRender : function(ct, position)
17105 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17107 var cfg = Roo.apply({}, this.getAutoCreate());
17111 cfg.cls += ' ' + this.cls;
17114 cfg.style = this.style;
17116 //Roo.log("adding to ");
17117 this.el = Roo.get(document.body).createChild(cfg, position);
17118 // Roo.log(this.el);
17123 initEvents : function()
17125 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17126 this.el.enableDisplayMode('block');
17128 if (this.over === false) {
17131 if (this.triggers === false) {
17134 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17135 var triggers = this.trigger ? this.trigger.split(' ') : [];
17136 Roo.each(triggers, function(trigger) {
17138 if (trigger == 'click') {
17139 on_el.on('click', this.toggle, this);
17140 } else if (trigger != 'manual') {
17141 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17142 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17144 on_el.on(eventIn ,this.enter, this);
17145 on_el.on(eventOut, this.leave, this);
17156 toggle : function () {
17157 this.hoverState == 'in' ? this.leave() : this.enter();
17160 enter : function () {
17162 clearTimeout(this.timeout);
17164 this.hoverState = 'in';
17166 if (!this.delay || !this.delay.show) {
17171 this.timeout = setTimeout(function () {
17172 if (_t.hoverState == 'in') {
17175 }, this.delay.show)
17178 leave : function() {
17179 clearTimeout(this.timeout);
17181 this.hoverState = 'out';
17183 if (!this.delay || !this.delay.hide) {
17188 this.timeout = setTimeout(function () {
17189 if (_t.hoverState == 'out') {
17192 }, this.delay.hide)
17195 show : function (on_el)
17198 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17202 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17203 if (this.html !== false) {
17204 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17206 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17207 if (!this.title.length) {
17208 this.el.select('.popover-title',true).hide();
17211 var placement = typeof this.placement == 'function' ?
17212 this.placement.call(this, this.el, on_el) :
17215 var autoToken = /\s?auto?\s?/i;
17216 var autoPlace = autoToken.test(placement);
17218 placement = placement.replace(autoToken, '') || 'top';
17222 //this.el.setXY([0,0]);
17224 this.el.dom.style.display='block';
17225 this.el.addClass(placement);
17227 //this.el.appendTo(on_el);
17229 var p = this.getPosition();
17230 var box = this.el.getBox();
17235 var align = Roo.bootstrap.Popover.alignment[placement];
17236 this.el.alignTo(on_el, align[0],align[1]);
17237 //var arrow = this.el.select('.arrow',true).first();
17238 //arrow.set(align[2],
17240 this.el.addClass('in');
17243 if (this.el.hasClass('fade')) {
17247 this.hoverState = 'in';
17249 this.fireEvent('show', this);
17254 this.el.setXY([0,0]);
17255 this.el.removeClass('in');
17257 this.hoverState = null;
17259 this.fireEvent('hide', this);
17264 Roo.bootstrap.Popover.alignment = {
17265 'left' : ['r-l', [-10,0], 'right'],
17266 'right' : ['l-r', [10,0], 'left'],
17267 'bottom' : ['t-b', [0,10], 'top'],
17268 'top' : [ 'b-t', [0,-10], 'bottom']
17279 * @class Roo.bootstrap.Progress
17280 * @extends Roo.bootstrap.Component
17281 * Bootstrap Progress class
17282 * @cfg {Boolean} striped striped of the progress bar
17283 * @cfg {Boolean} active animated of the progress bar
17287 * Create a new Progress
17288 * @param {Object} config The config object
17291 Roo.bootstrap.Progress = function(config){
17292 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17295 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17300 getAutoCreate : function(){
17308 cfg.cls += ' progress-striped';
17312 cfg.cls += ' active';
17331 * @class Roo.bootstrap.ProgressBar
17332 * @extends Roo.bootstrap.Component
17333 * Bootstrap ProgressBar class
17334 * @cfg {Number} aria_valuenow aria-value now
17335 * @cfg {Number} aria_valuemin aria-value min
17336 * @cfg {Number} aria_valuemax aria-value max
17337 * @cfg {String} label label for the progress bar
17338 * @cfg {String} panel (success | info | warning | danger )
17339 * @cfg {String} role role of the progress bar
17340 * @cfg {String} sr_only text
17344 * Create a new ProgressBar
17345 * @param {Object} config The config object
17348 Roo.bootstrap.ProgressBar = function(config){
17349 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17352 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17356 aria_valuemax : 100,
17362 getAutoCreate : function()
17367 cls: 'progress-bar',
17368 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17380 cfg.role = this.role;
17383 if(this.aria_valuenow){
17384 cfg['aria-valuenow'] = this.aria_valuenow;
17387 if(this.aria_valuemin){
17388 cfg['aria-valuemin'] = this.aria_valuemin;
17391 if(this.aria_valuemax){
17392 cfg['aria-valuemax'] = this.aria_valuemax;
17395 if(this.label && !this.sr_only){
17396 cfg.html = this.label;
17400 cfg.cls += ' progress-bar-' + this.panel;
17406 update : function(aria_valuenow)
17408 this.aria_valuenow = aria_valuenow;
17410 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17425 * @class Roo.bootstrap.TabGroup
17426 * @extends Roo.bootstrap.Column
17427 * Bootstrap Column class
17428 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17429 * @cfg {Boolean} carousel true to make the group behave like a carousel
17430 * @cfg {Boolean} bullets show bullets for the panels
17431 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17432 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17433 * @cfg {Boolean} showarrow (true|false) show arrow default true
17436 * Create a new TabGroup
17437 * @param {Object} config The config object
17440 Roo.bootstrap.TabGroup = function(config){
17441 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17443 this.navId = Roo.id();
17446 Roo.bootstrap.TabGroup.register(this);
17450 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17453 transition : false,
17458 slideOnTouch : false,
17461 getAutoCreate : function()
17463 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17465 cfg.cls += ' tab-content';
17467 if (this.carousel) {
17468 cfg.cls += ' carousel slide';
17471 cls : 'carousel-inner',
17475 if(this.bullets && !Roo.isTouch){
17478 cls : 'carousel-bullets',
17482 if(this.bullets_cls){
17483 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17490 cfg.cn[0].cn.push(bullets);
17493 if(this.showarrow){
17494 cfg.cn[0].cn.push({
17496 class : 'carousel-arrow',
17500 class : 'carousel-prev',
17504 class : 'fa fa-chevron-left'
17510 class : 'carousel-next',
17514 class : 'fa fa-chevron-right'
17527 initEvents: function()
17529 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17530 // this.el.on("touchstart", this.onTouchStart, this);
17533 if(this.autoslide){
17536 this.slideFn = window.setInterval(function() {
17537 _this.showPanelNext();
17541 if(this.showarrow){
17542 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17543 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17549 // onTouchStart : function(e, el, o)
17551 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17555 // this.showPanelNext();
17559 getChildContainer : function()
17561 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17565 * register a Navigation item
17566 * @param {Roo.bootstrap.NavItem} the navitem to add
17568 register : function(item)
17570 this.tabs.push( item);
17571 item.navId = this.navId; // not really needed..
17576 getActivePanel : function()
17579 Roo.each(this.tabs, function(t) {
17589 getPanelByName : function(n)
17592 Roo.each(this.tabs, function(t) {
17593 if (t.tabId == n) {
17601 indexOfPanel : function(p)
17604 Roo.each(this.tabs, function(t,i) {
17605 if (t.tabId == p.tabId) {
17614 * show a specific panel
17615 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17616 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17618 showPanel : function (pan)
17620 if(this.transition || typeof(pan) == 'undefined'){
17621 Roo.log("waiting for the transitionend");
17625 if (typeof(pan) == 'number') {
17626 pan = this.tabs[pan];
17629 if (typeof(pan) == 'string') {
17630 pan = this.getPanelByName(pan);
17633 var cur = this.getActivePanel();
17636 Roo.log('pan or acitve pan is undefined');
17640 if (pan.tabId == this.getActivePanel().tabId) {
17644 if (false === cur.fireEvent('beforedeactivate')) {
17648 if(this.bullets > 0 && !Roo.isTouch){
17649 this.setActiveBullet(this.indexOfPanel(pan));
17652 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17654 this.transition = true;
17655 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17656 var lr = dir == 'next' ? 'left' : 'right';
17657 pan.el.addClass(dir); // or prev
17658 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17659 cur.el.addClass(lr); // or right
17660 pan.el.addClass(lr);
17663 cur.el.on('transitionend', function() {
17664 Roo.log("trans end?");
17666 pan.el.removeClass([lr,dir]);
17667 pan.setActive(true);
17669 cur.el.removeClass([lr]);
17670 cur.setActive(false);
17672 _this.transition = false;
17674 }, this, { single: true } );
17679 cur.setActive(false);
17680 pan.setActive(true);
17685 showPanelNext : function()
17687 var i = this.indexOfPanel(this.getActivePanel());
17689 if (i >= this.tabs.length - 1 && !this.autoslide) {
17693 if (i >= this.tabs.length - 1 && this.autoslide) {
17697 this.showPanel(this.tabs[i+1]);
17700 showPanelPrev : function()
17702 var i = this.indexOfPanel(this.getActivePanel());
17704 if (i < 1 && !this.autoslide) {
17708 if (i < 1 && this.autoslide) {
17709 i = this.tabs.length;
17712 this.showPanel(this.tabs[i-1]);
17716 addBullet: function()
17718 if(!this.bullets || Roo.isTouch){
17721 var ctr = this.el.select('.carousel-bullets',true).first();
17722 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17723 var bullet = ctr.createChild({
17724 cls : 'bullet bullet-' + i
17725 },ctr.dom.lastChild);
17730 bullet.on('click', (function(e, el, o, ii, t){
17732 e.preventDefault();
17734 this.showPanel(ii);
17736 if(this.autoslide && this.slideFn){
17737 clearInterval(this.slideFn);
17738 this.slideFn = window.setInterval(function() {
17739 _this.showPanelNext();
17743 }).createDelegate(this, [i, bullet], true));
17748 setActiveBullet : function(i)
17754 Roo.each(this.el.select('.bullet', true).elements, function(el){
17755 el.removeClass('selected');
17758 var bullet = this.el.select('.bullet-' + i, true).first();
17764 bullet.addClass('selected');
17775 Roo.apply(Roo.bootstrap.TabGroup, {
17779 * register a Navigation Group
17780 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17782 register : function(navgrp)
17784 this.groups[navgrp.navId] = navgrp;
17788 * fetch a Navigation Group based on the navigation ID
17789 * if one does not exist , it will get created.
17790 * @param {string} the navgroup to add
17791 * @returns {Roo.bootstrap.NavGroup} the navgroup
17793 get: function(navId) {
17794 if (typeof(this.groups[navId]) == 'undefined') {
17795 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17797 return this.groups[navId] ;
17812 * @class Roo.bootstrap.TabPanel
17813 * @extends Roo.bootstrap.Component
17814 * Bootstrap TabPanel class
17815 * @cfg {Boolean} active panel active
17816 * @cfg {String} html panel content
17817 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17818 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17819 * @cfg {String} href click to link..
17823 * Create a new TabPanel
17824 * @param {Object} config The config object
17827 Roo.bootstrap.TabPanel = function(config){
17828 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17832 * Fires when the active status changes
17833 * @param {Roo.bootstrap.TabPanel} this
17834 * @param {Boolean} state the new state
17839 * @event beforedeactivate
17840 * Fires before a tab is de-activated - can be used to do validation on a form.
17841 * @param {Roo.bootstrap.TabPanel} this
17842 * @return {Boolean} false if there is an error
17845 'beforedeactivate': true
17848 this.tabId = this.tabId || Roo.id();
17852 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17860 getAutoCreate : function(){
17863 // item is needed for carousel - not sure if it has any effect otherwise
17864 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17865 html: this.html || ''
17869 cfg.cls += ' active';
17873 cfg.tabId = this.tabId;
17880 initEvents: function()
17882 var p = this.parent();
17884 this.navId = this.navId || p.navId;
17886 if (typeof(this.navId) != 'undefined') {
17887 // not really needed.. but just in case.. parent should be a NavGroup.
17888 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17892 var i = tg.tabs.length - 1;
17894 if(this.active && tg.bullets > 0 && i < tg.bullets){
17895 tg.setActiveBullet(i);
17899 this.el.on('click', this.onClick, this);
17902 this.el.on("touchstart", this.onTouchStart, this);
17903 this.el.on("touchmove", this.onTouchMove, this);
17904 this.el.on("touchend", this.onTouchEnd, this);
17909 onRender : function(ct, position)
17911 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17914 setActive : function(state)
17916 Roo.log("panel - set active " + this.tabId + "=" + state);
17918 this.active = state;
17920 this.el.removeClass('active');
17922 } else if (!this.el.hasClass('active')) {
17923 this.el.addClass('active');
17926 this.fireEvent('changed', this, state);
17929 onClick : function(e)
17931 e.preventDefault();
17933 if(!this.href.length){
17937 window.location.href = this.href;
17946 onTouchStart : function(e)
17948 this.swiping = false;
17950 this.startX = e.browserEvent.touches[0].clientX;
17951 this.startY = e.browserEvent.touches[0].clientY;
17954 onTouchMove : function(e)
17956 this.swiping = true;
17958 this.endX = e.browserEvent.touches[0].clientX;
17959 this.endY = e.browserEvent.touches[0].clientY;
17962 onTouchEnd : function(e)
17969 var tabGroup = this.parent();
17971 if(this.endX > this.startX){ // swiping right
17972 tabGroup.showPanelPrev();
17976 if(this.startX > this.endX){ // swiping left
17977 tabGroup.showPanelNext();
17996 * @class Roo.bootstrap.DateField
17997 * @extends Roo.bootstrap.Input
17998 * Bootstrap DateField class
17999 * @cfg {Number} weekStart default 0
18000 * @cfg {String} viewMode default empty, (months|years)
18001 * @cfg {String} minViewMode default empty, (months|years)
18002 * @cfg {Number} startDate default -Infinity
18003 * @cfg {Number} endDate default Infinity
18004 * @cfg {Boolean} todayHighlight default false
18005 * @cfg {Boolean} todayBtn default false
18006 * @cfg {Boolean} calendarWeeks default false
18007 * @cfg {Object} daysOfWeekDisabled default empty
18008 * @cfg {Boolean} singleMode default false (true | false)
18010 * @cfg {Boolean} keyboardNavigation default true
18011 * @cfg {String} language default en
18014 * Create a new DateField
18015 * @param {Object} config The config object
18018 Roo.bootstrap.DateField = function(config){
18019 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18023 * Fires when this field show.
18024 * @param {Roo.bootstrap.DateField} this
18025 * @param {Mixed} date The date value
18030 * Fires when this field hide.
18031 * @param {Roo.bootstrap.DateField} this
18032 * @param {Mixed} date The date value
18037 * Fires when select a date.
18038 * @param {Roo.bootstrap.DateField} this
18039 * @param {Mixed} date The date value
18043 * @event beforeselect
18044 * Fires when before select a date.
18045 * @param {Roo.bootstrap.DateField} this
18046 * @param {Mixed} date The date value
18048 beforeselect : true
18052 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18055 * @cfg {String} format
18056 * The default date format string which can be overriden for localization support. The format must be
18057 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18061 * @cfg {String} altFormats
18062 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18063 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18065 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18073 todayHighlight : false,
18079 keyboardNavigation: true,
18081 calendarWeeks: false,
18083 startDate: -Infinity,
18087 daysOfWeekDisabled: [],
18091 singleMode : false,
18093 UTCDate: function()
18095 return new Date(Date.UTC.apply(Date, arguments));
18098 UTCToday: function()
18100 var today = new Date();
18101 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18104 getDate: function() {
18105 var d = this.getUTCDate();
18106 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18109 getUTCDate: function() {
18113 setDate: function(d) {
18114 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18117 setUTCDate: function(d) {
18119 this.setValue(this.formatDate(this.date));
18122 onRender: function(ct, position)
18125 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18127 this.language = this.language || 'en';
18128 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18129 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18131 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18132 this.format = this.format || 'm/d/y';
18133 this.isInline = false;
18134 this.isInput = true;
18135 this.component = this.el.select('.add-on', true).first() || false;
18136 this.component = (this.component && this.component.length === 0) ? false : this.component;
18137 this.hasInput = this.component && this.inputEl().length;
18139 if (typeof(this.minViewMode === 'string')) {
18140 switch (this.minViewMode) {
18142 this.minViewMode = 1;
18145 this.minViewMode = 2;
18148 this.minViewMode = 0;
18153 if (typeof(this.viewMode === 'string')) {
18154 switch (this.viewMode) {
18167 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18169 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18171 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18173 this.picker().on('mousedown', this.onMousedown, this);
18174 this.picker().on('click', this.onClick, this);
18176 this.picker().addClass('datepicker-dropdown');
18178 this.startViewMode = this.viewMode;
18180 if(this.singleMode){
18181 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18182 v.setVisibilityMode(Roo.Element.DISPLAY);
18186 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18187 v.setStyle('width', '189px');
18191 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18192 if(!this.calendarWeeks){
18197 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18198 v.attr('colspan', function(i, val){
18199 return parseInt(val) + 1;
18204 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18206 this.setStartDate(this.startDate);
18207 this.setEndDate(this.endDate);
18209 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18216 if(this.isInline) {
18221 picker : function()
18223 return this.pickerEl;
18224 // return this.el.select('.datepicker', true).first();
18227 fillDow: function()
18229 var dowCnt = this.weekStart;
18238 if(this.calendarWeeks){
18246 while (dowCnt < this.weekStart + 7) {
18250 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18254 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18257 fillMonths: function()
18260 var months = this.picker().select('>.datepicker-months td', true).first();
18262 months.dom.innerHTML = '';
18268 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18271 months.createChild(month);
18278 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;
18280 if (this.date < this.startDate) {
18281 this.viewDate = new Date(this.startDate);
18282 } else if (this.date > this.endDate) {
18283 this.viewDate = new Date(this.endDate);
18285 this.viewDate = new Date(this.date);
18293 var d = new Date(this.viewDate),
18294 year = d.getUTCFullYear(),
18295 month = d.getUTCMonth(),
18296 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18297 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18298 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18299 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18300 currentDate = this.date && this.date.valueOf(),
18301 today = this.UTCToday();
18303 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18305 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18307 // this.picker.select('>tfoot th.today').
18308 // .text(dates[this.language].today)
18309 // .toggle(this.todayBtn !== false);
18311 this.updateNavArrows();
18314 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18316 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18318 prevMonth.setUTCDate(day);
18320 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18322 var nextMonth = new Date(prevMonth);
18324 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18326 nextMonth = nextMonth.valueOf();
18328 var fillMonths = false;
18330 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18332 while(prevMonth.valueOf() < nextMonth) {
18335 if (prevMonth.getUTCDay() === this.weekStart) {
18337 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18345 if(this.calendarWeeks){
18346 // ISO 8601: First week contains first thursday.
18347 // ISO also states week starts on Monday, but we can be more abstract here.
18349 // Start of current week: based on weekstart/current date
18350 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18351 // Thursday of this week
18352 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18353 // First Thursday of year, year from thursday
18354 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18355 // Calendar week: ms between thursdays, div ms per day, div 7 days
18356 calWeek = (th - yth) / 864e5 / 7 + 1;
18358 fillMonths.cn.push({
18366 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18368 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18371 if (this.todayHighlight &&
18372 prevMonth.getUTCFullYear() == today.getFullYear() &&
18373 prevMonth.getUTCMonth() == today.getMonth() &&
18374 prevMonth.getUTCDate() == today.getDate()) {
18375 clsName += ' today';
18378 if (currentDate && prevMonth.valueOf() === currentDate) {
18379 clsName += ' active';
18382 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18383 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18384 clsName += ' disabled';
18387 fillMonths.cn.push({
18389 cls: 'day ' + clsName,
18390 html: prevMonth.getDate()
18393 prevMonth.setDate(prevMonth.getDate()+1);
18396 var currentYear = this.date && this.date.getUTCFullYear();
18397 var currentMonth = this.date && this.date.getUTCMonth();
18399 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18401 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18402 v.removeClass('active');
18404 if(currentYear === year && k === currentMonth){
18405 v.addClass('active');
18408 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18409 v.addClass('disabled');
18415 year = parseInt(year/10, 10) * 10;
18417 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18419 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18422 for (var i = -1; i < 11; i++) {
18423 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18425 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18433 showMode: function(dir)
18436 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18439 Roo.each(this.picker().select('>div',true).elements, function(v){
18440 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18443 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18448 if(this.isInline) {
18452 this.picker().removeClass(['bottom', 'top']);
18454 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18456 * place to the top of element!
18460 this.picker().addClass('top');
18461 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18466 this.picker().addClass('bottom');
18468 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18471 parseDate : function(value)
18473 if(!value || value instanceof Date){
18476 var v = Date.parseDate(value, this.format);
18477 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18478 v = Date.parseDate(value, 'Y-m-d');
18480 if(!v && this.altFormats){
18481 if(!this.altFormatsArray){
18482 this.altFormatsArray = this.altFormats.split("|");
18484 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18485 v = Date.parseDate(value, this.altFormatsArray[i]);
18491 formatDate : function(date, fmt)
18493 return (!date || !(date instanceof Date)) ?
18494 date : date.dateFormat(fmt || this.format);
18497 onFocus : function()
18499 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18503 onBlur : function()
18505 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18507 var d = this.inputEl().getValue();
18516 this.picker().show();
18520 this.fireEvent('show', this, this.date);
18525 if(this.isInline) {
18528 this.picker().hide();
18529 this.viewMode = this.startViewMode;
18532 this.fireEvent('hide', this, this.date);
18536 onMousedown: function(e)
18538 e.stopPropagation();
18539 e.preventDefault();
18544 Roo.bootstrap.DateField.superclass.keyup.call(this);
18548 setValue: function(v)
18550 if(this.fireEvent('beforeselect', this, v) !== false){
18551 var d = new Date(this.parseDate(v) ).clearTime();
18553 if(isNaN(d.getTime())){
18554 this.date = this.viewDate = '';
18555 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18559 v = this.formatDate(d);
18561 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18563 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18567 this.fireEvent('select', this, this.date);
18571 getValue: function()
18573 return this.formatDate(this.date);
18576 fireKey: function(e)
18578 if (!this.picker().isVisible()){
18579 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18585 var dateChanged = false,
18587 newDate, newViewDate;
18592 e.preventDefault();
18596 if (!this.keyboardNavigation) {
18599 dir = e.keyCode == 37 ? -1 : 1;
18602 newDate = this.moveYear(this.date, dir);
18603 newViewDate = this.moveYear(this.viewDate, dir);
18604 } else if (e.shiftKey){
18605 newDate = this.moveMonth(this.date, dir);
18606 newViewDate = this.moveMonth(this.viewDate, dir);
18608 newDate = new Date(this.date);
18609 newDate.setUTCDate(this.date.getUTCDate() + dir);
18610 newViewDate = new Date(this.viewDate);
18611 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18613 if (this.dateWithinRange(newDate)){
18614 this.date = newDate;
18615 this.viewDate = newViewDate;
18616 this.setValue(this.formatDate(this.date));
18618 e.preventDefault();
18619 dateChanged = true;
18624 if (!this.keyboardNavigation) {
18627 dir = e.keyCode == 38 ? -1 : 1;
18629 newDate = this.moveYear(this.date, dir);
18630 newViewDate = this.moveYear(this.viewDate, dir);
18631 } else if (e.shiftKey){
18632 newDate = this.moveMonth(this.date, dir);
18633 newViewDate = this.moveMonth(this.viewDate, dir);
18635 newDate = new Date(this.date);
18636 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18637 newViewDate = new Date(this.viewDate);
18638 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18640 if (this.dateWithinRange(newDate)){
18641 this.date = newDate;
18642 this.viewDate = newViewDate;
18643 this.setValue(this.formatDate(this.date));
18645 e.preventDefault();
18646 dateChanged = true;
18650 this.setValue(this.formatDate(this.date));
18652 e.preventDefault();
18655 this.setValue(this.formatDate(this.date));
18669 onClick: function(e)
18671 e.stopPropagation();
18672 e.preventDefault();
18674 var target = e.getTarget();
18676 if(target.nodeName.toLowerCase() === 'i'){
18677 target = Roo.get(target).dom.parentNode;
18680 var nodeName = target.nodeName;
18681 var className = target.className;
18682 var html = target.innerHTML;
18683 //Roo.log(nodeName);
18685 switch(nodeName.toLowerCase()) {
18687 switch(className) {
18693 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18694 switch(this.viewMode){
18696 this.viewDate = this.moveMonth(this.viewDate, dir);
18700 this.viewDate = this.moveYear(this.viewDate, dir);
18706 var date = new Date();
18707 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18709 this.setValue(this.formatDate(this.date));
18716 if (className.indexOf('disabled') < 0) {
18717 this.viewDate.setUTCDate(1);
18718 if (className.indexOf('month') > -1) {
18719 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18721 var year = parseInt(html, 10) || 0;
18722 this.viewDate.setUTCFullYear(year);
18726 if(this.singleMode){
18727 this.setValue(this.formatDate(this.viewDate));
18738 //Roo.log(className);
18739 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18740 var day = parseInt(html, 10) || 1;
18741 var year = this.viewDate.getUTCFullYear(),
18742 month = this.viewDate.getUTCMonth();
18744 if (className.indexOf('old') > -1) {
18751 } else if (className.indexOf('new') > -1) {
18759 //Roo.log([year,month,day]);
18760 this.date = this.UTCDate(year, month, day,0,0,0,0);
18761 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18763 //Roo.log(this.formatDate(this.date));
18764 this.setValue(this.formatDate(this.date));
18771 setStartDate: function(startDate)
18773 this.startDate = startDate || -Infinity;
18774 if (this.startDate !== -Infinity) {
18775 this.startDate = this.parseDate(this.startDate);
18778 this.updateNavArrows();
18781 setEndDate: function(endDate)
18783 this.endDate = endDate || Infinity;
18784 if (this.endDate !== Infinity) {
18785 this.endDate = this.parseDate(this.endDate);
18788 this.updateNavArrows();
18791 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18793 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18794 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18795 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18797 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18798 return parseInt(d, 10);
18801 this.updateNavArrows();
18804 updateNavArrows: function()
18806 if(this.singleMode){
18810 var d = new Date(this.viewDate),
18811 year = d.getUTCFullYear(),
18812 month = d.getUTCMonth();
18814 Roo.each(this.picker().select('.prev', true).elements, function(v){
18816 switch (this.viewMode) {
18819 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18825 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18832 Roo.each(this.picker().select('.next', true).elements, function(v){
18834 switch (this.viewMode) {
18837 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18843 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18851 moveMonth: function(date, dir)
18856 var new_date = new Date(date.valueOf()),
18857 day = new_date.getUTCDate(),
18858 month = new_date.getUTCMonth(),
18859 mag = Math.abs(dir),
18861 dir = dir > 0 ? 1 : -1;
18864 // If going back one month, make sure month is not current month
18865 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18867 return new_date.getUTCMonth() == month;
18869 // If going forward one month, make sure month is as expected
18870 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18872 return new_date.getUTCMonth() != new_month;
18874 new_month = month + dir;
18875 new_date.setUTCMonth(new_month);
18876 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18877 if (new_month < 0 || new_month > 11) {
18878 new_month = (new_month + 12) % 12;
18881 // For magnitudes >1, move one month at a time...
18882 for (var i=0; i<mag; i++) {
18883 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18884 new_date = this.moveMonth(new_date, dir);
18886 // ...then reset the day, keeping it in the new month
18887 new_month = new_date.getUTCMonth();
18888 new_date.setUTCDate(day);
18890 return new_month != new_date.getUTCMonth();
18893 // Common date-resetting loop -- if date is beyond end of month, make it
18896 new_date.setUTCDate(--day);
18897 new_date.setUTCMonth(new_month);
18902 moveYear: function(date, dir)
18904 return this.moveMonth(date, dir*12);
18907 dateWithinRange: function(date)
18909 return date >= this.startDate && date <= this.endDate;
18915 this.picker().remove();
18918 validateValue : function(value)
18920 if(value.length < 1) {
18921 if(this.allowBlank){
18927 if(value.length < this.minLength){
18930 if(value.length > this.maxLength){
18934 var vt = Roo.form.VTypes;
18935 if(!vt[this.vtype](value, this)){
18939 if(typeof this.validator == "function"){
18940 var msg = this.validator(value);
18946 if(this.regex && !this.regex.test(value)){
18950 if(typeof(this.parseDate(value)) == 'undefined'){
18954 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18958 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18968 Roo.apply(Roo.bootstrap.DateField, {
18979 html: '<i class="fa fa-arrow-left"/>'
18989 html: '<i class="fa fa-arrow-right"/>'
19031 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19032 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19033 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19034 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19035 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19048 navFnc: 'FullYear',
19053 navFnc: 'FullYear',
19058 Roo.apply(Roo.bootstrap.DateField, {
19062 cls: 'datepicker dropdown-menu roo-dynamic',
19066 cls: 'datepicker-days',
19070 cls: 'table-condensed',
19072 Roo.bootstrap.DateField.head,
19076 Roo.bootstrap.DateField.footer
19083 cls: 'datepicker-months',
19087 cls: 'table-condensed',
19089 Roo.bootstrap.DateField.head,
19090 Roo.bootstrap.DateField.content,
19091 Roo.bootstrap.DateField.footer
19098 cls: 'datepicker-years',
19102 cls: 'table-condensed',
19104 Roo.bootstrap.DateField.head,
19105 Roo.bootstrap.DateField.content,
19106 Roo.bootstrap.DateField.footer
19125 * @class Roo.bootstrap.TimeField
19126 * @extends Roo.bootstrap.Input
19127 * Bootstrap DateField class
19131 * Create a new TimeField
19132 * @param {Object} config The config object
19135 Roo.bootstrap.TimeField = function(config){
19136 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19140 * Fires when this field show.
19141 * @param {Roo.bootstrap.DateField} thisthis
19142 * @param {Mixed} date The date value
19147 * Fires when this field hide.
19148 * @param {Roo.bootstrap.DateField} this
19149 * @param {Mixed} date The date value
19154 * Fires when select a date.
19155 * @param {Roo.bootstrap.DateField} this
19156 * @param {Mixed} date The date value
19162 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19165 * @cfg {String} format
19166 * The default time format string which can be overriden for localization support. The format must be
19167 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19171 onRender: function(ct, position)
19174 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19176 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19178 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19180 this.pop = this.picker().select('>.datepicker-time',true).first();
19181 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19183 this.picker().on('mousedown', this.onMousedown, this);
19184 this.picker().on('click', this.onClick, this);
19186 this.picker().addClass('datepicker-dropdown');
19191 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19192 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19193 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19194 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19195 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19196 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19200 fireKey: function(e){
19201 if (!this.picker().isVisible()){
19202 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19208 e.preventDefault();
19216 this.onTogglePeriod();
19219 this.onIncrementMinutes();
19222 this.onDecrementMinutes();
19231 onClick: function(e) {
19232 e.stopPropagation();
19233 e.preventDefault();
19236 picker : function()
19238 return this.el.select('.datepicker', true).first();
19241 fillTime: function()
19243 var time = this.pop.select('tbody', true).first();
19245 time.dom.innerHTML = '';
19260 cls: 'hours-up glyphicon glyphicon-chevron-up'
19280 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19301 cls: 'timepicker-hour',
19316 cls: 'timepicker-minute',
19331 cls: 'btn btn-primary period',
19353 cls: 'hours-down glyphicon glyphicon-chevron-down'
19373 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19391 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19398 var hours = this.time.getHours();
19399 var minutes = this.time.getMinutes();
19412 hours = hours - 12;
19416 hours = '0' + hours;
19420 minutes = '0' + minutes;
19423 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19424 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19425 this.pop.select('button', true).first().dom.innerHTML = period;
19431 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19433 var cls = ['bottom'];
19435 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19442 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19447 this.picker().addClass(cls.join('-'));
19451 Roo.each(cls, function(c){
19453 _this.picker().setTop(_this.inputEl().getHeight());
19457 _this.picker().setTop(0 - _this.picker().getHeight());
19462 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19466 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19473 onFocus : function()
19475 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19479 onBlur : function()
19481 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19487 this.picker().show();
19492 this.fireEvent('show', this, this.date);
19497 this.picker().hide();
19500 this.fireEvent('hide', this, this.date);
19503 setTime : function()
19506 this.setValue(this.time.format(this.format));
19508 this.fireEvent('select', this, this.date);
19513 onMousedown: function(e){
19514 e.stopPropagation();
19515 e.preventDefault();
19518 onIncrementHours: function()
19520 Roo.log('onIncrementHours');
19521 this.time = this.time.add(Date.HOUR, 1);
19526 onDecrementHours: function()
19528 Roo.log('onDecrementHours');
19529 this.time = this.time.add(Date.HOUR, -1);
19533 onIncrementMinutes: function()
19535 Roo.log('onIncrementMinutes');
19536 this.time = this.time.add(Date.MINUTE, 1);
19540 onDecrementMinutes: function()
19542 Roo.log('onDecrementMinutes');
19543 this.time = this.time.add(Date.MINUTE, -1);
19547 onTogglePeriod: function()
19549 Roo.log('onTogglePeriod');
19550 this.time = this.time.add(Date.HOUR, 12);
19557 Roo.apply(Roo.bootstrap.TimeField, {
19587 cls: 'btn btn-info ok',
19599 Roo.apply(Roo.bootstrap.TimeField, {
19603 cls: 'datepicker dropdown-menu',
19607 cls: 'datepicker-time',
19611 cls: 'table-condensed',
19613 Roo.bootstrap.TimeField.content,
19614 Roo.bootstrap.TimeField.footer
19633 * @class Roo.bootstrap.MonthField
19634 * @extends Roo.bootstrap.Input
19635 * Bootstrap MonthField class
19637 * @cfg {String} language default en
19640 * Create a new MonthField
19641 * @param {Object} config The config object
19644 Roo.bootstrap.MonthField = function(config){
19645 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19650 * Fires when this field show.
19651 * @param {Roo.bootstrap.MonthField} this
19652 * @param {Mixed} date The date value
19657 * Fires when this field hide.
19658 * @param {Roo.bootstrap.MonthField} this
19659 * @param {Mixed} date The date value
19664 * Fires when select a date.
19665 * @param {Roo.bootstrap.MonthField} this
19666 * @param {String} oldvalue The old value
19667 * @param {String} newvalue The new value
19673 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19675 onRender: function(ct, position)
19678 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19680 this.language = this.language || 'en';
19681 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19682 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19684 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19685 this.isInline = false;
19686 this.isInput = true;
19687 this.component = this.el.select('.add-on', true).first() || false;
19688 this.component = (this.component && this.component.length === 0) ? false : this.component;
19689 this.hasInput = this.component && this.inputEL().length;
19691 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19693 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19695 this.picker().on('mousedown', this.onMousedown, this);
19696 this.picker().on('click', this.onClick, this);
19698 this.picker().addClass('datepicker-dropdown');
19700 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19701 v.setStyle('width', '189px');
19708 if(this.isInline) {
19714 setValue: function(v, suppressEvent)
19716 var o = this.getValue();
19718 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19722 if(suppressEvent !== true){
19723 this.fireEvent('select', this, o, v);
19728 getValue: function()
19733 onClick: function(e)
19735 e.stopPropagation();
19736 e.preventDefault();
19738 var target = e.getTarget();
19740 if(target.nodeName.toLowerCase() === 'i'){
19741 target = Roo.get(target).dom.parentNode;
19744 var nodeName = target.nodeName;
19745 var className = target.className;
19746 var html = target.innerHTML;
19748 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19752 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19754 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19760 picker : function()
19762 return this.pickerEl;
19765 fillMonths: function()
19768 var months = this.picker().select('>.datepicker-months td', true).first();
19770 months.dom.innerHTML = '';
19776 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19779 months.createChild(month);
19788 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19789 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19792 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19793 e.removeClass('active');
19795 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19796 e.addClass('active');
19803 if(this.isInline) {
19807 this.picker().removeClass(['bottom', 'top']);
19809 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19811 * place to the top of element!
19815 this.picker().addClass('top');
19816 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19821 this.picker().addClass('bottom');
19823 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19826 onFocus : function()
19828 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19832 onBlur : function()
19834 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19836 var d = this.inputEl().getValue();
19845 this.picker().show();
19846 this.picker().select('>.datepicker-months', true).first().show();
19850 this.fireEvent('show', this, this.date);
19855 if(this.isInline) {
19858 this.picker().hide();
19859 this.fireEvent('hide', this, this.date);
19863 onMousedown: function(e)
19865 e.stopPropagation();
19866 e.preventDefault();
19871 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19875 fireKey: function(e)
19877 if (!this.picker().isVisible()){
19878 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19889 e.preventDefault();
19893 dir = e.keyCode == 37 ? -1 : 1;
19895 this.vIndex = this.vIndex + dir;
19897 if(this.vIndex < 0){
19901 if(this.vIndex > 11){
19905 if(isNaN(this.vIndex)){
19909 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19915 dir = e.keyCode == 38 ? -1 : 1;
19917 this.vIndex = this.vIndex + dir * 4;
19919 if(this.vIndex < 0){
19923 if(this.vIndex > 11){
19927 if(isNaN(this.vIndex)){
19931 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19936 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19937 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19941 e.preventDefault();
19944 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19945 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19961 this.picker().remove();
19966 Roo.apply(Roo.bootstrap.MonthField, {
19985 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19986 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19991 Roo.apply(Roo.bootstrap.MonthField, {
19995 cls: 'datepicker dropdown-menu roo-dynamic',
19999 cls: 'datepicker-months',
20003 cls: 'table-condensed',
20005 Roo.bootstrap.DateField.content
20025 * @class Roo.bootstrap.CheckBox
20026 * @extends Roo.bootstrap.Input
20027 * Bootstrap CheckBox class
20029 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20030 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20031 * @cfg {String} boxLabel The text that appears beside the checkbox
20032 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20033 * @cfg {Boolean} checked initnal the element
20034 * @cfg {Boolean} inline inline the element (default false)
20035 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20038 * Create a new CheckBox
20039 * @param {Object} config The config object
20042 Roo.bootstrap.CheckBox = function(config){
20043 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20048 * Fires when the element is checked or unchecked.
20049 * @param {Roo.bootstrap.CheckBox} this This input
20050 * @param {Boolean} checked The new checked value
20057 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20059 inputType: 'checkbox',
20067 getAutoCreate : function()
20069 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20075 cfg.cls = 'form-group ' + this.inputType; //input-group
20078 cfg.cls += ' ' + this.inputType + '-inline';
20084 type : this.inputType,
20085 value : this.inputValue,
20086 cls : 'roo-' + this.inputType, //'form-box',
20087 placeholder : this.placeholder || ''
20091 if(this.inputType != 'radio'){
20095 cls : 'roo-hidden-value',
20096 value : this.checked ? this.valueOff : this.inputValue
20101 if (this.weight) { // Validity check?
20102 cfg.cls += " " + this.inputType + "-" + this.weight;
20105 if (this.disabled) {
20106 input.disabled=true;
20110 input.checked = this.checked;
20117 input.name = this.name;
20119 if(this.inputType != 'radio'){
20120 hidden.name = this.name;
20121 input.name = '_hidden_' + this.name;
20126 input.cls += ' input-' + this.size;
20131 ['xs','sm','md','lg'].map(function(size){
20132 if (settings[size]) {
20133 cfg.cls += ' col-' + size + '-' + settings[size];
20137 var inputblock = input;
20139 if (this.before || this.after) {
20142 cls : 'input-group',
20147 inputblock.cn.push({
20149 cls : 'input-group-addon',
20154 inputblock.cn.push(input);
20156 if(this.inputType != 'radio'){
20157 inputblock.cn.push(hidden);
20161 inputblock.cn.push({
20163 cls : 'input-group-addon',
20170 if (align ==='left' && this.fieldLabel.length) {
20171 // Roo.log("left and has label");
20176 cls : 'control-label',
20177 html : this.fieldLabel
20188 if(this.labelWidth > 12){
20189 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20192 if(this.labelWidth < 13 && this.labelmd == 0){
20193 this.labelmd = this.labelWidth;
20196 if(this.labellg > 0){
20197 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20198 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20201 if(this.labelmd > 0){
20202 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20203 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20206 if(this.labelsm > 0){
20207 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20208 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20211 if(this.labelxs > 0){
20212 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20213 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20216 } else if ( this.fieldLabel.length) {
20217 // Roo.log(" label");
20221 tag: this.boxLabel ? 'span' : 'label',
20223 cls: 'control-label box-input-label',
20224 //cls : 'input-group-addon',
20225 html : this.fieldLabel
20235 // Roo.log(" no label && no align");
20236 cfg.cn = [ inputblock ] ;
20242 var boxLabelCfg = {
20244 //'for': id, // box label is handled by onclick - so no for...
20246 html: this.boxLabel
20250 boxLabelCfg.tooltip = this.tooltip;
20253 cfg.cn.push(boxLabelCfg);
20256 if(this.inputType != 'radio'){
20257 cfg.cn.push(hidden);
20265 * return the real input element.
20267 inputEl: function ()
20269 return this.el.select('input.roo-' + this.inputType,true).first();
20271 hiddenEl: function ()
20273 return this.el.select('input.roo-hidden-value',true).first();
20276 labelEl: function()
20278 return this.el.select('label.control-label',true).first();
20280 /* depricated... */
20284 return this.labelEl();
20287 boxLabelEl: function()
20289 return this.el.select('label.box-label',true).first();
20292 initEvents : function()
20294 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20296 this.inputEl().on('click', this.onClick, this);
20298 if (this.boxLabel) {
20299 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20302 this.startValue = this.getValue();
20305 Roo.bootstrap.CheckBox.register(this);
20309 onClick : function()
20311 this.setChecked(!this.checked);
20314 setChecked : function(state,suppressEvent)
20316 this.startValue = this.getValue();
20318 if(this.inputType == 'radio'){
20320 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20321 e.dom.checked = false;
20324 this.inputEl().dom.checked = true;
20326 this.inputEl().dom.value = this.inputValue;
20328 if(suppressEvent !== true){
20329 this.fireEvent('check', this, true);
20337 this.checked = state;
20339 this.inputEl().dom.checked = state;
20342 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20344 if(suppressEvent !== true){
20345 this.fireEvent('check', this, state);
20351 getValue : function()
20353 if(this.inputType == 'radio'){
20354 return this.getGroupValue();
20357 return this.hiddenEl().dom.value;
20361 getGroupValue : function()
20363 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20367 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20370 setValue : function(v,suppressEvent)
20372 if(this.inputType == 'radio'){
20373 this.setGroupValue(v, suppressEvent);
20377 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20382 setGroupValue : function(v, suppressEvent)
20384 this.startValue = this.getValue();
20386 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20387 e.dom.checked = false;
20389 if(e.dom.value == v){
20390 e.dom.checked = true;
20394 if(suppressEvent !== true){
20395 this.fireEvent('check', this, true);
20403 validate : function()
20407 (this.inputType == 'radio' && this.validateRadio()) ||
20408 (this.inputType == 'checkbox' && this.validateCheckbox())
20414 this.markInvalid();
20418 validateRadio : function()
20420 if(this.allowBlank){
20426 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20427 if(!e.dom.checked){
20439 validateCheckbox : function()
20442 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20443 //return (this.getValue() == this.inputValue) ? true : false;
20446 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20454 for(var i in group){
20459 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20466 * Mark this field as valid
20468 markValid : function()
20472 this.fireEvent('valid', this);
20474 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20477 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20484 if(this.inputType == 'radio'){
20485 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20486 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20487 e.findParent('.form-group', false, true).addClass(_this.validClass);
20494 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20495 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20499 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20505 for(var i in group){
20506 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20507 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20512 * Mark this field as invalid
20513 * @param {String} msg The validation message
20515 markInvalid : function(msg)
20517 if(this.allowBlank){
20523 this.fireEvent('invalid', this, msg);
20525 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20528 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20532 label.markInvalid();
20535 if(this.inputType == 'radio'){
20536 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20537 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20538 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20545 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20546 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20550 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20556 for(var i in group){
20557 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20558 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20563 clearInvalid : function()
20565 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20567 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20569 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20572 label.iconEl.removeClass(label.validClass);
20573 label.iconEl.removeClass(label.invalidClass);
20577 disable : function()
20579 if(this.inputType != 'radio'){
20580 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20587 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20588 _this.getActionEl().addClass(this.disabledClass);
20589 e.dom.disabled = true;
20593 this.disabled = true;
20594 this.fireEvent("disable", this);
20598 enable : function()
20600 if(this.inputType != 'radio'){
20601 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20608 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20609 _this.getActionEl().removeClass(this.disabledClass);
20610 e.dom.disabled = false;
20614 this.disabled = false;
20615 this.fireEvent("enable", this);
20621 Roo.apply(Roo.bootstrap.CheckBox, {
20626 * register a CheckBox Group
20627 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20629 register : function(checkbox)
20631 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20632 this.groups[checkbox.groupId] = {};
20635 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20639 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20643 * fetch a CheckBox Group based on the group ID
20644 * @param {string} the group ID
20645 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20647 get: function(groupId) {
20648 if (typeof(this.groups[groupId]) == 'undefined') {
20652 return this.groups[groupId] ;
20665 * @class Roo.bootstrap.Radio
20666 * @extends Roo.bootstrap.Component
20667 * Bootstrap Radio class
20668 * @cfg {String} boxLabel - the label associated
20669 * @cfg {String} value - the value of radio
20672 * Create a new Radio
20673 * @param {Object} config The config object
20675 Roo.bootstrap.Radio = function(config){
20676 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20680 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20686 getAutoCreate : function()
20690 cls : 'form-group radio',
20695 html : this.boxLabel
20703 initEvents : function()
20705 this.parent().register(this);
20707 this.el.on('click', this.onClick, this);
20711 onClick : function()
20713 this.setChecked(true);
20716 setChecked : function(state, suppressEvent)
20718 this.parent().setValue(this.value, suppressEvent);
20733 * @class Roo.bootstrap.SecurePass
20734 * @extends Roo.bootstrap.Input
20735 * Bootstrap SecurePass class
20739 * Create a new SecurePass
20740 * @param {Object} config The config object
20743 Roo.bootstrap.SecurePass = function (config) {
20744 // these go here, so the translation tool can replace them..
20746 PwdEmpty: "Please type a password, and then retype it to confirm.",
20747 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20748 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20749 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20750 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20751 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20752 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20753 TooWeak: "Your password is Too Weak."
20755 this.meterLabel = "Password strength:";
20756 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20757 this.meterClass = [
20758 "roo-password-meter-tooweak",
20759 "roo-password-meter-weak",
20760 "roo-password-meter-medium",
20761 "roo-password-meter-strong",
20762 "roo-password-meter-grey"
20767 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20770 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20772 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20774 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20775 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20776 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20777 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20778 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20779 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20780 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20790 * @cfg {String/Object} Label for the strength meter (defaults to
20791 * 'Password strength:')
20796 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20797 * ['Weak', 'Medium', 'Strong'])
20800 pwdStrengths: false,
20813 initEvents: function ()
20815 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20817 if (this.el.is('input[type=password]') && Roo.isSafari) {
20818 this.el.on('keydown', this.SafariOnKeyDown, this);
20821 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20824 onRender: function (ct, position)
20826 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20827 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20828 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20830 this.trigger.createChild({
20835 cls: 'roo-password-meter-grey col-xs-12',
20838 //width: this.meterWidth + 'px'
20842 cls: 'roo-password-meter-text'
20848 if (this.hideTrigger) {
20849 this.trigger.setDisplayed(false);
20851 this.setSize(this.width || '', this.height || '');
20854 onDestroy: function ()
20856 if (this.trigger) {
20857 this.trigger.removeAllListeners();
20858 this.trigger.remove();
20861 this.wrap.remove();
20863 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
20866 checkStrength: function ()
20868 var pwd = this.inputEl().getValue();
20869 if (pwd == this._lastPwd) {
20874 if (this.ClientSideStrongPassword(pwd)) {
20876 } else if (this.ClientSideMediumPassword(pwd)) {
20878 } else if (this.ClientSideWeakPassword(pwd)) {
20884 Roo.log('strength1: ' + strength);
20886 //var pm = this.trigger.child('div/div/div').dom;
20887 var pm = this.trigger.child('div/div');
20888 pm.removeClass(this.meterClass);
20889 pm.addClass(this.meterClass[strength]);
20892 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20894 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20896 this._lastPwd = pwd;
20900 Roo.bootstrap.SecurePass.superclass.reset.call(this);
20902 this._lastPwd = '';
20904 var pm = this.trigger.child('div/div');
20905 pm.removeClass(this.meterClass);
20906 pm.addClass('roo-password-meter-grey');
20909 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20912 this.inputEl().dom.type='password';
20915 validateValue: function (value)
20918 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
20921 if (value.length == 0) {
20922 if (this.allowBlank) {
20923 this.clearInvalid();
20927 this.markInvalid(this.errors.PwdEmpty);
20928 this.errorMsg = this.errors.PwdEmpty;
20936 if ('[\x21-\x7e]*'.match(value)) {
20937 this.markInvalid(this.errors.PwdBadChar);
20938 this.errorMsg = this.errors.PwdBadChar;
20941 if (value.length < 6) {
20942 this.markInvalid(this.errors.PwdShort);
20943 this.errorMsg = this.errors.PwdShort;
20946 if (value.length > 16) {
20947 this.markInvalid(this.errors.PwdLong);
20948 this.errorMsg = this.errors.PwdLong;
20952 if (this.ClientSideStrongPassword(value)) {
20954 } else if (this.ClientSideMediumPassword(value)) {
20956 } else if (this.ClientSideWeakPassword(value)) {
20963 if (strength < 2) {
20964 //this.markInvalid(this.errors.TooWeak);
20965 this.errorMsg = this.errors.TooWeak;
20970 console.log('strength2: ' + strength);
20972 //var pm = this.trigger.child('div/div/div').dom;
20974 var pm = this.trigger.child('div/div');
20975 pm.removeClass(this.meterClass);
20976 pm.addClass(this.meterClass[strength]);
20978 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
20980 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
20982 this.errorMsg = '';
20986 CharacterSetChecks: function (type)
20989 this.fResult = false;
20992 isctype: function (character, type)
20995 case this.kCapitalLetter:
20996 if (character >= 'A' && character <= 'Z') {
21001 case this.kSmallLetter:
21002 if (character >= 'a' && character <= 'z') {
21008 if (character >= '0' && character <= '9') {
21013 case this.kPunctuation:
21014 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21025 IsLongEnough: function (pwd, size)
21027 return !(pwd == null || isNaN(size) || pwd.length < size);
21030 SpansEnoughCharacterSets: function (word, nb)
21032 if (!this.IsLongEnough(word, nb))
21037 var characterSetChecks = new Array(
21038 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21039 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21042 for (var index = 0; index < word.length; ++index) {
21043 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21044 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21045 characterSetChecks[nCharSet].fResult = true;
21052 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21053 if (characterSetChecks[nCharSet].fResult) {
21058 if (nCharSets < nb) {
21064 ClientSideStrongPassword: function (pwd)
21066 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21069 ClientSideMediumPassword: function (pwd)
21071 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21074 ClientSideWeakPassword: function (pwd)
21076 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21079 })//<script type="text/javascript">
21082 * Based Ext JS Library 1.1.1
21083 * Copyright(c) 2006-2007, Ext JS, LLC.
21089 * @class Roo.HtmlEditorCore
21090 * @extends Roo.Component
21091 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21093 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21096 Roo.HtmlEditorCore = function(config){
21099 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21104 * @event initialize
21105 * Fires when the editor is fully initialized (including the iframe)
21106 * @param {Roo.HtmlEditorCore} this
21111 * Fires when the editor is first receives the focus. Any insertion must wait
21112 * until after this event.
21113 * @param {Roo.HtmlEditorCore} this
21117 * @event beforesync
21118 * Fires before the textarea is updated with content from the editor iframe. Return false
21119 * to cancel the sync.
21120 * @param {Roo.HtmlEditorCore} this
21121 * @param {String} html
21125 * @event beforepush
21126 * Fires before the iframe editor is updated with content from the textarea. Return false
21127 * to cancel the push.
21128 * @param {Roo.HtmlEditorCore} this
21129 * @param {String} html
21134 * Fires when the textarea is updated with content from the editor iframe.
21135 * @param {Roo.HtmlEditorCore} this
21136 * @param {String} html
21141 * Fires when the iframe editor is updated with content from the textarea.
21142 * @param {Roo.HtmlEditorCore} this
21143 * @param {String} html
21148 * @event editorevent
21149 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21150 * @param {Roo.HtmlEditorCore} this
21156 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21158 // defaults : white / black...
21159 this.applyBlacklists();
21166 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21170 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21176 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21181 * @cfg {Number} height (in pixels)
21185 * @cfg {Number} width (in pixels)
21190 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21193 stylesheets: false,
21198 // private properties
21199 validationEvent : false,
21201 initialized : false,
21203 sourceEditMode : false,
21204 onFocus : Roo.emptyFn,
21206 hideMode:'offsets',
21210 // blacklist + whitelisted elements..
21217 * Protected method that will not generally be called directly. It
21218 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21219 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21221 getDocMarkup : function(){
21225 // inherit styels from page...??
21226 if (this.stylesheets === false) {
21228 Roo.get(document.head).select('style').each(function(node) {
21229 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21232 Roo.get(document.head).select('link').each(function(node) {
21233 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21236 } else if (!this.stylesheets.length) {
21238 st = '<style type="text/css">' +
21239 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21245 st += '<style type="text/css">' +
21246 'IMG { cursor: pointer } ' +
21250 return '<html><head>' + st +
21251 //<style type="text/css">' +
21252 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21254 ' </head><body class="roo-htmleditor-body"></body></html>';
21258 onRender : function(ct, position)
21261 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21262 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21265 this.el.dom.style.border = '0 none';
21266 this.el.dom.setAttribute('tabIndex', -1);
21267 this.el.addClass('x-hidden hide');
21271 if(Roo.isIE){ // fix IE 1px bogus margin
21272 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21276 this.frameId = Roo.id();
21280 var iframe = this.owner.wrap.createChild({
21282 cls: 'form-control', // bootstrap..
21284 name: this.frameId,
21285 frameBorder : 'no',
21286 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21291 this.iframe = iframe.dom;
21293 this.assignDocWin();
21295 this.doc.designMode = 'on';
21298 this.doc.write(this.getDocMarkup());
21302 var task = { // must defer to wait for browser to be ready
21304 //console.log("run task?" + this.doc.readyState);
21305 this.assignDocWin();
21306 if(this.doc.body || this.doc.readyState == 'complete'){
21308 this.doc.designMode="on";
21312 Roo.TaskMgr.stop(task);
21313 this.initEditor.defer(10, this);
21320 Roo.TaskMgr.start(task);
21325 onResize : function(w, h)
21327 Roo.log('resize: ' +w + ',' + h );
21328 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21332 if(typeof w == 'number'){
21334 this.iframe.style.width = w + 'px';
21336 if(typeof h == 'number'){
21338 this.iframe.style.height = h + 'px';
21340 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21347 * Toggles the editor between standard and source edit mode.
21348 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21350 toggleSourceEdit : function(sourceEditMode){
21352 this.sourceEditMode = sourceEditMode === true;
21354 if(this.sourceEditMode){
21356 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21359 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21360 //this.iframe.className = '';
21363 //this.setSize(this.owner.wrap.getSize());
21364 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21371 * Protected method that will not generally be called directly. If you need/want
21372 * custom HTML cleanup, this is the method you should override.
21373 * @param {String} html The HTML to be cleaned
21374 * return {String} The cleaned HTML
21376 cleanHtml : function(html){
21377 html = String(html);
21378 if(html.length > 5){
21379 if(Roo.isSafari){ // strip safari nonsense
21380 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21383 if(html == ' '){
21390 * HTML Editor -> Textarea
21391 * Protected method that will not generally be called directly. Syncs the contents
21392 * of the editor iframe with the textarea.
21394 syncValue : function(){
21395 if(this.initialized){
21396 var bd = (this.doc.body || this.doc.documentElement);
21397 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21398 var html = bd.innerHTML;
21400 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21401 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21403 html = '<div style="'+m[0]+'">' + html + '</div>';
21406 html = this.cleanHtml(html);
21407 // fix up the special chars.. normaly like back quotes in word...
21408 // however we do not want to do this with chinese..
21409 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21410 var cc = b.charCodeAt();
21412 (cc >= 0x4E00 && cc < 0xA000 ) ||
21413 (cc >= 0x3400 && cc < 0x4E00 ) ||
21414 (cc >= 0xf900 && cc < 0xfb00 )
21420 if(this.owner.fireEvent('beforesync', this, html) !== false){
21421 this.el.dom.value = html;
21422 this.owner.fireEvent('sync', this, html);
21428 * Protected method that will not generally be called directly. Pushes the value of the textarea
21429 * into the iframe editor.
21431 pushValue : function(){
21432 if(this.initialized){
21433 var v = this.el.dom.value.trim();
21435 // if(v.length < 1){
21439 if(this.owner.fireEvent('beforepush', this, v) !== false){
21440 var d = (this.doc.body || this.doc.documentElement);
21442 this.cleanUpPaste();
21443 this.el.dom.value = d.innerHTML;
21444 this.owner.fireEvent('push', this, v);
21450 deferFocus : function(){
21451 this.focus.defer(10, this);
21455 focus : function(){
21456 if(this.win && !this.sourceEditMode){
21463 assignDocWin: function()
21465 var iframe = this.iframe;
21468 this.doc = iframe.contentWindow.document;
21469 this.win = iframe.contentWindow;
21471 // if (!Roo.get(this.frameId)) {
21474 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21475 // this.win = Roo.get(this.frameId).dom.contentWindow;
21477 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21481 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21482 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21487 initEditor : function(){
21488 //console.log("INIT EDITOR");
21489 this.assignDocWin();
21493 this.doc.designMode="on";
21495 this.doc.write(this.getDocMarkup());
21498 var dbody = (this.doc.body || this.doc.documentElement);
21499 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21500 // this copies styles from the containing element into thsi one..
21501 // not sure why we need all of this..
21502 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21504 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21505 //ss['background-attachment'] = 'fixed'; // w3c
21506 dbody.bgProperties = 'fixed'; // ie
21507 //Roo.DomHelper.applyStyles(dbody, ss);
21508 Roo.EventManager.on(this.doc, {
21509 //'mousedown': this.onEditorEvent,
21510 'mouseup': this.onEditorEvent,
21511 'dblclick': this.onEditorEvent,
21512 'click': this.onEditorEvent,
21513 'keyup': this.onEditorEvent,
21518 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21520 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21521 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21523 this.initialized = true;
21525 this.owner.fireEvent('initialize', this);
21530 onDestroy : function(){
21536 //for (var i =0; i < this.toolbars.length;i++) {
21537 // // fixme - ask toolbars for heights?
21538 // this.toolbars[i].onDestroy();
21541 //this.wrap.dom.innerHTML = '';
21542 //this.wrap.remove();
21547 onFirstFocus : function(){
21549 this.assignDocWin();
21552 this.activated = true;
21555 if(Roo.isGecko){ // prevent silly gecko errors
21557 var s = this.win.getSelection();
21558 if(!s.focusNode || s.focusNode.nodeType != 3){
21559 var r = s.getRangeAt(0);
21560 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21565 this.execCmd('useCSS', true);
21566 this.execCmd('styleWithCSS', false);
21569 this.owner.fireEvent('activate', this);
21573 adjustFont: function(btn){
21574 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21575 //if(Roo.isSafari){ // safari
21578 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21579 if(Roo.isSafari){ // safari
21580 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21581 v = (v < 10) ? 10 : v;
21582 v = (v > 48) ? 48 : v;
21583 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21588 v = Math.max(1, v+adjust);
21590 this.execCmd('FontSize', v );
21593 onEditorEvent : function(e)
21595 this.owner.fireEvent('editorevent', this, e);
21596 // this.updateToolbar();
21597 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21600 insertTag : function(tg)
21602 // could be a bit smarter... -> wrap the current selected tRoo..
21603 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21605 range = this.createRange(this.getSelection());
21606 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21607 wrappingNode.appendChild(range.extractContents());
21608 range.insertNode(wrappingNode);
21615 this.execCmd("formatblock", tg);
21619 insertText : function(txt)
21623 var range = this.createRange();
21624 range.deleteContents();
21625 //alert(Sender.getAttribute('label'));
21627 range.insertNode(this.doc.createTextNode(txt));
21633 * Executes a Midas editor command on the editor document and performs necessary focus and
21634 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21635 * @param {String} cmd The Midas command
21636 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21638 relayCmd : function(cmd, value){
21640 this.execCmd(cmd, value);
21641 this.owner.fireEvent('editorevent', this);
21642 //this.updateToolbar();
21643 this.owner.deferFocus();
21647 * Executes a Midas editor command directly on the editor document.
21648 * For visual commands, you should use {@link #relayCmd} instead.
21649 * <b>This should only be called after the editor is initialized.</b>
21650 * @param {String} cmd The Midas command
21651 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21653 execCmd : function(cmd, value){
21654 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21661 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21663 * @param {String} text | dom node..
21665 insertAtCursor : function(text)
21668 if(!this.activated){
21674 var r = this.doc.selection.createRange();
21685 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21689 // from jquery ui (MIT licenced)
21691 var win = this.win;
21693 if (win.getSelection && win.getSelection().getRangeAt) {
21694 range = win.getSelection().getRangeAt(0);
21695 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21696 range.insertNode(node);
21697 } else if (win.document.selection && win.document.selection.createRange) {
21698 // no firefox support
21699 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21700 win.document.selection.createRange().pasteHTML(txt);
21702 // no firefox support
21703 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21704 this.execCmd('InsertHTML', txt);
21713 mozKeyPress : function(e){
21715 var c = e.getCharCode(), cmd;
21718 c = String.fromCharCode(c).toLowerCase();
21732 this.cleanUpPaste.defer(100, this);
21740 e.preventDefault();
21748 fixKeys : function(){ // load time branching for fastest keydown performance
21750 return function(e){
21751 var k = e.getKey(), r;
21754 r = this.doc.selection.createRange();
21757 r.pasteHTML('    ');
21764 r = this.doc.selection.createRange();
21766 var target = r.parentElement();
21767 if(!target || target.tagName.toLowerCase() != 'li'){
21769 r.pasteHTML('<br />');
21775 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21776 this.cleanUpPaste.defer(100, this);
21782 }else if(Roo.isOpera){
21783 return function(e){
21784 var k = e.getKey();
21788 this.execCmd('InsertHTML','    ');
21791 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21792 this.cleanUpPaste.defer(100, this);
21797 }else if(Roo.isSafari){
21798 return function(e){
21799 var k = e.getKey();
21803 this.execCmd('InsertText','\t');
21807 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21808 this.cleanUpPaste.defer(100, this);
21816 getAllAncestors: function()
21818 var p = this.getSelectedNode();
21821 a.push(p); // push blank onto stack..
21822 p = this.getParentElement();
21826 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21830 a.push(this.doc.body);
21834 lastSelNode : false,
21837 getSelection : function()
21839 this.assignDocWin();
21840 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21843 getSelectedNode: function()
21845 // this may only work on Gecko!!!
21847 // should we cache this!!!!
21852 var range = this.createRange(this.getSelection()).cloneRange();
21855 var parent = range.parentElement();
21857 var testRange = range.duplicate();
21858 testRange.moveToElementText(parent);
21859 if (testRange.inRange(range)) {
21862 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21865 parent = parent.parentElement;
21870 // is ancestor a text element.
21871 var ac = range.commonAncestorContainer;
21872 if (ac.nodeType == 3) {
21873 ac = ac.parentNode;
21876 var ar = ac.childNodes;
21879 var other_nodes = [];
21880 var has_other_nodes = false;
21881 for (var i=0;i<ar.length;i++) {
21882 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21885 // fullly contained node.
21887 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21892 // probably selected..
21893 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21894 other_nodes.push(ar[i]);
21898 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21903 has_other_nodes = true;
21905 if (!nodes.length && other_nodes.length) {
21906 nodes= other_nodes;
21908 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21914 createRange: function(sel)
21916 // this has strange effects when using with
21917 // top toolbar - not sure if it's a great idea.
21918 //this.editor.contentWindow.focus();
21919 if (typeof sel != "undefined") {
21921 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21923 return this.doc.createRange();
21926 return this.doc.createRange();
21929 getParentElement: function()
21932 this.assignDocWin();
21933 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21935 var range = this.createRange(sel);
21938 var p = range.commonAncestorContainer;
21939 while (p.nodeType == 3) { // text node
21950 * Range intersection.. the hard stuff...
21954 * [ -- selected range --- ]
21958 * if end is before start or hits it. fail.
21959 * if start is after end or hits it fail.
21961 * if either hits (but other is outside. - then it's not
21967 // @see http://www.thismuchiknow.co.uk/?p=64.
21968 rangeIntersectsNode : function(range, node)
21970 var nodeRange = node.ownerDocument.createRange();
21972 nodeRange.selectNode(node);
21974 nodeRange.selectNodeContents(node);
21977 var rangeStartRange = range.cloneRange();
21978 rangeStartRange.collapse(true);
21980 var rangeEndRange = range.cloneRange();
21981 rangeEndRange.collapse(false);
21983 var nodeStartRange = nodeRange.cloneRange();
21984 nodeStartRange.collapse(true);
21986 var nodeEndRange = nodeRange.cloneRange();
21987 nodeEndRange.collapse(false);
21989 return rangeStartRange.compareBoundaryPoints(
21990 Range.START_TO_START, nodeEndRange) == -1 &&
21991 rangeEndRange.compareBoundaryPoints(
21992 Range.START_TO_START, nodeStartRange) == 1;
21996 rangeCompareNode : function(range, node)
21998 var nodeRange = node.ownerDocument.createRange();
22000 nodeRange.selectNode(node);
22002 nodeRange.selectNodeContents(node);
22006 range.collapse(true);
22008 nodeRange.collapse(true);
22010 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22011 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22013 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22015 var nodeIsBefore = ss == 1;
22016 var nodeIsAfter = ee == -1;
22018 if (nodeIsBefore && nodeIsAfter) {
22021 if (!nodeIsBefore && nodeIsAfter) {
22022 return 1; //right trailed.
22025 if (nodeIsBefore && !nodeIsAfter) {
22026 return 2; // left trailed.
22032 // private? - in a new class?
22033 cleanUpPaste : function()
22035 // cleans up the whole document..
22036 Roo.log('cleanuppaste');
22038 this.cleanUpChildren(this.doc.body);
22039 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22040 if (clean != this.doc.body.innerHTML) {
22041 this.doc.body.innerHTML = clean;
22046 cleanWordChars : function(input) {// change the chars to hex code
22047 var he = Roo.HtmlEditorCore;
22049 var output = input;
22050 Roo.each(he.swapCodes, function(sw) {
22051 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22053 output = output.replace(swapper, sw[1]);
22060 cleanUpChildren : function (n)
22062 if (!n.childNodes.length) {
22065 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22066 this.cleanUpChild(n.childNodes[i]);
22073 cleanUpChild : function (node)
22076 //console.log(node);
22077 if (node.nodeName == "#text") {
22078 // clean up silly Windows -- stuff?
22081 if (node.nodeName == "#comment") {
22082 node.parentNode.removeChild(node);
22083 // clean up silly Windows -- stuff?
22086 var lcname = node.tagName.toLowerCase();
22087 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22088 // whitelist of tags..
22090 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22092 node.parentNode.removeChild(node);
22097 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22099 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22100 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22102 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22103 // remove_keep_children = true;
22106 if (remove_keep_children) {
22107 this.cleanUpChildren(node);
22108 // inserts everything just before this node...
22109 while (node.childNodes.length) {
22110 var cn = node.childNodes[0];
22111 node.removeChild(cn);
22112 node.parentNode.insertBefore(cn, node);
22114 node.parentNode.removeChild(node);
22118 if (!node.attributes || !node.attributes.length) {
22119 this.cleanUpChildren(node);
22123 function cleanAttr(n,v)
22126 if (v.match(/^\./) || v.match(/^\//)) {
22129 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22132 if (v.match(/^#/)) {
22135 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22136 node.removeAttribute(n);
22140 var cwhite = this.cwhite;
22141 var cblack = this.cblack;
22143 function cleanStyle(n,v)
22145 if (v.match(/expression/)) { //XSS?? should we even bother..
22146 node.removeAttribute(n);
22150 var parts = v.split(/;/);
22153 Roo.each(parts, function(p) {
22154 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22158 var l = p.split(':').shift().replace(/\s+/g,'');
22159 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22161 if ( cwhite.length && cblack.indexOf(l) > -1) {
22162 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22163 //node.removeAttribute(n);
22167 // only allow 'c whitelisted system attributes'
22168 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22169 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22170 //node.removeAttribute(n);
22180 if (clean.length) {
22181 node.setAttribute(n, clean.join(';'));
22183 node.removeAttribute(n);
22189 for (var i = node.attributes.length-1; i > -1 ; i--) {
22190 var a = node.attributes[i];
22193 if (a.name.toLowerCase().substr(0,2)=='on') {
22194 node.removeAttribute(a.name);
22197 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22198 node.removeAttribute(a.name);
22201 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22202 cleanAttr(a.name,a.value); // fixme..
22205 if (a.name == 'style') {
22206 cleanStyle(a.name,a.value);
22209 /// clean up MS crap..
22210 // tecnically this should be a list of valid class'es..
22213 if (a.name == 'class') {
22214 if (a.value.match(/^Mso/)) {
22215 node.className = '';
22218 if (a.value.match(/^body$/)) {
22219 node.className = '';
22230 this.cleanUpChildren(node);
22236 * Clean up MS wordisms...
22238 cleanWord : function(node)
22243 this.cleanWord(this.doc.body);
22246 if (node.nodeName == "#text") {
22247 // clean up silly Windows -- stuff?
22250 if (node.nodeName == "#comment") {
22251 node.parentNode.removeChild(node);
22252 // clean up silly Windows -- stuff?
22256 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22257 node.parentNode.removeChild(node);
22261 // remove - but keep children..
22262 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22263 while (node.childNodes.length) {
22264 var cn = node.childNodes[0];
22265 node.removeChild(cn);
22266 node.parentNode.insertBefore(cn, node);
22268 node.parentNode.removeChild(node);
22269 this.iterateChildren(node, this.cleanWord);
22273 if (node.className.length) {
22275 var cn = node.className.split(/\W+/);
22277 Roo.each(cn, function(cls) {
22278 if (cls.match(/Mso[a-zA-Z]+/)) {
22283 node.className = cna.length ? cna.join(' ') : '';
22285 node.removeAttribute("class");
22289 if (node.hasAttribute("lang")) {
22290 node.removeAttribute("lang");
22293 if (node.hasAttribute("style")) {
22295 var styles = node.getAttribute("style").split(";");
22297 Roo.each(styles, function(s) {
22298 if (!s.match(/:/)) {
22301 var kv = s.split(":");
22302 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22305 // what ever is left... we allow.
22308 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22309 if (!nstyle.length) {
22310 node.removeAttribute('style');
22313 this.iterateChildren(node, this.cleanWord);
22319 * iterateChildren of a Node, calling fn each time, using this as the scole..
22320 * @param {DomNode} node node to iterate children of.
22321 * @param {Function} fn method of this class to call on each item.
22323 iterateChildren : function(node, fn)
22325 if (!node.childNodes.length) {
22328 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22329 fn.call(this, node.childNodes[i])
22335 * cleanTableWidths.
22337 * Quite often pasting from word etc.. results in tables with column and widths.
22338 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22341 cleanTableWidths : function(node)
22346 this.cleanTableWidths(this.doc.body);
22351 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22354 Roo.log(node.tagName);
22355 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22356 this.iterateChildren(node, this.cleanTableWidths);
22359 if (node.hasAttribute('width')) {
22360 node.removeAttribute('width');
22364 if (node.hasAttribute("style")) {
22367 var styles = node.getAttribute("style").split(";");
22369 Roo.each(styles, function(s) {
22370 if (!s.match(/:/)) {
22373 var kv = s.split(":");
22374 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22377 // what ever is left... we allow.
22380 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22381 if (!nstyle.length) {
22382 node.removeAttribute('style');
22386 this.iterateChildren(node, this.cleanTableWidths);
22394 domToHTML : function(currentElement, depth, nopadtext) {
22396 depth = depth || 0;
22397 nopadtext = nopadtext || false;
22399 if (!currentElement) {
22400 return this.domToHTML(this.doc.body);
22403 //Roo.log(currentElement);
22405 var allText = false;
22406 var nodeName = currentElement.nodeName;
22407 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22409 if (nodeName == '#text') {
22411 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22416 if (nodeName != 'BODY') {
22419 // Prints the node tagName, such as <A>, <IMG>, etc
22422 for(i = 0; i < currentElement.attributes.length;i++) {
22424 var aname = currentElement.attributes.item(i).name;
22425 if (!currentElement.attributes.item(i).value.length) {
22428 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22431 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22440 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22443 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22448 // Traverse the tree
22450 var currentElementChild = currentElement.childNodes.item(i);
22451 var allText = true;
22452 var innerHTML = '';
22454 while (currentElementChild) {
22455 // Formatting code (indent the tree so it looks nice on the screen)
22456 var nopad = nopadtext;
22457 if (lastnode == 'SPAN') {
22461 if (currentElementChild.nodeName == '#text') {
22462 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22463 toadd = nopadtext ? toadd : toadd.trim();
22464 if (!nopad && toadd.length > 80) {
22465 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22467 innerHTML += toadd;
22470 currentElementChild = currentElement.childNodes.item(i);
22476 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22478 // Recursively traverse the tree structure of the child node
22479 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22480 lastnode = currentElementChild.nodeName;
22482 currentElementChild=currentElement.childNodes.item(i);
22488 // The remaining code is mostly for formatting the tree
22489 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22494 ret+= "</"+tagName+">";
22500 applyBlacklists : function()
22502 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22503 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22507 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22508 if (b.indexOf(tag) > -1) {
22511 this.white.push(tag);
22515 Roo.each(w, function(tag) {
22516 if (b.indexOf(tag) > -1) {
22519 if (this.white.indexOf(tag) > -1) {
22522 this.white.push(tag);
22527 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22528 if (w.indexOf(tag) > -1) {
22531 this.black.push(tag);
22535 Roo.each(b, function(tag) {
22536 if (w.indexOf(tag) > -1) {
22539 if (this.black.indexOf(tag) > -1) {
22542 this.black.push(tag);
22547 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22548 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22552 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22553 if (b.indexOf(tag) > -1) {
22556 this.cwhite.push(tag);
22560 Roo.each(w, function(tag) {
22561 if (b.indexOf(tag) > -1) {
22564 if (this.cwhite.indexOf(tag) > -1) {
22567 this.cwhite.push(tag);
22572 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22573 if (w.indexOf(tag) > -1) {
22576 this.cblack.push(tag);
22580 Roo.each(b, function(tag) {
22581 if (w.indexOf(tag) > -1) {
22584 if (this.cblack.indexOf(tag) > -1) {
22587 this.cblack.push(tag);
22592 setStylesheets : function(stylesheets)
22594 if(typeof(stylesheets) == 'string'){
22595 Roo.get(this.iframe.contentDocument.head).createChild({
22597 rel : 'stylesheet',
22606 Roo.each(stylesheets, function(s) {
22611 Roo.get(_this.iframe.contentDocument.head).createChild({
22613 rel : 'stylesheet',
22622 removeStylesheets : function()
22626 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22631 // hide stuff that is not compatible
22645 * @event specialkey
22649 * @cfg {String} fieldClass @hide
22652 * @cfg {String} focusClass @hide
22655 * @cfg {String} autoCreate @hide
22658 * @cfg {String} inputType @hide
22661 * @cfg {String} invalidClass @hide
22664 * @cfg {String} invalidText @hide
22667 * @cfg {String} msgFx @hide
22670 * @cfg {String} validateOnBlur @hide
22674 Roo.HtmlEditorCore.white = [
22675 'area', 'br', 'img', 'input', 'hr', 'wbr',
22677 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22678 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22679 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22680 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22681 'table', 'ul', 'xmp',
22683 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22686 'dir', 'menu', 'ol', 'ul', 'dl',
22692 Roo.HtmlEditorCore.black = [
22693 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22695 'base', 'basefont', 'bgsound', 'blink', 'body',
22696 'frame', 'frameset', 'head', 'html', 'ilayer',
22697 'iframe', 'layer', 'link', 'meta', 'object',
22698 'script', 'style' ,'title', 'xml' // clean later..
22700 Roo.HtmlEditorCore.clean = [
22701 'script', 'style', 'title', 'xml'
22703 Roo.HtmlEditorCore.remove = [
22708 Roo.HtmlEditorCore.ablack = [
22712 Roo.HtmlEditorCore.aclean = [
22713 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22717 Roo.HtmlEditorCore.pwhite= [
22718 'http', 'https', 'mailto'
22721 // white listed style attributes.
22722 Roo.HtmlEditorCore.cwhite= [
22723 // 'text-align', /// default is to allow most things..
22729 // black listed style attributes.
22730 Roo.HtmlEditorCore.cblack= [
22731 // 'font-size' -- this can be set by the project
22735 Roo.HtmlEditorCore.swapCodes =[
22754 * @class Roo.bootstrap.HtmlEditor
22755 * @extends Roo.bootstrap.TextArea
22756 * Bootstrap HtmlEditor class
22759 * Create a new HtmlEditor
22760 * @param {Object} config The config object
22763 Roo.bootstrap.HtmlEditor = function(config){
22764 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22765 if (!this.toolbars) {
22766 this.toolbars = [];
22769 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22772 * @event initialize
22773 * Fires when the editor is fully initialized (including the iframe)
22774 * @param {HtmlEditor} this
22779 * Fires when the editor is first receives the focus. Any insertion must wait
22780 * until after this event.
22781 * @param {HtmlEditor} this
22785 * @event beforesync
22786 * Fires before the textarea is updated with content from the editor iframe. Return false
22787 * to cancel the sync.
22788 * @param {HtmlEditor} this
22789 * @param {String} html
22793 * @event beforepush
22794 * Fires before the iframe editor is updated with content from the textarea. Return false
22795 * to cancel the push.
22796 * @param {HtmlEditor} this
22797 * @param {String} html
22802 * Fires when the textarea is updated with content from the editor iframe.
22803 * @param {HtmlEditor} this
22804 * @param {String} html
22809 * Fires when the iframe editor is updated with content from the textarea.
22810 * @param {HtmlEditor} this
22811 * @param {String} html
22815 * @event editmodechange
22816 * Fires when the editor switches edit modes
22817 * @param {HtmlEditor} this
22818 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22820 editmodechange: true,
22822 * @event editorevent
22823 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22824 * @param {HtmlEditor} this
22828 * @event firstfocus
22829 * Fires when on first focus - needed by toolbars..
22830 * @param {HtmlEditor} this
22835 * Auto save the htmlEditor value as a file into Events
22836 * @param {HtmlEditor} this
22840 * @event savedpreview
22841 * preview the saved version of htmlEditor
22842 * @param {HtmlEditor} this
22849 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22853 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22858 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
22863 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22868 * @cfg {Number} height (in pixels)
22872 * @cfg {Number} width (in pixels)
22877 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22880 stylesheets: false,
22885 // private properties
22886 validationEvent : false,
22888 initialized : false,
22891 onFocus : Roo.emptyFn,
22893 hideMode:'offsets',
22895 tbContainer : false,
22897 toolbarContainer :function() {
22898 return this.wrap.select('.x-html-editor-tb',true).first();
22902 * Protected method that will not generally be called directly. It
22903 * is called when the editor creates its toolbar. Override this method if you need to
22904 * add custom toolbar buttons.
22905 * @param {HtmlEditor} editor
22907 createToolbar : function(){
22908 Roo.log('renewing');
22909 Roo.log("create toolbars");
22911 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22912 this.toolbars[0].render(this.toolbarContainer());
22916 // if (!editor.toolbars || !editor.toolbars.length) {
22917 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22920 // for (var i =0 ; i < editor.toolbars.length;i++) {
22921 // editor.toolbars[i] = Roo.factory(
22922 // typeof(editor.toolbars[i]) == 'string' ?
22923 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22924 // Roo.bootstrap.HtmlEditor);
22925 // editor.toolbars[i].init(editor);
22931 onRender : function(ct, position)
22933 // Roo.log("Call onRender: " + this.xtype);
22935 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22937 this.wrap = this.inputEl().wrap({
22938 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22941 this.editorcore.onRender(ct, position);
22943 if (this.resizable) {
22944 this.resizeEl = new Roo.Resizable(this.wrap, {
22948 minHeight : this.height,
22949 height: this.height,
22950 handles : this.resizable,
22953 resize : function(r, w, h) {
22954 _t.onResize(w,h); // -something
22960 this.createToolbar(this);
22963 if(!this.width && this.resizable){
22964 this.setSize(this.wrap.getSize());
22966 if (this.resizeEl) {
22967 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22968 // should trigger onReize..
22974 onResize : function(w, h)
22976 Roo.log('resize: ' +w + ',' + h );
22977 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22981 if(this.inputEl() ){
22982 if(typeof w == 'number'){
22983 var aw = w - this.wrap.getFrameWidth('lr');
22984 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22987 if(typeof h == 'number'){
22988 var tbh = -11; // fixme it needs to tool bar size!
22989 for (var i =0; i < this.toolbars.length;i++) {
22990 // fixme - ask toolbars for heights?
22991 tbh += this.toolbars[i].el.getHeight();
22992 //if (this.toolbars[i].footer) {
22993 // tbh += this.toolbars[i].footer.el.getHeight();
23001 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23002 ah -= 5; // knock a few pixes off for look..
23003 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23007 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23008 this.editorcore.onResize(ew,eh);
23013 * Toggles the editor between standard and source edit mode.
23014 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23016 toggleSourceEdit : function(sourceEditMode)
23018 this.editorcore.toggleSourceEdit(sourceEditMode);
23020 if(this.editorcore.sourceEditMode){
23021 Roo.log('editor - showing textarea');
23024 // Roo.log(this.syncValue());
23026 this.inputEl().removeClass(['hide', 'x-hidden']);
23027 this.inputEl().dom.removeAttribute('tabIndex');
23028 this.inputEl().focus();
23030 Roo.log('editor - hiding textarea');
23032 // Roo.log(this.pushValue());
23035 this.inputEl().addClass(['hide', 'x-hidden']);
23036 this.inputEl().dom.setAttribute('tabIndex', -1);
23037 //this.deferFocus();
23040 if(this.resizable){
23041 this.setSize(this.wrap.getSize());
23044 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23047 // private (for BoxComponent)
23048 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23050 // private (for BoxComponent)
23051 getResizeEl : function(){
23055 // private (for BoxComponent)
23056 getPositionEl : function(){
23061 initEvents : function(){
23062 this.originalValue = this.getValue();
23066 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23069 // markInvalid : Roo.emptyFn,
23071 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23074 // clearInvalid : Roo.emptyFn,
23076 setValue : function(v){
23077 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23078 this.editorcore.pushValue();
23083 deferFocus : function(){
23084 this.focus.defer(10, this);
23088 focus : function(){
23089 this.editorcore.focus();
23095 onDestroy : function(){
23101 for (var i =0; i < this.toolbars.length;i++) {
23102 // fixme - ask toolbars for heights?
23103 this.toolbars[i].onDestroy();
23106 this.wrap.dom.innerHTML = '';
23107 this.wrap.remove();
23112 onFirstFocus : function(){
23113 //Roo.log("onFirstFocus");
23114 this.editorcore.onFirstFocus();
23115 for (var i =0; i < this.toolbars.length;i++) {
23116 this.toolbars[i].onFirstFocus();
23122 syncValue : function()
23124 this.editorcore.syncValue();
23127 pushValue : function()
23129 this.editorcore.pushValue();
23133 // hide stuff that is not compatible
23147 * @event specialkey
23151 * @cfg {String} fieldClass @hide
23154 * @cfg {String} focusClass @hide
23157 * @cfg {String} autoCreate @hide
23160 * @cfg {String} inputType @hide
23163 * @cfg {String} invalidClass @hide
23166 * @cfg {String} invalidText @hide
23169 * @cfg {String} msgFx @hide
23172 * @cfg {String} validateOnBlur @hide
23181 Roo.namespace('Roo.bootstrap.htmleditor');
23183 * @class Roo.bootstrap.HtmlEditorToolbar1
23188 new Roo.bootstrap.HtmlEditor({
23191 new Roo.bootstrap.HtmlEditorToolbar1({
23192 disable : { fonts: 1 , format: 1, ..., ... , ...],
23198 * @cfg {Object} disable List of elements to disable..
23199 * @cfg {Array} btns List of additional buttons.
23203 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23206 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23209 Roo.apply(this, config);
23211 // default disabled, based on 'good practice'..
23212 this.disable = this.disable || {};
23213 Roo.applyIf(this.disable, {
23216 specialElements : true
23218 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23220 this.editor = config.editor;
23221 this.editorcore = config.editor.editorcore;
23223 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23225 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23226 // dont call parent... till later.
23228 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23233 editorcore : false,
23238 "h1","h2","h3","h4","h5","h6",
23240 "abbr", "acronym", "address", "cite", "samp", "var",
23244 onRender : function(ct, position)
23246 // Roo.log("Call onRender: " + this.xtype);
23248 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23250 this.el.dom.style.marginBottom = '0';
23252 var editorcore = this.editorcore;
23253 var editor= this.editor;
23256 var btn = function(id,cmd , toggle, handler, html){
23258 var event = toggle ? 'toggle' : 'click';
23263 xns: Roo.bootstrap,
23266 enableToggle:toggle !== false,
23268 pressed : toggle ? false : null,
23271 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23272 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23278 // var cb_box = function...
23283 xns: Roo.bootstrap,
23284 glyphicon : 'font',
23288 xns: Roo.bootstrap,
23292 Roo.each(this.formats, function(f) {
23293 style.menu.items.push({
23295 xns: Roo.bootstrap,
23296 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23301 editorcore.insertTag(this.tagname);
23308 children.push(style);
23310 btn('bold',false,true);
23311 btn('italic',false,true);
23312 btn('align-left', 'justifyleft',true);
23313 btn('align-center', 'justifycenter',true);
23314 btn('align-right' , 'justifyright',true);
23315 btn('link', false, false, function(btn) {
23316 //Roo.log("create link?");
23317 var url = prompt(this.createLinkText, this.defaultLinkValue);
23318 if(url && url != 'http:/'+'/'){
23319 this.editorcore.relayCmd('createlink', url);
23322 btn('list','insertunorderedlist',true);
23323 btn('pencil', false,true, function(btn){
23325 this.toggleSourceEdit(btn.pressed);
23328 if (this.editor.btns.length > 0) {
23329 for (var i = 0; i<this.editor.btns.length; i++) {
23330 children.push(this.editor.btns[i]);
23338 xns: Roo.bootstrap,
23343 xns: Roo.bootstrap,
23348 cog.menu.items.push({
23350 xns: Roo.bootstrap,
23351 html : Clean styles,
23356 editorcore.insertTag(this.tagname);
23365 this.xtype = 'NavSimplebar';
23367 for(var i=0;i< children.length;i++) {
23369 this.buttons.add(this.addxtypeChild(children[i]));
23373 editor.on('editorevent', this.updateToolbar, this);
23375 onBtnClick : function(id)
23377 this.editorcore.relayCmd(id);
23378 this.editorcore.focus();
23382 * Protected method that will not generally be called directly. It triggers
23383 * a toolbar update by reading the markup state of the current selection in the editor.
23385 updateToolbar: function(){
23387 if(!this.editorcore.activated){
23388 this.editor.onFirstFocus(); // is this neeed?
23392 var btns = this.buttons;
23393 var doc = this.editorcore.doc;
23394 btns.get('bold').setActive(doc.queryCommandState('bold'));
23395 btns.get('italic').setActive(doc.queryCommandState('italic'));
23396 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23398 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23399 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23400 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23402 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23403 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23406 var ans = this.editorcore.getAllAncestors();
23407 if (this.formatCombo) {
23410 var store = this.formatCombo.store;
23411 this.formatCombo.setValue("");
23412 for (var i =0; i < ans.length;i++) {
23413 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23415 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23423 // hides menus... - so this cant be on a menu...
23424 Roo.bootstrap.MenuMgr.hideAll();
23426 Roo.bootstrap.MenuMgr.hideAll();
23427 //this.editorsyncValue();
23429 onFirstFocus: function() {
23430 this.buttons.each(function(item){
23434 toggleSourceEdit : function(sourceEditMode){
23437 if(sourceEditMode){
23438 Roo.log("disabling buttons");
23439 this.buttons.each( function(item){
23440 if(item.cmd != 'pencil'){
23446 Roo.log("enabling buttons");
23447 if(this.editorcore.initialized){
23448 this.buttons.each( function(item){
23454 Roo.log("calling toggole on editor");
23455 // tell the editor that it's been pressed..
23456 this.editor.toggleSourceEdit(sourceEditMode);
23466 * @class Roo.bootstrap.Table.AbstractSelectionModel
23467 * @extends Roo.util.Observable
23468 * Abstract base class for grid SelectionModels. It provides the interface that should be
23469 * implemented by descendant classes. This class should not be directly instantiated.
23472 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23473 this.locked = false;
23474 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23478 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23479 /** @ignore Called by the grid automatically. Do not call directly. */
23480 init : function(grid){
23486 * Locks the selections.
23489 this.locked = true;
23493 * Unlocks the selections.
23495 unlock : function(){
23496 this.locked = false;
23500 * Returns true if the selections are locked.
23501 * @return {Boolean}
23503 isLocked : function(){
23504 return this.locked;
23508 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23509 * @class Roo.bootstrap.Table.RowSelectionModel
23510 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23511 * It supports multiple selections and keyboard selection/navigation.
23513 * @param {Object} config
23516 Roo.bootstrap.Table.RowSelectionModel = function(config){
23517 Roo.apply(this, config);
23518 this.selections = new Roo.util.MixedCollection(false, function(o){
23523 this.lastActive = false;
23527 * @event selectionchange
23528 * Fires when the selection changes
23529 * @param {SelectionModel} this
23531 "selectionchange" : true,
23533 * @event afterselectionchange
23534 * Fires after the selection changes (eg. by key press or clicking)
23535 * @param {SelectionModel} this
23537 "afterselectionchange" : true,
23539 * @event beforerowselect
23540 * Fires when a row is selected being selected, return false to cancel.
23541 * @param {SelectionModel} this
23542 * @param {Number} rowIndex The selected index
23543 * @param {Boolean} keepExisting False if other selections will be cleared
23545 "beforerowselect" : true,
23548 * Fires when a row is selected.
23549 * @param {SelectionModel} this
23550 * @param {Number} rowIndex The selected index
23551 * @param {Roo.data.Record} r The record
23553 "rowselect" : true,
23555 * @event rowdeselect
23556 * Fires when a row is deselected.
23557 * @param {SelectionModel} this
23558 * @param {Number} rowIndex The selected index
23560 "rowdeselect" : true
23562 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23563 this.locked = false;
23566 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23568 * @cfg {Boolean} singleSelect
23569 * True to allow selection of only one row at a time (defaults to false)
23571 singleSelect : false,
23574 initEvents : function()
23577 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23578 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23579 //}else{ // allow click to work like normal
23580 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23582 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23583 this.grid.on("rowclick", this.handleMouseDown, this);
23585 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23586 "up" : function(e){
23588 this.selectPrevious(e.shiftKey);
23589 }else if(this.last !== false && this.lastActive !== false){
23590 var last = this.last;
23591 this.selectRange(this.last, this.lastActive-1);
23592 this.grid.getView().focusRow(this.lastActive);
23593 if(last !== false){
23597 this.selectFirstRow();
23599 this.fireEvent("afterselectionchange", this);
23601 "down" : function(e){
23603 this.selectNext(e.shiftKey);
23604 }else if(this.last !== false && this.lastActive !== false){
23605 var last = this.last;
23606 this.selectRange(this.last, this.lastActive+1);
23607 this.grid.getView().focusRow(this.lastActive);
23608 if(last !== false){
23612 this.selectFirstRow();
23614 this.fireEvent("afterselectionchange", this);
23618 this.grid.store.on('load', function(){
23619 this.selections.clear();
23622 var view = this.grid.view;
23623 view.on("refresh", this.onRefresh, this);
23624 view.on("rowupdated", this.onRowUpdated, this);
23625 view.on("rowremoved", this.onRemove, this);
23630 onRefresh : function()
23632 var ds = this.grid.store, i, v = this.grid.view;
23633 var s = this.selections;
23634 s.each(function(r){
23635 if((i = ds.indexOfId(r.id)) != -1){
23644 onRemove : function(v, index, r){
23645 this.selections.remove(r);
23649 onRowUpdated : function(v, index, r){
23650 if(this.isSelected(r)){
23651 v.onRowSelect(index);
23657 * @param {Array} records The records to select
23658 * @param {Boolean} keepExisting (optional) True to keep existing selections
23660 selectRecords : function(records, keepExisting)
23663 this.clearSelections();
23665 var ds = this.grid.store;
23666 for(var i = 0, len = records.length; i < len; i++){
23667 this.selectRow(ds.indexOf(records[i]), true);
23672 * Gets the number of selected rows.
23675 getCount : function(){
23676 return this.selections.length;
23680 * Selects the first row in the grid.
23682 selectFirstRow : function(){
23687 * Select the last row.
23688 * @param {Boolean} keepExisting (optional) True to keep existing selections
23690 selectLastRow : function(keepExisting){
23691 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23692 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23696 * Selects the row immediately following the last selected row.
23697 * @param {Boolean} keepExisting (optional) True to keep existing selections
23699 selectNext : function(keepExisting)
23701 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23702 this.selectRow(this.last+1, keepExisting);
23703 this.grid.getView().focusRow(this.last);
23708 * Selects the row that precedes the last selected row.
23709 * @param {Boolean} keepExisting (optional) True to keep existing selections
23711 selectPrevious : function(keepExisting){
23713 this.selectRow(this.last-1, keepExisting);
23714 this.grid.getView().focusRow(this.last);
23719 * Returns the selected records
23720 * @return {Array} Array of selected records
23722 getSelections : function(){
23723 return [].concat(this.selections.items);
23727 * Returns the first selected record.
23730 getSelected : function(){
23731 return this.selections.itemAt(0);
23736 * Clears all selections.
23738 clearSelections : function(fast)
23744 var ds = this.grid.store;
23745 var s = this.selections;
23746 s.each(function(r){
23747 this.deselectRow(ds.indexOfId(r.id));
23751 this.selections.clear();
23758 * Selects all rows.
23760 selectAll : function(){
23764 this.selections.clear();
23765 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23766 this.selectRow(i, true);
23771 * Returns True if there is a selection.
23772 * @return {Boolean}
23774 hasSelection : function(){
23775 return this.selections.length > 0;
23779 * Returns True if the specified row is selected.
23780 * @param {Number/Record} record The record or index of the record to check
23781 * @return {Boolean}
23783 isSelected : function(index){
23784 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23785 return (r && this.selections.key(r.id) ? true : false);
23789 * Returns True if the specified record id is selected.
23790 * @param {String} id The id of record to check
23791 * @return {Boolean}
23793 isIdSelected : function(id){
23794 return (this.selections.key(id) ? true : false);
23799 handleMouseDBClick : function(e, t){
23803 handleMouseDown : function(e, t)
23805 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23806 if(this.isLocked() || rowIndex < 0 ){
23809 if(e.shiftKey && this.last !== false){
23810 var last = this.last;
23811 this.selectRange(last, rowIndex, e.ctrlKey);
23812 this.last = last; // reset the last
23816 var isSelected = this.isSelected(rowIndex);
23817 //Roo.log("select row:" + rowIndex);
23819 this.deselectRow(rowIndex);
23821 this.selectRow(rowIndex, true);
23825 if(e.button !== 0 && isSelected){
23826 alert('rowIndex 2: ' + rowIndex);
23827 view.focusRow(rowIndex);
23828 }else if(e.ctrlKey && isSelected){
23829 this.deselectRow(rowIndex);
23830 }else if(!isSelected){
23831 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23832 view.focusRow(rowIndex);
23836 this.fireEvent("afterselectionchange", this);
23839 handleDragableRowClick : function(grid, rowIndex, e)
23841 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23842 this.selectRow(rowIndex, false);
23843 grid.view.focusRow(rowIndex);
23844 this.fireEvent("afterselectionchange", this);
23849 * Selects multiple rows.
23850 * @param {Array} rows Array of the indexes of the row to select
23851 * @param {Boolean} keepExisting (optional) True to keep existing selections
23853 selectRows : function(rows, keepExisting){
23855 this.clearSelections();
23857 for(var i = 0, len = rows.length; i < len; i++){
23858 this.selectRow(rows[i], true);
23863 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23864 * @param {Number} startRow The index of the first row in the range
23865 * @param {Number} endRow The index of the last row in the range
23866 * @param {Boolean} keepExisting (optional) True to retain existing selections
23868 selectRange : function(startRow, endRow, keepExisting){
23873 this.clearSelections();
23875 if(startRow <= endRow){
23876 for(var i = startRow; i <= endRow; i++){
23877 this.selectRow(i, true);
23880 for(var i = startRow; i >= endRow; i--){
23881 this.selectRow(i, true);
23887 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23888 * @param {Number} startRow The index of the first row in the range
23889 * @param {Number} endRow The index of the last row in the range
23891 deselectRange : function(startRow, endRow, preventViewNotify){
23895 for(var i = startRow; i <= endRow; i++){
23896 this.deselectRow(i, preventViewNotify);
23902 * @param {Number} row The index of the row to select
23903 * @param {Boolean} keepExisting (optional) True to keep existing selections
23905 selectRow : function(index, keepExisting, preventViewNotify)
23907 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23910 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23911 if(!keepExisting || this.singleSelect){
23912 this.clearSelections();
23915 var r = this.grid.store.getAt(index);
23916 //console.log('selectRow - record id :' + r.id);
23918 this.selections.add(r);
23919 this.last = this.lastActive = index;
23920 if(!preventViewNotify){
23921 var proxy = new Roo.Element(
23922 this.grid.getRowDom(index)
23924 proxy.addClass('bg-info info');
23926 this.fireEvent("rowselect", this, index, r);
23927 this.fireEvent("selectionchange", this);
23933 * @param {Number} row The index of the row to deselect
23935 deselectRow : function(index, preventViewNotify)
23940 if(this.last == index){
23943 if(this.lastActive == index){
23944 this.lastActive = false;
23947 var r = this.grid.store.getAt(index);
23952 this.selections.remove(r);
23953 //.console.log('deselectRow - record id :' + r.id);
23954 if(!preventViewNotify){
23956 var proxy = new Roo.Element(
23957 this.grid.getRowDom(index)
23959 proxy.removeClass('bg-info info');
23961 this.fireEvent("rowdeselect", this, index);
23962 this.fireEvent("selectionchange", this);
23966 restoreLast : function(){
23968 this.last = this._last;
23973 acceptsNav : function(row, col, cm){
23974 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23978 onEditorKey : function(field, e){
23979 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23984 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23986 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23988 }else if(k == e.ENTER && !e.ctrlKey){
23992 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23994 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23996 }else if(k == e.ESC){
24000 g.startEditing(newCell[0], newCell[1]);
24006 * Ext JS Library 1.1.1
24007 * Copyright(c) 2006-2007, Ext JS, LLC.
24009 * Originally Released Under LGPL - original licence link has changed is not relivant.
24012 * <script type="text/javascript">
24016 * @class Roo.bootstrap.PagingToolbar
24017 * @extends Roo.bootstrap.NavSimplebar
24018 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24020 * Create a new PagingToolbar
24021 * @param {Object} config The config object
24022 * @param {Roo.data.Store} store
24024 Roo.bootstrap.PagingToolbar = function(config)
24026 // old args format still supported... - xtype is prefered..
24027 // created from xtype...
24029 this.ds = config.dataSource;
24031 if (config.store && !this.ds) {
24032 this.store= Roo.factory(config.store, Roo.data);
24033 this.ds = this.store;
24034 this.ds.xmodule = this.xmodule || false;
24037 this.toolbarItems = [];
24038 if (config.items) {
24039 this.toolbarItems = config.items;
24042 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24047 this.bind(this.ds);
24050 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24054 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24056 * @cfg {Roo.data.Store} dataSource
24057 * The underlying data store providing the paged data
24060 * @cfg {String/HTMLElement/Element} container
24061 * container The id or element that will contain the toolbar
24064 * @cfg {Boolean} displayInfo
24065 * True to display the displayMsg (defaults to false)
24068 * @cfg {Number} pageSize
24069 * The number of records to display per page (defaults to 20)
24073 * @cfg {String} displayMsg
24074 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24076 displayMsg : 'Displaying {0} - {1} of {2}',
24078 * @cfg {String} emptyMsg
24079 * The message to display when no records are found (defaults to "No data to display")
24081 emptyMsg : 'No data to display',
24083 * Customizable piece of the default paging text (defaults to "Page")
24086 beforePageText : "Page",
24088 * Customizable piece of the default paging text (defaults to "of %0")
24091 afterPageText : "of {0}",
24093 * Customizable piece of the default paging text (defaults to "First Page")
24096 firstText : "First Page",
24098 * Customizable piece of the default paging text (defaults to "Previous Page")
24101 prevText : "Previous Page",
24103 * Customizable piece of the default paging text (defaults to "Next Page")
24106 nextText : "Next Page",
24108 * Customizable piece of the default paging text (defaults to "Last Page")
24111 lastText : "Last Page",
24113 * Customizable piece of the default paging text (defaults to "Refresh")
24116 refreshText : "Refresh",
24120 onRender : function(ct, position)
24122 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24123 this.navgroup.parentId = this.id;
24124 this.navgroup.onRender(this.el, null);
24125 // add the buttons to the navgroup
24127 if(this.displayInfo){
24128 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24129 this.displayEl = this.el.select('.x-paging-info', true).first();
24130 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24131 // this.displayEl = navel.el.select('span',true).first();
24137 Roo.each(_this.buttons, function(e){ // this might need to use render????
24138 Roo.factory(e).onRender(_this.el, null);
24142 Roo.each(_this.toolbarItems, function(e) {
24143 _this.navgroup.addItem(e);
24147 this.first = this.navgroup.addItem({
24148 tooltip: this.firstText,
24150 icon : 'fa fa-backward',
24152 preventDefault: true,
24153 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24156 this.prev = this.navgroup.addItem({
24157 tooltip: this.prevText,
24159 icon : 'fa fa-step-backward',
24161 preventDefault: true,
24162 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24164 //this.addSeparator();
24167 var field = this.navgroup.addItem( {
24169 cls : 'x-paging-position',
24171 html : this.beforePageText +
24172 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24173 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24176 this.field = field.el.select('input', true).first();
24177 this.field.on("keydown", this.onPagingKeydown, this);
24178 this.field.on("focus", function(){this.dom.select();});
24181 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24182 //this.field.setHeight(18);
24183 //this.addSeparator();
24184 this.next = this.navgroup.addItem({
24185 tooltip: this.nextText,
24187 html : ' <i class="fa fa-step-forward">',
24189 preventDefault: true,
24190 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24192 this.last = this.navgroup.addItem({
24193 tooltip: this.lastText,
24194 icon : 'fa fa-forward',
24197 preventDefault: true,
24198 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24200 //this.addSeparator();
24201 this.loading = this.navgroup.addItem({
24202 tooltip: this.refreshText,
24203 icon: 'fa fa-refresh',
24204 preventDefault: true,
24205 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24211 updateInfo : function(){
24212 if(this.displayEl){
24213 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24214 var msg = count == 0 ?
24218 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24220 this.displayEl.update(msg);
24225 onLoad : function(ds, r, o)
24227 this.cursor = o.params ? o.params.start : 0;
24228 var d = this.getPageData(),
24233 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24234 this.field.dom.value = ap;
24235 this.first.setDisabled(ap == 1);
24236 this.prev.setDisabled(ap == 1);
24237 this.next.setDisabled(ap == ps);
24238 this.last.setDisabled(ap == ps);
24239 this.loading.enable();
24244 getPageData : function(){
24245 var total = this.ds.getTotalCount();
24248 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24249 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24254 onLoadError : function(){
24255 this.loading.enable();
24259 onPagingKeydown : function(e){
24260 var k = e.getKey();
24261 var d = this.getPageData();
24263 var v = this.field.dom.value, pageNum;
24264 if(!v || isNaN(pageNum = parseInt(v, 10))){
24265 this.field.dom.value = d.activePage;
24268 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24269 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24272 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))
24274 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24275 this.field.dom.value = pageNum;
24276 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24279 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24281 var v = this.field.dom.value, pageNum;
24282 var increment = (e.shiftKey) ? 10 : 1;
24283 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24286 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24287 this.field.dom.value = d.activePage;
24290 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24292 this.field.dom.value = parseInt(v, 10) + increment;
24293 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24294 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24301 beforeLoad : function(){
24303 this.loading.disable();
24308 onClick : function(which){
24317 ds.load({params:{start: 0, limit: this.pageSize}});
24320 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24323 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24326 var total = ds.getTotalCount();
24327 var extra = total % this.pageSize;
24328 var lastStart = extra ? (total - extra) : total-this.pageSize;
24329 ds.load({params:{start: lastStart, limit: this.pageSize}});
24332 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24338 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24339 * @param {Roo.data.Store} store The data store to unbind
24341 unbind : function(ds){
24342 ds.un("beforeload", this.beforeLoad, this);
24343 ds.un("load", this.onLoad, this);
24344 ds.un("loadexception", this.onLoadError, this);
24345 ds.un("remove", this.updateInfo, this);
24346 ds.un("add", this.updateInfo, this);
24347 this.ds = undefined;
24351 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24352 * @param {Roo.data.Store} store The data store to bind
24354 bind : function(ds){
24355 ds.on("beforeload", this.beforeLoad, this);
24356 ds.on("load", this.onLoad, this);
24357 ds.on("loadexception", this.onLoadError, this);
24358 ds.on("remove", this.updateInfo, this);
24359 ds.on("add", this.updateInfo, this);
24370 * @class Roo.bootstrap.MessageBar
24371 * @extends Roo.bootstrap.Component
24372 * Bootstrap MessageBar class
24373 * @cfg {String} html contents of the MessageBar
24374 * @cfg {String} weight (info | success | warning | danger) default info
24375 * @cfg {String} beforeClass insert the bar before the given class
24376 * @cfg {Boolean} closable (true | false) default false
24377 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24380 * Create a new Element
24381 * @param {Object} config The config object
24384 Roo.bootstrap.MessageBar = function(config){
24385 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24388 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24394 beforeClass: 'bootstrap-sticky-wrap',
24396 getAutoCreate : function(){
24400 cls: 'alert alert-dismissable alert-' + this.weight,
24405 html: this.html || ''
24411 cfg.cls += ' alert-messages-fixed';
24425 onRender : function(ct, position)
24427 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24430 var cfg = Roo.apply({}, this.getAutoCreate());
24434 cfg.cls += ' ' + this.cls;
24437 cfg.style = this.style;
24439 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24441 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24444 this.el.select('>button.close').on('click', this.hide, this);
24450 if (!this.rendered) {
24456 this.fireEvent('show', this);
24462 if (!this.rendered) {
24468 this.fireEvent('hide', this);
24471 update : function()
24473 // var e = this.el.dom.firstChild;
24475 // if(this.closable){
24476 // e = e.nextSibling;
24479 // e.data = this.html || '';
24481 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24497 * @class Roo.bootstrap.Graph
24498 * @extends Roo.bootstrap.Component
24499 * Bootstrap Graph class
24503 @cfg {String} graphtype bar | vbar | pie
24504 @cfg {number} g_x coodinator | centre x (pie)
24505 @cfg {number} g_y coodinator | centre y (pie)
24506 @cfg {number} g_r radius (pie)
24507 @cfg {number} g_height height of the chart (respected by all elements in the set)
24508 @cfg {number} g_width width of the chart (respected by all elements in the set)
24509 @cfg {Object} title The title of the chart
24512 -opts (object) options for the chart
24514 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24515 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24517 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.
24518 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24520 o stretch (boolean)
24522 -opts (object) options for the pie
24525 o startAngle (number)
24526 o endAngle (number)
24530 * Create a new Input
24531 * @param {Object} config The config object
24534 Roo.bootstrap.Graph = function(config){
24535 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24541 * The img click event for the img.
24542 * @param {Roo.EventObject} e
24548 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24559 //g_colors: this.colors,
24566 getAutoCreate : function(){
24577 onRender : function(ct,position){
24580 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24582 if (typeof(Raphael) == 'undefined') {
24583 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24587 this.raphael = Raphael(this.el.dom);
24589 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24590 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24591 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24592 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24594 r.text(160, 10, "Single Series Chart").attr(txtattr);
24595 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24596 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24597 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24599 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24600 r.barchart(330, 10, 300, 220, data1);
24601 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24602 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24605 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24606 // r.barchart(30, 30, 560, 250, xdata, {
24607 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24608 // axis : "0 0 1 1",
24609 // axisxlabels : xdata
24610 // //yvalues : cols,
24613 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24615 // this.load(null,xdata,{
24616 // axis : "0 0 1 1",
24617 // axisxlabels : xdata
24622 load : function(graphtype,xdata,opts)
24624 this.raphael.clear();
24626 graphtype = this.graphtype;
24631 var r = this.raphael,
24632 fin = function () {
24633 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24635 fout = function () {
24636 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24638 pfin = function() {
24639 this.sector.stop();
24640 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24643 this.label[0].stop();
24644 this.label[0].attr({ r: 7.5 });
24645 this.label[1].attr({ "font-weight": 800 });
24648 pfout = function() {
24649 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24652 this.label[0].animate({ r: 5 }, 500, "bounce");
24653 this.label[1].attr({ "font-weight": 400 });
24659 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24662 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24665 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24666 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24668 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24675 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24680 setTitle: function(o)
24685 initEvents: function() {
24688 this.el.on('click', this.onClick, this);
24692 onClick : function(e)
24694 Roo.log('img onclick');
24695 this.fireEvent('click', this, e);
24707 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24710 * @class Roo.bootstrap.dash.NumberBox
24711 * @extends Roo.bootstrap.Component
24712 * Bootstrap NumberBox class
24713 * @cfg {String} headline Box headline
24714 * @cfg {String} content Box content
24715 * @cfg {String} icon Box icon
24716 * @cfg {String} footer Footer text
24717 * @cfg {String} fhref Footer href
24720 * Create a new NumberBox
24721 * @param {Object} config The config object
24725 Roo.bootstrap.dash.NumberBox = function(config){
24726 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24730 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24739 getAutoCreate : function(){
24743 cls : 'small-box ',
24751 cls : 'roo-headline',
24752 html : this.headline
24756 cls : 'roo-content',
24757 html : this.content
24771 cls : 'ion ' + this.icon
24780 cls : 'small-box-footer',
24781 href : this.fhref || '#',
24785 cfg.cn.push(footer);
24792 onRender : function(ct,position){
24793 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24800 setHeadline: function (value)
24802 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24805 setFooter: function (value, href)
24807 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24810 this.el.select('a.small-box-footer',true).first().attr('href', href);
24815 setContent: function (value)
24817 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24820 initEvents: function()
24834 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24837 * @class Roo.bootstrap.dash.TabBox
24838 * @extends Roo.bootstrap.Component
24839 * Bootstrap TabBox class
24840 * @cfg {String} title Title of the TabBox
24841 * @cfg {String} icon Icon of the TabBox
24842 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24843 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24846 * Create a new TabBox
24847 * @param {Object} config The config object
24851 Roo.bootstrap.dash.TabBox = function(config){
24852 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24857 * When a pane is added
24858 * @param {Roo.bootstrap.dash.TabPane} pane
24862 * @event activatepane
24863 * When a pane is activated
24864 * @param {Roo.bootstrap.dash.TabPane} pane
24866 "activatepane" : true
24874 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24879 tabScrollable : false,
24881 getChildContainer : function()
24883 return this.el.select('.tab-content', true).first();
24886 getAutoCreate : function(){
24890 cls: 'pull-left header',
24898 cls: 'fa ' + this.icon
24904 cls: 'nav nav-tabs pull-right',
24910 if(this.tabScrollable){
24917 cls: 'nav nav-tabs pull-right',
24928 cls: 'nav-tabs-custom',
24933 cls: 'tab-content no-padding',
24941 initEvents : function()
24943 //Roo.log('add add pane handler');
24944 this.on('addpane', this.onAddPane, this);
24947 * Updates the box title
24948 * @param {String} html to set the title to.
24950 setTitle : function(value)
24952 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24954 onAddPane : function(pane)
24956 this.panes.push(pane);
24957 //Roo.log('addpane');
24959 // tabs are rendere left to right..
24960 if(!this.showtabs){
24964 var ctr = this.el.select('.nav-tabs', true).first();
24967 var existing = ctr.select('.nav-tab',true);
24968 var qty = existing.getCount();;
24971 var tab = ctr.createChild({
24973 cls : 'nav-tab' + (qty ? '' : ' active'),
24981 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24984 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24986 pane.el.addClass('active');
24991 onTabClick : function(ev,un,ob,pane)
24993 //Roo.log('tab - prev default');
24994 ev.preventDefault();
24997 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24998 pane.tab.addClass('active');
24999 //Roo.log(pane.title);
25000 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25001 // technically we should have a deactivate event.. but maybe add later.
25002 // and it should not de-activate the selected tab...
25003 this.fireEvent('activatepane', pane);
25004 pane.el.addClass('active');
25005 pane.fireEvent('activate');
25010 getActivePane : function()
25013 Roo.each(this.panes, function(p) {
25014 if(p.el.hasClass('active')){
25035 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25037 * @class Roo.bootstrap.TabPane
25038 * @extends Roo.bootstrap.Component
25039 * Bootstrap TabPane class
25040 * @cfg {Boolean} active (false | true) Default false
25041 * @cfg {String} title title of panel
25045 * Create a new TabPane
25046 * @param {Object} config The config object
25049 Roo.bootstrap.dash.TabPane = function(config){
25050 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25056 * When a pane is activated
25057 * @param {Roo.bootstrap.dash.TabPane} pane
25064 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25069 // the tabBox that this is attached to.
25072 getAutoCreate : function()
25080 cfg.cls += ' active';
25085 initEvents : function()
25087 //Roo.log('trigger add pane handler');
25088 this.parent().fireEvent('addpane', this)
25092 * Updates the tab title
25093 * @param {String} html to set the title to.
25095 setTitle: function(str)
25101 this.tab.select('a', true).first().dom.innerHTML = str;
25118 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25121 * @class Roo.bootstrap.menu.Menu
25122 * @extends Roo.bootstrap.Component
25123 * Bootstrap Menu class - container for Menu
25124 * @cfg {String} html Text of the menu
25125 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25126 * @cfg {String} icon Font awesome icon
25127 * @cfg {String} pos Menu align to (top | bottom) default bottom
25131 * Create a new Menu
25132 * @param {Object} config The config object
25136 Roo.bootstrap.menu.Menu = function(config){
25137 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25141 * @event beforeshow
25142 * Fires before this menu is displayed
25143 * @param {Roo.bootstrap.menu.Menu} this
25147 * @event beforehide
25148 * Fires before this menu is hidden
25149 * @param {Roo.bootstrap.menu.Menu} this
25154 * Fires after this menu is displayed
25155 * @param {Roo.bootstrap.menu.Menu} this
25160 * Fires after this menu is hidden
25161 * @param {Roo.bootstrap.menu.Menu} this
25166 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25167 * @param {Roo.bootstrap.menu.Menu} this
25168 * @param {Roo.EventObject} e
25175 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25179 weight : 'default',
25184 getChildContainer : function() {
25185 if(this.isSubMenu){
25189 return this.el.select('ul.dropdown-menu', true).first();
25192 getAutoCreate : function()
25197 cls : 'roo-menu-text',
25205 cls : 'fa ' + this.icon
25216 cls : 'dropdown-button btn btn-' + this.weight,
25221 cls : 'dropdown-toggle btn btn-' + this.weight,
25231 cls : 'dropdown-menu'
25237 if(this.pos == 'top'){
25238 cfg.cls += ' dropup';
25241 if(this.isSubMenu){
25244 cls : 'dropdown-menu'
25251 onRender : function(ct, position)
25253 this.isSubMenu = ct.hasClass('dropdown-submenu');
25255 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25258 initEvents : function()
25260 if(this.isSubMenu){
25264 this.hidden = true;
25266 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25267 this.triggerEl.on('click', this.onTriggerPress, this);
25269 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25270 this.buttonEl.on('click', this.onClick, this);
25276 if(this.isSubMenu){
25280 return this.el.select('ul.dropdown-menu', true).first();
25283 onClick : function(e)
25285 this.fireEvent("click", this, e);
25288 onTriggerPress : function(e)
25290 if (this.isVisible()) {
25297 isVisible : function(){
25298 return !this.hidden;
25303 this.fireEvent("beforeshow", this);
25305 this.hidden = false;
25306 this.el.addClass('open');
25308 Roo.get(document).on("mouseup", this.onMouseUp, this);
25310 this.fireEvent("show", this);
25317 this.fireEvent("beforehide", this);
25319 this.hidden = true;
25320 this.el.removeClass('open');
25322 Roo.get(document).un("mouseup", this.onMouseUp);
25324 this.fireEvent("hide", this);
25327 onMouseUp : function()
25341 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25344 * @class Roo.bootstrap.menu.Item
25345 * @extends Roo.bootstrap.Component
25346 * Bootstrap MenuItem class
25347 * @cfg {Boolean} submenu (true | false) default false
25348 * @cfg {String} html text of the item
25349 * @cfg {String} href the link
25350 * @cfg {Boolean} disable (true | false) default false
25351 * @cfg {Boolean} preventDefault (true | false) default true
25352 * @cfg {String} icon Font awesome icon
25353 * @cfg {String} pos Submenu align to (left | right) default right
25357 * Create a new Item
25358 * @param {Object} config The config object
25362 Roo.bootstrap.menu.Item = function(config){
25363 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25367 * Fires when the mouse is hovering over this menu
25368 * @param {Roo.bootstrap.menu.Item} this
25369 * @param {Roo.EventObject} e
25374 * Fires when the mouse exits this menu
25375 * @param {Roo.bootstrap.menu.Item} this
25376 * @param {Roo.EventObject} e
25382 * The raw click event for the entire grid.
25383 * @param {Roo.EventObject} e
25389 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25394 preventDefault: true,
25399 getAutoCreate : function()
25404 cls : 'roo-menu-item-text',
25412 cls : 'fa ' + this.icon
25421 href : this.href || '#',
25428 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25432 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25434 if(this.pos == 'left'){
25435 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25442 initEvents : function()
25444 this.el.on('mouseover', this.onMouseOver, this);
25445 this.el.on('mouseout', this.onMouseOut, this);
25447 this.el.select('a', true).first().on('click', this.onClick, this);
25451 onClick : function(e)
25453 if(this.preventDefault){
25454 e.preventDefault();
25457 this.fireEvent("click", this, e);
25460 onMouseOver : function(e)
25462 if(this.submenu && this.pos == 'left'){
25463 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25466 this.fireEvent("mouseover", this, e);
25469 onMouseOut : function(e)
25471 this.fireEvent("mouseout", this, e);
25483 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25486 * @class Roo.bootstrap.menu.Separator
25487 * @extends Roo.bootstrap.Component
25488 * Bootstrap Separator class
25491 * Create a new Separator
25492 * @param {Object} config The config object
25496 Roo.bootstrap.menu.Separator = function(config){
25497 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25500 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25502 getAutoCreate : function(){
25523 * @class Roo.bootstrap.Tooltip
25524 * Bootstrap Tooltip class
25525 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25526 * to determine which dom element triggers the tooltip.
25528 * It needs to add support for additional attributes like tooltip-position
25531 * Create a new Toolti
25532 * @param {Object} config The config object
25535 Roo.bootstrap.Tooltip = function(config){
25536 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25538 this.alignment = Roo.bootstrap.Tooltip.alignment;
25540 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25541 this.alignment = config.alignment;
25546 Roo.apply(Roo.bootstrap.Tooltip, {
25548 * @function init initialize tooltip monitoring.
25552 currentTip : false,
25553 currentRegion : false,
25559 Roo.get(document).on('mouseover', this.enter ,this);
25560 Roo.get(document).on('mouseout', this.leave, this);
25563 this.currentTip = new Roo.bootstrap.Tooltip();
25566 enter : function(ev)
25568 var dom = ev.getTarget();
25570 //Roo.log(['enter',dom]);
25571 var el = Roo.fly(dom);
25572 if (this.currentEl) {
25574 //Roo.log(this.currentEl);
25575 //Roo.log(this.currentEl.contains(dom));
25576 if (this.currentEl == el) {
25579 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25585 if (this.currentTip.el) {
25586 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25590 if(!el || el.dom == document){
25596 // you can not look for children, as if el is the body.. then everythign is the child..
25597 if (!el.attr('tooltip')) { //
25598 if (!el.select("[tooltip]").elements.length) {
25601 // is the mouse over this child...?
25602 bindEl = el.select("[tooltip]").first();
25603 var xy = ev.getXY();
25604 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25605 //Roo.log("not in region.");
25608 //Roo.log("child element over..");
25611 this.currentEl = bindEl;
25612 this.currentTip.bind(bindEl);
25613 this.currentRegion = Roo.lib.Region.getRegion(dom);
25614 this.currentTip.enter();
25617 leave : function(ev)
25619 var dom = ev.getTarget();
25620 //Roo.log(['leave',dom]);
25621 if (!this.currentEl) {
25626 if (dom != this.currentEl.dom) {
25629 var xy = ev.getXY();
25630 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25633 // only activate leave if mouse cursor is outside... bounding box..
25638 if (this.currentTip) {
25639 this.currentTip.leave();
25641 //Roo.log('clear currentEl');
25642 this.currentEl = false;
25647 'left' : ['r-l', [-2,0], 'right'],
25648 'right' : ['l-r', [2,0], 'left'],
25649 'bottom' : ['t-b', [0,2], 'top'],
25650 'top' : [ 'b-t', [0,-2], 'bottom']
25656 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25661 delay : null, // can be { show : 300 , hide: 500}
25665 hoverState : null, //???
25667 placement : 'bottom',
25671 getAutoCreate : function(){
25678 cls : 'tooltip-arrow'
25681 cls : 'tooltip-inner'
25688 bind : function(el)
25694 enter : function () {
25696 if (this.timeout != null) {
25697 clearTimeout(this.timeout);
25700 this.hoverState = 'in';
25701 //Roo.log("enter - show");
25702 if (!this.delay || !this.delay.show) {
25707 this.timeout = setTimeout(function () {
25708 if (_t.hoverState == 'in') {
25711 }, this.delay.show);
25715 clearTimeout(this.timeout);
25717 this.hoverState = 'out';
25718 if (!this.delay || !this.delay.hide) {
25724 this.timeout = setTimeout(function () {
25725 //Roo.log("leave - timeout");
25727 if (_t.hoverState == 'out') {
25729 Roo.bootstrap.Tooltip.currentEl = false;
25734 show : function (msg)
25737 this.render(document.body);
25740 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25742 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25744 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25746 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25748 var placement = typeof this.placement == 'function' ?
25749 this.placement.call(this, this.el, on_el) :
25752 var autoToken = /\s?auto?\s?/i;
25753 var autoPlace = autoToken.test(placement);
25755 placement = placement.replace(autoToken, '') || 'top';
25759 //this.el.setXY([0,0]);
25761 //this.el.dom.style.display='block';
25763 //this.el.appendTo(on_el);
25765 var p = this.getPosition();
25766 var box = this.el.getBox();
25772 var align = this.alignment[placement];
25774 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25776 if(placement == 'top' || placement == 'bottom'){
25778 placement = 'right';
25781 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25782 placement = 'left';
25785 var scroll = Roo.select('body', true).first().getScroll();
25787 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25793 this.el.alignTo(this.bindEl, align[0],align[1]);
25794 //var arrow = this.el.select('.arrow',true).first();
25795 //arrow.set(align[2],
25797 this.el.addClass(placement);
25799 this.el.addClass('in fade');
25801 this.hoverState = null;
25803 if (this.el.hasClass('fade')) {
25814 //this.el.setXY([0,0]);
25815 this.el.removeClass('in');
25831 * @class Roo.bootstrap.LocationPicker
25832 * @extends Roo.bootstrap.Component
25833 * Bootstrap LocationPicker class
25834 * @cfg {Number} latitude Position when init default 0
25835 * @cfg {Number} longitude Position when init default 0
25836 * @cfg {Number} zoom default 15
25837 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25838 * @cfg {Boolean} mapTypeControl default false
25839 * @cfg {Boolean} disableDoubleClickZoom default false
25840 * @cfg {Boolean} scrollwheel default true
25841 * @cfg {Boolean} streetViewControl default false
25842 * @cfg {Number} radius default 0
25843 * @cfg {String} locationName
25844 * @cfg {Boolean} draggable default true
25845 * @cfg {Boolean} enableAutocomplete default false
25846 * @cfg {Boolean} enableReverseGeocode default true
25847 * @cfg {String} markerTitle
25850 * Create a new LocationPicker
25851 * @param {Object} config The config object
25855 Roo.bootstrap.LocationPicker = function(config){
25857 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25862 * Fires when the picker initialized.
25863 * @param {Roo.bootstrap.LocationPicker} this
25864 * @param {Google Location} location
25868 * @event positionchanged
25869 * Fires when the picker position changed.
25870 * @param {Roo.bootstrap.LocationPicker} this
25871 * @param {Google Location} location
25873 positionchanged : true,
25876 * Fires when the map resize.
25877 * @param {Roo.bootstrap.LocationPicker} this
25882 * Fires when the map show.
25883 * @param {Roo.bootstrap.LocationPicker} this
25888 * Fires when the map hide.
25889 * @param {Roo.bootstrap.LocationPicker} this
25894 * Fires when click the map.
25895 * @param {Roo.bootstrap.LocationPicker} this
25896 * @param {Map event} e
25900 * @event mapRightClick
25901 * Fires when right click the map.
25902 * @param {Roo.bootstrap.LocationPicker} this
25903 * @param {Map event} e
25905 mapRightClick : true,
25907 * @event markerClick
25908 * Fires when click the marker.
25909 * @param {Roo.bootstrap.LocationPicker} this
25910 * @param {Map event} e
25912 markerClick : true,
25914 * @event markerRightClick
25915 * Fires when right click the marker.
25916 * @param {Roo.bootstrap.LocationPicker} this
25917 * @param {Map event} e
25919 markerRightClick : true,
25921 * @event OverlayViewDraw
25922 * Fires when OverlayView Draw
25923 * @param {Roo.bootstrap.LocationPicker} this
25925 OverlayViewDraw : true,
25927 * @event OverlayViewOnAdd
25928 * Fires when OverlayView Draw
25929 * @param {Roo.bootstrap.LocationPicker} this
25931 OverlayViewOnAdd : true,
25933 * @event OverlayViewOnRemove
25934 * Fires when OverlayView Draw
25935 * @param {Roo.bootstrap.LocationPicker} this
25937 OverlayViewOnRemove : true,
25939 * @event OverlayViewShow
25940 * Fires when OverlayView Draw
25941 * @param {Roo.bootstrap.LocationPicker} this
25942 * @param {Pixel} cpx
25944 OverlayViewShow : true,
25946 * @event OverlayViewHide
25947 * Fires when OverlayView Draw
25948 * @param {Roo.bootstrap.LocationPicker} this
25950 OverlayViewHide : true,
25952 * @event loadexception
25953 * Fires when load google lib failed.
25954 * @param {Roo.bootstrap.LocationPicker} this
25956 loadexception : true
25961 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25963 gMapContext: false,
25969 mapTypeControl: false,
25970 disableDoubleClickZoom: false,
25972 streetViewControl: false,
25976 enableAutocomplete: false,
25977 enableReverseGeocode: true,
25980 getAutoCreate: function()
25985 cls: 'roo-location-picker'
25991 initEvents: function(ct, position)
25993 if(!this.el.getWidth() || this.isApplied()){
25997 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26002 initial: function()
26004 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26005 this.fireEvent('loadexception', this);
26009 if(!this.mapTypeId){
26010 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26013 this.gMapContext = this.GMapContext();
26015 this.initOverlayView();
26017 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26021 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26022 _this.setPosition(_this.gMapContext.marker.position);
26025 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26026 _this.fireEvent('mapClick', this, event);
26030 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26031 _this.fireEvent('mapRightClick', this, event);
26035 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26036 _this.fireEvent('markerClick', this, event);
26040 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26041 _this.fireEvent('markerRightClick', this, event);
26045 this.setPosition(this.gMapContext.location);
26047 this.fireEvent('initial', this, this.gMapContext.location);
26050 initOverlayView: function()
26054 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26058 _this.fireEvent('OverlayViewDraw', _this);
26063 _this.fireEvent('OverlayViewOnAdd', _this);
26066 onRemove: function()
26068 _this.fireEvent('OverlayViewOnRemove', _this);
26071 show: function(cpx)
26073 _this.fireEvent('OverlayViewShow', _this, cpx);
26078 _this.fireEvent('OverlayViewHide', _this);
26084 fromLatLngToContainerPixel: function(event)
26086 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26089 isApplied: function()
26091 return this.getGmapContext() == false ? false : true;
26094 getGmapContext: function()
26096 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26099 GMapContext: function()
26101 var position = new google.maps.LatLng(this.latitude, this.longitude);
26103 var _map = new google.maps.Map(this.el.dom, {
26106 mapTypeId: this.mapTypeId,
26107 mapTypeControl: this.mapTypeControl,
26108 disableDoubleClickZoom: this.disableDoubleClickZoom,
26109 scrollwheel: this.scrollwheel,
26110 streetViewControl: this.streetViewControl,
26111 locationName: this.locationName,
26112 draggable: this.draggable,
26113 enableAutocomplete: this.enableAutocomplete,
26114 enableReverseGeocode: this.enableReverseGeocode
26117 var _marker = new google.maps.Marker({
26118 position: position,
26120 title: this.markerTitle,
26121 draggable: this.draggable
26128 location: position,
26129 radius: this.radius,
26130 locationName: this.locationName,
26131 addressComponents: {
26132 formatted_address: null,
26133 addressLine1: null,
26134 addressLine2: null,
26136 streetNumber: null,
26140 stateOrProvince: null
26143 domContainer: this.el.dom,
26144 geodecoder: new google.maps.Geocoder()
26148 drawCircle: function(center, radius, options)
26150 if (this.gMapContext.circle != null) {
26151 this.gMapContext.circle.setMap(null);
26155 options = Roo.apply({}, options, {
26156 strokeColor: "#0000FF",
26157 strokeOpacity: .35,
26159 fillColor: "#0000FF",
26163 options.map = this.gMapContext.map;
26164 options.radius = radius;
26165 options.center = center;
26166 this.gMapContext.circle = new google.maps.Circle(options);
26167 return this.gMapContext.circle;
26173 setPosition: function(location)
26175 this.gMapContext.location = location;
26176 this.gMapContext.marker.setPosition(location);
26177 this.gMapContext.map.panTo(location);
26178 this.drawCircle(location, this.gMapContext.radius, {});
26182 if (this.gMapContext.settings.enableReverseGeocode) {
26183 this.gMapContext.geodecoder.geocode({
26184 latLng: this.gMapContext.location
26185 }, function(results, status) {
26187 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26188 _this.gMapContext.locationName = results[0].formatted_address;
26189 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26191 _this.fireEvent('positionchanged', this, location);
26198 this.fireEvent('positionchanged', this, location);
26203 google.maps.event.trigger(this.gMapContext.map, "resize");
26205 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26207 this.fireEvent('resize', this);
26210 setPositionByLatLng: function(latitude, longitude)
26212 this.setPosition(new google.maps.LatLng(latitude, longitude));
26215 getCurrentPosition: function()
26218 latitude: this.gMapContext.location.lat(),
26219 longitude: this.gMapContext.location.lng()
26223 getAddressName: function()
26225 return this.gMapContext.locationName;
26228 getAddressComponents: function()
26230 return this.gMapContext.addressComponents;
26233 address_component_from_google_geocode: function(address_components)
26237 for (var i = 0; i < address_components.length; i++) {
26238 var component = address_components[i];
26239 if (component.types.indexOf("postal_code") >= 0) {
26240 result.postalCode = component.short_name;
26241 } else if (component.types.indexOf("street_number") >= 0) {
26242 result.streetNumber = component.short_name;
26243 } else if (component.types.indexOf("route") >= 0) {
26244 result.streetName = component.short_name;
26245 } else if (component.types.indexOf("neighborhood") >= 0) {
26246 result.city = component.short_name;
26247 } else if (component.types.indexOf("locality") >= 0) {
26248 result.city = component.short_name;
26249 } else if (component.types.indexOf("sublocality") >= 0) {
26250 result.district = component.short_name;
26251 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26252 result.stateOrProvince = component.short_name;
26253 } else if (component.types.indexOf("country") >= 0) {
26254 result.country = component.short_name;
26258 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26259 result.addressLine2 = "";
26263 setZoomLevel: function(zoom)
26265 this.gMapContext.map.setZoom(zoom);
26278 this.fireEvent('show', this);
26289 this.fireEvent('hide', this);
26294 Roo.apply(Roo.bootstrap.LocationPicker, {
26296 OverlayView : function(map, options)
26298 options = options || {};
26312 * @class Roo.bootstrap.Alert
26313 * @extends Roo.bootstrap.Component
26314 * Bootstrap Alert class
26315 * @cfg {String} title The title of alert
26316 * @cfg {String} html The content of alert
26317 * @cfg {String} weight ( success | info | warning | danger )
26318 * @cfg {String} faicon font-awesomeicon
26321 * Create a new alert
26322 * @param {Object} config The config object
26326 Roo.bootstrap.Alert = function(config){
26327 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26331 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26338 getAutoCreate : function()
26347 cls : 'roo-alert-icon'
26352 cls : 'roo-alert-title',
26357 cls : 'roo-alert-text',
26364 cfg.cn[0].cls += ' fa ' + this.faicon;
26368 cfg.cls += ' alert-' + this.weight;
26374 initEvents: function()
26376 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26379 setTitle : function(str)
26381 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26384 setText : function(str)
26386 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26389 setWeight : function(weight)
26392 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26395 this.weight = weight;
26397 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26400 setIcon : function(icon)
26403 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26406 this.faicon = icon;
26408 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26429 * @class Roo.bootstrap.UploadCropbox
26430 * @extends Roo.bootstrap.Component
26431 * Bootstrap UploadCropbox class
26432 * @cfg {String} emptyText show when image has been loaded
26433 * @cfg {String} rotateNotify show when image too small to rotate
26434 * @cfg {Number} errorTimeout default 3000
26435 * @cfg {Number} minWidth default 300
26436 * @cfg {Number} minHeight default 300
26437 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26438 * @cfg {Boolean} isDocument (true|false) default false
26439 * @cfg {String} url action url
26440 * @cfg {String} paramName default 'imageUpload'
26441 * @cfg {String} method default POST
26442 * @cfg {Boolean} loadMask (true|false) default true
26443 * @cfg {Boolean} loadingText default 'Loading...'
26446 * Create a new UploadCropbox
26447 * @param {Object} config The config object
26450 Roo.bootstrap.UploadCropbox = function(config){
26451 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26455 * @event beforeselectfile
26456 * Fire before select file
26457 * @param {Roo.bootstrap.UploadCropbox} this
26459 "beforeselectfile" : true,
26462 * Fire after initEvent
26463 * @param {Roo.bootstrap.UploadCropbox} this
26468 * Fire after initEvent
26469 * @param {Roo.bootstrap.UploadCropbox} this
26470 * @param {String} data
26475 * Fire when preparing the file data
26476 * @param {Roo.bootstrap.UploadCropbox} this
26477 * @param {Object} file
26482 * Fire when get exception
26483 * @param {Roo.bootstrap.UploadCropbox} this
26484 * @param {XMLHttpRequest} xhr
26486 "exception" : true,
26488 * @event beforeloadcanvas
26489 * Fire before load the canvas
26490 * @param {Roo.bootstrap.UploadCropbox} this
26491 * @param {String} src
26493 "beforeloadcanvas" : true,
26496 * Fire when trash image
26497 * @param {Roo.bootstrap.UploadCropbox} this
26502 * Fire when download the image
26503 * @param {Roo.bootstrap.UploadCropbox} this
26507 * @event footerbuttonclick
26508 * Fire when footerbuttonclick
26509 * @param {Roo.bootstrap.UploadCropbox} this
26510 * @param {String} type
26512 "footerbuttonclick" : true,
26516 * @param {Roo.bootstrap.UploadCropbox} this
26521 * Fire when rotate the image
26522 * @param {Roo.bootstrap.UploadCropbox} this
26523 * @param {String} pos
26528 * Fire when inspect the file
26529 * @param {Roo.bootstrap.UploadCropbox} this
26530 * @param {Object} file
26535 * Fire when xhr upload the file
26536 * @param {Roo.bootstrap.UploadCropbox} this
26537 * @param {Object} data
26542 * Fire when arrange the file data
26543 * @param {Roo.bootstrap.UploadCropbox} this
26544 * @param {Object} formData
26549 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26552 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26554 emptyText : 'Click to upload image',
26555 rotateNotify : 'Image is too small to rotate',
26556 errorTimeout : 3000,
26570 cropType : 'image/jpeg',
26572 canvasLoaded : false,
26573 isDocument : false,
26575 paramName : 'imageUpload',
26577 loadingText : 'Loading...',
26580 getAutoCreate : function()
26584 cls : 'roo-upload-cropbox',
26588 cls : 'roo-upload-cropbox-selector',
26593 cls : 'roo-upload-cropbox-body',
26594 style : 'cursor:pointer',
26598 cls : 'roo-upload-cropbox-preview'
26602 cls : 'roo-upload-cropbox-thumb'
26606 cls : 'roo-upload-cropbox-empty-notify',
26607 html : this.emptyText
26611 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26612 html : this.rotateNotify
26618 cls : 'roo-upload-cropbox-footer',
26621 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26631 onRender : function(ct, position)
26633 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26635 if (this.buttons.length) {
26637 Roo.each(this.buttons, function(bb) {
26639 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26641 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26647 this.maskEl = this.el;
26651 initEvents : function()
26653 this.urlAPI = (window.createObjectURL && window) ||
26654 (window.URL && URL.revokeObjectURL && URL) ||
26655 (window.webkitURL && webkitURL);
26657 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26658 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26660 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26661 this.selectorEl.hide();
26663 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26664 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26666 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26667 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26668 this.thumbEl.hide();
26670 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26671 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26673 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26674 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26675 this.errorEl.hide();
26677 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26678 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26679 this.footerEl.hide();
26681 this.setThumbBoxSize();
26687 this.fireEvent('initial', this);
26694 window.addEventListener("resize", function() { _this.resize(); } );
26696 this.bodyEl.on('click', this.beforeSelectFile, this);
26699 this.bodyEl.on('touchstart', this.onTouchStart, this);
26700 this.bodyEl.on('touchmove', this.onTouchMove, this);
26701 this.bodyEl.on('touchend', this.onTouchEnd, this);
26705 this.bodyEl.on('mousedown', this.onMouseDown, this);
26706 this.bodyEl.on('mousemove', this.onMouseMove, this);
26707 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26708 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26709 Roo.get(document).on('mouseup', this.onMouseUp, this);
26712 this.selectorEl.on('change', this.onFileSelected, this);
26718 this.baseScale = 1;
26720 this.baseRotate = 1;
26721 this.dragable = false;
26722 this.pinching = false;
26725 this.cropData = false;
26726 this.notifyEl.dom.innerHTML = this.emptyText;
26728 this.selectorEl.dom.value = '';
26732 resize : function()
26734 if(this.fireEvent('resize', this) != false){
26735 this.setThumbBoxPosition();
26736 this.setCanvasPosition();
26740 onFooterButtonClick : function(e, el, o, type)
26743 case 'rotate-left' :
26744 this.onRotateLeft(e);
26746 case 'rotate-right' :
26747 this.onRotateRight(e);
26750 this.beforeSelectFile(e);
26765 this.fireEvent('footerbuttonclick', this, type);
26768 beforeSelectFile : function(e)
26770 e.preventDefault();
26772 if(this.fireEvent('beforeselectfile', this) != false){
26773 this.selectorEl.dom.click();
26777 onFileSelected : function(e)
26779 e.preventDefault();
26781 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26785 var file = this.selectorEl.dom.files[0];
26787 if(this.fireEvent('inspect', this, file) != false){
26788 this.prepare(file);
26793 trash : function(e)
26795 this.fireEvent('trash', this);
26798 download : function(e)
26800 this.fireEvent('download', this);
26803 loadCanvas : function(src)
26805 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26809 this.imageEl = document.createElement('img');
26813 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26815 this.imageEl.src = src;
26819 onLoadCanvas : function()
26821 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26822 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26824 this.bodyEl.un('click', this.beforeSelectFile, this);
26826 this.notifyEl.hide();
26827 this.thumbEl.show();
26828 this.footerEl.show();
26830 this.baseRotateLevel();
26832 if(this.isDocument){
26833 this.setThumbBoxSize();
26836 this.setThumbBoxPosition();
26838 this.baseScaleLevel();
26844 this.canvasLoaded = true;
26847 this.maskEl.unmask();
26852 setCanvasPosition : function()
26854 if(!this.canvasEl){
26858 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26859 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26861 this.previewEl.setLeft(pw);
26862 this.previewEl.setTop(ph);
26866 onMouseDown : function(e)
26870 this.dragable = true;
26871 this.pinching = false;
26873 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26874 this.dragable = false;
26878 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26879 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26883 onMouseMove : function(e)
26887 if(!this.canvasLoaded){
26891 if (!this.dragable){
26895 var minX = Math.ceil(this.thumbEl.getLeft(true));
26896 var minY = Math.ceil(this.thumbEl.getTop(true));
26898 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26899 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26901 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26902 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26904 x = x - this.mouseX;
26905 y = y - this.mouseY;
26907 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26908 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26910 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26911 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26913 this.previewEl.setLeft(bgX);
26914 this.previewEl.setTop(bgY);
26916 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26917 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26920 onMouseUp : function(e)
26924 this.dragable = false;
26927 onMouseWheel : function(e)
26931 this.startScale = this.scale;
26933 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26935 if(!this.zoomable()){
26936 this.scale = this.startScale;
26945 zoomable : function()
26947 var minScale = this.thumbEl.getWidth() / this.minWidth;
26949 if(this.minWidth < this.minHeight){
26950 minScale = this.thumbEl.getHeight() / this.minHeight;
26953 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26954 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26958 (this.rotate == 0 || this.rotate == 180) &&
26960 width > this.imageEl.OriginWidth ||
26961 height > this.imageEl.OriginHeight ||
26962 (width < this.minWidth && height < this.minHeight)
26970 (this.rotate == 90 || this.rotate == 270) &&
26972 width > this.imageEl.OriginWidth ||
26973 height > this.imageEl.OriginHeight ||
26974 (width < this.minHeight && height < this.minWidth)
26981 !this.isDocument &&
26982 (this.rotate == 0 || this.rotate == 180) &&
26984 width < this.minWidth ||
26985 width > this.imageEl.OriginWidth ||
26986 height < this.minHeight ||
26987 height > this.imageEl.OriginHeight
26994 !this.isDocument &&
26995 (this.rotate == 90 || this.rotate == 270) &&
26997 width < this.minHeight ||
26998 width > this.imageEl.OriginWidth ||
26999 height < this.minWidth ||
27000 height > this.imageEl.OriginHeight
27010 onRotateLeft : function(e)
27012 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27014 var minScale = this.thumbEl.getWidth() / this.minWidth;
27016 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27017 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27019 this.startScale = this.scale;
27021 while (this.getScaleLevel() < minScale){
27023 this.scale = this.scale + 1;
27025 if(!this.zoomable()){
27030 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27031 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27036 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27043 this.scale = this.startScale;
27045 this.onRotateFail();
27050 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27052 if(this.isDocument){
27053 this.setThumbBoxSize();
27054 this.setThumbBoxPosition();
27055 this.setCanvasPosition();
27060 this.fireEvent('rotate', this, 'left');
27064 onRotateRight : function(e)
27066 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27068 var minScale = this.thumbEl.getWidth() / this.minWidth;
27070 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27071 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27073 this.startScale = this.scale;
27075 while (this.getScaleLevel() < minScale){
27077 this.scale = this.scale + 1;
27079 if(!this.zoomable()){
27084 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27085 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27090 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27097 this.scale = this.startScale;
27099 this.onRotateFail();
27104 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27106 if(this.isDocument){
27107 this.setThumbBoxSize();
27108 this.setThumbBoxPosition();
27109 this.setCanvasPosition();
27114 this.fireEvent('rotate', this, 'right');
27117 onRotateFail : function()
27119 this.errorEl.show(true);
27123 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27128 this.previewEl.dom.innerHTML = '';
27130 var canvasEl = document.createElement("canvas");
27132 var contextEl = canvasEl.getContext("2d");
27134 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27135 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27136 var center = this.imageEl.OriginWidth / 2;
27138 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27139 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27140 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27141 center = this.imageEl.OriginHeight / 2;
27144 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27146 contextEl.translate(center, center);
27147 contextEl.rotate(this.rotate * Math.PI / 180);
27149 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27151 this.canvasEl = document.createElement("canvas");
27153 this.contextEl = this.canvasEl.getContext("2d");
27155 switch (this.rotate) {
27158 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27159 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27161 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27166 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27167 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27169 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27170 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27174 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27179 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27180 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27182 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27183 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);
27187 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);
27192 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27193 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27195 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27196 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27200 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);
27207 this.previewEl.appendChild(this.canvasEl);
27209 this.setCanvasPosition();
27214 if(!this.canvasLoaded){
27218 var imageCanvas = document.createElement("canvas");
27220 var imageContext = imageCanvas.getContext("2d");
27222 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27223 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27225 var center = imageCanvas.width / 2;
27227 imageContext.translate(center, center);
27229 imageContext.rotate(this.rotate * Math.PI / 180);
27231 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27233 var canvas = document.createElement("canvas");
27235 var context = canvas.getContext("2d");
27237 canvas.width = this.minWidth;
27238 canvas.height = this.minHeight;
27240 switch (this.rotate) {
27243 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27244 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27246 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27247 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27249 var targetWidth = this.minWidth - 2 * x;
27250 var targetHeight = this.minHeight - 2 * y;
27254 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27255 scale = targetWidth / width;
27258 if(x > 0 && y == 0){
27259 scale = targetHeight / height;
27262 if(x > 0 && y > 0){
27263 scale = targetWidth / width;
27265 if(width < height){
27266 scale = targetHeight / height;
27270 context.scale(scale, scale);
27272 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27273 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27275 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27276 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27278 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27283 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27284 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27286 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27287 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27289 var targetWidth = this.minWidth - 2 * x;
27290 var targetHeight = this.minHeight - 2 * y;
27294 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27295 scale = targetWidth / width;
27298 if(x > 0 && y == 0){
27299 scale = targetHeight / height;
27302 if(x > 0 && y > 0){
27303 scale = targetWidth / width;
27305 if(width < height){
27306 scale = targetHeight / height;
27310 context.scale(scale, scale);
27312 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27313 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27315 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27316 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27318 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27320 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27325 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27326 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27328 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27329 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27331 var targetWidth = this.minWidth - 2 * x;
27332 var targetHeight = this.minHeight - 2 * y;
27336 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27337 scale = targetWidth / width;
27340 if(x > 0 && y == 0){
27341 scale = targetHeight / height;
27344 if(x > 0 && y > 0){
27345 scale = targetWidth / width;
27347 if(width < height){
27348 scale = targetHeight / height;
27352 context.scale(scale, scale);
27354 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27355 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27357 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27358 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27360 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27361 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27363 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27368 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27369 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27371 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27372 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27374 var targetWidth = this.minWidth - 2 * x;
27375 var targetHeight = this.minHeight - 2 * y;
27379 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27380 scale = targetWidth / width;
27383 if(x > 0 && y == 0){
27384 scale = targetHeight / height;
27387 if(x > 0 && y > 0){
27388 scale = targetWidth / width;
27390 if(width < height){
27391 scale = targetHeight / height;
27395 context.scale(scale, scale);
27397 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27398 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27400 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27401 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27403 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27405 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27412 this.cropData = canvas.toDataURL(this.cropType);
27414 if(this.fireEvent('crop', this, this.cropData) !== false){
27415 this.process(this.file, this.cropData);
27422 setThumbBoxSize : function()
27426 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27427 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27428 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27430 this.minWidth = width;
27431 this.minHeight = height;
27433 if(this.rotate == 90 || this.rotate == 270){
27434 this.minWidth = height;
27435 this.minHeight = width;
27440 width = Math.ceil(this.minWidth * height / this.minHeight);
27442 if(this.minWidth > this.minHeight){
27444 height = Math.ceil(this.minHeight * width / this.minWidth);
27447 this.thumbEl.setStyle({
27448 width : width + 'px',
27449 height : height + 'px'
27456 setThumbBoxPosition : function()
27458 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27459 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27461 this.thumbEl.setLeft(x);
27462 this.thumbEl.setTop(y);
27466 baseRotateLevel : function()
27468 this.baseRotate = 1;
27471 typeof(this.exif) != 'undefined' &&
27472 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27473 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27475 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27478 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27482 baseScaleLevel : function()
27486 if(this.isDocument){
27488 if(this.baseRotate == 6 || this.baseRotate == 8){
27490 height = this.thumbEl.getHeight();
27491 this.baseScale = height / this.imageEl.OriginWidth;
27493 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27494 width = this.thumbEl.getWidth();
27495 this.baseScale = width / this.imageEl.OriginHeight;
27501 height = this.thumbEl.getHeight();
27502 this.baseScale = height / this.imageEl.OriginHeight;
27504 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27505 width = this.thumbEl.getWidth();
27506 this.baseScale = width / this.imageEl.OriginWidth;
27512 if(this.baseRotate == 6 || this.baseRotate == 8){
27514 width = this.thumbEl.getHeight();
27515 this.baseScale = width / this.imageEl.OriginHeight;
27517 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27518 height = this.thumbEl.getWidth();
27519 this.baseScale = height / this.imageEl.OriginHeight;
27522 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27523 height = this.thumbEl.getWidth();
27524 this.baseScale = height / this.imageEl.OriginHeight;
27526 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27527 width = this.thumbEl.getHeight();
27528 this.baseScale = width / this.imageEl.OriginWidth;
27535 width = this.thumbEl.getWidth();
27536 this.baseScale = width / this.imageEl.OriginWidth;
27538 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27539 height = this.thumbEl.getHeight();
27540 this.baseScale = height / this.imageEl.OriginHeight;
27543 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27545 height = this.thumbEl.getHeight();
27546 this.baseScale = height / this.imageEl.OriginHeight;
27548 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27549 width = this.thumbEl.getWidth();
27550 this.baseScale = width / this.imageEl.OriginWidth;
27558 getScaleLevel : function()
27560 return this.baseScale * Math.pow(1.1, this.scale);
27563 onTouchStart : function(e)
27565 if(!this.canvasLoaded){
27566 this.beforeSelectFile(e);
27570 var touches = e.browserEvent.touches;
27576 if(touches.length == 1){
27577 this.onMouseDown(e);
27581 if(touches.length != 2){
27587 for(var i = 0, finger; finger = touches[i]; i++){
27588 coords.push(finger.pageX, finger.pageY);
27591 var x = Math.pow(coords[0] - coords[2], 2);
27592 var y = Math.pow(coords[1] - coords[3], 2);
27594 this.startDistance = Math.sqrt(x + y);
27596 this.startScale = this.scale;
27598 this.pinching = true;
27599 this.dragable = false;
27603 onTouchMove : function(e)
27605 if(!this.pinching && !this.dragable){
27609 var touches = e.browserEvent.touches;
27616 this.onMouseMove(e);
27622 for(var i = 0, finger; finger = touches[i]; i++){
27623 coords.push(finger.pageX, finger.pageY);
27626 var x = Math.pow(coords[0] - coords[2], 2);
27627 var y = Math.pow(coords[1] - coords[3], 2);
27629 this.endDistance = Math.sqrt(x + y);
27631 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27633 if(!this.zoomable()){
27634 this.scale = this.startScale;
27642 onTouchEnd : function(e)
27644 this.pinching = false;
27645 this.dragable = false;
27649 process : function(file, crop)
27652 this.maskEl.mask(this.loadingText);
27655 this.xhr = new XMLHttpRequest();
27657 file.xhr = this.xhr;
27659 this.xhr.open(this.method, this.url, true);
27662 "Accept": "application/json",
27663 "Cache-Control": "no-cache",
27664 "X-Requested-With": "XMLHttpRequest"
27667 for (var headerName in headers) {
27668 var headerValue = headers[headerName];
27670 this.xhr.setRequestHeader(headerName, headerValue);
27676 this.xhr.onload = function()
27678 _this.xhrOnLoad(_this.xhr);
27681 this.xhr.onerror = function()
27683 _this.xhrOnError(_this.xhr);
27686 var formData = new FormData();
27688 formData.append('returnHTML', 'NO');
27691 formData.append('crop', crop);
27694 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27695 formData.append(this.paramName, file, file.name);
27698 if(typeof(file.filename) != 'undefined'){
27699 formData.append('filename', file.filename);
27702 if(typeof(file.mimetype) != 'undefined'){
27703 formData.append('mimetype', file.mimetype);
27706 if(this.fireEvent('arrange', this, formData) != false){
27707 this.xhr.send(formData);
27711 xhrOnLoad : function(xhr)
27714 this.maskEl.unmask();
27717 if (xhr.readyState !== 4) {
27718 this.fireEvent('exception', this, xhr);
27722 var response = Roo.decode(xhr.responseText);
27724 if(!response.success){
27725 this.fireEvent('exception', this, xhr);
27729 var response = Roo.decode(xhr.responseText);
27731 this.fireEvent('upload', this, response);
27735 xhrOnError : function()
27738 this.maskEl.unmask();
27741 Roo.log('xhr on error');
27743 var response = Roo.decode(xhr.responseText);
27749 prepare : function(file)
27752 this.maskEl.mask(this.loadingText);
27758 if(typeof(file) === 'string'){
27759 this.loadCanvas(file);
27763 if(!file || !this.urlAPI){
27768 this.cropType = file.type;
27772 if(this.fireEvent('prepare', this, this.file) != false){
27774 var reader = new FileReader();
27776 reader.onload = function (e) {
27777 if (e.target.error) {
27778 Roo.log(e.target.error);
27782 var buffer = e.target.result,
27783 dataView = new DataView(buffer),
27785 maxOffset = dataView.byteLength - 4,
27789 if (dataView.getUint16(0) === 0xffd8) {
27790 while (offset < maxOffset) {
27791 markerBytes = dataView.getUint16(offset);
27793 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27794 markerLength = dataView.getUint16(offset + 2) + 2;
27795 if (offset + markerLength > dataView.byteLength) {
27796 Roo.log('Invalid meta data: Invalid segment size.');
27800 if(markerBytes == 0xffe1){
27801 _this.parseExifData(
27808 offset += markerLength;
27818 var url = _this.urlAPI.createObjectURL(_this.file);
27820 _this.loadCanvas(url);
27825 reader.readAsArrayBuffer(this.file);
27831 parseExifData : function(dataView, offset, length)
27833 var tiffOffset = offset + 10,
27837 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27838 // No Exif data, might be XMP data instead
27842 // Check for the ASCII code for "Exif" (0x45786966):
27843 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27844 // No Exif data, might be XMP data instead
27847 if (tiffOffset + 8 > dataView.byteLength) {
27848 Roo.log('Invalid Exif data: Invalid segment size.');
27851 // Check for the two null bytes:
27852 if (dataView.getUint16(offset + 8) !== 0x0000) {
27853 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27856 // Check the byte alignment:
27857 switch (dataView.getUint16(tiffOffset)) {
27859 littleEndian = true;
27862 littleEndian = false;
27865 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27868 // Check for the TIFF tag marker (0x002A):
27869 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27870 Roo.log('Invalid Exif data: Missing TIFF marker.');
27873 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27874 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27876 this.parseExifTags(
27879 tiffOffset + dirOffset,
27884 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27889 if (dirOffset + 6 > dataView.byteLength) {
27890 Roo.log('Invalid Exif data: Invalid directory offset.');
27893 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27894 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27895 if (dirEndOffset + 4 > dataView.byteLength) {
27896 Roo.log('Invalid Exif data: Invalid directory size.');
27899 for (i = 0; i < tagsNumber; i += 1) {
27903 dirOffset + 2 + 12 * i, // tag offset
27907 // Return the offset to the next directory:
27908 return dataView.getUint32(dirEndOffset, littleEndian);
27911 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27913 var tag = dataView.getUint16(offset, littleEndian);
27915 this.exif[tag] = this.getExifValue(
27919 dataView.getUint16(offset + 2, littleEndian), // tag type
27920 dataView.getUint32(offset + 4, littleEndian), // tag length
27925 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27927 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27936 Roo.log('Invalid Exif data: Invalid tag type.');
27940 tagSize = tagType.size * length;
27941 // Determine if the value is contained in the dataOffset bytes,
27942 // or if the value at the dataOffset is a pointer to the actual data:
27943 dataOffset = tagSize > 4 ?
27944 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27945 if (dataOffset + tagSize > dataView.byteLength) {
27946 Roo.log('Invalid Exif data: Invalid data offset.');
27949 if (length === 1) {
27950 return tagType.getValue(dataView, dataOffset, littleEndian);
27953 for (i = 0; i < length; i += 1) {
27954 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27957 if (tagType.ascii) {
27959 // Concatenate the chars:
27960 for (i = 0; i < values.length; i += 1) {
27962 // Ignore the terminating NULL byte(s):
27963 if (c === '\u0000') {
27975 Roo.apply(Roo.bootstrap.UploadCropbox, {
27977 'Orientation': 0x0112
27981 1: 0, //'top-left',
27983 3: 180, //'bottom-right',
27984 // 4: 'bottom-left',
27986 6: 90, //'right-top',
27987 // 7: 'right-bottom',
27988 8: 270 //'left-bottom'
27992 // byte, 8-bit unsigned int:
27994 getValue: function (dataView, dataOffset) {
27995 return dataView.getUint8(dataOffset);
27999 // ascii, 8-bit byte:
28001 getValue: function (dataView, dataOffset) {
28002 return String.fromCharCode(dataView.getUint8(dataOffset));
28007 // short, 16 bit int:
28009 getValue: function (dataView, dataOffset, littleEndian) {
28010 return dataView.getUint16(dataOffset, littleEndian);
28014 // long, 32 bit int:
28016 getValue: function (dataView, dataOffset, littleEndian) {
28017 return dataView.getUint32(dataOffset, littleEndian);
28021 // rational = two long values, first is numerator, second is denominator:
28023 getValue: function (dataView, dataOffset, littleEndian) {
28024 return dataView.getUint32(dataOffset, littleEndian) /
28025 dataView.getUint32(dataOffset + 4, littleEndian);
28029 // slong, 32 bit signed int:
28031 getValue: function (dataView, dataOffset, littleEndian) {
28032 return dataView.getInt32(dataOffset, littleEndian);
28036 // srational, two slongs, first is numerator, second is denominator:
28038 getValue: function (dataView, dataOffset, littleEndian) {
28039 return dataView.getInt32(dataOffset, littleEndian) /
28040 dataView.getInt32(dataOffset + 4, littleEndian);
28050 cls : 'btn-group roo-upload-cropbox-rotate-left',
28051 action : 'rotate-left',
28055 cls : 'btn btn-default',
28056 html : '<i class="fa fa-undo"></i>'
28062 cls : 'btn-group roo-upload-cropbox-picture',
28063 action : 'picture',
28067 cls : 'btn btn-default',
28068 html : '<i class="fa fa-picture-o"></i>'
28074 cls : 'btn-group roo-upload-cropbox-rotate-right',
28075 action : 'rotate-right',
28079 cls : 'btn btn-default',
28080 html : '<i class="fa fa-repeat"></i>'
28088 cls : 'btn-group roo-upload-cropbox-rotate-left',
28089 action : 'rotate-left',
28093 cls : 'btn btn-default',
28094 html : '<i class="fa fa-undo"></i>'
28100 cls : 'btn-group roo-upload-cropbox-download',
28101 action : 'download',
28105 cls : 'btn btn-default',
28106 html : '<i class="fa fa-download"></i>'
28112 cls : 'btn-group roo-upload-cropbox-crop',
28117 cls : 'btn btn-default',
28118 html : '<i class="fa fa-crop"></i>'
28124 cls : 'btn-group roo-upload-cropbox-trash',
28129 cls : 'btn btn-default',
28130 html : '<i class="fa fa-trash"></i>'
28136 cls : 'btn-group roo-upload-cropbox-rotate-right',
28137 action : 'rotate-right',
28141 cls : 'btn btn-default',
28142 html : '<i class="fa fa-repeat"></i>'
28150 cls : 'btn-group roo-upload-cropbox-rotate-left',
28151 action : 'rotate-left',
28155 cls : 'btn btn-default',
28156 html : '<i class="fa fa-undo"></i>'
28162 cls : 'btn-group roo-upload-cropbox-rotate-right',
28163 action : 'rotate-right',
28167 cls : 'btn btn-default',
28168 html : '<i class="fa fa-repeat"></i>'
28181 * @class Roo.bootstrap.DocumentManager
28182 * @extends Roo.bootstrap.Component
28183 * Bootstrap DocumentManager class
28184 * @cfg {String} paramName default 'imageUpload'
28185 * @cfg {String} toolTipName default 'filename'
28186 * @cfg {String} method default POST
28187 * @cfg {String} url action url
28188 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28189 * @cfg {Boolean} multiple multiple upload default true
28190 * @cfg {Number} thumbSize default 300
28191 * @cfg {String} fieldLabel
28192 * @cfg {Number} labelWidth default 4
28193 * @cfg {String} labelAlign (left|top) default left
28194 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28195 * @cfg {Number} labellg set the width of label (1-12)
28196 * @cfg {Number} labelmd set the width of label (1-12)
28197 * @cfg {Number} labelsm set the width of label (1-12)
28198 * @cfg {Number} labelxs set the width of label (1-12)
28201 * Create a new DocumentManager
28202 * @param {Object} config The config object
28205 Roo.bootstrap.DocumentManager = function(config){
28206 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28209 this.delegates = [];
28214 * Fire when initial the DocumentManager
28215 * @param {Roo.bootstrap.DocumentManager} this
28220 * inspect selected file
28221 * @param {Roo.bootstrap.DocumentManager} this
28222 * @param {File} file
28227 * Fire when xhr load exception
28228 * @param {Roo.bootstrap.DocumentManager} this
28229 * @param {XMLHttpRequest} xhr
28231 "exception" : true,
28233 * @event afterupload
28234 * Fire when xhr load exception
28235 * @param {Roo.bootstrap.DocumentManager} this
28236 * @param {XMLHttpRequest} xhr
28238 "afterupload" : true,
28241 * prepare the form data
28242 * @param {Roo.bootstrap.DocumentManager} this
28243 * @param {Object} formData
28248 * Fire when remove the file
28249 * @param {Roo.bootstrap.DocumentManager} this
28250 * @param {Object} file
28255 * Fire after refresh the file
28256 * @param {Roo.bootstrap.DocumentManager} this
28261 * Fire after click the image
28262 * @param {Roo.bootstrap.DocumentManager} this
28263 * @param {Object} file
28268 * Fire when upload a image and editable set to true
28269 * @param {Roo.bootstrap.DocumentManager} this
28270 * @param {Object} file
28274 * @event beforeselectfile
28275 * Fire before select file
28276 * @param {Roo.bootstrap.DocumentManager} this
28278 "beforeselectfile" : true,
28281 * Fire before process file
28282 * @param {Roo.bootstrap.DocumentManager} this
28283 * @param {Object} file
28290 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28299 paramName : 'imageUpload',
28300 toolTipName : 'filename',
28303 labelAlign : 'left',
28313 getAutoCreate : function()
28315 var managerWidget = {
28317 cls : 'roo-document-manager',
28321 cls : 'roo-document-manager-selector',
28326 cls : 'roo-document-manager-uploader',
28330 cls : 'roo-document-manager-upload-btn',
28331 html : '<i class="fa fa-plus"></i>'
28342 cls : 'column col-md-12',
28347 if(this.fieldLabel.length){
28352 cls : 'column col-md-12',
28353 html : this.fieldLabel
28357 cls : 'column col-md-12',
28362 if(this.labelAlign == 'left'){
28367 html : this.fieldLabel
28376 if(this.labelWidth > 12){
28377 content[0].style = "width: " + this.labelWidth + 'px';
28380 if(this.labelWidth < 13 && this.labelmd == 0){
28381 this.labelmd = this.labelWidth;
28384 if(this.labellg > 0){
28385 content[0].cls += ' col-lg-' + this.labellg;
28386 content[1].cls += ' col-lg-' + (12 - this.labellg);
28389 if(this.labelmd > 0){
28390 content[0].cls += ' col-md-' + this.labelmd;
28391 content[1].cls += ' col-md-' + (12 - this.labelmd);
28394 if(this.labelsm > 0){
28395 content[0].cls += ' col-sm-' + this.labelsm;
28396 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28399 if(this.labelxs > 0){
28400 content[0].cls += ' col-xs-' + this.labelxs;
28401 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28409 cls : 'row clearfix',
28417 initEvents : function()
28419 this.managerEl = this.el.select('.roo-document-manager', true).first();
28420 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28422 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28423 this.selectorEl.hide();
28426 this.selectorEl.attr('multiple', 'multiple');
28429 this.selectorEl.on('change', this.onFileSelected, this);
28431 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28432 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28434 this.uploader.on('click', this.onUploaderClick, this);
28436 this.renderProgressDialog();
28440 window.addEventListener("resize", function() { _this.refresh(); } );
28442 this.fireEvent('initial', this);
28445 renderProgressDialog : function()
28449 this.progressDialog = new Roo.bootstrap.Modal({
28450 cls : 'roo-document-manager-progress-dialog',
28451 allow_close : false,
28461 btnclick : function() {
28462 _this.uploadCancel();
28468 this.progressDialog.render(Roo.get(document.body));
28470 this.progress = new Roo.bootstrap.Progress({
28471 cls : 'roo-document-manager-progress',
28476 this.progress.render(this.progressDialog.getChildContainer());
28478 this.progressBar = new Roo.bootstrap.ProgressBar({
28479 cls : 'roo-document-manager-progress-bar',
28482 aria_valuemax : 12,
28486 this.progressBar.render(this.progress.getChildContainer());
28489 onUploaderClick : function(e)
28491 e.preventDefault();
28493 if(this.fireEvent('beforeselectfile', this) != false){
28494 this.selectorEl.dom.click();
28499 onFileSelected : function(e)
28501 e.preventDefault();
28503 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28507 Roo.each(this.selectorEl.dom.files, function(file){
28508 if(this.fireEvent('inspect', this, file) != false){
28509 this.files.push(file);
28519 this.selectorEl.dom.value = '';
28521 if(!this.files.length){
28525 if(this.boxes > 0 && this.files.length > this.boxes){
28526 this.files = this.files.slice(0, this.boxes);
28529 this.uploader.show();
28531 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28532 this.uploader.hide();
28541 Roo.each(this.files, function(file){
28543 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28544 var f = this.renderPreview(file);
28549 if(file.type.indexOf('image') != -1){
28550 this.delegates.push(
28552 _this.process(file);
28553 }).createDelegate(this)
28561 _this.process(file);
28562 }).createDelegate(this)
28567 this.files = files;
28569 this.delegates = this.delegates.concat(docs);
28571 if(!this.delegates.length){
28576 this.progressBar.aria_valuemax = this.delegates.length;
28583 arrange : function()
28585 if(!this.delegates.length){
28586 this.progressDialog.hide();
28591 var delegate = this.delegates.shift();
28593 this.progressDialog.show();
28595 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28597 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28602 refresh : function()
28604 this.uploader.show();
28606 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28607 this.uploader.hide();
28610 Roo.isTouch ? this.closable(false) : this.closable(true);
28612 this.fireEvent('refresh', this);
28615 onRemove : function(e, el, o)
28617 e.preventDefault();
28619 this.fireEvent('remove', this, o);
28623 remove : function(o)
28627 Roo.each(this.files, function(file){
28628 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28637 this.files = files;
28644 Roo.each(this.files, function(file){
28649 file.target.remove();
28658 onClick : function(e, el, o)
28660 e.preventDefault();
28662 this.fireEvent('click', this, o);
28666 closable : function(closable)
28668 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28670 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28682 xhrOnLoad : function(xhr)
28684 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28688 if (xhr.readyState !== 4) {
28690 this.fireEvent('exception', this, xhr);
28694 var response = Roo.decode(xhr.responseText);
28696 if(!response.success){
28698 this.fireEvent('exception', this, xhr);
28702 var file = this.renderPreview(response.data);
28704 this.files.push(file);
28708 this.fireEvent('afterupload', this, xhr);
28712 xhrOnError : function(xhr)
28714 Roo.log('xhr on error');
28716 var response = Roo.decode(xhr.responseText);
28723 process : function(file)
28725 if(this.fireEvent('process', this, file) !== false){
28726 if(this.editable && file.type.indexOf('image') != -1){
28727 this.fireEvent('edit', this, file);
28731 this.uploadStart(file, false);
28738 uploadStart : function(file, crop)
28740 this.xhr = new XMLHttpRequest();
28742 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28747 file.xhr = this.xhr;
28749 this.managerEl.createChild({
28751 cls : 'roo-document-manager-loading',
28755 tooltip : file.name,
28756 cls : 'roo-document-manager-thumb',
28757 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28763 this.xhr.open(this.method, this.url, true);
28766 "Accept": "application/json",
28767 "Cache-Control": "no-cache",
28768 "X-Requested-With": "XMLHttpRequest"
28771 for (var headerName in headers) {
28772 var headerValue = headers[headerName];
28774 this.xhr.setRequestHeader(headerName, headerValue);
28780 this.xhr.onload = function()
28782 _this.xhrOnLoad(_this.xhr);
28785 this.xhr.onerror = function()
28787 _this.xhrOnError(_this.xhr);
28790 var formData = new FormData();
28792 formData.append('returnHTML', 'NO');
28795 formData.append('crop', crop);
28798 formData.append(this.paramName, file, file.name);
28805 if(this.fireEvent('prepare', this, formData, options) != false){
28807 if(options.manually){
28811 this.xhr.send(formData);
28815 this.uploadCancel();
28818 uploadCancel : function()
28824 this.delegates = [];
28826 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28833 renderPreview : function(file)
28835 if(typeof(file.target) != 'undefined' && file.target){
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="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
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.item = []; //fetch country JSON
37849 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
37851 //setting properties..
37852 preferedCountries: undefined, //array
37854 filterCountries: undefined, //array
37856 displayMode: undefined, //string
37858 listWidth: undefined, //number
37860 validClass : "has-success",
37862 invalidClass: "has-warning",
37865 getAutoCreate : function()
37871 * Render classic select for iso
37873 if(Roo.isIOS && this.useNativeIOS){
37874 cfg = this.getAutoCreateNativeIOS();
37881 if(Roo.isTouch && this.mobileTouchView){
37882 cfg = this.getAutoCreateTouchView();
37886 var align = this.labelAlign || this.parentLabelAlign();
37897 type : this.inputType,
37898 cls : 'form-control',
37899 autocomplete: 'new-password',
37900 placeholder : this.placeholder || ''
37906 _initEventsCalled : false,
37909 initEvents: function()
37911 if (this._initEventsCalled) { // as we call render... prevent looping...
37914 this._initEventsCalled = true;
37917 throw "can not find store for combo";
37920 this.store = Roo.factory(this.store, Roo.data);
37921 this.store.parent = this;
37923 // if we are building from html. then this element is so complex, that we can not really
37924 // use the rendered HTML.
37925 // so we have to trash and replace the previous code.
37926 if (Roo.XComponent.build_from_html) {
37928 // remove this element....
37929 var e = this.el.dom, k=0;
37930 while (e ) { e = e.previousSibling; ++k;}
37935 this.rendered = false;
37937 this.render(this.parent().getChildContainer(true), k);
37943 if(Roo.isIOS && this.useNativeIOS){
37944 this.initIOSView();
37952 if(Roo.isTouch && this.mobileTouchView){
37953 this.initTouchView();
37958 this.initTickableEvents();
37962 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
37964 if(this.hiddenName){
37966 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
37968 this.hiddenField.dom.value =
37969 this.hiddenValue !== undefined ? this.hiddenValue :
37970 this.value !== undefined ? this.value : '';
37972 // prevent input submission
37973 this.el.dom.removeAttribute('name');
37974 this.hiddenField.dom.setAttribute('name', this.hiddenName);
37979 // this.el.dom.setAttribute('autocomplete', 'off');
37982 var cls = 'x-combo-list';
37984 //this.list = new Roo.Layer({
37985 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37991 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
37992 _this.list.setWidth(lw);
37995 this.list.on('mouseover', this.onViewOver, this);
37996 this.list.on('mousemove', this.onViewMove, this);
37998 this.list.on('scroll', this.onViewScroll, this);
38001 this.list.swallowEvent('mousewheel');
38002 this.assetHeight = 0;
38005 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38006 this.assetHeight += this.header.getHeight();
38009 this.innerList = this.list.createChild({cls:cls+'-inner'});
38010 this.innerList.on('mouseover', this.onViewOver, this);
38011 this.innerList.on('mousemove', this.onViewMove, this);
38012 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38014 if(this.allowBlank && !this.pageSize && !this.disableClear){
38015 this.footer = this.list.createChild({cls:cls+'-ft'});
38016 this.pageTb = new Roo.Toolbar(this.footer);
38020 this.footer = this.list.createChild({cls:cls+'-ft'});
38021 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38022 {pageSize: this.pageSize});
38026 if (this.pageTb && this.allowBlank && !this.disableClear) {
38028 this.pageTb.add(new Roo.Toolbar.Fill(), {
38029 cls: 'x-btn-icon x-btn-clear',
38031 handler: function()
38034 _this.clearValue();
38035 _this.onSelect(false, -1);
38040 this.assetHeight += this.footer.getHeight();
38045 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
38048 this.view = new Roo.View(this.list, this.tpl, {
38049 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38051 //this.view.wrapEl.setDisplayed(false);
38052 this.view.on('click', this.onViewClick, this);
38055 this.store.on('beforeload', this.onBeforeLoad, this);
38056 this.store.on('load', this.onLoad, this);
38057 this.store.on('loadexception', this.onLoadException, this);
38059 if(this.resizable){
38060 this.resizer = new Roo.Resizable(this.list, {
38061 pinned:true, handles:'se'
38063 this.resizer.on('resize', function(r, w, h){
38064 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38065 this.listWidth = w;
38066 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38067 this.restrictHeight();
38069 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38072 if(!this.editable){
38073 this.editable = true;
38074 this.setEditable(false);
38079 if (typeof(this.events.add.listeners) != 'undefined') {
38081 this.addicon = this.wrap.createChild(
38082 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38084 this.addicon.on('click', function(e) {
38085 this.fireEvent('add', this);
38088 if (typeof(this.events.edit.listeners) != 'undefined') {
38090 this.editicon = this.wrap.createChild(
38091 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38092 if (this.addicon) {
38093 this.editicon.setStyle('margin-left', '40px');
38095 this.editicon.on('click', function(e) {
38097 // we fire even if inothing is selected..
38098 this.fireEvent('edit', this, this.lastData );
38104 this.keyNav = new Roo.KeyNav(this.inputEl(), {
38105 "up" : function(e){
38106 this.inKeyMode = true;
38110 "down" : function(e){
38111 if(!this.isExpanded()){
38112 this.onTriggerClick();
38114 this.inKeyMode = true;
38119 "enter" : function(e){
38120 // this.onViewClick();
38124 if(this.fireEvent("specialkey", this, e)){
38125 this.onViewClick(false);
38131 "esc" : function(e){
38135 "tab" : function(e){
38138 if(this.fireEvent("specialkey", this, e)){
38139 this.onViewClick(false);
38147 doRelay : function(foo, bar, hname){
38148 if(hname == 'down' || this.scope.isExpanded()){
38149 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38158 this.queryDelay = Math.max(this.queryDelay || 10,
38159 this.mode == 'local' ? 10 : 250);
38162 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38164 if(this.typeAhead){
38165 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38167 if(this.editable !== false){
38168 this.inputEl().on("keyup", this.onKeyUp, this);
38170 if(this.forceSelection){
38171 this.inputEl().on('blur', this.doForce, this);
38175 this.choices = this.el.select('ul.roo-select2-choices', true).first();
38176 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
38180 initTickableEvents: function()
38184 if(this.hiddenName){
38186 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
38188 this.hiddenField.dom.value =
38189 this.hiddenValue !== undefined ? this.hiddenValue :
38190 this.value !== undefined ? this.value : '';
38192 // prevent input submission
38193 this.el.dom.removeAttribute('name');
38194 this.hiddenField.dom.setAttribute('name', this.hiddenName);
38199 // this.list = this.el.select('ul.dropdown-menu',true).first();
38201 this.choices = this.el.select('ul.roo-select2-choices', true).first();
38202 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
38203 if(this.triggerList){
38204 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
38207 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
38208 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
38210 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
38211 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
38213 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
38214 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
38216 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
38217 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
38218 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
38221 this.cancelBtn.hide();
38226 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
38227 _this.list.setWidth(lw);
38230 this.list.on('mouseover', this.onViewOver, this);
38231 this.list.on('mousemove', this.onViewMove, this);
38233 this.list.on('scroll', this.onViewScroll, this);
38236 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>';
38239 this.view = new Roo.View(this.list, this.tpl, {
38240 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
38243 //this.view.wrapEl.setDisplayed(false);
38244 this.view.on('click', this.onViewClick, this);
38248 this.store.on('beforeload', this.onBeforeLoad, this);
38249 this.store.on('load', this.onLoad, this);
38250 this.store.on('loadexception', this.onLoadException, this);
38253 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
38254 "up" : function(e){
38255 this.inKeyMode = true;
38259 "down" : function(e){
38260 this.inKeyMode = true;
38264 "enter" : function(e){
38265 if(this.fireEvent("specialkey", this, e)){
38266 this.onViewClick(false);
38272 "esc" : function(e){
38273 this.onTickableFooterButtonClick(e, false, false);
38276 "tab" : function(e){
38277 this.fireEvent("specialkey", this, e);
38279 this.onTickableFooterButtonClick(e, false, false);
38286 doRelay : function(e, fn, key){
38287 if(this.scope.isExpanded()){
38288 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38297 this.queryDelay = Math.max(this.queryDelay || 10,
38298 this.mode == 'local' ? 10 : 250);
38301 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38303 if(this.typeAhead){
38304 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38307 if(this.editable !== false){
38308 this.tickableInputEl().on("keyup", this.onKeyUp, this);
38311 this.indicator = this.indicatorEl();
38313 if(this.indicator){
38314 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
38315 this.indicator.hide();
38320 onDestroy : function(){
38322 this.view.setStore(null);
38323 this.view.el.removeAllListeners();
38324 this.view.el.remove();
38325 this.view.purgeListeners();
38328 this.list.dom.innerHTML = '';
38332 this.store.un('beforeload', this.onBeforeLoad, this);
38333 this.store.un('load', this.onLoad, this);
38334 this.store.un('loadexception', this.onLoadException, this);
38336 Roo.bootstrap.PhoneInput.superclass.onDestroy.call(this);
38340 fireKey : function(e){
38341 if(e.isNavKeyPress() && !this.list.isVisible()){
38342 this.fireEvent("specialkey", this, e);
38347 onResize: function(w, h){
38348 // Roo.bootstrap.PhoneInput.superclass.onResize.apply(this, arguments);
38350 // if(typeof w != 'number'){
38351 // // we do not handle it!?!?
38354 // var tw = this.trigger.getWidth();
38355 // // tw += this.addicon ? this.addicon.getWidth() : 0;
38356 // // tw += this.editicon ? this.editicon.getWidth() : 0;
38358 // this.inputEl().setWidth( this.adjustWidth('input', x));
38360 // //this.trigger.setStyle('left', x+'px');
38362 // if(this.list && this.listWidth === undefined){
38363 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38364 // this.list.setWidth(lw);
38365 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38373 * Allow or prevent the user from directly editing the field text. If false is passed,
38374 * the user will only be able to select from the items defined in the dropdown list. This method
38375 * is the runtime equivalent of setting the 'editable' config option at config time.
38376 * @param {Boolean} value True to allow the user to directly edit the field text
38378 setEditable : function(value){
38379 if(value == this.editable){
38382 this.editable = value;
38384 this.inputEl().dom.setAttribute('readOnly', true);
38385 this.inputEl().on('mousedown', this.onTriggerClick, this);
38386 this.inputEl().addClass('x-combo-noedit');
38388 this.inputEl().dom.setAttribute('readOnly', false);
38389 this.inputEl().un('mousedown', this.onTriggerClick, this);
38390 this.inputEl().removeClass('x-combo-noedit');
38396 onBeforeLoad : function(combo,opts){
38397 if(!this.hasFocus){
38401 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
38403 this.restrictHeight();
38404 this.selectedIndex = -1;
38408 onLoad : function(){
38410 this.hasQuery = false;
38412 if(!this.hasFocus){
38416 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
38417 this.loading.hide();
38420 if(this.store.getCount() > 0){
38423 this.restrictHeight();
38424 if(this.lastQuery == this.allQuery){
38425 if(this.editable && !this.tickable){
38426 this.inputEl().dom.select();
38430 !this.selectByValue(this.value, true) &&
38433 !this.store.lastOptions ||
38434 typeof(this.store.lastOptions.add) == 'undefined' ||
38435 this.store.lastOptions.add != true
38438 this.select(0, true);
38441 if(this.autoFocus){
38444 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38445 this.taTask.delay(this.typeAheadDelay);
38449 this.onEmptyResults();
38455 onLoadException : function()
38457 this.hasQuery = false;
38459 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
38460 this.loading.hide();
38463 if(this.tickable && this.editable){
38468 // only causes errors at present
38469 //Roo.log(this.store.reader.jsonData);
38470 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38472 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38478 onTypeAhead : function(){
38479 if(this.store.getCount() > 0){
38480 var r = this.store.getAt(0);
38481 var newValue = r.data[this.displayField];
38482 var len = newValue.length;
38483 var selStart = this.getRawValue().length;
38485 if(selStart != len){
38486 this.setRawValue(newValue);
38487 this.selectText(selStart, newValue.length);
38493 onSelect : function(record, index){
38495 if(this.fireEvent('beforeselect', this, record, index) !== false){
38497 this.setFromData(index > -1 ? record.data : false);
38500 this.fireEvent('select', this, record, index);
38505 * Returns the currently selected field value or empty string if no value is set.
38506 * @return {String} value The selected value
38508 getValue : function()
38510 if(Roo.isIOS && this.useNativeIOS){
38511 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
38515 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
38518 if(this.valueField){
38519 return typeof this.value != 'undefined' ? this.value : '';
38521 return Roo.bootstrap.PhoneInput.superclass.getValue.call(this);
38525 getRawValue : function()
38527 if(Roo.isIOS && this.useNativeIOS){
38528 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
38531 var v = this.inputEl().getValue();
38537 * Clears any text/value currently set in the field
38539 clearValue : function(){
38541 if(this.hiddenField){
38542 this.hiddenField.dom.value = '';
38545 this.setRawValue('');
38546 this.lastSelectionText = '';
38547 this.lastData = false;
38549 var close = this.closeTriggerEl();
38560 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38561 * will be displayed in the field. If the value does not match the data value of an existing item,
38562 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38563 * Otherwise the field will be blank (although the value will still be set).
38564 * @param {String} value The value to match
38566 setValue : function(v)
38568 if(Roo.isIOS && this.useNativeIOS){
38569 this.setIOSValue(v);
38579 if(this.valueField){
38580 var r = this.findRecord(this.valueField, v);
38582 text = r.data[this.displayField];
38583 }else if(this.valueNotFoundText !== undefined){
38584 text = this.valueNotFoundText;
38587 this.lastSelectionText = text;
38588 if(this.hiddenField){
38589 this.hiddenField.dom.value = v;
38591 Roo.bootstrap.PhoneInput.superclass.setValue.call(this, text);
38594 var close = this.closeTriggerEl();
38597 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
38603 * @property {Object} the last set data for the element
38608 * Sets the value of the field based on a object which is related to the record format for the store.
38609 * @param {Object} value the value to set as. or false on reset?
38611 setFromData : function(o){
38618 var dv = ''; // display value
38619 var vv = ''; // value value..
38621 if (this.displayField) {
38622 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
38624 // this is an error condition!!!
38625 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
38628 if(this.valueField){
38629 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
38632 var close = this.closeTriggerEl();
38635 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
38638 if(this.hiddenField){
38639 this.hiddenField.dom.value = vv;
38641 this.lastSelectionText = dv;
38642 Roo.bootstrap.PhoneInput.superclass.setValue.call(this, dv);
38646 // no hidden field.. - we store the value in 'value', but still display
38647 // display field!!!!
38648 this.lastSelectionText = dv;
38649 Roo.bootstrap.PhoneInput.superclass.setValue.call(this, dv);
38656 reset : function(){
38657 // overridden so that last data is reset..
38664 this.setValue(this.originalValue);
38665 //this.clearInvalid();
38666 this.lastData = false;
38668 this.view.clearSelections();
38674 findRecord : function(prop, value){
38676 if(this.store.getCount() > 0){
38677 this.store.each(function(r){
38678 if(r.data[prop] == value){
38688 getName: function()
38690 // returns hidden if it's set..
38691 if (!this.rendered) {return ''};
38692 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
38696 onViewMove : function(e, t){
38697 this.inKeyMode = false;
38701 onViewOver : function(e, t){
38702 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38705 var item = this.view.findItemFromChild(t);
38708 var index = this.view.indexOf(item);
38709 this.select(index, false);
38714 onViewClick : function(view, doFocus, el, e)
38716 var index = this.view.getSelectedIndexes()[0];
38718 var r = this.store.getAt(index);
38722 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
38729 Roo.each(this.tickItems, function(v,k){
38731 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
38732 _this.tickItems.splice(k, 1);
38734 if(typeof(e) == 'undefined' && view == false){
38735 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
38747 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
38748 this.tickItems.push(r.data);
38751 if(typeof(e) == 'undefined' && view == false){
38752 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
38759 this.onSelect(r, index);
38761 if(doFocus !== false && !this.blockFocus){
38762 this.inputEl().focus();
38767 restrictHeight : function(){
38768 //this.innerList.dom.style.height = '';
38769 //var inner = this.innerList.dom;
38770 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38771 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38772 //this.list.beginUpdate();
38773 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38774 this.list.alignTo(this.inputEl(), this.listAlign);
38775 this.list.alignTo(this.inputEl(), this.listAlign);
38776 //this.list.endUpdate();
38780 onEmptyResults : function(){
38782 if(this.tickable && this.editable){
38783 this.restrictHeight();
38791 * Returns true if the dropdown list is expanded, else false.
38793 isExpanded : function(){
38794 return this.list.isVisible();
38798 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38799 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38800 * @param {String} value The data value of the item to select
38801 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38802 * selected item if it is not currently in view (defaults to true)
38803 * @return {Boolean} True if the value matched an item in the list, else false
38805 selectByValue : function(v, scrollIntoView){
38806 if(v !== undefined && v !== null){
38807 var r = this.findRecord(this.valueField || this.displayField, v);
38809 this.select(this.store.indexOf(r), scrollIntoView);
38817 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38818 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38819 * @param {Number} index The zero-based index of the list item to select
38820 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38821 * selected item if it is not currently in view (defaults to true)
38823 select : function(index, scrollIntoView){
38824 this.selectedIndex = index;
38825 this.view.select(index);
38826 if(scrollIntoView !== false){
38827 var el = this.view.getNode(index);
38829 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
38832 this.list.scrollChildIntoView(el, false);
38838 selectNext : function(){
38839 var ct = this.store.getCount();
38841 if(this.selectedIndex == -1){
38843 }else if(this.selectedIndex < ct-1){
38844 this.select(this.selectedIndex+1);
38850 selectPrev : function(){
38851 var ct = this.store.getCount();
38853 if(this.selectedIndex == -1){
38855 }else if(this.selectedIndex != 0){
38856 this.select(this.selectedIndex-1);
38862 onKeyUp : function(e){
38863 if(this.editable !== false && !e.isSpecialKey()){
38864 this.lastKey = e.getKey();
38865 this.dqTask.delay(this.queryDelay);
38870 validateBlur : function(){
38871 return !this.list || !this.list.isVisible();
38875 initQuery : function(){
38877 var v = this.getRawValue();
38879 if(this.tickable && this.editable){
38880 v = this.tickableInputEl().getValue();
38887 doForce : function(){
38888 if(this.inputEl().dom.value.length > 0){
38889 this.inputEl().dom.value =
38890 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38896 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38897 * query allowing the query action to be canceled if needed.
38898 * @param {String} query The SQL query to execute
38899 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38900 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38901 * saved in the current store (defaults to false)
38903 doQuery : function(q, forceAll){
38905 if(q === undefined || q === null){
38910 forceAll: forceAll,
38914 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38919 forceAll = qe.forceAll;
38920 if(forceAll === true || (q.length >= this.minChars)){
38922 this.hasQuery = true;
38924 if(this.lastQuery != q || this.alwaysQuery){
38925 this.lastQuery = q;
38926 if(this.mode == 'local'){
38927 this.selectedIndex = -1;
38929 this.store.clearFilter();
38932 if(this.specialFilter){
38933 this.fireEvent('specialfilter', this);
38938 this.store.filter(this.displayField, q);
38941 this.store.fireEvent("datachanged", this.store);
38948 this.store.baseParams[this.queryParam] = q;
38950 var options = {params : this.getParams(q)};
38953 options.add = true;
38954 options.params.start = this.page * this.pageSize;
38957 this.store.load(options);
38960 * this code will make the page width larger, at the beginning, the list not align correctly,
38961 * we should expand the list on onLoad
38962 * so command out it
38967 this.selectedIndex = -1;
38972 this.loadNext = false;
38976 getParams : function(q){
38978 //p[this.queryParam] = q;
38982 p.limit = this.pageSize;
38988 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38990 collapse : function(){
38991 if(!this.isExpanded()){
38997 this.hasFocus = false;
39001 this.cancelBtn.hide();
39002 this.trigger.show();
39005 this.tickableInputEl().dom.value = '';
39006 this.tickableInputEl().blur();
39011 Roo.get(document).un('mousedown', this.collapseIf, this);
39012 Roo.get(document).un('mousewheel', this.collapseIf, this);
39013 if (!this.editable) {
39014 Roo.get(document).un('keydown', this.listKeyPress, this);
39016 this.fireEvent('collapse', this);
39022 collapseIf : function(e){
39023 var in_combo = e.within(this.el);
39024 var in_list = e.within(this.list);
39025 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39027 if (in_combo || in_list || is_list) {
39028 //e.stopPropagation();
39033 this.onTickableFooterButtonClick(e, false, false);
39041 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39043 expand : function(){
39045 if(this.isExpanded() || !this.hasFocus){
39049 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39050 this.list.setWidth(lw);
39056 this.restrictHeight();
39060 this.tickItems = Roo.apply([], this.item);
39063 this.cancelBtn.show();
39064 this.trigger.hide();
39067 this.tickableInputEl().focus();
39072 Roo.get(document).on('mousedown', this.collapseIf, this);
39073 Roo.get(document).on('mousewheel', this.collapseIf, this);
39074 if (!this.editable) {
39075 Roo.get(document).on('keydown', this.listKeyPress, this);
39078 this.fireEvent('expand', this);
39082 // Implements the default empty TriggerField.onTriggerClick function
39083 onTriggerClick : function(e)
39085 Roo.log('trigger click');
39087 if(this.disabled || !this.triggerList){
39092 this.loadNext = false;
39094 if(this.isExpanded()){
39096 if (!this.blockFocus) {
39097 this.inputEl().focus();
39101 this.hasFocus = true;
39102 if(this.triggerAction == 'all') {
39103 this.doQuery(this.allQuery, true);
39105 this.doQuery(this.getRawValue());
39107 if (!this.blockFocus) {
39108 this.inputEl().focus();
39113 onTickableTriggerClick : function(e)
39120 this.loadNext = false;
39121 this.hasFocus = true;
39123 if(this.triggerAction == 'all') {
39124 this.doQuery(this.allQuery, true);
39126 this.doQuery(this.getRawValue());
39130 onSearchFieldClick : function(e)
39132 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
39133 this.onTickableFooterButtonClick(e, false, false);
39137 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
39142 this.loadNext = false;
39143 this.hasFocus = true;
39145 if(this.triggerAction == 'all') {
39146 this.doQuery(this.allQuery, true);
39148 this.doQuery(this.getRawValue());
39152 listKeyPress : function(e)
39154 //Roo.log('listkeypress');
39155 // scroll to first matching element based on key pres..
39156 if (e.isSpecialKey()) {
39159 var k = String.fromCharCode(e.getKey()).toUpperCase();
39162 var csel = this.view.getSelectedNodes();
39163 var cselitem = false;
39165 var ix = this.view.indexOf(csel[0]);
39166 cselitem = this.store.getAt(ix);
39167 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39173 this.store.each(function(v) {
39175 // start at existing selection.
39176 if (cselitem.id == v.id) {
39182 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39183 match = this.store.indexOf(v);
39189 if (match === false) {
39190 return true; // no more action?
39193 this.view.select(match);
39194 var sn = Roo.get(this.view.getSelectedNodes()[0]);
39195 sn.scrollIntoView(sn.dom.parentNode, false);
39198 onViewScroll : function(e, t){
39200 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){
39204 this.hasQuery = true;
39206 this.loading = this.list.select('.loading', true).first();
39208 if(this.loading === null){
39209 this.list.createChild({
39211 cls: 'loading roo-select2-more-results roo-select2-active',
39212 html: 'Loading more results...'
39215 this.loading = this.list.select('.loading', true).first();
39217 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
39219 this.loading.hide();
39222 this.loading.show();
39227 this.loadNext = true;
39229 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
39234 addItem : function(o)
39236 var dv = ''; // display value
39238 if (this.displayField) {
39239 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39241 // this is an error condition!!!
39242 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39249 var choice = this.choices.createChild({
39251 cls: 'roo-select2-search-choice',
39260 cls: 'roo-select2-search-choice-close fa fa-times',
39265 }, this.searchField);
39267 var close = choice.select('a.roo-select2-search-choice-close', true).first();
39269 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
39277 this.inputEl().dom.value = '';
39282 onRemoveItem : function(e, _self, o)
39284 e.preventDefault();
39286 this.lastItem = Roo.apply([], this.item);
39288 var index = this.item.indexOf(o.data) * 1;
39291 Roo.log('not this item?!');
39295 this.item.splice(index, 1);
39300 this.fireEvent('remove', this, e);
39306 syncValue : function()
39308 if(!this.item.length){
39315 Roo.each(this.item, function(i){
39316 if(_this.valueField){
39317 value.push(i[_this.valueField]);
39324 this.value = value.join(',');
39326 if(this.hiddenField){
39327 this.hiddenField.dom.value = this.value;
39330 this.store.fireEvent("datachanged", this.store);
39335 clearItem : function()
39337 if(!this.multiple){
39343 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
39351 if(this.tickable && !Roo.isTouch){
39352 this.view.refresh();
39356 inputEl: function ()
39358 if(Roo.isIOS && this.useNativeIOS){
39359 return this.el.select('select.roo-ios-select', true).first();
39362 if(Roo.isTouch && this.mobileTouchView){
39363 return this.el.select('input.form-control',true).first();
39367 return this.searchField;
39370 return this.el.select('input.form-control',true).first();
39373 onTickableFooterButtonClick : function(e, btn, el)
39375 e.preventDefault();
39377 this.lastItem = Roo.apply([], this.item);
39379 if(btn && btn.name == 'cancel'){
39380 this.tickItems = Roo.apply([], this.item);
39389 Roo.each(this.tickItems, function(o){
39397 validate : function()
39399 var v = this.getRawValue();
39402 v = this.getValue();
39405 if(this.disabled || this.allowBlank || v.length){
39410 this.markInvalid();
39414 tickableInputEl : function()
39416 if(!this.tickable || !this.editable){
39417 return this.inputEl();
39420 return this.inputEl().select('.roo-select2-search-field-input', true).first();
39424 getAutoCreateTouchView : function()
39429 cls: 'form-group' //input-group
39435 type : this.inputType,
39436 cls : 'form-control x-combo-noedit',
39437 autocomplete: 'new-password',
39438 placeholder : this.placeholder || '',
39443 input.name = this.name;
39447 input.cls += ' input-' + this.size;
39450 if (this.disabled) {
39451 input.disabled = true;
39462 inputblock.cls += ' input-group';
39464 inputblock.cn.unshift({
39466 cls : 'input-group-addon',
39471 if(this.removable && !this.multiple){
39472 inputblock.cls += ' roo-removable';
39474 inputblock.cn.push({
39477 cls : 'roo-combo-removable-btn close'
39481 if(this.hasFeedback && !this.allowBlank){
39483 inputblock.cls += ' has-feedback';
39485 inputblock.cn.push({
39487 cls: 'glyphicon form-control-feedback'
39494 inputblock.cls += (this.before) ? '' : ' input-group';
39496 inputblock.cn.push({
39498 cls : 'input-group-addon',
39509 cls: 'form-hidden-field'
39523 cls: 'form-hidden-field'
39527 cls: 'roo-select2-choices',
39531 cls: 'roo-select2-search-field',
39544 cls: 'roo-select2-container input-group roo-touchview-PhoneInput ',
39550 if(!this.multiple && this.showToggleBtn){
39557 if (this.caret != false) {
39560 cls: 'fa fa-' + this.caret
39565 PhoneInput.cn.push({
39567 cls : 'input-group-addon btn dropdown-toggle',
39572 cls: 'PhoneInput-clear',
39586 PhoneInput.cls += ' roo-select2-container-multi';
39589 var align = this.labelAlign || this.parentLabelAlign();
39591 if (align ==='left' && this.fieldLabel.length) {
39596 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
39597 tooltip : 'This field is required'
39601 cls : 'control-label',
39602 html : this.fieldLabel
39613 var labelCfg = cfg.cn[1];
39614 var contentCfg = cfg.cn[2];
39617 if(this.indicatorpos == 'right'){
39621 cls : 'control-label',
39622 html : this.fieldLabel,
39626 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
39627 tooltip : 'This field is required'
39640 labelCfg = cfg.cn[0];
39641 contentCfg = cfg.cn[2];
39643 if(this.labelWidth > 12){
39644 labelCfg.style = "width: " + this.labelWidth + 'px';
39647 if(this.labelWidth < 13 && this.labelmd == 0){
39648 this.labelmd = this.labelWidth;
39651 if(this.labellg > 0){
39652 labelCfg.cls += ' col-lg-' + this.labellg;
39653 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
39656 if(this.labelmd > 0){
39657 labelCfg.cls += ' col-md-' + this.labelmd;
39658 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
39661 if(this.labelsm > 0){
39662 labelCfg.cls += ' col-sm-' + this.labelsm;
39663 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
39666 if(this.labelxs > 0){
39667 labelCfg.cls += ' col-xs-' + this.labelxs;
39668 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
39672 } else if ( this.fieldLabel.length) {
39676 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
39677 tooltip : 'This field is required'
39681 cls : 'control-label',
39682 html : this.fieldLabel
39693 if(this.indicatorpos == 'right'){
39697 cls : 'control-label',
39698 html : this.fieldLabel,
39702 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
39703 tooltip : 'This field is required'
39716 cfg.cn = PhoneInput;
39720 var settings = this;
39722 ['xs','sm','md','lg'].map(function(size){
39723 if (settings[size]) {
39724 cfg.cls += ' col-' + size + '-' + settings[size];
39731 initTouchView : function()
39733 this.renderTouchView();
39735 this.touchViewEl.on('scroll', function(){
39736 this.el.dom.scrollTop = 0;
39739 this.originalValue = this.getValue();
39741 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
39743 this.inputEl().on("click", this.showTouchView, this);
39744 if (this.triggerEl) {
39745 this.triggerEl.on("click", this.showTouchView, this);
39749 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
39750 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
39752 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
39754 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
39755 this.store.on('load', this.onTouchViewLoad, this);
39756 this.store.on('loadexception', this.onTouchViewLoadException, this);
39758 if(this.hiddenName){
39760 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
39762 this.hiddenField.dom.value =
39763 this.hiddenValue !== undefined ? this.hiddenValue :
39764 this.value !== undefined ? this.value : '';
39766 this.el.dom.removeAttribute('name');
39767 this.hiddenField.dom.setAttribute('name', this.hiddenName);
39771 this.choices = this.el.select('ul.roo-select2-choices', true).first();
39772 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
39775 if(this.removable && !this.multiple){
39776 var close = this.closeTriggerEl();
39778 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
39779 close.on('click', this.removeBtnClick, this, close);
39783 * fix the bug in Safari iOS8
39785 this.inputEl().on("focus", function(e){
39786 document.activeElement.blur();
39794 renderTouchView : function()
39796 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.PhoneInput.touchViewTemplate);
39797 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
39799 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
39800 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
39802 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
39803 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
39804 this.touchViewBodyEl.setStyle('overflow', 'auto');
39806 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
39807 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
39809 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
39810 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
39814 showTouchView : function()
39820 this.touchViewHeaderEl.hide();
39822 if(this.modalTitle.length){
39823 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
39824 this.touchViewHeaderEl.show();
39827 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
39828 this.touchViewEl.show();
39830 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
39831 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
39832 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
39834 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
39836 if(this.modalTitle.length){
39837 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
39840 this.touchViewBodyEl.setHeight(bodyHeight);
39844 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
39846 this.touchViewEl.addClass('in');
39849 this.doTouchViewQuery();
39853 hideTouchView : function()
39855 this.touchViewEl.removeClass('in');
39859 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
39861 this.touchViewEl.setStyle('display', 'none');
39866 setTouchViewValue : function()
39873 Roo.each(this.tickItems, function(o){
39878 this.hideTouchView();
39881 doTouchViewQuery : function()
39890 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
39894 if(!this.alwaysQuery || this.mode == 'local'){
39895 this.onTouchViewLoad();
39902 onTouchViewBeforeLoad : function(combo,opts)
39908 onTouchViewLoad : function()
39910 if(this.store.getCount() < 1){
39911 this.onTouchViewEmptyResults();
39915 this.clearTouchView();
39917 var rawValue = this.getRawValue();
39919 var template = (this.multiple) ? Roo.bootstrap.PhoneInput.listItemCheckbox : Roo.bootstrap.PhoneInput.listItemRadio;
39921 this.tickItems = [];
39923 this.store.data.each(function(d, rowIndex){
39924 var row = this.touchViewListGroup.createChild(template);
39926 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
39927 row.addClass(d.data.cls);
39930 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
39933 html : d.data[this.displayField]
39936 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
39937 row.select('.roo-PhoneInput-list-group-item-value', true).first().dom.innerHTML = cfg.html;
39940 row.removeClass('selected');
39941 if(!this.multiple && this.valueField &&
39942 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
39945 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
39946 row.addClass('selected');
39949 if(this.multiple && this.valueField &&
39950 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
39954 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
39955 this.tickItems.push(d.data);
39958 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
39962 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-PhoneInput-list-group-item-box > input:checked', true).first();
39964 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
39966 if(this.modalTitle.length){
39967 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
39970 var listHeight = this.touchViewListGroup.getHeight();
39974 if(firstChecked && listHeight > bodyHeight){
39975 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
39980 onTouchViewLoadException : function()
39982 this.hideTouchView();
39985 onTouchViewEmptyResults : function()
39987 this.clearTouchView();
39989 this.touchViewListGroup.createChild(Roo.bootstrap.PhoneInput.emptyResult);
39991 this.touchViewListGroup.select('.roo-PhoneInput-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
39995 clearTouchView : function()
39997 this.touchViewListGroup.dom.innerHTML = '';
40000 onTouchViewClick : function(e, el, o)
40002 e.preventDefault();
40005 var rowIndex = o.rowIndex;
40007 var r = this.store.getAt(rowIndex);
40009 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
40011 if(!this.multiple){
40012 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-PhoneInput-list-group-item-box > input:checked', true).elements, function(c){
40013 c.dom.removeAttribute('checked');
40016 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
40018 this.setFromData(r.data);
40020 var close = this.closeTriggerEl();
40026 this.hideTouchView();
40028 this.fireEvent('select', this, r, rowIndex);
40033 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
40034 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().dom.removeAttribute('checked');
40035 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
40039 row.select('.roo-PhoneInput-list-group-item-box > input', true).first().attr('checked', true);
40040 this.addItem(r.data);
40041 this.tickItems.push(r.data);
40045 getAutoCreateNativeIOS : function()
40048 cls: 'form-group' //input-group,
40053 cls : 'roo-ios-select'
40057 PhoneInput.name = this.name;
40060 if (this.disabled) {
40061 PhoneInput.disabled = true;
40064 var settings = this;
40066 ['xs','sm','md','lg'].map(function(size){
40067 if (settings[size]) {
40068 cfg.cls += ' col-' + size + '-' + settings[size];
40072 cfg.cn = PhoneInput;
40078 initIOSView : function()
40080 this.store.on('load', this.onIOSViewLoad, this);
40085 onIOSViewLoad : function()
40087 if(this.store.getCount() < 1){
40091 this.clearIOSView();
40093 if(this.allowBlank) {
40095 var default_text = '-- SELECT --';
40097 var opt = this.inputEl().createChild({
40100 html : default_text
40104 o[this.valueField] = 0;
40105 o[this.displayField] = default_text;
40107 this.ios_options.push({
40114 this.store.data.each(function(d, rowIndex){
40118 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
40119 html = d.data[this.displayField];
40124 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
40125 value = d.data[this.valueField];
40134 if(this.value == d.data[this.valueField]){
40135 option['selected'] = true;
40138 var opt = this.inputEl().createChild(option);
40140 this.ios_options.push({
40147 this.inputEl().on('change', function(){
40148 this.fireEvent('select', this);
40153 clearIOSView: function()
40155 this.inputEl().dom.innerHTML = '';
40157 this.ios_options = [];
40160 setIOSValue: function(v)
40164 if(!this.ios_options){
40168 Roo.each(this.ios_options, function(opts){
40170 opts.el.dom.removeAttribute('selected');
40172 if(opts.data[this.valueField] != v){
40176 opts.el.dom.setAttribute('selected', true);
40182 * @cfg {Boolean} grow
40186 * @cfg {Number} growMin
40190 * @cfg {Number} growMax
40199 Roo.apply(Roo.bootstrap.PhoneInput, {
40203 cls: 'modal-header',
40225 cls: 'list-group-item',
40229 cls: 'roo-PhoneInput-list-group-item-value'
40233 cls: 'roo-PhoneInput-list-group-item-box pull-xs-right radio-inline radio radio-info',
40247 listItemCheckbox : {
40249 cls: 'list-group-item',
40253 cls: 'roo-PhoneInput-list-group-item-value'
40257 cls: 'roo-PhoneInput-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
40273 cls: 'alert alert-danger roo-PhoneInput-touch-view-empty-result'
40278 cls: 'modal-footer',
40286 cls: 'col-xs-6 text-left',
40289 cls: 'btn btn-danger roo-touch-view-cancel',
40295 cls: 'col-xs-6 text-right',
40298 cls: 'btn btn-success roo-touch-view-ok',