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 // if parent was disabled, then do not try and create the children..
251 if(!this[cntr](true)){
256 cn = Roo.factory(tree);
258 cn.parentType = this.xtype; //??
259 cn.parentId = this.id;
261 var build_from_html = Roo.XComponent.build_from_html;
264 // does the container contain child eleemnts with 'xtype' attributes.
265 // that match this xtype..
266 // note - when we render we create these as well..
267 // so we should check to see if body has xtype set.
268 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
270 var self_cntr_el = Roo.get(this[cntr](false));
271 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
273 //Roo.log(Roo.XComponent.build_from_html);
274 //Roo.log("got echild:");
277 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
278 // and are not displayed -this causes this to use up the wrong element when matching.
279 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
282 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
283 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
289 //echild.dom.removeAttribute('xtype');
291 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
292 Roo.debug && Roo.log(self_cntr_el);
293 Roo.debug && Roo.log(echild);
294 Roo.debug && Roo.log(cn);
300 // if object has flexy:if - then it may or may not be rendered.
301 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
302 // skip a flexy if element.
303 Roo.debug && Roo.log('skipping render');
304 Roo.debug && Roo.log(tree);
306 Roo.debug && Roo.log('skipping all children');
307 skip_children = true;
312 // actually if flexy:foreach is found, we really want to create
313 // multiple copies here...
315 //Roo.log(this[cntr]());
316 // some elements do not have render methods.. like the layouts...
318 if(this[cntr](true) === false){
323 cn.render && cn.render(this[cntr](true));
326 // then add the element..
333 if (typeof (tree.menu) != 'undefined') {
334 tree.menu.parentType = cn.xtype;
335 tree.menu.triggerEl = cn.el;
336 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
340 if (!tree.items || !tree.items.length) {
342 //Roo.log(["no children", this]);
347 var items = tree.items;
350 //Roo.log(items.length);
352 if (!skip_children) {
353 for(var i =0;i < items.length;i++) {
354 // Roo.log(['add child', items[i]]);
355 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
361 //Roo.log("fire childrenrendered");
363 cn.fireEvent('childrenrendered', this);
368 * Show a component - removes 'hidden' class
376 this.getEl().removeClass('hidden');
380 * Hide a component - adds 'hidden' class
384 if(!this.getEl() || this.getEl().hasClass('hidden')){
388 this.getEl().addClass('hidden');
401 * @class Roo.bootstrap.Body
402 * @extends Roo.bootstrap.Component
403 * Bootstrap Body class
407 * @param {Object} config The config object
410 Roo.bootstrap.Body = function(config){
412 config = config || {};
414 Roo.bootstrap.Body.superclass.constructor.call(this, config);
415 this.el = Roo.get(config.el ? config.el : document.body );
416 if (this.cls && this.cls.length) {
417 Roo.get(document.body).addClass(this.cls);
421 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
423 is_body : true,// just to make sure it's constructed?
428 onRender : function(ct, position)
430 /* Roo.log("Roo.bootstrap.Body - onRender");
431 if (this.cls && this.cls.length) {
432 Roo.get(document.body).addClass(this.cls);
451 * @class Roo.bootstrap.ButtonGroup
452 * @extends Roo.bootstrap.Component
453 * Bootstrap ButtonGroup class
454 * @cfg {String} size lg | sm | xs (default empty normal)
455 * @cfg {String} align vertical | justified (default none)
456 * @cfg {String} direction up | down (default down)
457 * @cfg {Boolean} toolbar false | true
458 * @cfg {Boolean} btn true | false
463 * @param {Object} config The config object
466 Roo.bootstrap.ButtonGroup = function(config){
467 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
470 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
478 getAutoCreate : function(){
484 cfg.html = this.html || cfg.html;
495 if (['vertical','justified'].indexOf(this.align)!==-1) {
496 cfg.cls = 'btn-group-' + this.align;
498 if (this.align == 'justified') {
499 console.log(this.items);
503 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
504 cfg.cls += ' btn-group-' + this.size;
507 if (this.direction == 'up') {
508 cfg.cls += ' dropup' ;
524 * @class Roo.bootstrap.Button
525 * @extends Roo.bootstrap.Component
526 * Bootstrap Button class
527 * @cfg {String} html The button content
528 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
529 * @cfg {String} size ( lg | sm | xs)
530 * @cfg {String} tag ( a | input | submit)
531 * @cfg {String} href empty or href
532 * @cfg {Boolean} disabled default false;
533 * @cfg {Boolean} isClose default false;
534 * @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)
535 * @cfg {String} badge text for badge
536 * @cfg {String} theme default
537 * @cfg {Boolean} inverse
538 * @cfg {Boolean} toggle
539 * @cfg {String} ontext text for on toggle state
540 * @cfg {String} offtext text for off toggle state
541 * @cfg {Boolean} defaulton
542 * @cfg {Boolean} preventDefault default true
543 * @cfg {Boolean} removeClass remove the standard class..
544 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
547 * Create a new button
548 * @param {Object} config The config object
552 Roo.bootstrap.Button = function(config){
553 Roo.bootstrap.Button.superclass.constructor.call(this, config);
554 this.weightClass = ["btn-default",
566 * When a butotn is pressed
567 * @param {Roo.bootstrap.Button} this
568 * @param {Roo.EventObject} e
573 * After the button has been toggles
574 * @param {Roo.EventObject} e
575 * @param {boolean} pressed (also available as button.pressed)
581 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
599 preventDefault: true,
608 getAutoCreate : function(){
616 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
617 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
622 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
624 if (this.toggle == true) {
627 cls: 'slider-frame roo-button',
632 'data-off-text':'OFF',
633 cls: 'slider-button',
639 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640 cfg.cls += ' '+this.weight;
649 cfg["aria-hidden"] = true;
651 cfg.html = "×";
657 if (this.theme==='default') {
658 cfg.cls = 'btn roo-button';
660 //if (this.parentType != 'Navbar') {
661 this.weight = this.weight.length ? this.weight : 'default';
663 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
665 cfg.cls += ' btn-' + this.weight;
667 } else if (this.theme==='glow') {
670 cfg.cls = 'btn-glow roo-button';
672 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
674 cfg.cls += ' ' + this.weight;
680 this.cls += ' inverse';
685 cfg.cls += ' active';
689 cfg.disabled = 'disabled';
693 Roo.log('changing to ul' );
695 this.glyphicon = 'caret';
698 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
700 //gsRoo.log(this.parentType);
701 if (this.parentType === 'Navbar' && !this.parent().bar) {
702 Roo.log('changing to li?');
711 href : this.href || '#'
714 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
715 cfg.cls += ' dropdown';
722 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
724 if (this.glyphicon) {
725 cfg.html = ' ' + cfg.html;
730 cls: 'glyphicon glyphicon-' + this.glyphicon
740 // cfg.cls='btn roo-button';
744 var value = cfg.html;
749 cls: 'glyphicon glyphicon-' + this.glyphicon,
768 cfg.cls += ' dropdown';
769 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
772 if (cfg.tag !== 'a' && this.href !== '') {
773 throw "Tag must be a to set href.";
774 } else if (this.href.length > 0) {
775 cfg.href = this.href;
778 if(this.removeClass){
783 cfg.target = this.target;
788 initEvents: function() {
789 // Roo.log('init events?');
790 // Roo.log(this.el.dom);
793 if (typeof (this.menu) != 'undefined') {
794 this.menu.parentType = this.xtype;
795 this.menu.triggerEl = this.el;
796 this.addxtype(Roo.apply({}, this.menu));
800 if (this.el.hasClass('roo-button')) {
801 this.el.on('click', this.onClick, this);
803 this.el.select('.roo-button').on('click', this.onClick, this);
806 if(this.removeClass){
807 this.el.on('click', this.onClick, this);
810 this.el.enableDisplayMode();
813 onClick : function(e)
820 Roo.log('button on click ');
821 if(this.preventDefault){
824 if (this.pressed === true || this.pressed === false) {
825 this.pressed = !this.pressed;
826 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
827 this.fireEvent('toggle', this, e, this.pressed);
831 this.fireEvent('click', this, e);
835 * Enables this button
839 this.disabled = false;
840 this.el.removeClass('disabled');
844 * Disable this button
848 this.disabled = true;
849 this.el.addClass('disabled');
852 * sets the active state on/off,
853 * @param {Boolean} state (optional) Force a particular state
855 setActive : function(v) {
857 this.el[v ? 'addClass' : 'removeClass']('active');
860 * toggles the current active state
862 toggleActive : function()
864 var active = this.el.hasClass('active');
865 this.setActive(!active);
869 setText : function(str)
871 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
875 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
886 setWeight : function(str)
888 this.el.removeClass(this.weightClass);
889 this.el.addClass('btn-' + str);
903 * @class Roo.bootstrap.Column
904 * @extends Roo.bootstrap.Component
905 * Bootstrap Column class
906 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
907 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
908 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
909 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
910 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
911 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
912 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
913 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
916 * @cfg {Boolean} hidden (true|false) hide the element
917 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
918 * @cfg {String} fa (ban|check|...) font awesome icon
919 * @cfg {Number} fasize (1|2|....) font awsome size
921 * @cfg {String} icon (info-sign|check|...) glyphicon name
923 * @cfg {String} html content of column.
926 * Create a new Column
927 * @param {Object} config The config object
930 Roo.bootstrap.Column = function(config){
931 Roo.bootstrap.Column.superclass.constructor.call(this, config);
934 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
952 getAutoCreate : function(){
953 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
961 ['xs','sm','md','lg'].map(function(size){
962 //Roo.log( size + ':' + settings[size]);
964 if (settings[size+'off'] !== false) {
965 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
968 if (settings[size] === false) {
972 if (!settings[size]) { // 0 = hidden
973 cfg.cls += ' hidden-' + size;
976 cfg.cls += ' col-' + size + '-' + settings[size];
981 cfg.cls += ' hidden';
984 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
985 cfg.cls +=' alert alert-' + this.alert;
989 if (this.html.length) {
990 cfg.html = this.html;
994 if (this.fasize > 1) {
995 fasize = ' fa-' + this.fasize + 'x';
997 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1002 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1021 * @class Roo.bootstrap.Container
1022 * @extends Roo.bootstrap.Component
1023 * Bootstrap Container class
1024 * @cfg {Boolean} jumbotron is it a jumbotron element
1025 * @cfg {String} html content of element
1026 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1027 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1028 * @cfg {String} header content of header (for panel)
1029 * @cfg {String} footer content of footer (for panel)
1030 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1031 * @cfg {String} tag (header|aside|section) type of HTML tag.
1032 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1033 * @cfg {String} fa font awesome icon
1034 * @cfg {String} icon (info-sign|check|...) glyphicon name
1035 * @cfg {Boolean} hidden (true|false) hide the element
1036 * @cfg {Boolean} expandable (true|false) default false
1037 * @cfg {Boolean} expanded (true|false) default true
1038 * @cfg {String} rheader contet on the right of header
1039 * @cfg {Boolean} clickable (true|false) default false
1043 * Create a new Container
1044 * @param {Object} config The config object
1047 Roo.bootstrap.Container = function(config){
1048 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1054 * After the panel has been expand
1056 * @param {Roo.bootstrap.Container} this
1061 * After the panel has been collapsed
1063 * @param {Roo.bootstrap.Container} this
1068 * When a element is chick
1069 * @param {Roo.bootstrap.Container} this
1070 * @param {Roo.EventObject} e
1076 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1094 getChildContainer : function() {
1100 if (this.panel.length) {
1101 return this.el.select('.panel-body',true).first();
1108 getAutoCreate : function(){
1111 tag : this.tag || 'div',
1115 if (this.jumbotron) {
1116 cfg.cls = 'jumbotron';
1121 // - this is applied by the parent..
1123 // cfg.cls = this.cls + '';
1126 if (this.sticky.length) {
1128 var bd = Roo.get(document.body);
1129 if (!bd.hasClass('bootstrap-sticky')) {
1130 bd.addClass('bootstrap-sticky');
1131 Roo.select('html',true).setStyle('height', '100%');
1134 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1138 if (this.well.length) {
1139 switch (this.well) {
1142 cfg.cls +=' well well-' +this.well;
1151 cfg.cls += ' hidden';
1155 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1156 cfg.cls +=' alert alert-' + this.alert;
1161 if (this.panel.length) {
1162 cfg.cls += ' panel panel-' + this.panel;
1164 if (this.header.length) {
1168 if(this.expandable){
1170 cfg.cls = cfg.cls + ' expandable';
1174 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1182 cls : 'panel-title',
1183 html : (this.expandable ? ' ' : '') + this.header
1187 cls: 'panel-header-right',
1193 cls : 'panel-heading',
1194 style : this.expandable ? 'cursor: pointer' : '',
1202 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1207 if (this.footer.length) {
1209 cls : 'panel-footer',
1218 body.html = this.html || cfg.html;
1219 // prefix with the icons..
1221 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1224 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1229 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1230 cfg.cls = 'container';
1236 initEvents: function()
1238 if(this.expandable){
1239 var headerEl = this.headerEl();
1242 headerEl.on('click', this.onToggleClick, this);
1247 this.el.on('click', this.onClick, this);
1252 onToggleClick : function()
1254 var headerEl = this.headerEl();
1270 if(this.fireEvent('expand', this)) {
1272 this.expanded = true;
1274 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1276 this.el.select('.panel-body',true).first().removeClass('hide');
1278 var toggleEl = this.toggleEl();
1284 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1289 collapse : function()
1291 if(this.fireEvent('collapse', this)) {
1293 this.expanded = false;
1295 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1296 this.el.select('.panel-body',true).first().addClass('hide');
1298 var toggleEl = this.toggleEl();
1304 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1308 toggleEl : function()
1310 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1314 return this.el.select('.panel-heading .fa',true).first();
1317 headerEl : function()
1319 if(!this.el || !this.panel.length || !this.header.length){
1323 return this.el.select('.panel-heading',true).first()
1328 if(!this.el || !this.panel.length){
1332 return this.el.select('.panel-body',true).first()
1335 titleEl : function()
1337 if(!this.el || !this.panel.length || !this.header.length){
1341 return this.el.select('.panel-title',true).first();
1344 setTitle : function(v)
1346 var titleEl = this.titleEl();
1352 titleEl.dom.innerHTML = v;
1355 getTitle : function()
1358 var titleEl = this.titleEl();
1364 return titleEl.dom.innerHTML;
1367 setRightTitle : function(v)
1369 var t = this.el.select('.panel-header-right',true).first();
1375 t.dom.innerHTML = v;
1378 onClick : function(e)
1382 this.fireEvent('click', this, e);
1385 allChildren : function()
1387 var r=new Roo.util.MixedCollection(false, function(o){
1388 return o.id || (o.id = Roo.id());
1390 var iter = function(el) {
1397 Roo.each(el.items,function(e) {
1406 checkEmpty : function()
1408 var items = this.allChildren();
1411 items.each(function(f){
1412 if(f.el.isVisible()) {
1431 * @class Roo.bootstrap.Img
1432 * @extends Roo.bootstrap.Component
1433 * Bootstrap Img class
1434 * @cfg {Boolean} imgResponsive false | true
1435 * @cfg {String} border rounded | circle | thumbnail
1436 * @cfg {String} src image source
1437 * @cfg {String} alt image alternative text
1438 * @cfg {String} href a tag href
1439 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1440 * @cfg {String} xsUrl xs image source
1441 * @cfg {String} smUrl sm image source
1442 * @cfg {String} mdUrl md image source
1443 * @cfg {String} lgUrl lg image source
1446 * Create a new Input
1447 * @param {Object} config The config object
1450 Roo.bootstrap.Img = function(config){
1451 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1457 * The img click event for the img.
1458 * @param {Roo.EventObject} e
1464 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1466 imgResponsive: true,
1476 getAutoCreate : function()
1478 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1479 return this.createSingleImg();
1484 cls: 'roo-image-responsive-group',
1489 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1491 if(!_this[size + 'Url']){
1497 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1498 html: _this.html || cfg.html,
1499 src: _this[size + 'Url']
1502 img.cls += ' roo-image-responsive-' + size;
1504 var s = ['xs', 'sm', 'md', 'lg'];
1506 s.splice(s.indexOf(size), 1);
1508 Roo.each(s, function(ss){
1509 img.cls += ' hidden-' + ss;
1512 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1513 cfg.cls += ' img-' + _this.border;
1517 cfg.alt = _this.alt;
1530 a.target = _this.target;
1534 cfg.cn.push((_this.href) ? a : img);
1541 createSingleImg : function()
1545 cls: (this.imgResponsive) ? 'img-responsive' : '',
1547 src : 'about:blank' // just incase src get's set to undefined?!?
1550 cfg.html = this.html || cfg.html;
1552 cfg.src = this.src || cfg.src;
1554 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1555 cfg.cls += ' img-' + this.border;
1572 a.target = this.target;
1577 return (this.href) ? a : cfg;
1580 initEvents: function()
1583 this.el.on('click', this.onClick, this);
1588 onClick : function(e)
1590 Roo.log('img onclick');
1591 this.fireEvent('click', this, e);
1594 * Sets the url of the image - used to update it
1595 * @param {String} url the url of the image
1598 setSrc : function(url)
1602 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1603 this.el.dom.src = url;
1607 this.el.select('img', true).first().dom.src = url;
1623 * @class Roo.bootstrap.Link
1624 * @extends Roo.bootstrap.Component
1625 * Bootstrap Link Class
1626 * @cfg {String} alt image alternative text
1627 * @cfg {String} href a tag href
1628 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1629 * @cfg {String} html the content of the link.
1630 * @cfg {String} anchor name for the anchor link
1631 * @cfg {String} fa - favicon
1633 * @cfg {Boolean} preventDefault (true | false) default false
1637 * Create a new Input
1638 * @param {Object} config The config object
1641 Roo.bootstrap.Link = function(config){
1642 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1648 * The img click event for the img.
1649 * @param {Roo.EventObject} e
1655 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1659 preventDefault: false,
1665 getAutoCreate : function()
1667 var html = this.html || '';
1669 if (this.fa !== false) {
1670 html = '<i class="fa fa-' + this.fa + '"></i>';
1675 // anchor's do not require html/href...
1676 if (this.anchor === false) {
1678 cfg.href = this.href || '#';
1680 cfg.name = this.anchor;
1681 if (this.html !== false || this.fa !== false) {
1684 if (this.href !== false) {
1685 cfg.href = this.href;
1689 if(this.alt !== false){
1694 if(this.target !== false) {
1695 cfg.target = this.target;
1701 initEvents: function() {
1703 if(!this.href || this.preventDefault){
1704 this.el.on('click', this.onClick, this);
1708 onClick : function(e)
1710 if(this.preventDefault){
1713 //Roo.log('img onclick');
1714 this.fireEvent('click', this, e);
1727 * @class Roo.bootstrap.Header
1728 * @extends Roo.bootstrap.Component
1729 * Bootstrap Header class
1730 * @cfg {String} html content of header
1731 * @cfg {Number} level (1|2|3|4|5|6) default 1
1734 * Create a new Header
1735 * @param {Object} config The config object
1739 Roo.bootstrap.Header = function(config){
1740 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1743 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1751 getAutoCreate : function(){
1756 tag: 'h' + (1 *this.level),
1757 html: this.html || ''
1769 * Ext JS Library 1.1.1
1770 * Copyright(c) 2006-2007, Ext JS, LLC.
1772 * Originally Released Under LGPL - original licence link has changed is not relivant.
1775 * <script type="text/javascript">
1779 * @class Roo.bootstrap.MenuMgr
1780 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1783 Roo.bootstrap.MenuMgr = function(){
1784 var menus, active, groups = {}, attached = false, lastShow = new Date();
1786 // private - called when first menu is created
1789 active = new Roo.util.MixedCollection();
1790 Roo.get(document).addKeyListener(27, function(){
1791 if(active.length > 0){
1799 if(active && active.length > 0){
1800 var c = active.clone();
1810 if(active.length < 1){
1811 Roo.get(document).un("mouseup", onMouseDown);
1819 var last = active.last();
1820 lastShow = new Date();
1823 Roo.get(document).on("mouseup", onMouseDown);
1828 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1829 m.parentMenu.activeChild = m;
1830 }else if(last && last.isVisible()){
1831 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1836 function onBeforeHide(m){
1838 m.activeChild.hide();
1840 if(m.autoHideTimer){
1841 clearTimeout(m.autoHideTimer);
1842 delete m.autoHideTimer;
1847 function onBeforeShow(m){
1848 var pm = m.parentMenu;
1849 if(!pm && !m.allowOtherMenus){
1851 }else if(pm && pm.activeChild && active != m){
1852 pm.activeChild.hide();
1856 // private this should really trigger on mouseup..
1857 function onMouseDown(e){
1858 Roo.log("on Mouse Up");
1860 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1861 Roo.log("MenuManager hideAll");
1870 function onBeforeCheck(mi, state){
1872 var g = groups[mi.group];
1873 for(var i = 0, l = g.length; i < l; i++){
1875 g[i].setChecked(false);
1884 * Hides all menus that are currently visible
1886 hideAll : function(){
1891 register : function(menu){
1895 menus[menu.id] = menu;
1896 menu.on("beforehide", onBeforeHide);
1897 menu.on("hide", onHide);
1898 menu.on("beforeshow", onBeforeShow);
1899 menu.on("show", onShow);
1901 if(g && menu.events["checkchange"]){
1905 groups[g].push(menu);
1906 menu.on("checkchange", onCheck);
1911 * Returns a {@link Roo.menu.Menu} object
1912 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1913 * be used to generate and return a new Menu instance.
1915 get : function(menu){
1916 if(typeof menu == "string"){ // menu id
1918 }else if(menu.events){ // menu instance
1921 /*else if(typeof menu.length == 'number'){ // array of menu items?
1922 return new Roo.bootstrap.Menu({items:menu});
1923 }else{ // otherwise, must be a config
1924 return new Roo.bootstrap.Menu(menu);
1931 unregister : function(menu){
1932 delete menus[menu.id];
1933 menu.un("beforehide", onBeforeHide);
1934 menu.un("hide", onHide);
1935 menu.un("beforeshow", onBeforeShow);
1936 menu.un("show", onShow);
1938 if(g && menu.events["checkchange"]){
1939 groups[g].remove(menu);
1940 menu.un("checkchange", onCheck);
1945 registerCheckable : function(menuItem){
1946 var g = menuItem.group;
1951 groups[g].push(menuItem);
1952 menuItem.on("beforecheckchange", onBeforeCheck);
1957 unregisterCheckable : function(menuItem){
1958 var g = menuItem.group;
1960 groups[g].remove(menuItem);
1961 menuItem.un("beforecheckchange", onBeforeCheck);
1973 * @class Roo.bootstrap.Menu
1974 * @extends Roo.bootstrap.Component
1975 * Bootstrap Menu class - container for MenuItems
1976 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1977 * @cfg {bool} hidden if the menu should be hidden when rendered.
1978 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1979 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1983 * @param {Object} config The config object
1987 Roo.bootstrap.Menu = function(config){
1988 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1989 if (this.registerMenu && this.type != 'treeview') {
1990 Roo.bootstrap.MenuMgr.register(this);
1995 * Fires before this menu is displayed
1996 * @param {Roo.menu.Menu} this
2001 * Fires before this menu is hidden
2002 * @param {Roo.menu.Menu} this
2007 * Fires after this menu is displayed
2008 * @param {Roo.menu.Menu} this
2013 * Fires after this menu is hidden
2014 * @param {Roo.menu.Menu} this
2019 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2020 * @param {Roo.menu.Menu} this
2021 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2022 * @param {Roo.EventObject} e
2027 * Fires when the mouse is hovering over this menu
2028 * @param {Roo.menu.Menu} this
2029 * @param {Roo.EventObject} e
2030 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2035 * Fires when the mouse exits this menu
2036 * @param {Roo.menu.Menu} this
2037 * @param {Roo.EventObject} e
2038 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2043 * Fires when a menu item contained in this menu is clicked
2044 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2045 * @param {Roo.EventObject} e
2049 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2052 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2056 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2059 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2061 registerMenu : true,
2063 menuItems :false, // stores the menu items..
2073 getChildContainer : function() {
2077 getAutoCreate : function(){
2079 //if (['right'].indexOf(this.align)!==-1) {
2080 // cfg.cn[1].cls += ' pull-right'
2086 cls : 'dropdown-menu' ,
2087 style : 'z-index:1000'
2091 if (this.type === 'submenu') {
2092 cfg.cls = 'submenu active';
2094 if (this.type === 'treeview') {
2095 cfg.cls = 'treeview-menu';
2100 initEvents : function() {
2102 // Roo.log("ADD event");
2103 // Roo.log(this.triggerEl.dom);
2105 this.triggerEl.on('click', this.onTriggerClick, this);
2107 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2109 this.triggerEl.addClass('dropdown-toggle');
2112 this.el.on('touchstart' , this.onTouch, this);
2114 this.el.on('click' , this.onClick, this);
2116 this.el.on("mouseover", this.onMouseOver, this);
2117 this.el.on("mouseout", this.onMouseOut, this);
2121 findTargetItem : function(e)
2123 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2127 //Roo.log(t); Roo.log(t.id);
2129 //Roo.log(this.menuitems);
2130 return this.menuitems.get(t.id);
2132 //return this.items.get(t.menuItemId);
2138 onTouch : function(e)
2140 Roo.log("menu.onTouch");
2141 //e.stopEvent(); this make the user popdown broken
2145 onClick : function(e)
2147 Roo.log("menu.onClick");
2149 var t = this.findTargetItem(e);
2150 if(!t || t.isContainer){
2155 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2156 if(t == this.activeItem && t.shouldDeactivate(e)){
2157 this.activeItem.deactivate();
2158 delete this.activeItem;
2162 this.setActiveItem(t, true);
2170 Roo.log('pass click event');
2174 this.fireEvent("click", this, t, e);
2178 if(!t.href.length || t.href == '#'){
2179 (function() { _this.hide(); }).defer(100);
2184 onMouseOver : function(e){
2185 var t = this.findTargetItem(e);
2188 // if(t.canActivate && !t.disabled){
2189 // this.setActiveItem(t, true);
2193 this.fireEvent("mouseover", this, e, t);
2195 isVisible : function(){
2196 return !this.hidden;
2198 onMouseOut : function(e){
2199 var t = this.findTargetItem(e);
2202 // if(t == this.activeItem && t.shouldDeactivate(e)){
2203 // this.activeItem.deactivate();
2204 // delete this.activeItem;
2207 this.fireEvent("mouseout", this, e, t);
2212 * Displays this menu relative to another element
2213 * @param {String/HTMLElement/Roo.Element} element The element to align to
2214 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2215 * the element (defaults to this.defaultAlign)
2216 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2218 show : function(el, pos, parentMenu){
2219 this.parentMenu = parentMenu;
2223 this.fireEvent("beforeshow", this);
2224 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2227 * Displays this menu at a specific xy position
2228 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2229 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2231 showAt : function(xy, parentMenu, /* private: */_e){
2232 this.parentMenu = parentMenu;
2237 this.fireEvent("beforeshow", this);
2238 //xy = this.el.adjustForConstraints(xy);
2242 this.hideMenuItems();
2243 this.hidden = false;
2244 this.triggerEl.addClass('open');
2246 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2247 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2250 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2255 this.fireEvent("show", this);
2261 this.doFocus.defer(50, this);
2265 doFocus : function(){
2267 this.focusEl.focus();
2272 * Hides this menu and optionally all parent menus
2273 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2275 hide : function(deep)
2278 this.hideMenuItems();
2279 if(this.el && this.isVisible()){
2280 this.fireEvent("beforehide", this);
2281 if(this.activeItem){
2282 this.activeItem.deactivate();
2283 this.activeItem = null;
2285 this.triggerEl.removeClass('open');;
2287 this.fireEvent("hide", this);
2289 if(deep === true && this.parentMenu){
2290 this.parentMenu.hide(true);
2294 onTriggerClick : function(e)
2296 Roo.log('trigger click');
2298 var target = e.getTarget();
2300 Roo.log(target.nodeName.toLowerCase());
2302 if(target.nodeName.toLowerCase() === 'i'){
2308 onTriggerPress : function(e)
2310 Roo.log('trigger press');
2311 //Roo.log(e.getTarget());
2312 // Roo.log(this.triggerEl.dom);
2314 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2315 var pel = Roo.get(e.getTarget());
2316 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2317 Roo.log('is treeview or dropdown?');
2321 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2325 if (this.isVisible()) {
2330 this.show(this.triggerEl, false, false);
2333 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2340 hideMenuItems : function()
2342 Roo.log("hide Menu Items");
2346 //$(backdrop).remove()
2347 this.el.select('.open',true).each(function(aa) {
2349 aa.removeClass('open');
2350 //var parent = getParent($(this))
2351 //var relatedTarget = { relatedTarget: this }
2353 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2354 //if (e.isDefaultPrevented()) return
2355 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2358 addxtypeChild : function (tree, cntr) {
2359 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2361 this.menuitems.add(comp);
2373 this.getEl().dom.innerHTML = '';
2374 this.menuitems.clear();
2388 * @class Roo.bootstrap.MenuItem
2389 * @extends Roo.bootstrap.Component
2390 * Bootstrap MenuItem class
2391 * @cfg {String} html the menu label
2392 * @cfg {String} href the link
2393 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2394 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2395 * @cfg {Boolean} active used on sidebars to highlight active itesm
2396 * @cfg {String} fa favicon to show on left of menu item.
2397 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2401 * Create a new MenuItem
2402 * @param {Object} config The config object
2406 Roo.bootstrap.MenuItem = function(config){
2407 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2412 * The raw click event for the entire grid.
2413 * @param {Roo.bootstrap.MenuItem} this
2414 * @param {Roo.EventObject} e
2420 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2424 preventDefault: false,
2425 isContainer : false,
2429 getAutoCreate : function(){
2431 if(this.isContainer){
2434 cls: 'dropdown-menu-item'
2448 if (this.fa !== false) {
2451 cls : 'fa fa-' + this.fa
2460 cls: 'dropdown-menu-item',
2463 if (this.parent().type == 'treeview') {
2464 cfg.cls = 'treeview-menu';
2467 cfg.cls += ' active';
2472 anc.href = this.href || cfg.cn[0].href ;
2473 ctag.html = this.html || cfg.cn[0].html ;
2477 initEvents: function()
2479 if (this.parent().type == 'treeview') {
2480 this.el.select('a').on('click', this.onClick, this);
2484 this.menu.parentType = this.xtype;
2485 this.menu.triggerEl = this.el;
2486 this.menu = this.addxtype(Roo.apply({}, this.menu));
2490 onClick : function(e)
2492 Roo.log('item on click ');
2494 if(this.preventDefault){
2497 //this.parent().hideMenuItems();
2499 this.fireEvent('click', this, e);
2518 * @class Roo.bootstrap.MenuSeparator
2519 * @extends Roo.bootstrap.Component
2520 * Bootstrap MenuSeparator class
2523 * Create a new MenuItem
2524 * @param {Object} config The config object
2528 Roo.bootstrap.MenuSeparator = function(config){
2529 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2532 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2534 getAutoCreate : function(){
2553 * @class Roo.bootstrap.Modal
2554 * @extends Roo.bootstrap.Component
2555 * Bootstrap Modal class
2556 * @cfg {String} title Title of dialog
2557 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2558 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2559 * @cfg {Boolean} specificTitle default false
2560 * @cfg {Array} buttons Array of buttons or standard button set..
2561 * @cfg {String} buttonPosition (left|right|center) default right
2562 * @cfg {Boolean} animate default true
2563 * @cfg {Boolean} allow_close default true
2564 * @cfg {Boolean} fitwindow default false
2565 * @cfg {String} size (sm|lg) default empty
2569 * Create a new Modal Dialog
2570 * @param {Object} config The config object
2573 Roo.bootstrap.Modal = function(config){
2574 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2579 * The raw btnclick event for the button
2580 * @param {Roo.EventObject} e
2585 * Fire when dialog resize
2586 * @param {Roo.bootstrap.Modal} this
2587 * @param {Roo.EventObject} e
2591 this.buttons = this.buttons || [];
2594 this.tmpl = Roo.factory(this.tmpl);
2599 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2601 title : 'test dialog',
2611 specificTitle: false,
2613 buttonPosition: 'right',
2632 onRender : function(ct, position)
2634 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2637 var cfg = Roo.apply({}, this.getAutoCreate());
2640 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2642 //if (!cfg.name.length) {
2646 cfg.cls += ' ' + this.cls;
2649 cfg.style = this.style;
2651 this.el = Roo.get(document.body).createChild(cfg, position);
2653 //var type = this.el.dom.type;
2656 if(this.tabIndex !== undefined){
2657 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2660 this.dialogEl = this.el.select('.modal-dialog',true).first();
2661 this.bodyEl = this.el.select('.modal-body',true).first();
2662 this.closeEl = this.el.select('.modal-header .close', true).first();
2663 this.headerEl = this.el.select('.modal-header',true).first();
2664 this.titleEl = this.el.select('.modal-title',true).first();
2665 this.footerEl = this.el.select('.modal-footer',true).first();
2667 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2668 this.maskEl.enableDisplayMode("block");
2670 //this.el.addClass("x-dlg-modal");
2672 if (this.buttons.length) {
2673 Roo.each(this.buttons, function(bb) {
2674 var b = Roo.apply({}, bb);
2675 b.xns = b.xns || Roo.bootstrap;
2676 b.xtype = b.xtype || 'Button';
2677 if (typeof(b.listeners) == 'undefined') {
2678 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2681 var btn = Roo.factory(b);
2683 btn.render(this.el.select('.modal-footer div').first());
2687 // render the children.
2690 if(typeof(this.items) != 'undefined'){
2691 var items = this.items;
2694 for(var i =0;i < items.length;i++) {
2695 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2699 this.items = nitems;
2701 // where are these used - they used to be body/close/footer
2705 //this.el.addClass([this.fieldClass, this.cls]);
2709 getAutoCreate : function(){
2714 html : this.html || ''
2719 cls : 'modal-title',
2723 if(this.specificTitle){
2729 if (this.allow_close) {
2741 if(this.size.length){
2742 size = 'modal-' + this.size;
2747 style : 'display: none',
2750 cls: "modal-dialog " + size,
2753 cls : "modal-content",
2756 cls : 'modal-header',
2761 cls : 'modal-footer',
2765 cls: 'btn-' + this.buttonPosition
2782 modal.cls += ' fade';
2788 getChildContainer : function() {
2793 getButtonContainer : function() {
2794 return this.el.select('.modal-footer div',true).first();
2797 initEvents : function()
2799 if (this.allow_close) {
2800 this.closeEl.on('click', this.hide, this);
2802 Roo.EventManager.onWindowResize(this.resize, this, true);
2809 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2810 if (this.fitwindow) {
2811 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2812 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2817 setSize : function(w,h)
2827 if (!this.rendered) {
2831 this.el.setStyle('display', 'block');
2833 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2836 this.el.addClass('in');
2839 this.el.addClass('in');
2843 // not sure how we can show data in here..
2845 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2848 Roo.get(document.body).addClass("x-body-masked");
2850 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2851 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2856 this.fireEvent('show', this);
2858 // set zindex here - otherwise it appears to be ignored...
2859 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2862 this.items.forEach( function(e) {
2863 e.layout ? e.layout() : false;
2871 if(this.fireEvent("beforehide", this) !== false){
2873 Roo.get(document.body).removeClass("x-body-masked");
2874 this.el.removeClass('in');
2875 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2877 if(this.animate){ // why
2879 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2881 this.el.setStyle('display', 'none');
2883 this.fireEvent('hide', this);
2887 addButton : function(str, cb)
2891 var b = Roo.apply({}, { html : str } );
2892 b.xns = b.xns || Roo.bootstrap;
2893 b.xtype = b.xtype || 'Button';
2894 if (typeof(b.listeners) == 'undefined') {
2895 b.listeners = { click : cb.createDelegate(this) };
2898 var btn = Roo.factory(b);
2900 btn.render(this.el.select('.modal-footer div').first());
2906 setDefaultButton : function(btn)
2908 //this.el.select('.modal-footer').()
2912 resizeTo: function(w,h)
2916 this.dialogEl.setWidth(w);
2917 if (this.diff === false) {
2918 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2921 this.bodyEl.setHeight(h-this.diff);
2923 this.fireEvent('resize', this);
2926 setContentSize : function(w, h)
2930 onButtonClick: function(btn,e)
2933 this.fireEvent('btnclick', btn.name, e);
2936 * Set the title of the Dialog
2937 * @param {String} str new Title
2939 setTitle: function(str) {
2940 this.titleEl.dom.innerHTML = str;
2943 * Set the body of the Dialog
2944 * @param {String} str new Title
2946 setBody: function(str) {
2947 this.bodyEl.dom.innerHTML = str;
2950 * Set the body of the Dialog using the template
2951 * @param {Obj} data - apply this data to the template and replace the body contents.
2953 applyBody: function(obj)
2956 Roo.log("Error - using apply Body without a template");
2959 this.tmpl.overwrite(this.bodyEl, obj);
2965 Roo.apply(Roo.bootstrap.Modal, {
2967 * Button config that displays a single OK button
2976 * Button config that displays Yes and No buttons
2992 * Button config that displays OK and Cancel buttons
3007 * Button config that displays Yes, No and Cancel buttons
3031 * messagebox - can be used as a replace
3035 * @class Roo.MessageBox
3036 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3040 Roo.Msg.alert('Status', 'Changes saved successfully.');
3042 // Prompt for user data:
3043 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3045 // process text value...
3049 // Show a dialog using config options:
3051 title:'Save Changes?',
3052 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3053 buttons: Roo.Msg.YESNOCANCEL,
3060 Roo.bootstrap.MessageBox = function(){
3061 var dlg, opt, mask, waitTimer;
3062 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3063 var buttons, activeTextEl, bwidth;
3067 var handleButton = function(button){
3069 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3073 var handleHide = function(){
3075 dlg.el.removeClass(opt.cls);
3078 // Roo.TaskMgr.stop(waitTimer);
3079 // waitTimer = null;
3084 var updateButtons = function(b){
3087 buttons["ok"].hide();
3088 buttons["cancel"].hide();
3089 buttons["yes"].hide();
3090 buttons["no"].hide();
3091 //dlg.footer.dom.style.display = 'none';
3094 dlg.footerEl.dom.style.display = '';
3095 for(var k in buttons){
3096 if(typeof buttons[k] != "function"){
3099 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3100 width += buttons[k].el.getWidth()+15;
3110 var handleEsc = function(d, k, e){
3111 if(opt && opt.closable !== false){
3121 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3122 * @return {Roo.BasicDialog} The BasicDialog element
3124 getDialog : function(){
3126 dlg = new Roo.bootstrap.Modal( {
3129 //constraintoviewport:false,
3131 //collapsible : false,
3136 //buttonAlign:"center",
3137 closeClick : function(){
3138 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3141 handleButton("cancel");
3146 dlg.on("hide", handleHide);
3148 //dlg.addKeyListener(27, handleEsc);
3150 this.buttons = buttons;
3151 var bt = this.buttonText;
3152 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3153 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3154 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3155 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3157 bodyEl = dlg.bodyEl.createChild({
3159 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3160 '<textarea class="roo-mb-textarea"></textarea>' +
3161 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3163 msgEl = bodyEl.dom.firstChild;
3164 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3165 textboxEl.enableDisplayMode();
3166 textboxEl.addKeyListener([10,13], function(){
3167 if(dlg.isVisible() && opt && opt.buttons){
3170 }else if(opt.buttons.yes){
3171 handleButton("yes");
3175 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3176 textareaEl.enableDisplayMode();
3177 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3178 progressEl.enableDisplayMode();
3180 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3181 var pf = progressEl.dom.firstChild;
3183 pp = Roo.get(pf.firstChild);
3184 pp.setHeight(pf.offsetHeight);
3192 * Updates the message box body text
3193 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3194 * the XHTML-compliant non-breaking space character '&#160;')
3195 * @return {Roo.MessageBox} This message box
3197 updateText : function(text)
3199 if(!dlg.isVisible() && !opt.width){
3200 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3201 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3203 msgEl.innerHTML = text || ' ';
3205 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3206 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3208 Math.min(opt.width || cw , this.maxWidth),
3209 Math.max(opt.minWidth || this.minWidth, bwidth)
3212 activeTextEl.setWidth(w);
3214 if(dlg.isVisible()){
3215 dlg.fixedcenter = false;
3217 // to big, make it scroll. = But as usual stupid IE does not support
3220 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3221 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3222 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3224 bodyEl.dom.style.height = '';
3225 bodyEl.dom.style.overflowY = '';
3228 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3230 bodyEl.dom.style.overflowX = '';
3233 dlg.setContentSize(w, bodyEl.getHeight());
3234 if(dlg.isVisible()){
3235 dlg.fixedcenter = true;
3241 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3242 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3243 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3244 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3245 * @return {Roo.MessageBox} This message box
3247 updateProgress : function(value, text){
3249 this.updateText(text);
3252 if (pp) { // weird bug on my firefox - for some reason this is not defined
3253 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3254 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3260 * Returns true if the message box is currently displayed
3261 * @return {Boolean} True if the message box is visible, else false
3263 isVisible : function(){
3264 return dlg && dlg.isVisible();
3268 * Hides the message box if it is displayed
3271 if(this.isVisible()){
3277 * Displays a new message box, or reinitializes an existing message box, based on the config options
3278 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3279 * The following config object properties are supported:
3281 Property Type Description
3282 ---------- --------------- ------------------------------------------------------------------------------------
3283 animEl String/Element An id or Element from which the message box should animate as it opens and
3284 closes (defaults to undefined)
3285 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3286 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3287 closable Boolean False to hide the top-right close button (defaults to true). Note that
3288 progress and wait dialogs will ignore this property and always hide the
3289 close button as they can only be closed programmatically.
3290 cls String A custom CSS class to apply to the message box element
3291 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3292 displayed (defaults to 75)
3293 fn Function A callback function to execute after closing the dialog. The arguments to the
3294 function will be btn (the name of the button that was clicked, if applicable,
3295 e.g. "ok"), and text (the value of the active text field, if applicable).
3296 Progress and wait dialogs will ignore this option since they do not respond to
3297 user actions and can only be closed programmatically, so any required function
3298 should be called by the same code after it closes the dialog.
3299 icon String A CSS class that provides a background image to be used as an icon for
3300 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3301 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3302 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3303 modal Boolean False to allow user interaction with the page while the message box is
3304 displayed (defaults to true)
3305 msg String A string that will replace the existing message box body text (defaults
3306 to the XHTML-compliant non-breaking space character ' ')
3307 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3308 progress Boolean True to display a progress bar (defaults to false)
3309 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3310 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3311 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3312 title String The title text
3313 value String The string value to set into the active textbox element if displayed
3314 wait Boolean True to display a progress bar (defaults to false)
3315 width Number The width of the dialog in pixels
3322 msg: 'Please enter your address:',
3324 buttons: Roo.MessageBox.OKCANCEL,
3327 animEl: 'addAddressBtn'
3330 * @param {Object} config Configuration options
3331 * @return {Roo.MessageBox} This message box
3333 show : function(options)
3336 // this causes nightmares if you show one dialog after another
3337 // especially on callbacks..
3339 if(this.isVisible()){
3342 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3343 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3344 Roo.log("New Dialog Message:" + options.msg )
3345 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3346 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3349 var d = this.getDialog();
3351 d.setTitle(opt.title || " ");
3352 d.closeEl.setDisplayed(opt.closable !== false);
3353 activeTextEl = textboxEl;
3354 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3359 textareaEl.setHeight(typeof opt.multiline == "number" ?
3360 opt.multiline : this.defaultTextHeight);
3361 activeTextEl = textareaEl;
3370 progressEl.setDisplayed(opt.progress === true);
3371 this.updateProgress(0);
3372 activeTextEl.dom.value = opt.value || "";
3374 dlg.setDefaultButton(activeTextEl);
3376 var bs = opt.buttons;
3380 }else if(bs && bs.yes){
3381 db = buttons["yes"];
3383 dlg.setDefaultButton(db);
3385 bwidth = updateButtons(opt.buttons);
3386 this.updateText(opt.msg);
3388 d.el.addClass(opt.cls);
3390 d.proxyDrag = opt.proxyDrag === true;
3391 d.modal = opt.modal !== false;
3392 d.mask = opt.modal !== false ? mask : false;
3394 // force it to the end of the z-index stack so it gets a cursor in FF
3395 document.body.appendChild(dlg.el.dom);
3396 d.animateTarget = null;
3397 d.show(options.animEl);
3403 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3404 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3405 * and closing the message box when the process is complete.
3406 * @param {String} title The title bar text
3407 * @param {String} msg The message box body text
3408 * @return {Roo.MessageBox} This message box
3410 progress : function(title, msg){
3417 minWidth: this.minProgressWidth,
3424 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3425 * If a callback function is passed it will be called after the user clicks the button, and the
3426 * id of the button that was clicked will be passed as the only parameter to the callback
3427 * (could also be the top-right close button).
3428 * @param {String} title The title bar text
3429 * @param {String} msg The message box body text
3430 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3431 * @param {Object} scope (optional) The scope of the callback function
3432 * @return {Roo.MessageBox} This message box
3434 alert : function(title, msg, fn, scope)
3449 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3450 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3451 * You are responsible for closing the message box when the process is complete.
3452 * @param {String} msg The message box body text
3453 * @param {String} title (optional) The title bar text
3454 * @return {Roo.MessageBox} This message box
3456 wait : function(msg, title){
3467 waitTimer = Roo.TaskMgr.start({
3469 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3477 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3478 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3479 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3480 * @param {String} title The title bar text
3481 * @param {String} msg The message box body text
3482 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3483 * @param {Object} scope (optional) The scope of the callback function
3484 * @return {Roo.MessageBox} This message box
3486 confirm : function(title, msg, fn, scope){
3490 buttons: this.YESNO,
3499 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3500 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3501 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3502 * (could also be the top-right close button) and the text that was entered will be passed as the two
3503 * parameters to the callback.
3504 * @param {String} title The title bar text
3505 * @param {String} msg The message box body text
3506 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3507 * @param {Object} scope (optional) The scope of the callback function
3508 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3509 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3510 * @return {Roo.MessageBox} This message box
3512 prompt : function(title, msg, fn, scope, multiline){
3516 buttons: this.OKCANCEL,
3521 multiline: multiline,
3528 * Button config that displays a single OK button
3533 * Button config that displays Yes and No buttons
3536 YESNO : {yes:true, no:true},
3538 * Button config that displays OK and Cancel buttons
3541 OKCANCEL : {ok:true, cancel:true},
3543 * Button config that displays Yes, No and Cancel buttons
3546 YESNOCANCEL : {yes:true, no:true, cancel:true},
3549 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3552 defaultTextHeight : 75,
3554 * The maximum width in pixels of the message box (defaults to 600)
3559 * The minimum width in pixels of the message box (defaults to 100)
3564 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3565 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3568 minProgressWidth : 250,
3570 * An object containing the default button text strings that can be overriden for localized language support.
3571 * Supported properties are: ok, cancel, yes and no.
3572 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3585 * Shorthand for {@link Roo.MessageBox}
3587 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3588 Roo.Msg = Roo.Msg || Roo.MessageBox;
3597 * @class Roo.bootstrap.Navbar
3598 * @extends Roo.bootstrap.Component
3599 * Bootstrap Navbar class
3602 * Create a new Navbar
3603 * @param {Object} config The config object
3607 Roo.bootstrap.Navbar = function(config){
3608 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3612 * @event beforetoggle
3613 * Fire before toggle the menu
3614 * @param {Roo.EventObject} e
3616 "beforetoggle" : true
3620 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3629 getAutoCreate : function(){
3632 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3636 initEvents :function ()
3638 //Roo.log(this.el.select('.navbar-toggle',true));
3639 this.el.select('.navbar-toggle',true).on('click', function() {
3640 if(this.fireEvent('beforetoggle', this) !== false){
3641 this.el.select('.navbar-collapse',true).toggleClass('in');
3651 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3653 var size = this.el.getSize();
3654 this.maskEl.setSize(size.width, size.height);
3655 this.maskEl.enableDisplayMode("block");
3664 getChildContainer : function()
3666 if (this.el.select('.collapse').getCount()) {
3667 return this.el.select('.collapse',true).first();
3700 * @class Roo.bootstrap.NavSimplebar
3701 * @extends Roo.bootstrap.Navbar
3702 * Bootstrap Sidebar class
3704 * @cfg {Boolean} inverse is inverted color
3706 * @cfg {String} type (nav | pills | tabs)
3707 * @cfg {Boolean} arrangement stacked | justified
3708 * @cfg {String} align (left | right) alignment
3710 * @cfg {Boolean} main (true|false) main nav bar? default false
3711 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3713 * @cfg {String} tag (header|footer|nav|div) default is nav
3719 * Create a new Sidebar
3720 * @param {Object} config The config object
3724 Roo.bootstrap.NavSimplebar = function(config){
3725 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3728 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3744 getAutoCreate : function(){
3748 tag : this.tag || 'div',
3761 this.type = this.type || 'nav';
3762 if (['tabs','pills'].indexOf(this.type)!==-1) {
3763 cfg.cn[0].cls += ' nav-' + this.type
3767 if (this.type!=='nav') {
3768 Roo.log('nav type must be nav/tabs/pills')
3770 cfg.cn[0].cls += ' navbar-nav'
3776 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3777 cfg.cn[0].cls += ' nav-' + this.arrangement;
3781 if (this.align === 'right') {
3782 cfg.cn[0].cls += ' navbar-right';
3786 cfg.cls += ' navbar-inverse';
3813 * @class Roo.bootstrap.NavHeaderbar
3814 * @extends Roo.bootstrap.NavSimplebar
3815 * Bootstrap Sidebar class
3817 * @cfg {String} brand what is brand
3818 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3819 * @cfg {String} brand_href href of the brand
3820 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3821 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3822 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3823 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3826 * Create a new Sidebar
3827 * @param {Object} config The config object
3831 Roo.bootstrap.NavHeaderbar = function(config){
3832 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3836 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3843 desktopCenter : false,
3846 getAutoCreate : function(){
3849 tag: this.nav || 'nav',
3856 if (this.desktopCenter) {
3857 cn.push({cls : 'container', cn : []});
3864 cls: 'navbar-header',
3869 cls: 'navbar-toggle',
3870 'data-toggle': 'collapse',
3875 html: 'Toggle navigation'
3897 cls: 'collapse navbar-collapse',
3901 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3903 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3904 cfg.cls += ' navbar-' + this.position;
3906 // tag can override this..
3908 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3911 if (this.brand !== '') {
3914 href: this.brand_href ? this.brand_href : '#',
3915 cls: 'navbar-brand',
3923 cfg.cls += ' main-nav';
3931 getHeaderChildContainer : function()
3933 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3934 return this.el.select('.navbar-header',true).first();
3937 return this.getChildContainer();
3941 initEvents : function()
3943 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3945 if (this.autohide) {
3950 Roo.get(document).on('scroll',function(e) {
3951 var ns = Roo.get(document).getScroll().top;
3952 var os = prevScroll;
3956 ft.removeClass('slideDown');
3957 ft.addClass('slideUp');
3960 ft.removeClass('slideUp');
3961 ft.addClass('slideDown');
3982 * @class Roo.bootstrap.NavSidebar
3983 * @extends Roo.bootstrap.Navbar
3984 * Bootstrap Sidebar class
3987 * Create a new Sidebar
3988 * @param {Object} config The config object
3992 Roo.bootstrap.NavSidebar = function(config){
3993 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3996 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3998 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4000 getAutoCreate : function(){
4005 cls: 'sidebar sidebar-nav'
4027 * @class Roo.bootstrap.NavGroup
4028 * @extends Roo.bootstrap.Component
4029 * Bootstrap NavGroup class
4030 * @cfg {String} align (left|right)
4031 * @cfg {Boolean} inverse
4032 * @cfg {String} type (nav|pills|tab) default nav
4033 * @cfg {String} navId - reference Id for navbar.
4037 * Create a new nav group
4038 * @param {Object} config The config object
4041 Roo.bootstrap.NavGroup = function(config){
4042 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4045 Roo.bootstrap.NavGroup.register(this);
4049 * Fires when the active item changes
4050 * @param {Roo.bootstrap.NavGroup} this
4051 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4052 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4059 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4070 getAutoCreate : function()
4072 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4079 if (['tabs','pills'].indexOf(this.type)!==-1) {
4080 cfg.cls += ' nav-' + this.type
4082 if (this.type!=='nav') {
4083 Roo.log('nav type must be nav/tabs/pills')
4085 cfg.cls += ' navbar-nav'
4088 if (this.parent() && this.parent().sidebar) {
4091 cls: 'dashboard-menu sidebar-menu'
4097 if (this.form === true) {
4103 if (this.align === 'right') {
4104 cfg.cls += ' navbar-right';
4106 cfg.cls += ' navbar-left';
4110 if (this.align === 'right') {
4111 cfg.cls += ' navbar-right';
4115 cfg.cls += ' navbar-inverse';
4123 * sets the active Navigation item
4124 * @param {Roo.bootstrap.NavItem} the new current navitem
4126 setActiveItem : function(item)
4129 Roo.each(this.navItems, function(v){
4134 v.setActive(false, true);
4141 item.setActive(true, true);
4142 this.fireEvent('changed', this, item, prev);
4147 * gets the active Navigation item
4148 * @return {Roo.bootstrap.NavItem} the current navitem
4150 getActive : function()
4154 Roo.each(this.navItems, function(v){
4165 indexOfNav : function()
4169 Roo.each(this.navItems, function(v,i){
4180 * adds a Navigation item
4181 * @param {Roo.bootstrap.NavItem} the navitem to add
4183 addItem : function(cfg)
4185 var cn = new Roo.bootstrap.NavItem(cfg);
4187 cn.parentId = this.id;
4188 cn.onRender(this.el, null);
4192 * register a Navigation item
4193 * @param {Roo.bootstrap.NavItem} the navitem to add
4195 register : function(item)
4197 this.navItems.push( item);
4198 item.navId = this.navId;
4203 * clear all the Navigation item
4206 clearAll : function()
4209 this.el.dom.innerHTML = '';
4212 getNavItem: function(tabId)
4215 Roo.each(this.navItems, function(e) {
4216 if (e.tabId == tabId) {
4226 setActiveNext : function()
4228 var i = this.indexOfNav(this.getActive());
4229 if (i > this.navItems.length) {
4232 this.setActiveItem(this.navItems[i+1]);
4234 setActivePrev : function()
4236 var i = this.indexOfNav(this.getActive());
4240 this.setActiveItem(this.navItems[i-1]);
4242 clearWasActive : function(except) {
4243 Roo.each(this.navItems, function(e) {
4244 if (e.tabId != except.tabId && e.was_active) {
4245 e.was_active = false;
4252 getWasActive : function ()
4255 Roo.each(this.navItems, function(e) {
4270 Roo.apply(Roo.bootstrap.NavGroup, {
4274 * register a Navigation Group
4275 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4277 register : function(navgrp)
4279 this.groups[navgrp.navId] = navgrp;
4283 * fetch a Navigation Group based on the navigation ID
4284 * @param {string} the navgroup to add
4285 * @returns {Roo.bootstrap.NavGroup} the navgroup
4287 get: function(navId) {
4288 if (typeof(this.groups[navId]) == 'undefined') {
4290 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4292 return this.groups[navId] ;
4307 * @class Roo.bootstrap.NavItem
4308 * @extends Roo.bootstrap.Component
4309 * Bootstrap Navbar.NavItem class
4310 * @cfg {String} href link to
4311 * @cfg {String} html content of button
4312 * @cfg {String} badge text inside badge
4313 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4314 * @cfg {String} glyphicon name of glyphicon
4315 * @cfg {String} icon name of font awesome icon
4316 * @cfg {Boolean} active Is item active
4317 * @cfg {Boolean} disabled Is item disabled
4319 * @cfg {Boolean} preventDefault (true | false) default false
4320 * @cfg {String} tabId the tab that this item activates.
4321 * @cfg {String} tagtype (a|span) render as a href or span?
4322 * @cfg {Boolean} animateRef (true|false) link to element default false
4325 * Create a new Navbar Item
4326 * @param {Object} config The config object
4328 Roo.bootstrap.NavItem = function(config){
4329 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4334 * The raw click event for the entire grid.
4335 * @param {Roo.EventObject} e
4340 * Fires when the active item active state changes
4341 * @param {Roo.bootstrap.NavItem} this
4342 * @param {boolean} state the new state
4348 * Fires when scroll to element
4349 * @param {Roo.bootstrap.NavItem} this
4350 * @param {Object} options
4351 * @param {Roo.EventObject} e
4359 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4367 preventDefault : false,
4374 getAutoCreate : function(){
4383 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4385 if (this.disabled) {
4386 cfg.cls += ' disabled';
4389 if (this.href || this.html || this.glyphicon || this.icon) {
4393 href : this.href || "#",
4394 html: this.html || ''
4399 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4402 if(this.glyphicon) {
4403 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4408 cfg.cn[0].html += " <span class='caret'></span>";
4412 if (this.badge !== '') {
4414 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4422 initEvents: function()
4424 if (typeof (this.menu) != 'undefined') {
4425 this.menu.parentType = this.xtype;
4426 this.menu.triggerEl = this.el;
4427 this.menu = this.addxtype(Roo.apply({}, this.menu));
4430 this.el.select('a',true).on('click', this.onClick, this);
4432 if(this.tagtype == 'span'){
4433 this.el.select('span',true).on('click', this.onClick, this);
4436 // at this point parent should be available..
4437 this.parent().register(this);
4440 onClick : function(e)
4442 if (e.getTarget('.dropdown-menu-item')) {
4443 // did you click on a menu itemm.... - then don't trigger onclick..
4448 this.preventDefault ||
4451 Roo.log("NavItem - prevent Default?");
4455 if (this.disabled) {
4459 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4460 if (tg && tg.transition) {
4461 Roo.log("waiting for the transitionend");
4467 //Roo.log("fire event clicked");
4468 if(this.fireEvent('click', this, e) === false){
4472 if(this.tagtype == 'span'){
4476 //Roo.log(this.href);
4477 var ael = this.el.select('a',true).first();
4480 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4481 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4482 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4483 return; // ignore... - it's a 'hash' to another page.
4485 Roo.log("NavItem - prevent Default?");
4487 this.scrollToElement(e);
4491 var p = this.parent();
4493 if (['tabs','pills'].indexOf(p.type)!==-1) {
4494 if (typeof(p.setActiveItem) !== 'undefined') {
4495 p.setActiveItem(this);
4499 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4500 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4501 // remove the collapsed menu expand...
4502 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4506 isActive: function () {
4509 setActive : function(state, fire, is_was_active)
4511 if (this.active && !state && this.navId) {
4512 this.was_active = true;
4513 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4515 nv.clearWasActive(this);
4519 this.active = state;
4522 this.el.removeClass('active');
4523 } else if (!this.el.hasClass('active')) {
4524 this.el.addClass('active');
4527 this.fireEvent('changed', this, state);
4530 // show a panel if it's registered and related..
4532 if (!this.navId || !this.tabId || !state || is_was_active) {
4536 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4540 var pan = tg.getPanelByName(this.tabId);
4544 // if we can not flip to new panel - go back to old nav highlight..
4545 if (false == tg.showPanel(pan)) {
4546 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4548 var onav = nv.getWasActive();
4550 onav.setActive(true, false, true);
4559 // this should not be here...
4560 setDisabled : function(state)
4562 this.disabled = state;
4564 this.el.removeClass('disabled');
4565 } else if (!this.el.hasClass('disabled')) {
4566 this.el.addClass('disabled');
4572 * Fetch the element to display the tooltip on.
4573 * @return {Roo.Element} defaults to this.el
4575 tooltipEl : function()
4577 return this.el.select('' + this.tagtype + '', true).first();
4580 scrollToElement : function(e)
4582 var c = document.body;
4585 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4587 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4588 c = document.documentElement;
4591 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4597 var o = target.calcOffsetsTo(c);
4604 this.fireEvent('scrollto', this, options, e);
4606 Roo.get(c).scrollTo('top', options.value, true);
4619 * <span> icon </span>
4620 * <span> text </span>
4621 * <span>badge </span>
4625 * @class Roo.bootstrap.NavSidebarItem
4626 * @extends Roo.bootstrap.NavItem
4627 * Bootstrap Navbar.NavSidebarItem class
4628 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4629 * {Boolean} open is the menu open
4630 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4631 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4632 * {String} buttonSize (sm|md|lg)the extra classes for the button
4633 * {Boolean} showArrow show arrow next to the text (default true)
4635 * Create a new Navbar Button
4636 * @param {Object} config The config object
4638 Roo.bootstrap.NavSidebarItem = function(config){
4639 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4644 * The raw click event for the entire grid.
4645 * @param {Roo.EventObject} e
4650 * Fires when the active item active state changes
4651 * @param {Roo.bootstrap.NavSidebarItem} this
4652 * @param {boolean} state the new state
4660 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4662 badgeWeight : 'default',
4668 buttonWeight : 'default',
4674 getAutoCreate : function(){
4679 href : this.href || '#',
4685 if(this.buttonView){
4688 href : this.href || '#',
4689 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4702 cfg.cls += ' active';
4705 if (this.disabled) {
4706 cfg.cls += ' disabled';
4709 cfg.cls += ' open x-open';
4712 if (this.glyphicon || this.icon) {
4713 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4714 a.cn.push({ tag : 'i', cls : c }) ;
4717 if(!this.buttonView){
4720 html : this.html || ''
4727 if (this.badge !== '') {
4728 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4734 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4737 a.cls += ' dropdown-toggle treeview' ;
4743 initEvents : function()
4745 if (typeof (this.menu) != 'undefined') {
4746 this.menu.parentType = this.xtype;
4747 this.menu.triggerEl = this.el;
4748 this.menu = this.addxtype(Roo.apply({}, this.menu));
4751 this.el.on('click', this.onClick, this);
4753 if(this.badge !== ''){
4754 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4759 onClick : function(e)
4766 if(this.preventDefault){
4770 this.fireEvent('click', this);
4773 disable : function()
4775 this.setDisabled(true);
4780 this.setDisabled(false);
4783 setDisabled : function(state)
4785 if(this.disabled == state){
4789 this.disabled = state;
4792 this.el.addClass('disabled');
4796 this.el.removeClass('disabled');
4801 setActive : function(state)
4803 if(this.active == state){
4807 this.active = state;
4810 this.el.addClass('active');
4814 this.el.removeClass('active');
4819 isActive: function ()
4824 setBadge : function(str)
4830 this.badgeEl.dom.innerHTML = str;
4847 * @class Roo.bootstrap.Row
4848 * @extends Roo.bootstrap.Component
4849 * Bootstrap Row class (contains columns...)
4853 * @param {Object} config The config object
4856 Roo.bootstrap.Row = function(config){
4857 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4860 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4862 getAutoCreate : function(){
4881 * @class Roo.bootstrap.Element
4882 * @extends Roo.bootstrap.Component
4883 * Bootstrap Element class
4884 * @cfg {String} html contents of the element
4885 * @cfg {String} tag tag of the element
4886 * @cfg {String} cls class of the element
4887 * @cfg {Boolean} preventDefault (true|false) default false
4888 * @cfg {Boolean} clickable (true|false) default false
4891 * Create a new Element
4892 * @param {Object} config The config object
4895 Roo.bootstrap.Element = function(config){
4896 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4902 * When a element is chick
4903 * @param {Roo.bootstrap.Element} this
4904 * @param {Roo.EventObject} e
4910 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4915 preventDefault: false,
4918 getAutoCreate : function(){
4929 initEvents: function()
4931 Roo.bootstrap.Element.superclass.initEvents.call(this);
4934 this.el.on('click', this.onClick, this);
4939 onClick : function(e)
4941 if(this.preventDefault){
4945 this.fireEvent('click', this, e);
4948 getValue : function()
4950 return this.el.dom.innerHTML;
4953 setValue : function(value)
4955 this.el.dom.innerHTML = value;
4970 * @class Roo.bootstrap.Pagination
4971 * @extends Roo.bootstrap.Component
4972 * Bootstrap Pagination class
4973 * @cfg {String} size xs | sm | md | lg
4974 * @cfg {Boolean} inverse false | true
4977 * Create a new Pagination
4978 * @param {Object} config The config object
4981 Roo.bootstrap.Pagination = function(config){
4982 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4985 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4991 getAutoCreate : function(){
4997 cfg.cls += ' inverse';
5003 cfg.cls += " " + this.cls;
5021 * @class Roo.bootstrap.PaginationItem
5022 * @extends Roo.bootstrap.Component
5023 * Bootstrap PaginationItem class
5024 * @cfg {String} html text
5025 * @cfg {String} href the link
5026 * @cfg {Boolean} preventDefault (true | false) default true
5027 * @cfg {Boolean} active (true | false) default false
5028 * @cfg {Boolean} disabled default false
5032 * Create a new PaginationItem
5033 * @param {Object} config The config object
5037 Roo.bootstrap.PaginationItem = function(config){
5038 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5043 * The raw click event for the entire grid.
5044 * @param {Roo.EventObject} e
5050 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5054 preventDefault: true,
5059 getAutoCreate : function(){
5065 href : this.href ? this.href : '#',
5066 html : this.html ? this.html : ''
5076 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5080 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5086 initEvents: function() {
5088 this.el.on('click', this.onClick, this);
5091 onClick : function(e)
5093 Roo.log('PaginationItem on click ');
5094 if(this.preventDefault){
5102 this.fireEvent('click', this, e);
5118 * @class Roo.bootstrap.Slider
5119 * @extends Roo.bootstrap.Component
5120 * Bootstrap Slider class
5123 * Create a new Slider
5124 * @param {Object} config The config object
5127 Roo.bootstrap.Slider = function(config){
5128 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5131 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5133 getAutoCreate : function(){
5137 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5141 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5153 * Ext JS Library 1.1.1
5154 * Copyright(c) 2006-2007, Ext JS, LLC.
5156 * Originally Released Under LGPL - original licence link has changed is not relivant.
5159 * <script type="text/javascript">
5164 * @class Roo.grid.ColumnModel
5165 * @extends Roo.util.Observable
5166 * This is the default implementation of a ColumnModel used by the Grid. It defines
5167 * the columns in the grid.
5170 var colModel = new Roo.grid.ColumnModel([
5171 {header: "Ticker", width: 60, sortable: true, locked: true},
5172 {header: "Company Name", width: 150, sortable: true},
5173 {header: "Market Cap.", width: 100, sortable: true},
5174 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5175 {header: "Employees", width: 100, sortable: true, resizable: false}
5180 * The config options listed for this class are options which may appear in each
5181 * individual column definition.
5182 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5184 * @param {Object} config An Array of column config objects. See this class's
5185 * config objects for details.
5187 Roo.grid.ColumnModel = function(config){
5189 * The config passed into the constructor
5191 this.config = config;
5194 // if no id, create one
5195 // if the column does not have a dataIndex mapping,
5196 // map it to the order it is in the config
5197 for(var i = 0, len = config.length; i < len; i++){
5199 if(typeof c.dataIndex == "undefined"){
5202 if(typeof c.renderer == "string"){
5203 c.renderer = Roo.util.Format[c.renderer];
5205 if(typeof c.id == "undefined"){
5208 if(c.editor && c.editor.xtype){
5209 c.editor = Roo.factory(c.editor, Roo.grid);
5211 if(c.editor && c.editor.isFormField){
5212 c.editor = new Roo.grid.GridEditor(c.editor);
5214 this.lookup[c.id] = c;
5218 * The width of columns which have no width specified (defaults to 100)
5221 this.defaultWidth = 100;
5224 * Default sortable of columns which have no sortable specified (defaults to false)
5227 this.defaultSortable = false;
5231 * @event widthchange
5232 * Fires when the width of a column changes.
5233 * @param {ColumnModel} this
5234 * @param {Number} columnIndex The column index
5235 * @param {Number} newWidth The new width
5237 "widthchange": true,
5239 * @event headerchange
5240 * Fires when the text of a header changes.
5241 * @param {ColumnModel} this
5242 * @param {Number} columnIndex The column index
5243 * @param {Number} newText The new header text
5245 "headerchange": true,
5247 * @event hiddenchange
5248 * Fires when a column is hidden or "unhidden".
5249 * @param {ColumnModel} this
5250 * @param {Number} columnIndex The column index
5251 * @param {Boolean} hidden true if hidden, false otherwise
5253 "hiddenchange": true,
5255 * @event columnmoved
5256 * Fires when a column is moved.
5257 * @param {ColumnModel} this
5258 * @param {Number} oldIndex
5259 * @param {Number} newIndex
5261 "columnmoved" : true,
5263 * @event columlockchange
5264 * Fires when a column's locked state is changed
5265 * @param {ColumnModel} this
5266 * @param {Number} colIndex
5267 * @param {Boolean} locked true if locked
5269 "columnlockchange" : true
5271 Roo.grid.ColumnModel.superclass.constructor.call(this);
5273 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5275 * @cfg {String} header The header text to display in the Grid view.
5278 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5279 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5280 * specified, the column's index is used as an index into the Record's data Array.
5283 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5284 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5287 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5288 * Defaults to the value of the {@link #defaultSortable} property.
5289 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5292 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5295 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5298 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5301 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5304 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5305 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5306 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5307 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5310 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5313 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5316 * @cfg {String} cursor (Optional)
5319 * @cfg {String} tooltip (Optional)
5322 * @cfg {Number} xs (Optional)
5325 * @cfg {Number} sm (Optional)
5328 * @cfg {Number} md (Optional)
5331 * @cfg {Number} lg (Optional)
5334 * Returns the id of the column at the specified index.
5335 * @param {Number} index The column index
5336 * @return {String} the id
5338 getColumnId : function(index){
5339 return this.config[index].id;
5343 * Returns the column for a specified id.
5344 * @param {String} id The column id
5345 * @return {Object} the column
5347 getColumnById : function(id){
5348 return this.lookup[id];
5353 * Returns the column for a specified dataIndex.
5354 * @param {String} dataIndex The column dataIndex
5355 * @return {Object|Boolean} the column or false if not found
5357 getColumnByDataIndex: function(dataIndex){
5358 var index = this.findColumnIndex(dataIndex);
5359 return index > -1 ? this.config[index] : false;
5363 * Returns the index for a specified column id.
5364 * @param {String} id The column id
5365 * @return {Number} the index, or -1 if not found
5367 getIndexById : function(id){
5368 for(var i = 0, len = this.config.length; i < len; i++){
5369 if(this.config[i].id == id){
5377 * Returns the index for a specified column dataIndex.
5378 * @param {String} dataIndex The column dataIndex
5379 * @return {Number} the index, or -1 if not found
5382 findColumnIndex : function(dataIndex){
5383 for(var i = 0, len = this.config.length; i < len; i++){
5384 if(this.config[i].dataIndex == dataIndex){
5392 moveColumn : function(oldIndex, newIndex){
5393 var c = this.config[oldIndex];
5394 this.config.splice(oldIndex, 1);
5395 this.config.splice(newIndex, 0, c);
5396 this.dataMap = null;
5397 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5400 isLocked : function(colIndex){
5401 return this.config[colIndex].locked === true;
5404 setLocked : function(colIndex, value, suppressEvent){
5405 if(this.isLocked(colIndex) == value){
5408 this.config[colIndex].locked = value;
5410 this.fireEvent("columnlockchange", this, colIndex, value);
5414 getTotalLockedWidth : function(){
5416 for(var i = 0; i < this.config.length; i++){
5417 if(this.isLocked(i) && !this.isHidden(i)){
5418 this.totalWidth += this.getColumnWidth(i);
5424 getLockedCount : function(){
5425 for(var i = 0, len = this.config.length; i < len; i++){
5426 if(!this.isLocked(i)){
5431 return this.config.length;
5435 * Returns the number of columns.
5438 getColumnCount : function(visibleOnly){
5439 if(visibleOnly === true){
5441 for(var i = 0, len = this.config.length; i < len; i++){
5442 if(!this.isHidden(i)){
5448 return this.config.length;
5452 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5453 * @param {Function} fn
5454 * @param {Object} scope (optional)
5455 * @return {Array} result
5457 getColumnsBy : function(fn, scope){
5459 for(var i = 0, len = this.config.length; i < len; i++){
5460 var c = this.config[i];
5461 if(fn.call(scope||this, c, i) === true){
5469 * Returns true if the specified column is sortable.
5470 * @param {Number} col The column index
5473 isSortable : function(col){
5474 if(typeof this.config[col].sortable == "undefined"){
5475 return this.defaultSortable;
5477 return this.config[col].sortable;
5481 * Returns the rendering (formatting) function defined for the column.
5482 * @param {Number} col The column index.
5483 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5485 getRenderer : function(col){
5486 if(!this.config[col].renderer){
5487 return Roo.grid.ColumnModel.defaultRenderer;
5489 return this.config[col].renderer;
5493 * Sets the rendering (formatting) function for a column.
5494 * @param {Number} col The column index
5495 * @param {Function} fn The function to use to process the cell's raw data
5496 * to return HTML markup for the grid view. The render function is called with
5497 * the following parameters:<ul>
5498 * <li>Data value.</li>
5499 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5500 * <li>css A CSS style string to apply to the table cell.</li>
5501 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5502 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5503 * <li>Row index</li>
5504 * <li>Column index</li>
5505 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5507 setRenderer : function(col, fn){
5508 this.config[col].renderer = fn;
5512 * Returns the width for the specified column.
5513 * @param {Number} col The column index
5516 getColumnWidth : function(col){
5517 return this.config[col].width * 1 || this.defaultWidth;
5521 * Sets the width for a column.
5522 * @param {Number} col The column index
5523 * @param {Number} width The new width
5525 setColumnWidth : function(col, width, suppressEvent){
5526 this.config[col].width = width;
5527 this.totalWidth = null;
5529 this.fireEvent("widthchange", this, col, width);
5534 * Returns the total width of all columns.
5535 * @param {Boolean} includeHidden True to include hidden column widths
5538 getTotalWidth : function(includeHidden){
5539 if(!this.totalWidth){
5540 this.totalWidth = 0;
5541 for(var i = 0, len = this.config.length; i < len; i++){
5542 if(includeHidden || !this.isHidden(i)){
5543 this.totalWidth += this.getColumnWidth(i);
5547 return this.totalWidth;
5551 * Returns the header for the specified column.
5552 * @param {Number} col The column index
5555 getColumnHeader : function(col){
5556 return this.config[col].header;
5560 * Sets the header for a column.
5561 * @param {Number} col The column index
5562 * @param {String} header The new header
5564 setColumnHeader : function(col, header){
5565 this.config[col].header = header;
5566 this.fireEvent("headerchange", this, col, header);
5570 * Returns the tooltip for the specified column.
5571 * @param {Number} col The column index
5574 getColumnTooltip : function(col){
5575 return this.config[col].tooltip;
5578 * Sets the tooltip for a column.
5579 * @param {Number} col The column index
5580 * @param {String} tooltip The new tooltip
5582 setColumnTooltip : function(col, tooltip){
5583 this.config[col].tooltip = tooltip;
5587 * Returns the dataIndex for the specified column.
5588 * @param {Number} col The column index
5591 getDataIndex : function(col){
5592 return this.config[col].dataIndex;
5596 * Sets the dataIndex for a column.
5597 * @param {Number} col The column index
5598 * @param {Number} dataIndex The new dataIndex
5600 setDataIndex : function(col, dataIndex){
5601 this.config[col].dataIndex = dataIndex;
5607 * Returns true if the cell is editable.
5608 * @param {Number} colIndex The column index
5609 * @param {Number} rowIndex The row index - this is nto actually used..?
5612 isCellEditable : function(colIndex, rowIndex){
5613 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5617 * Returns the editor defined for the cell/column.
5618 * return false or null to disable editing.
5619 * @param {Number} colIndex The column index
5620 * @param {Number} rowIndex The row index
5623 getCellEditor : function(colIndex, rowIndex){
5624 return this.config[colIndex].editor;
5628 * Sets if a column is editable.
5629 * @param {Number} col The column index
5630 * @param {Boolean} editable True if the column is editable
5632 setEditable : function(col, editable){
5633 this.config[col].editable = editable;
5638 * Returns true if the column is hidden.
5639 * @param {Number} colIndex The column index
5642 isHidden : function(colIndex){
5643 return this.config[colIndex].hidden;
5648 * Returns true if the column width cannot be changed
5650 isFixed : function(colIndex){
5651 return this.config[colIndex].fixed;
5655 * Returns true if the column can be resized
5658 isResizable : function(colIndex){
5659 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5662 * Sets if a column is hidden.
5663 * @param {Number} colIndex The column index
5664 * @param {Boolean} hidden True if the column is hidden
5666 setHidden : function(colIndex, hidden){
5667 this.config[colIndex].hidden = hidden;
5668 this.totalWidth = null;
5669 this.fireEvent("hiddenchange", this, colIndex, hidden);
5673 * Sets the editor for a column.
5674 * @param {Number} col The column index
5675 * @param {Object} editor The editor object
5677 setEditor : function(col, editor){
5678 this.config[col].editor = editor;
5682 Roo.grid.ColumnModel.defaultRenderer = function(value)
5684 if(typeof value == "object") {
5687 if(typeof value == "string" && value.length < 1){
5691 return String.format("{0}", value);
5694 // Alias for backwards compatibility
5695 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5698 * Ext JS Library 1.1.1
5699 * Copyright(c) 2006-2007, Ext JS, LLC.
5701 * Originally Released Under LGPL - original licence link has changed is not relivant.
5704 * <script type="text/javascript">
5708 * @class Roo.LoadMask
5709 * A simple utility class for generically masking elements while loading data. If the element being masked has
5710 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5711 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5712 * element's UpdateManager load indicator and will be destroyed after the initial load.
5714 * Create a new LoadMask
5715 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5716 * @param {Object} config The config object
5718 Roo.LoadMask = function(el, config){
5719 this.el = Roo.get(el);
5720 Roo.apply(this, config);
5722 this.store.on('beforeload', this.onBeforeLoad, this);
5723 this.store.on('load', this.onLoad, this);
5724 this.store.on('loadexception', this.onLoadException, this);
5725 this.removeMask = false;
5727 var um = this.el.getUpdateManager();
5728 um.showLoadIndicator = false; // disable the default indicator
5729 um.on('beforeupdate', this.onBeforeLoad, this);
5730 um.on('update', this.onLoad, this);
5731 um.on('failure', this.onLoad, this);
5732 this.removeMask = true;
5736 Roo.LoadMask.prototype = {
5738 * @cfg {Boolean} removeMask
5739 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5740 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5744 * The text to display in a centered loading message box (defaults to 'Loading...')
5748 * @cfg {String} msgCls
5749 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5751 msgCls : 'x-mask-loading',
5754 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5760 * Disables the mask to prevent it from being displayed
5762 disable : function(){
5763 this.disabled = true;
5767 * Enables the mask so that it can be displayed
5769 enable : function(){
5770 this.disabled = false;
5773 onLoadException : function()
5777 if (typeof(arguments[3]) != 'undefined') {
5778 Roo.MessageBox.alert("Error loading",arguments[3]);
5782 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5783 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5790 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5795 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5799 onBeforeLoad : function(){
5801 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5806 destroy : function(){
5808 this.store.un('beforeload', this.onBeforeLoad, this);
5809 this.store.un('load', this.onLoad, this);
5810 this.store.un('loadexception', this.onLoadException, this);
5812 var um = this.el.getUpdateManager();
5813 um.un('beforeupdate', this.onBeforeLoad, this);
5814 um.un('update', this.onLoad, this);
5815 um.un('failure', this.onLoad, this);
5826 * @class Roo.bootstrap.Table
5827 * @extends Roo.bootstrap.Component
5828 * Bootstrap Table class
5829 * @cfg {String} cls table class
5830 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5831 * @cfg {String} bgcolor Specifies the background color for a table
5832 * @cfg {Number} border Specifies whether the table cells should have borders or not
5833 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5834 * @cfg {Number} cellspacing Specifies the space between cells
5835 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5836 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5837 * @cfg {String} sortable Specifies that the table should be sortable
5838 * @cfg {String} summary Specifies a summary of the content of a table
5839 * @cfg {Number} width Specifies the width of a table
5840 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5842 * @cfg {boolean} striped Should the rows be alternative striped
5843 * @cfg {boolean} bordered Add borders to the table
5844 * @cfg {boolean} hover Add hover highlighting
5845 * @cfg {boolean} condensed Format condensed
5846 * @cfg {boolean} responsive Format condensed
5847 * @cfg {Boolean} loadMask (true|false) default false
5848 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5849 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5850 * @cfg {Boolean} rowSelection (true|false) default false
5851 * @cfg {Boolean} cellSelection (true|false) default false
5852 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5853 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5854 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5858 * Create a new Table
5859 * @param {Object} config The config object
5862 Roo.bootstrap.Table = function(config){
5863 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5868 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5869 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5870 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5871 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5873 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5875 this.sm.grid = this;
5876 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5877 this.sm = this.selModel;
5878 this.sm.xmodule = this.xmodule || false;
5881 if (this.cm && typeof(this.cm.config) == 'undefined') {
5882 this.colModel = new Roo.grid.ColumnModel(this.cm);
5883 this.cm = this.colModel;
5884 this.cm.xmodule = this.xmodule || false;
5887 this.store= Roo.factory(this.store, Roo.data);
5888 this.ds = this.store;
5889 this.ds.xmodule = this.xmodule || false;
5892 if (this.footer && this.store) {
5893 this.footer.dataSource = this.ds;
5894 this.footer = Roo.factory(this.footer);
5901 * Fires when a cell is clicked
5902 * @param {Roo.bootstrap.Table} this
5903 * @param {Roo.Element} el
5904 * @param {Number} rowIndex
5905 * @param {Number} columnIndex
5906 * @param {Roo.EventObject} e
5910 * @event celldblclick
5911 * Fires when a cell is double clicked
5912 * @param {Roo.bootstrap.Table} this
5913 * @param {Roo.Element} el
5914 * @param {Number} rowIndex
5915 * @param {Number} columnIndex
5916 * @param {Roo.EventObject} e
5918 "celldblclick" : true,
5921 * Fires when a row is clicked
5922 * @param {Roo.bootstrap.Table} this
5923 * @param {Roo.Element} el
5924 * @param {Number} rowIndex
5925 * @param {Roo.EventObject} e
5929 * @event rowdblclick
5930 * Fires when a row is double clicked
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Roo.EventObject} e
5936 "rowdblclick" : true,
5939 * Fires when a mouseover occur
5940 * @param {Roo.bootstrap.Table} this
5941 * @param {Roo.Element} el
5942 * @param {Number} rowIndex
5943 * @param {Number} columnIndex
5944 * @param {Roo.EventObject} e
5949 * Fires when a mouseout occur
5950 * @param {Roo.bootstrap.Table} this
5951 * @param {Roo.Element} el
5952 * @param {Number} rowIndex
5953 * @param {Number} columnIndex
5954 * @param {Roo.EventObject} e
5959 * Fires when a row is rendered, so you can change add a style to it.
5960 * @param {Roo.bootstrap.Table} this
5961 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5965 * @event rowsrendered
5966 * Fires when all the rows have been rendered
5967 * @param {Roo.bootstrap.Table} this
5969 'rowsrendered' : true,
5971 * @event contextmenu
5972 * The raw contextmenu event for the entire grid.
5973 * @param {Roo.EventObject} e
5975 "contextmenu" : true,
5977 * @event rowcontextmenu
5978 * Fires when a row is right clicked
5979 * @param {Roo.bootstrap.Table} this
5980 * @param {Number} rowIndex
5981 * @param {Roo.EventObject} e
5983 "rowcontextmenu" : true,
5985 * @event cellcontextmenu
5986 * Fires when a cell is right clicked
5987 * @param {Roo.bootstrap.Table} this
5988 * @param {Number} rowIndex
5989 * @param {Number} cellIndex
5990 * @param {Roo.EventObject} e
5992 "cellcontextmenu" : true,
5994 * @event headercontextmenu
5995 * Fires when a header is right clicked
5996 * @param {Roo.bootstrap.Table} this
5997 * @param {Number} columnIndex
5998 * @param {Roo.EventObject} e
6000 "headercontextmenu" : true
6004 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6030 rowSelection : false,
6031 cellSelection : false,
6034 // Roo.Element - the tbody
6036 // Roo.Element - thead element
6039 container: false, // used by gridpanel...
6043 getAutoCreate : function()
6045 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6052 if (this.scrollBody) {
6053 cfg.cls += ' table-body-fixed';
6056 cfg.cls += ' table-striped';
6060 cfg.cls += ' table-hover';
6062 if (this.bordered) {
6063 cfg.cls += ' table-bordered';
6065 if (this.condensed) {
6066 cfg.cls += ' table-condensed';
6068 if (this.responsive) {
6069 cfg.cls += ' table-responsive';
6073 cfg.cls+= ' ' +this.cls;
6076 // this lot should be simplifed...
6079 cfg.align=this.align;
6082 cfg.bgcolor=this.bgcolor;
6085 cfg.border=this.border;
6087 if (this.cellpadding) {
6088 cfg.cellpadding=this.cellpadding;
6090 if (this.cellspacing) {
6091 cfg.cellspacing=this.cellspacing;
6094 cfg.frame=this.frame;
6097 cfg.rules=this.rules;
6099 if (this.sortable) {
6100 cfg.sortable=this.sortable;
6103 cfg.summary=this.summary;
6106 cfg.width=this.width;
6109 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6112 if(this.store || this.cm){
6113 if(this.headerShow){
6114 cfg.cn.push(this.renderHeader());
6117 cfg.cn.push(this.renderBody());
6119 if(this.footerShow){
6120 cfg.cn.push(this.renderFooter());
6122 // where does this come from?
6123 //cfg.cls+= ' TableGrid';
6126 return { cn : [ cfg ] };
6129 initEvents : function()
6131 if(!this.store || !this.cm){
6134 if (this.selModel) {
6135 this.selModel.initEvents();
6139 //Roo.log('initEvents with ds!!!!');
6141 this.mainBody = this.el.select('tbody', true).first();
6142 this.mainHead = this.el.select('thead', true).first();
6149 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6150 e.on('click', _this.sort, _this);
6153 this.mainBody.on("click", this.onClick, this);
6154 this.mainBody.on("dblclick", this.onDblClick, this);
6156 // why is this done????? = it breaks dialogs??
6157 //this.parent().el.setStyle('position', 'relative');
6161 this.footer.parentId = this.id;
6162 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6165 this.el.select('tfoot tr td').first().addClass('hide');
6169 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6171 this.store.on('load', this.onLoad, this);
6172 this.store.on('beforeload', this.onBeforeLoad, this);
6173 this.store.on('update', this.onUpdate, this);
6174 this.store.on('add', this.onAdd, this);
6175 this.store.on("clear", this.clear, this);
6177 this.el.on("contextmenu", this.onContextMenu, this);
6179 this.mainBody.on('scroll', this.onBodyScroll, this);
6181 this.cm.on("headerchange", this.onHeaderChange, this);
6185 onContextMenu : function(e, t)
6187 this.processEvent("contextmenu", e);
6190 processEvent : function(name, e)
6192 if (name != 'touchstart' ) {
6193 this.fireEvent(name, e);
6196 var t = e.getTarget();
6198 var cell = Roo.get(t);
6204 if(cell.findParent('tfoot', false, true)){
6208 if(cell.findParent('thead', false, true)){
6210 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6211 cell = Roo.get(t).findParent('th', false, true);
6213 Roo.log("failed to find th in thead?");
6214 Roo.log(e.getTarget());
6219 var cellIndex = cell.dom.cellIndex;
6221 var ename = name == 'touchstart' ? 'click' : name;
6222 this.fireEvent("header" + ename, this, cellIndex, e);
6227 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6228 cell = Roo.get(t).findParent('td', false, true);
6230 Roo.log("failed to find th in tbody?");
6231 Roo.log(e.getTarget());
6236 var row = cell.findParent('tr', false, true);
6237 var cellIndex = cell.dom.cellIndex;
6238 var rowIndex = row.dom.rowIndex - 1;
6242 this.fireEvent("row" + name, this, rowIndex, e);
6246 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6252 onMouseover : function(e, el)
6254 var cell = Roo.get(el);
6260 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6261 cell = cell.findParent('td', false, true);
6264 var row = cell.findParent('tr', false, true);
6265 var cellIndex = cell.dom.cellIndex;
6266 var rowIndex = row.dom.rowIndex - 1; // start from 0
6268 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6272 onMouseout : function(e, el)
6274 var cell = Roo.get(el);
6280 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6281 cell = cell.findParent('td', false, true);
6284 var row = cell.findParent('tr', false, true);
6285 var cellIndex = cell.dom.cellIndex;
6286 var rowIndex = row.dom.rowIndex - 1; // start from 0
6288 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6292 onClick : function(e, el)
6294 var cell = Roo.get(el);
6296 if(!cell || (!this.cellSelection && !this.rowSelection)){
6300 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6301 cell = cell.findParent('td', false, true);
6304 if(!cell || typeof(cell) == 'undefined'){
6308 var row = cell.findParent('tr', false, true);
6310 if(!row || typeof(row) == 'undefined'){
6314 var cellIndex = cell.dom.cellIndex;
6315 var rowIndex = this.getRowIndex(row);
6317 // why??? - should these not be based on SelectionModel?
6318 if(this.cellSelection){
6319 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6322 if(this.rowSelection){
6323 this.fireEvent('rowclick', this, row, rowIndex, e);
6329 onDblClick : function(e,el)
6331 var cell = Roo.get(el);
6333 if(!cell || (!this.cellSelection && !this.rowSelection)){
6337 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6338 cell = cell.findParent('td', false, true);
6341 if(!cell || typeof(cell) == 'undefined'){
6345 var row = cell.findParent('tr', false, true);
6347 if(!row || typeof(row) == 'undefined'){
6351 var cellIndex = cell.dom.cellIndex;
6352 var rowIndex = this.getRowIndex(row);
6354 if(this.cellSelection){
6355 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6358 if(this.rowSelection){
6359 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6363 sort : function(e,el)
6365 var col = Roo.get(el);
6367 if(!col.hasClass('sortable')){
6371 var sort = col.attr('sort');
6374 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6378 this.store.sortInfo = {field : sort, direction : dir};
6381 Roo.log("calling footer first");
6382 this.footer.onClick('first');
6385 this.store.load({ params : { start : 0 } });
6389 renderHeader : function()
6397 this.totalWidth = 0;
6399 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6401 var config = cm.config[i];
6406 html: cm.getColumnHeader(i)
6411 if(typeof(config.sortable) != 'undefined' && config.sortable){
6413 c.html = '<i class="glyphicon"></i>' + c.html;
6416 if(typeof(config.lgHeader) != 'undefined'){
6417 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6420 if(typeof(config.mdHeader) != 'undefined'){
6421 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6424 if(typeof(config.smHeader) != 'undefined'){
6425 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6428 if(typeof(config.xsHeader) != 'undefined'){
6429 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6436 if(typeof(config.tooltip) != 'undefined'){
6437 c.tooltip = config.tooltip;
6440 if(typeof(config.colspan) != 'undefined'){
6441 c.colspan = config.colspan;
6444 if(typeof(config.hidden) != 'undefined' && config.hidden){
6445 c.style += ' display:none;';
6448 if(typeof(config.dataIndex) != 'undefined'){
6449 c.sort = config.dataIndex;
6454 if(typeof(config.align) != 'undefined' && config.align.length){
6455 c.style += ' text-align:' + config.align + ';';
6458 if(typeof(config.width) != 'undefined'){
6459 c.style += ' width:' + config.width + 'px;';
6460 this.totalWidth += config.width;
6462 this.totalWidth += 100; // assume minimum of 100 per column?
6465 if(typeof(config.cls) != 'undefined'){
6466 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6469 ['xs','sm','md','lg'].map(function(size){
6471 if(typeof(config[size]) == 'undefined'){
6475 if (!config[size]) { // 0 = hidden
6476 c.cls += ' hidden-' + size;
6480 c.cls += ' col-' + size + '-' + config[size];
6490 renderBody : function()
6500 colspan : this.cm.getColumnCount()
6510 renderFooter : function()
6520 colspan : this.cm.getColumnCount()
6534 // Roo.log('ds onload');
6539 var ds = this.store;
6541 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6542 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6543 if (_this.store.sortInfo) {
6545 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6546 e.select('i', true).addClass(['glyphicon-arrow-up']);
6549 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6550 e.select('i', true).addClass(['glyphicon-arrow-down']);
6555 var tbody = this.mainBody;
6557 if(ds.getCount() > 0){
6558 ds.data.each(function(d,rowIndex){
6559 var row = this.renderRow(cm, ds, rowIndex);
6561 tbody.createChild(row);
6565 if(row.cellObjects.length){
6566 Roo.each(row.cellObjects, function(r){
6567 _this.renderCellObject(r);
6574 Roo.each(this.el.select('tbody td', true).elements, function(e){
6575 e.on('mouseover', _this.onMouseover, _this);
6578 Roo.each(this.el.select('tbody td', true).elements, function(e){
6579 e.on('mouseout', _this.onMouseout, _this);
6581 this.fireEvent('rowsrendered', this);
6582 //if(this.loadMask){
6583 // this.maskEl.hide();
6590 onUpdate : function(ds,record)
6592 this.refreshRow(record);
6596 onRemove : function(ds, record, index, isUpdate){
6597 if(isUpdate !== true){
6598 this.fireEvent("beforerowremoved", this, index, record);
6600 var bt = this.mainBody.dom;
6602 var rows = this.el.select('tbody > tr', true).elements;
6604 if(typeof(rows[index]) != 'undefined'){
6605 bt.removeChild(rows[index].dom);
6608 // if(bt.rows[index]){
6609 // bt.removeChild(bt.rows[index]);
6612 if(isUpdate !== true){
6613 //this.stripeRows(index);
6614 //this.syncRowHeights(index, index);
6616 this.fireEvent("rowremoved", this, index, record);
6620 onAdd : function(ds, records, rowIndex)
6622 //Roo.log('on Add called');
6623 // - note this does not handle multiple adding very well..
6624 var bt = this.mainBody.dom;
6625 for (var i =0 ; i < records.length;i++) {
6626 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6627 //Roo.log(records[i]);
6628 //Roo.log(this.store.getAt(rowIndex+i));
6629 this.insertRow(this.store, rowIndex + i, false);
6636 refreshRow : function(record){
6637 var ds = this.store, index;
6638 if(typeof record == 'number'){
6640 record = ds.getAt(index);
6642 index = ds.indexOf(record);
6644 this.insertRow(ds, index, true);
6646 this.onRemove(ds, record, index+1, true);
6648 //this.syncRowHeights(index, index);
6650 this.fireEvent("rowupdated", this, index, record);
6653 insertRow : function(dm, rowIndex, isUpdate){
6656 this.fireEvent("beforerowsinserted", this, rowIndex);
6658 //var s = this.getScrollState();
6659 var row = this.renderRow(this.cm, this.store, rowIndex);
6660 // insert before rowIndex..
6661 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6665 if(row.cellObjects.length){
6666 Roo.each(row.cellObjects, function(r){
6667 _this.renderCellObject(r);
6672 this.fireEvent("rowsinserted", this, rowIndex);
6673 //this.syncRowHeights(firstRow, lastRow);
6674 //this.stripeRows(firstRow);
6681 getRowDom : function(rowIndex)
6683 var rows = this.el.select('tbody > tr', true).elements;
6685 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6688 // returns the object tree for a tr..
6691 renderRow : function(cm, ds, rowIndex)
6694 var d = ds.getAt(rowIndex);
6701 var cellObjects = [];
6703 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6704 var config = cm.config[i];
6706 var renderer = cm.getRenderer(i);
6710 if(typeof(renderer) !== 'undefined'){
6711 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6713 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6714 // and are rendered into the cells after the row is rendered - using the id for the element.
6716 if(typeof(value) === 'object'){
6726 rowIndex : rowIndex,
6731 this.fireEvent('rowclass', this, rowcfg);
6735 cls : rowcfg.rowClass,
6737 html: (typeof(value) === 'object') ? '' : value
6744 if(typeof(config.colspan) != 'undefined'){
6745 td.colspan = config.colspan;
6748 if(typeof(config.hidden) != 'undefined' && config.hidden){
6749 td.style += ' display:none;';
6752 if(typeof(config.align) != 'undefined' && config.align.length){
6753 td.style += ' text-align:' + config.align + ';';
6756 if(typeof(config.width) != 'undefined'){
6757 td.style += ' width:' + config.width + 'px;';
6760 if(typeof(config.cursor) != 'undefined'){
6761 td.style += ' cursor:' + config.cursor + ';';
6764 if(typeof(config.cls) != 'undefined'){
6765 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6768 ['xs','sm','md','lg'].map(function(size){
6770 if(typeof(config[size]) == 'undefined'){
6774 if (!config[size]) { // 0 = hidden
6775 td.cls += ' hidden-' + size;
6779 td.cls += ' col-' + size + '-' + config[size];
6787 row.cellObjects = cellObjects;
6795 onBeforeLoad : function()
6797 //Roo.log('ds onBeforeLoad');
6801 //if(this.loadMask){
6802 // this.maskEl.show();
6810 this.el.select('tbody', true).first().dom.innerHTML = '';
6813 * Show or hide a row.
6814 * @param {Number} rowIndex to show or hide
6815 * @param {Boolean} state hide
6817 setRowVisibility : function(rowIndex, state)
6819 var bt = this.mainBody.dom;
6821 var rows = this.el.select('tbody > tr', true).elements;
6823 if(typeof(rows[rowIndex]) == 'undefined'){
6826 rows[rowIndex].dom.style.display = state ? '' : 'none';
6830 getSelectionModel : function(){
6832 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6834 return this.selModel;
6837 * Render the Roo.bootstrap object from renderder
6839 renderCellObject : function(r)
6843 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6845 var t = r.cfg.render(r.container);
6848 Roo.each(r.cfg.cn, function(c){
6850 container: t.getChildContainer(),
6853 _this.renderCellObject(child);
6858 getRowIndex : function(row)
6862 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6873 * Returns the grid's underlying element = used by panel.Grid
6874 * @return {Element} The element
6876 getGridEl : function(){
6880 * Forces a resize - used by panel.Grid
6881 * @return {Element} The element
6883 autoSize : function()
6885 //var ctr = Roo.get(this.container.dom.parentElement);
6886 var ctr = Roo.get(this.el.dom);
6888 var thd = this.getGridEl().select('thead',true).first();
6889 var tbd = this.getGridEl().select('tbody', true).first();
6890 var tfd = this.getGridEl().select('tfoot', true).first();
6892 var cw = ctr.getWidth();
6896 tbd.setSize(ctr.getWidth(),
6897 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6899 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6902 cw = Math.max(cw, this.totalWidth);
6903 this.getGridEl().select('tr',true).setWidth(cw);
6904 // resize 'expandable coloumn?
6906 return; // we doe not have a view in this design..
6909 onBodyScroll: function()
6911 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6913 this.mainHead.setStyle({
6914 'position' : 'relative',
6915 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6921 var scrollHeight = this.mainBody.dom.scrollHeight;
6923 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6925 var height = this.mainBody.getHeight();
6927 if(scrollHeight - height == scrollTop) {
6929 var total = this.ds.getTotalCount();
6931 if(this.footer.cursor + this.footer.pageSize < total){
6933 this.footer.ds.load({
6935 start : this.footer.cursor + this.footer.pageSize,
6936 limit : this.footer.pageSize
6946 onHeaderChange : function()
6949 var header = this.renderHeader();
6950 var table = this.el.select('table', true).first();
6952 this.mainHead.remove();
6953 this.mainHead = table.createChild(header, this.mainBody, false);
6968 * @class Roo.bootstrap.TableCell
6969 * @extends Roo.bootstrap.Component
6970 * Bootstrap TableCell class
6971 * @cfg {String} html cell contain text
6972 * @cfg {String} cls cell class
6973 * @cfg {String} tag cell tag (td|th) default td
6974 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6975 * @cfg {String} align Aligns the content in a cell
6976 * @cfg {String} axis Categorizes cells
6977 * @cfg {String} bgcolor Specifies the background color of a cell
6978 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6979 * @cfg {Number} colspan Specifies the number of columns a cell should span
6980 * @cfg {String} headers Specifies one or more header cells a cell is related to
6981 * @cfg {Number} height Sets the height of a cell
6982 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6983 * @cfg {Number} rowspan Sets the number of rows a cell should span
6984 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6985 * @cfg {String} valign Vertical aligns the content in a cell
6986 * @cfg {Number} width Specifies the width of a cell
6989 * Create a new TableCell
6990 * @param {Object} config The config object
6993 Roo.bootstrap.TableCell = function(config){
6994 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6997 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7017 getAutoCreate : function(){
7018 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7038 cfg.align=this.align
7044 cfg.bgcolor=this.bgcolor
7047 cfg.charoff=this.charoff
7050 cfg.colspan=this.colspan
7053 cfg.headers=this.headers
7056 cfg.height=this.height
7059 cfg.nowrap=this.nowrap
7062 cfg.rowspan=this.rowspan
7065 cfg.scope=this.scope
7068 cfg.valign=this.valign
7071 cfg.width=this.width
7090 * @class Roo.bootstrap.TableRow
7091 * @extends Roo.bootstrap.Component
7092 * Bootstrap TableRow class
7093 * @cfg {String} cls row class
7094 * @cfg {String} align Aligns the content in a table row
7095 * @cfg {String} bgcolor Specifies a background color for a table row
7096 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7097 * @cfg {String} valign Vertical aligns the content in a table row
7100 * Create a new TableRow
7101 * @param {Object} config The config object
7104 Roo.bootstrap.TableRow = function(config){
7105 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7108 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7116 getAutoCreate : function(){
7117 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7127 cfg.align = this.align;
7130 cfg.bgcolor = this.bgcolor;
7133 cfg.charoff = this.charoff;
7136 cfg.valign = this.valign;
7154 * @class Roo.bootstrap.TableBody
7155 * @extends Roo.bootstrap.Component
7156 * Bootstrap TableBody class
7157 * @cfg {String} cls element class
7158 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7159 * @cfg {String} align Aligns the content inside the element
7160 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7161 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7164 * Create a new TableBody
7165 * @param {Object} config The config object
7168 Roo.bootstrap.TableBody = function(config){
7169 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7172 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7180 getAutoCreate : function(){
7181 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7195 cfg.align = this.align;
7198 cfg.charoff = this.charoff;
7201 cfg.valign = this.valign;
7208 // initEvents : function()
7215 // this.store = Roo.factory(this.store, Roo.data);
7216 // this.store.on('load', this.onLoad, this);
7218 // this.store.load();
7222 // onLoad: function ()
7224 // this.fireEvent('load', this);
7234 * Ext JS Library 1.1.1
7235 * Copyright(c) 2006-2007, Ext JS, LLC.
7237 * Originally Released Under LGPL - original licence link has changed is not relivant.
7240 * <script type="text/javascript">
7243 // as we use this in bootstrap.
7244 Roo.namespace('Roo.form');
7246 * @class Roo.form.Action
7247 * Internal Class used to handle form actions
7249 * @param {Roo.form.BasicForm} el The form element or its id
7250 * @param {Object} config Configuration options
7255 // define the action interface
7256 Roo.form.Action = function(form, options){
7258 this.options = options || {};
7261 * Client Validation Failed
7264 Roo.form.Action.CLIENT_INVALID = 'client';
7266 * Server Validation Failed
7269 Roo.form.Action.SERVER_INVALID = 'server';
7271 * Connect to Server Failed
7274 Roo.form.Action.CONNECT_FAILURE = 'connect';
7276 * Reading Data from Server Failed
7279 Roo.form.Action.LOAD_FAILURE = 'load';
7281 Roo.form.Action.prototype = {
7283 failureType : undefined,
7284 response : undefined,
7288 run : function(options){
7293 success : function(response){
7298 handleResponse : function(response){
7302 // default connection failure
7303 failure : function(response){
7305 this.response = response;
7306 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7307 this.form.afterAction(this, false);
7310 processResponse : function(response){
7311 this.response = response;
7312 if(!response.responseText){
7315 this.result = this.handleResponse(response);
7319 // utility functions used internally
7320 getUrl : function(appendParams){
7321 var url = this.options.url || this.form.url || this.form.el.dom.action;
7323 var p = this.getParams();
7325 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7331 getMethod : function(){
7332 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7335 getParams : function(){
7336 var bp = this.form.baseParams;
7337 var p = this.options.params;
7339 if(typeof p == "object"){
7340 p = Roo.urlEncode(Roo.applyIf(p, bp));
7341 }else if(typeof p == 'string' && bp){
7342 p += '&' + Roo.urlEncode(bp);
7345 p = Roo.urlEncode(bp);
7350 createCallback : function(){
7352 success: this.success,
7353 failure: this.failure,
7355 timeout: (this.form.timeout*1000),
7356 upload: this.form.fileUpload ? this.success : undefined
7361 Roo.form.Action.Submit = function(form, options){
7362 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7365 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7368 haveProgress : false,
7369 uploadComplete : false,
7371 // uploadProgress indicator.
7372 uploadProgress : function()
7374 if (!this.form.progressUrl) {
7378 if (!this.haveProgress) {
7379 Roo.MessageBox.progress("Uploading", "Uploading");
7381 if (this.uploadComplete) {
7382 Roo.MessageBox.hide();
7386 this.haveProgress = true;
7388 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7390 var c = new Roo.data.Connection();
7392 url : this.form.progressUrl,
7397 success : function(req){
7398 //console.log(data);
7402 rdata = Roo.decode(req.responseText)
7404 Roo.log("Invalid data from server..");
7408 if (!rdata || !rdata.success) {
7410 Roo.MessageBox.alert(Roo.encode(rdata));
7413 var data = rdata.data;
7415 if (this.uploadComplete) {
7416 Roo.MessageBox.hide();
7421 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7422 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7425 this.uploadProgress.defer(2000,this);
7428 failure: function(data) {
7429 Roo.log('progress url failed ');
7440 // run get Values on the form, so it syncs any secondary forms.
7441 this.form.getValues();
7443 var o = this.options;
7444 var method = this.getMethod();
7445 var isPost = method == 'POST';
7446 if(o.clientValidation === false || this.form.isValid()){
7448 if (this.form.progressUrl) {
7449 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7450 (new Date() * 1) + '' + Math.random());
7455 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7456 form:this.form.el.dom,
7457 url:this.getUrl(!isPost),
7459 params:isPost ? this.getParams() : null,
7460 isUpload: this.form.fileUpload
7463 this.uploadProgress();
7465 }else if (o.clientValidation !== false){ // client validation failed
7466 this.failureType = Roo.form.Action.CLIENT_INVALID;
7467 this.form.afterAction(this, false);
7471 success : function(response)
7473 this.uploadComplete= true;
7474 if (this.haveProgress) {
7475 Roo.MessageBox.hide();
7479 var result = this.processResponse(response);
7480 if(result === true || result.success){
7481 this.form.afterAction(this, true);
7485 this.form.markInvalid(result.errors);
7486 this.failureType = Roo.form.Action.SERVER_INVALID;
7488 this.form.afterAction(this, false);
7490 failure : function(response)
7492 this.uploadComplete= true;
7493 if (this.haveProgress) {
7494 Roo.MessageBox.hide();
7497 this.response = response;
7498 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7499 this.form.afterAction(this, false);
7502 handleResponse : function(response){
7503 if(this.form.errorReader){
7504 var rs = this.form.errorReader.read(response);
7507 for(var i = 0, len = rs.records.length; i < len; i++) {
7508 var r = rs.records[i];
7512 if(errors.length < 1){
7516 success : rs.success,
7522 ret = Roo.decode(response.responseText);
7526 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7536 Roo.form.Action.Load = function(form, options){
7537 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7538 this.reader = this.form.reader;
7541 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7546 Roo.Ajax.request(Roo.apply(
7547 this.createCallback(), {
7548 method:this.getMethod(),
7549 url:this.getUrl(false),
7550 params:this.getParams()
7554 success : function(response){
7556 var result = this.processResponse(response);
7557 if(result === true || !result.success || !result.data){
7558 this.failureType = Roo.form.Action.LOAD_FAILURE;
7559 this.form.afterAction(this, false);
7562 this.form.clearInvalid();
7563 this.form.setValues(result.data);
7564 this.form.afterAction(this, true);
7567 handleResponse : function(response){
7568 if(this.form.reader){
7569 var rs = this.form.reader.read(response);
7570 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7572 success : rs.success,
7576 return Roo.decode(response.responseText);
7580 Roo.form.Action.ACTION_TYPES = {
7581 'load' : Roo.form.Action.Load,
7582 'submit' : Roo.form.Action.Submit
7591 * @class Roo.bootstrap.Form
7592 * @extends Roo.bootstrap.Component
7593 * Bootstrap Form class
7594 * @cfg {String} method GET | POST (default POST)
7595 * @cfg {String} labelAlign top | left (default top)
7596 * @cfg {String} align left | right - for navbars
7597 * @cfg {Boolean} loadMask load mask when submit (default true)
7602 * @param {Object} config The config object
7606 Roo.bootstrap.Form = function(config){
7608 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7610 Roo.bootstrap.Form.popover.apply();
7614 * @event clientvalidation
7615 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7616 * @param {Form} this
7617 * @param {Boolean} valid true if the form has passed client-side validation
7619 clientvalidation: true,
7621 * @event beforeaction
7622 * Fires before any action is performed. Return false to cancel the action.
7623 * @param {Form} this
7624 * @param {Action} action The action to be performed
7628 * @event actionfailed
7629 * Fires when an action fails.
7630 * @param {Form} this
7631 * @param {Action} action The action that failed
7633 actionfailed : true,
7635 * @event actioncomplete
7636 * Fires when an action is completed.
7637 * @param {Form} this
7638 * @param {Action} action The action that completed
7640 actioncomplete : true
7644 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7647 * @cfg {String} method
7648 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7653 * The URL to use for form actions if one isn't supplied in the action options.
7656 * @cfg {Boolean} fileUpload
7657 * Set to true if this form is a file upload.
7661 * @cfg {Object} baseParams
7662 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7666 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7670 * @cfg {Sting} align (left|right) for navbar forms
7675 activeAction : null,
7678 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7679 * element by passing it or its id or mask the form itself by passing in true.
7682 waitMsgTarget : false,
7687 * @cfg {Boolean} errorMask (true|false) default false
7692 * @cfg {Number} maskOffset Default 100
7697 * @cfg {Boolean} maskBody
7701 getAutoCreate : function(){
7705 method : this.method || 'POST',
7706 id : this.id || Roo.id(),
7709 if (this.parent().xtype.match(/^Nav/)) {
7710 cfg.cls = 'navbar-form navbar-' + this.align;
7714 if (this.labelAlign == 'left' ) {
7715 cfg.cls += ' form-horizontal';
7721 initEvents : function()
7723 this.el.on('submit', this.onSubmit, this);
7724 // this was added as random key presses on the form where triggering form submit.
7725 this.el.on('keypress', function(e) {
7726 if (e.getCharCode() != 13) {
7729 // we might need to allow it for textareas.. and some other items.
7730 // check e.getTarget().
7732 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7736 Roo.log("keypress blocked");
7744 onSubmit : function(e){
7749 * Returns true if client-side validation on the form is successful.
7752 isValid : function(){
7753 var items = this.getItems();
7757 items.each(function(f){
7763 if(!target && f.el.isVisible(true)){
7769 if(this.errorMask && !valid){
7770 Roo.bootstrap.Form.popover.mask(this, target);
7777 * Returns true if any fields in this form have changed since their original load.
7780 isDirty : function(){
7782 var items = this.getItems();
7783 items.each(function(f){
7793 * Performs a predefined action (submit or load) or custom actions you define on this form.
7794 * @param {String} actionName The name of the action type
7795 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7796 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7797 * accept other config options):
7799 Property Type Description
7800 ---------------- --------------- ----------------------------------------------------------------------------------
7801 url String The url for the action (defaults to the form's url)
7802 method String The form method to use (defaults to the form's method, or POST if not defined)
7803 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7804 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7805 validate the form on the client (defaults to false)
7807 * @return {BasicForm} this
7809 doAction : function(action, options){
7810 if(typeof action == 'string'){
7811 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7813 if(this.fireEvent('beforeaction', this, action) !== false){
7814 this.beforeAction(action);
7815 action.run.defer(100, action);
7821 beforeAction : function(action){
7822 var o = action.options;
7827 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7829 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7832 // not really supported yet.. ??
7834 //if(this.waitMsgTarget === true){
7835 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7836 //}else if(this.waitMsgTarget){
7837 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7838 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7840 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7846 afterAction : function(action, success){
7847 this.activeAction = null;
7848 var o = action.options;
7853 Roo.get(document.body).unmask();
7859 //if(this.waitMsgTarget === true){
7860 // this.el.unmask();
7861 //}else if(this.waitMsgTarget){
7862 // this.waitMsgTarget.unmask();
7864 // Roo.MessageBox.updateProgress(1);
7865 // Roo.MessageBox.hide();
7872 Roo.callback(o.success, o.scope, [this, action]);
7873 this.fireEvent('actioncomplete', this, action);
7877 // failure condition..
7878 // we have a scenario where updates need confirming.
7879 // eg. if a locking scenario exists..
7880 // we look for { errors : { needs_confirm : true }} in the response.
7882 (typeof(action.result) != 'undefined') &&
7883 (typeof(action.result.errors) != 'undefined') &&
7884 (typeof(action.result.errors.needs_confirm) != 'undefined')
7887 Roo.log("not supported yet");
7890 Roo.MessageBox.confirm(
7891 "Change requires confirmation",
7892 action.result.errorMsg,
7897 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7907 Roo.callback(o.failure, o.scope, [this, action]);
7908 // show an error message if no failed handler is set..
7909 if (!this.hasListener('actionfailed')) {
7910 Roo.log("need to add dialog support");
7912 Roo.MessageBox.alert("Error",
7913 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7914 action.result.errorMsg :
7915 "Saving Failed, please check your entries or try again"
7920 this.fireEvent('actionfailed', this, action);
7925 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7926 * @param {String} id The value to search for
7929 findField : function(id){
7930 var items = this.getItems();
7931 var field = items.get(id);
7933 items.each(function(f){
7934 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7941 return field || null;
7944 * Mark fields in this form invalid in bulk.
7945 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7946 * @return {BasicForm} this
7948 markInvalid : function(errors){
7949 if(errors instanceof Array){
7950 for(var i = 0, len = errors.length; i < len; i++){
7951 var fieldError = errors[i];
7952 var f = this.findField(fieldError.id);
7954 f.markInvalid(fieldError.msg);
7960 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7961 field.markInvalid(errors[id]);
7965 //Roo.each(this.childForms || [], function (f) {
7966 // f.markInvalid(errors);
7973 * Set values for fields in this form in bulk.
7974 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7975 * @return {BasicForm} this
7977 setValues : function(values){
7978 if(values instanceof Array){ // array of objects
7979 for(var i = 0, len = values.length; i < len; i++){
7981 var f = this.findField(v.id);
7983 f.setValue(v.value);
7984 if(this.trackResetOnLoad){
7985 f.originalValue = f.getValue();
7989 }else{ // object hash
7992 if(typeof values[id] != 'function' && (field = this.findField(id))){
7994 if (field.setFromData &&
7996 field.displayField &&
7997 // combos' with local stores can
7998 // be queried via setValue()
7999 // to set their value..
8000 (field.store && !field.store.isLocal)
8004 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8005 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8006 field.setFromData(sd);
8008 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8010 field.setFromData(values);
8013 field.setValue(values[id]);
8017 if(this.trackResetOnLoad){
8018 field.originalValue = field.getValue();
8024 //Roo.each(this.childForms || [], function (f) {
8025 // f.setValues(values);
8032 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8033 * they are returned as an array.
8034 * @param {Boolean} asString
8037 getValues : function(asString){
8038 //if (this.childForms) {
8039 // copy values from the child forms
8040 // Roo.each(this.childForms, function (f) {
8041 // this.setValues(f.getValues());
8047 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8048 if(asString === true){
8051 return Roo.urlDecode(fs);
8055 * Returns the fields in this form as an object with key/value pairs.
8056 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8059 getFieldValues : function(with_hidden)
8061 var items = this.getItems();
8063 items.each(function(f){
8069 var v = f.getValue();
8071 if (f.inputType =='radio') {
8072 if (typeof(ret[f.getName()]) == 'undefined') {
8073 ret[f.getName()] = ''; // empty..
8076 if (!f.el.dom.checked) {
8084 if(f.xtype == 'MoneyField'){
8085 ret[f.currencyName] = f.getCurrency();
8088 // not sure if this supported any more..
8089 if ((typeof(v) == 'object') && f.getRawValue) {
8090 v = f.getRawValue() ; // dates..
8092 // combo boxes where name != hiddenName...
8093 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8094 ret[f.name] = f.getRawValue();
8096 ret[f.getName()] = v;
8103 * Clears all invalid messages in this form.
8104 * @return {BasicForm} this
8106 clearInvalid : function(){
8107 var items = this.getItems();
8109 items.each(function(f){
8118 * @return {BasicForm} this
8121 var items = this.getItems();
8122 items.each(function(f){
8126 Roo.each(this.childForms || [], function (f) {
8134 getItems : function()
8136 var r=new Roo.util.MixedCollection(false, function(o){
8137 return o.id || (o.id = Roo.id());
8139 var iter = function(el) {
8146 Roo.each(el.items,function(e) {
8155 hideFields : function(items)
8157 Roo.each(items, function(i){
8159 var f = this.findField(i);
8165 if(f.xtype == 'DateField'){
8166 f.setVisible(false);
8175 showFields : function(items)
8177 Roo.each(items, function(i){
8179 var f = this.findField(i);
8185 if(f.xtype == 'DateField'){
8197 Roo.apply(Roo.bootstrap.Form, {
8224 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8225 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8226 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8227 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8230 this.maskEl.top.enableDisplayMode("block");
8231 this.maskEl.left.enableDisplayMode("block");
8232 this.maskEl.bottom.enableDisplayMode("block");
8233 this.maskEl.right.enableDisplayMode("block");
8235 this.toolTip = new Roo.bootstrap.Tooltip({
8236 cls : 'roo-form-error-popover',
8238 'left' : ['r-l', [-2,0], 'right'],
8239 'right' : ['l-r', [2,0], 'left'],
8240 'bottom' : ['tl-bl', [0,2], 'top'],
8241 'top' : [ 'bl-tl', [0,-2], 'bottom']
8245 this.toolTip.render(Roo.get(document.body));
8247 this.toolTip.el.enableDisplayMode("block");
8249 Roo.get(document.body).on('click', function(){
8253 Roo.get(document.body).on('touchstart', function(){
8257 this.isApplied = true
8260 mask : function(form, target)
8264 this.target = target;
8266 if(!this.form.errorMask || !target.el){
8270 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8272 Roo.log(scrollable);
8274 var ot = this.target.el.calcOffsetsTo(scrollable);
8276 var scrollTo = ot[1] - this.form.maskOffset;
8278 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8280 scrollable.scrollTo('top', scrollTo);
8282 var box = this.target.el.getBox();
8284 var zIndex = Roo.bootstrap.Modal.zIndex++;
8287 this.maskEl.top.setStyle('position', 'absolute');
8288 this.maskEl.top.setStyle('z-index', zIndex);
8289 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8290 this.maskEl.top.setLeft(0);
8291 this.maskEl.top.setTop(0);
8292 this.maskEl.top.show();
8294 this.maskEl.left.setStyle('position', 'absolute');
8295 this.maskEl.left.setStyle('z-index', zIndex);
8296 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8297 this.maskEl.left.setLeft(0);
8298 this.maskEl.left.setTop(box.y - this.padding);
8299 this.maskEl.left.show();
8301 this.maskEl.bottom.setStyle('position', 'absolute');
8302 this.maskEl.bottom.setStyle('z-index', zIndex);
8303 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8304 this.maskEl.bottom.setLeft(0);
8305 this.maskEl.bottom.setTop(box.bottom + this.padding);
8306 this.maskEl.bottom.show();
8308 this.maskEl.right.setStyle('position', 'absolute');
8309 this.maskEl.right.setStyle('z-index', zIndex);
8310 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8311 this.maskEl.right.setLeft(box.right + this.padding);
8312 this.maskEl.right.setTop(box.y - this.padding);
8313 this.maskEl.right.show();
8315 this.toolTip.bindEl = this.target.el;
8317 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8319 var tip = this.target.blankText;
8321 if(this.target.getValue() !== '' ) {
8323 if (this.target.invalidText.length) {
8324 tip = this.target.invalidText;
8325 } else if (this.target.regexText.length){
8326 tip = this.target.regexText;
8330 this.toolTip.show(tip);
8332 this.intervalID = window.setInterval(function() {
8333 Roo.bootstrap.Form.popover.unmask();
8336 window.onwheel = function(){ return false;};
8338 (function(){ this.isMasked = true; }).defer(500, this);
8344 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8348 this.maskEl.top.setStyle('position', 'absolute');
8349 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8350 this.maskEl.top.hide();
8352 this.maskEl.left.setStyle('position', 'absolute');
8353 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8354 this.maskEl.left.hide();
8356 this.maskEl.bottom.setStyle('position', 'absolute');
8357 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8358 this.maskEl.bottom.hide();
8360 this.maskEl.right.setStyle('position', 'absolute');
8361 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8362 this.maskEl.right.hide();
8364 this.toolTip.hide();
8366 this.toolTip.el.hide();
8368 window.onwheel = function(){ return true;};
8370 if(this.intervalID){
8371 window.clearInterval(this.intervalID);
8372 this.intervalID = false;
8375 this.isMasked = false;
8385 * Ext JS Library 1.1.1
8386 * Copyright(c) 2006-2007, Ext JS, LLC.
8388 * Originally Released Under LGPL - original licence link has changed is not relivant.
8391 * <script type="text/javascript">
8394 * @class Roo.form.VTypes
8395 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8398 Roo.form.VTypes = function(){
8399 // closure these in so they are only created once.
8400 var alpha = /^[a-zA-Z_]+$/;
8401 var alphanum = /^[a-zA-Z0-9_]+$/;
8402 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8403 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8405 // All these messages and functions are configurable
8408 * The function used to validate email addresses
8409 * @param {String} value The email address
8411 'email' : function(v){
8412 return email.test(v);
8415 * The error text to display when the email validation function returns false
8418 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8420 * The keystroke filter mask to be applied on email input
8423 'emailMask' : /[a-z0-9_\.\-@]/i,
8426 * The function used to validate URLs
8427 * @param {String} value The URL
8429 'url' : function(v){
8433 * The error text to display when the url validation function returns false
8436 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8439 * The function used to validate alpha values
8440 * @param {String} value The value
8442 'alpha' : function(v){
8443 return alpha.test(v);
8446 * The error text to display when the alpha validation function returns false
8449 'alphaText' : 'This field should only contain letters and _',
8451 * The keystroke filter mask to be applied on alpha input
8454 'alphaMask' : /[a-z_]/i,
8457 * The function used to validate alphanumeric values
8458 * @param {String} value The value
8460 'alphanum' : function(v){
8461 return alphanum.test(v);
8464 * The error text to display when the alphanumeric validation function returns false
8467 'alphanumText' : 'This field should only contain letters, numbers and _',
8469 * The keystroke filter mask to be applied on alphanumeric input
8472 'alphanumMask' : /[a-z0-9_]/i
8482 * @class Roo.bootstrap.Input
8483 * @extends Roo.bootstrap.Component
8484 * Bootstrap Input class
8485 * @cfg {Boolean} disabled is it disabled
8486 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8487 * @cfg {String} name name of the input
8488 * @cfg {string} fieldLabel - the label associated
8489 * @cfg {string} placeholder - placeholder to put in text.
8490 * @cfg {string} before - input group add on before
8491 * @cfg {string} after - input group add on after
8492 * @cfg {string} size - (lg|sm) or leave empty..
8493 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8494 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8495 * @cfg {Number} md colspan out of 12 for computer-sized screens
8496 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8497 * @cfg {string} value default value of the input
8498 * @cfg {Number} labelWidth set the width of label
8499 * @cfg {Number} labellg set the width of label (1-12)
8500 * @cfg {Number} labelmd set the width of label (1-12)
8501 * @cfg {Number} labelsm set the width of label (1-12)
8502 * @cfg {Number} labelxs set the width of label (1-12)
8503 * @cfg {String} labelAlign (top|left)
8504 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8505 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8506 * @cfg {String} indicatorpos (left|right) default left
8508 * @cfg {String} align (left|center|right) Default left
8509 * @cfg {Boolean} forceFeedback (true|false) Default false
8515 * Create a new Input
8516 * @param {Object} config The config object
8519 Roo.bootstrap.Input = function(config){
8521 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8526 * Fires when this field receives input focus.
8527 * @param {Roo.form.Field} this
8532 * Fires when this field loses input focus.
8533 * @param {Roo.form.Field} this
8538 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8539 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8540 * @param {Roo.form.Field} this
8541 * @param {Roo.EventObject} e The event object
8546 * Fires just before the field blurs if the field value has changed.
8547 * @param {Roo.form.Field} this
8548 * @param {Mixed} newValue The new value
8549 * @param {Mixed} oldValue The original value
8554 * Fires after the field has been marked as invalid.
8555 * @param {Roo.form.Field} this
8556 * @param {String} msg The validation message
8561 * Fires after the field has been validated with no errors.
8562 * @param {Roo.form.Field} this
8567 * Fires after the key up
8568 * @param {Roo.form.Field} this
8569 * @param {Roo.EventObject} e The event Object
8575 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8577 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8578 automatic validation (defaults to "keyup").
8580 validationEvent : "keyup",
8582 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8584 validateOnBlur : true,
8586 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8588 validationDelay : 250,
8590 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8592 focusClass : "x-form-focus", // not needed???
8596 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8598 invalidClass : "has-warning",
8601 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8603 validClass : "has-success",
8606 * @cfg {Boolean} hasFeedback (true|false) default true
8611 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8613 invalidFeedbackClass : "glyphicon-warning-sign",
8616 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8618 validFeedbackClass : "glyphicon-ok",
8621 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8623 selectOnFocus : false,
8626 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8630 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8635 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8637 disableKeyFilter : false,
8640 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8644 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8648 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8650 blankText : "Please complete this mandatory field",
8653 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8657 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8659 maxLength : Number.MAX_VALUE,
8661 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8663 minLengthText : "The minimum length for this field is {0}",
8665 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8667 maxLengthText : "The maximum length for this field is {0}",
8671 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8672 * If available, this function will be called only after the basic validators all return true, and will be passed the
8673 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8677 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8678 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8679 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8683 * @cfg {String} regexText -- Depricated - use Invalid Text
8688 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8694 autocomplete: false,
8713 formatedValue : false,
8714 forceFeedback : false,
8716 indicatorpos : 'left',
8723 parentLabelAlign : function()
8726 while (parent.parent()) {
8727 parent = parent.parent();
8728 if (typeof(parent.labelAlign) !='undefined') {
8729 return parent.labelAlign;
8736 getAutoCreate : function()
8738 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8744 if(this.inputType != 'hidden'){
8745 cfg.cls = 'form-group' //input-group
8751 type : this.inputType,
8753 cls : 'form-control',
8754 placeholder : this.placeholder || '',
8755 autocomplete : this.autocomplete || 'new-password'
8759 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8762 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8763 input.maxLength = this.maxLength;
8766 if (this.disabled) {
8767 input.disabled=true;
8770 if (this.readOnly) {
8771 input.readonly=true;
8775 input.name = this.name;
8779 input.cls += ' input-' + this.size;
8783 ['xs','sm','md','lg'].map(function(size){
8784 if (settings[size]) {
8785 cfg.cls += ' col-' + size + '-' + settings[size];
8789 var inputblock = input;
8793 cls: 'glyphicon form-control-feedback'
8796 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8799 cls : 'has-feedback',
8807 if (this.before || this.after) {
8810 cls : 'input-group',
8814 if (this.before && typeof(this.before) == 'string') {
8816 inputblock.cn.push({
8818 cls : 'roo-input-before input-group-addon',
8822 if (this.before && typeof(this.before) == 'object') {
8823 this.before = Roo.factory(this.before);
8825 inputblock.cn.push({
8827 cls : 'roo-input-before input-group-' +
8828 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8832 inputblock.cn.push(input);
8834 if (this.after && typeof(this.after) == 'string') {
8835 inputblock.cn.push({
8837 cls : 'roo-input-after input-group-addon',
8841 if (this.after && typeof(this.after) == 'object') {
8842 this.after = Roo.factory(this.after);
8844 inputblock.cn.push({
8846 cls : 'roo-input-after input-group-' +
8847 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8851 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8852 inputblock.cls += ' has-feedback';
8853 inputblock.cn.push(feedback);
8857 if (align ==='left' && this.fieldLabel.length) {
8859 cfg.cls += ' roo-form-group-label-left';
8864 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8865 tooltip : 'This field is required'
8870 cls : 'control-label',
8871 html : this.fieldLabel
8882 var labelCfg = cfg.cn[1];
8883 var contentCfg = cfg.cn[2];
8885 if(this.indicatorpos == 'right'){
8890 cls : 'control-label',
8894 html : this.fieldLabel
8898 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8899 tooltip : 'This field is required'
8912 labelCfg = cfg.cn[0];
8913 contentCfg = cfg.cn[1];
8917 if(this.labelWidth > 12){
8918 labelCfg.style = "width: " + this.labelWidth + 'px';
8921 if(this.labelWidth < 13 && this.labelmd == 0){
8922 this.labelmd = this.labelWidth;
8925 if(this.labellg > 0){
8926 labelCfg.cls += ' col-lg-' + this.labellg;
8927 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8930 if(this.labelmd > 0){
8931 labelCfg.cls += ' col-md-' + this.labelmd;
8932 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8935 if(this.labelsm > 0){
8936 labelCfg.cls += ' col-sm-' + this.labelsm;
8937 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8940 if(this.labelxs > 0){
8941 labelCfg.cls += ' col-xs-' + this.labelxs;
8942 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8946 } else if ( this.fieldLabel.length) {
8951 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8952 tooltip : 'This field is required'
8956 //cls : 'input-group-addon',
8957 html : this.fieldLabel
8965 if(this.indicatorpos == 'right'){
8970 //cls : 'input-group-addon',
8971 html : this.fieldLabel
8976 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8977 tooltip : 'This field is required'
8997 if (this.parentType === 'Navbar' && this.parent().bar) {
8998 cfg.cls += ' navbar-form';
9001 if (this.parentType === 'NavGroup') {
9002 cfg.cls += ' navbar-form';
9010 * return the real input element.
9012 inputEl: function ()
9014 return this.el.select('input.form-control',true).first();
9017 tooltipEl : function()
9019 return this.inputEl();
9022 indicatorEl : function()
9024 var indicator = this.el.select('i.roo-required-indicator',true).first();
9034 setDisabled : function(v)
9036 var i = this.inputEl().dom;
9038 i.removeAttribute('disabled');
9042 i.setAttribute('disabled','true');
9044 initEvents : function()
9047 this.inputEl().on("keydown" , this.fireKey, this);
9048 this.inputEl().on("focus", this.onFocus, this);
9049 this.inputEl().on("blur", this.onBlur, this);
9051 this.inputEl().relayEvent('keyup', this);
9053 this.indicator = this.indicatorEl();
9056 this.indicator.addClass('invisible');
9060 // reference to original value for reset
9061 this.originalValue = this.getValue();
9062 //Roo.form.TextField.superclass.initEvents.call(this);
9063 if(this.validationEvent == 'keyup'){
9064 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9065 this.inputEl().on('keyup', this.filterValidation, this);
9067 else if(this.validationEvent !== false){
9068 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9071 if(this.selectOnFocus){
9072 this.on("focus", this.preFocus, this);
9075 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9076 this.inputEl().on("keypress", this.filterKeys, this);
9078 this.inputEl().relayEvent('keypress', this);
9081 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9082 this.el.on("click", this.autoSize, this);
9085 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9086 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9089 if (typeof(this.before) == 'object') {
9090 this.before.render(this.el.select('.roo-input-before',true).first());
9092 if (typeof(this.after) == 'object') {
9093 this.after.render(this.el.select('.roo-input-after',true).first());
9098 filterValidation : function(e){
9099 if(!e.isNavKeyPress()){
9100 this.validationTask.delay(this.validationDelay);
9104 * Validates the field value
9105 * @return {Boolean} True if the value is valid, else false
9107 validate : function(){
9108 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9109 if(this.disabled || this.validateValue(this.getRawValue())){
9120 * Validates a value according to the field's validation rules and marks the field as invalid
9121 * if the validation fails
9122 * @param {Mixed} value The value to validate
9123 * @return {Boolean} True if the value is valid, else false
9125 validateValue : function(value)
9127 if(this.getEl().hasClass('hidden')){
9131 if(value.length < 1) { // if it's blank
9132 if(this.allowBlank){
9138 if(value.length < this.minLength){
9141 if(value.length > this.maxLength){
9145 var vt = Roo.form.VTypes;
9146 if(!vt[this.vtype](value, this)){
9150 if(typeof this.validator == "function"){
9151 var msg = this.validator(value);
9155 if (typeof(msg) == 'string') {
9156 this.invalidText = msg;
9160 if(this.regex && !this.regex.test(value)){
9168 fireKey : function(e){
9169 //Roo.log('field ' + e.getKey());
9170 if(e.isNavKeyPress()){
9171 this.fireEvent("specialkey", this, e);
9174 focus : function (selectText){
9176 this.inputEl().focus();
9177 if(selectText === true){
9178 this.inputEl().dom.select();
9184 onFocus : function(){
9185 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9186 // this.el.addClass(this.focusClass);
9189 this.hasFocus = true;
9190 this.startValue = this.getValue();
9191 this.fireEvent("focus", this);
9195 beforeBlur : Roo.emptyFn,
9199 onBlur : function(){
9201 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9202 //this.el.removeClass(this.focusClass);
9204 this.hasFocus = false;
9205 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9208 var v = this.getValue();
9209 if(String(v) !== String(this.startValue)){
9210 this.fireEvent('change', this, v, this.startValue);
9212 this.fireEvent("blur", this);
9216 * Resets the current field value to the originally loaded value and clears any validation messages
9219 this.setValue(this.originalValue);
9223 * Returns the name of the field
9224 * @return {Mixed} name The name field
9226 getName: function(){
9230 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9231 * @return {Mixed} value The field value
9233 getValue : function(){
9235 var v = this.inputEl().getValue();
9240 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9241 * @return {Mixed} value The field value
9243 getRawValue : function(){
9244 var v = this.inputEl().getValue();
9250 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9251 * @param {Mixed} value The value to set
9253 setRawValue : function(v){
9254 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9257 selectText : function(start, end){
9258 var v = this.getRawValue();
9260 start = start === undefined ? 0 : start;
9261 end = end === undefined ? v.length : end;
9262 var d = this.inputEl().dom;
9263 if(d.setSelectionRange){
9264 d.setSelectionRange(start, end);
9265 }else if(d.createTextRange){
9266 var range = d.createTextRange();
9267 range.moveStart("character", start);
9268 range.moveEnd("character", v.length-end);
9275 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9276 * @param {Mixed} value The value to set
9278 setValue : function(v){
9281 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9287 processValue : function(value){
9288 if(this.stripCharsRe){
9289 var newValue = value.replace(this.stripCharsRe, '');
9290 if(newValue !== value){
9291 this.setRawValue(newValue);
9298 preFocus : function(){
9300 if(this.selectOnFocus){
9301 this.inputEl().dom.select();
9304 filterKeys : function(e){
9306 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9309 var c = e.getCharCode(), cc = String.fromCharCode(c);
9310 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9313 if(!this.maskRe.test(cc)){
9318 * Clear any invalid styles/messages for this field
9320 clearInvalid : function(){
9322 if(!this.el || this.preventMark){ // not rendered
9327 this.el.removeClass(this.invalidClass);
9329 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9331 var feedback = this.el.select('.form-control-feedback', true).first();
9334 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9339 this.fireEvent('valid', this);
9343 * Mark this field as valid
9345 markValid : function()
9347 if(!this.el || this.preventMark){ // not rendered...
9351 this.el.removeClass([this.invalidClass, this.validClass]);
9353 var feedback = this.el.select('.form-control-feedback', true).first();
9356 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9360 this.indicator.removeClass('visible');
9361 this.indicator.addClass('invisible');
9368 if(this.allowBlank && !this.getRawValue().length){
9372 this.el.addClass(this.validClass);
9374 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9376 var feedback = this.el.select('.form-control-feedback', true).first();
9379 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9380 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9385 this.fireEvent('valid', this);
9389 * Mark this field as invalid
9390 * @param {String} msg The validation message
9392 markInvalid : function(msg)
9394 if(!this.el || this.preventMark){ // not rendered
9398 this.el.removeClass([this.invalidClass, this.validClass]);
9400 var feedback = this.el.select('.form-control-feedback', true).first();
9403 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9410 if(this.allowBlank && !this.getRawValue().length){
9415 this.indicator.removeClass('invisible');
9416 this.indicator.addClass('visible');
9419 this.el.addClass(this.invalidClass);
9421 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9423 var feedback = this.el.select('.form-control-feedback', true).first();
9426 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9428 if(this.getValue().length || this.forceFeedback){
9429 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9436 this.fireEvent('invalid', this, msg);
9439 SafariOnKeyDown : function(event)
9441 // this is a workaround for a password hang bug on chrome/ webkit.
9442 if (this.inputEl().dom.type != 'password') {
9446 var isSelectAll = false;
9448 if(this.inputEl().dom.selectionEnd > 0){
9449 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9451 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9452 event.preventDefault();
9457 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9459 event.preventDefault();
9460 // this is very hacky as keydown always get's upper case.
9462 var cc = String.fromCharCode(event.getCharCode());
9463 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9467 adjustWidth : function(tag, w){
9468 tag = tag.toLowerCase();
9469 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9470 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9474 if(tag == 'textarea'){
9477 }else if(Roo.isOpera){
9481 if(tag == 'textarea'){
9489 setFieldLabel : function(v)
9496 var ar = this.el.select('label > span',true);
9498 if (ar.elements.length) {
9499 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9500 this.fieldLabel = v;
9504 var br = this.el.select('label',true);
9506 if(br.elements.length) {
9507 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9508 this.fieldLabel = v;
9512 Roo.log('Cannot Found any of label > span || label in input');
9516 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9517 this.fieldLabel = v;
9532 * @class Roo.bootstrap.TextArea
9533 * @extends Roo.bootstrap.Input
9534 * Bootstrap TextArea class
9535 * @cfg {Number} cols Specifies the visible width of a text area
9536 * @cfg {Number} rows Specifies the visible number of lines in a text area
9537 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9538 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9539 * @cfg {string} html text
9542 * Create a new TextArea
9543 * @param {Object} config The config object
9546 Roo.bootstrap.TextArea = function(config){
9547 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9551 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9561 getAutoCreate : function(){
9563 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9569 if(this.inputType != 'hidden'){
9570 cfg.cls = 'form-group' //input-group
9578 value : this.value || '',
9579 html: this.html || '',
9580 cls : 'form-control',
9581 placeholder : this.placeholder || ''
9585 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9586 input.maxLength = this.maxLength;
9590 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9594 input.cols = this.cols;
9597 if (this.readOnly) {
9598 input.readonly = true;
9602 input.name = this.name;
9606 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9610 ['xs','sm','md','lg'].map(function(size){
9611 if (settings[size]) {
9612 cfg.cls += ' col-' + size + '-' + settings[size];
9616 var inputblock = input;
9618 if(this.hasFeedback && !this.allowBlank){
9622 cls: 'glyphicon form-control-feedback'
9626 cls : 'has-feedback',
9635 if (this.before || this.after) {
9638 cls : 'input-group',
9642 inputblock.cn.push({
9644 cls : 'input-group-addon',
9649 inputblock.cn.push(input);
9651 if(this.hasFeedback && !this.allowBlank){
9652 inputblock.cls += ' has-feedback';
9653 inputblock.cn.push(feedback);
9657 inputblock.cn.push({
9659 cls : 'input-group-addon',
9666 if (align ==='left' && this.fieldLabel.length) {
9671 cls : 'control-label',
9672 html : this.fieldLabel
9683 if(this.labelWidth > 12){
9684 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9687 if(this.labelWidth < 13 && this.labelmd == 0){
9688 this.labelmd = this.labelWidth;
9691 if(this.labellg > 0){
9692 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9693 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9696 if(this.labelmd > 0){
9697 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9698 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9701 if(this.labelsm > 0){
9702 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9703 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9706 if(this.labelxs > 0){
9707 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9708 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9711 } else if ( this.fieldLabel.length) {
9716 //cls : 'input-group-addon',
9717 html : this.fieldLabel
9735 if (this.disabled) {
9736 input.disabled=true;
9743 * return the real textarea element.
9745 inputEl: function ()
9747 return this.el.select('textarea.form-control',true).first();
9751 * Clear any invalid styles/messages for this field
9753 clearInvalid : function()
9756 if(!this.el || this.preventMark){ // not rendered
9760 var label = this.el.select('label', true).first();
9761 var icon = this.el.select('i.fa-star', true).first();
9767 this.el.removeClass(this.invalidClass);
9769 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9771 var feedback = this.el.select('.form-control-feedback', true).first();
9774 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9779 this.fireEvent('valid', this);
9783 * Mark this field as valid
9785 markValid : function()
9787 if(!this.el || this.preventMark){ // not rendered
9791 this.el.removeClass([this.invalidClass, this.validClass]);
9793 var feedback = this.el.select('.form-control-feedback', true).first();
9796 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9799 if(this.disabled || this.allowBlank){
9803 var label = this.el.select('label', true).first();
9804 var icon = this.el.select('i.fa-star', true).first();
9810 this.el.addClass(this.validClass);
9812 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9814 var feedback = this.el.select('.form-control-feedback', true).first();
9817 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9818 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9823 this.fireEvent('valid', this);
9827 * Mark this field as invalid
9828 * @param {String} msg The validation message
9830 markInvalid : function(msg)
9832 if(!this.el || this.preventMark){ // not rendered
9836 this.el.removeClass([this.invalidClass, this.validClass]);
9838 var feedback = this.el.select('.form-control-feedback', true).first();
9841 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9844 if(this.disabled || this.allowBlank){
9848 var label = this.el.select('label', true).first();
9849 var icon = this.el.select('i.fa-star', true).first();
9851 if(!this.getValue().length && label && !icon){
9852 this.el.createChild({
9854 cls : 'text-danger fa fa-lg fa-star',
9855 tooltip : 'This field is required',
9856 style : 'margin-right:5px;'
9860 this.el.addClass(this.invalidClass);
9862 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9864 var feedback = this.el.select('.form-control-feedback', true).first();
9867 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9869 if(this.getValue().length || this.forceFeedback){
9870 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9877 this.fireEvent('invalid', this, msg);
9885 * trigger field - base class for combo..
9890 * @class Roo.bootstrap.TriggerField
9891 * @extends Roo.bootstrap.Input
9892 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9893 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9894 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9895 * for which you can provide a custom implementation. For example:
9897 var trigger = new Roo.bootstrap.TriggerField();
9898 trigger.onTriggerClick = myTriggerFn;
9899 trigger.applyTo('my-field');
9902 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9903 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9904 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9905 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9906 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9909 * Create a new TriggerField.
9910 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9911 * to the base TextField)
9913 Roo.bootstrap.TriggerField = function(config){
9914 this.mimicing = false;
9915 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9918 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9920 * @cfg {String} triggerClass A CSS class to apply to the trigger
9923 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9928 * @cfg {Boolean} removable (true|false) special filter default false
9932 /** @cfg {Boolean} grow @hide */
9933 /** @cfg {Number} growMin @hide */
9934 /** @cfg {Number} growMax @hide */
9940 autoSize: Roo.emptyFn,
9947 actionMode : 'wrap',
9952 getAutoCreate : function(){
9954 var align = this.labelAlign || this.parentLabelAlign();
9959 cls: 'form-group' //input-group
9966 type : this.inputType,
9967 cls : 'form-control',
9968 autocomplete: 'new-password',
9969 placeholder : this.placeholder || ''
9973 input.name = this.name;
9976 input.cls += ' input-' + this.size;
9979 if (this.disabled) {
9980 input.disabled=true;
9983 var inputblock = input;
9985 if(this.hasFeedback && !this.allowBlank){
9989 cls: 'glyphicon form-control-feedback'
9992 if(this.removable && !this.editable && !this.tickable){
9994 cls : 'has-feedback',
10000 cls : 'roo-combo-removable-btn close'
10007 cls : 'has-feedback',
10016 if(this.removable && !this.editable && !this.tickable){
10018 cls : 'roo-removable',
10024 cls : 'roo-combo-removable-btn close'
10031 if (this.before || this.after) {
10034 cls : 'input-group',
10038 inputblock.cn.push({
10040 cls : 'input-group-addon',
10045 inputblock.cn.push(input);
10047 if(this.hasFeedback && !this.allowBlank){
10048 inputblock.cls += ' has-feedback';
10049 inputblock.cn.push(feedback);
10053 inputblock.cn.push({
10055 cls : 'input-group-addon',
10068 cls: 'form-hidden-field'
10082 cls: 'form-hidden-field'
10086 cls: 'roo-select2-choices',
10090 cls: 'roo-select2-search-field',
10103 cls: 'roo-select2-container input-group',
10108 // cls: 'typeahead typeahead-long dropdown-menu',
10109 // style: 'display:none'
10114 if(!this.multiple && this.showToggleBtn){
10120 if (this.caret != false) {
10123 cls: 'fa fa-' + this.caret
10130 cls : 'input-group-addon btn dropdown-toggle',
10135 cls: 'combobox-clear',
10149 combobox.cls += ' roo-select2-container-multi';
10152 if (align ==='left' && this.fieldLabel.length) {
10154 cfg.cls += ' roo-form-group-label-left';
10159 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10160 tooltip : 'This field is required'
10165 cls : 'control-label',
10166 html : this.fieldLabel
10178 var labelCfg = cfg.cn[1];
10179 var contentCfg = cfg.cn[2];
10181 if(this.indicatorpos == 'right'){
10186 cls : 'control-label',
10190 html : this.fieldLabel
10194 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10195 tooltip : 'This field is required'
10208 labelCfg = cfg.cn[0];
10209 contentCfg = cfg.cn[1];
10212 if(this.labelWidth > 12){
10213 labelCfg.style = "width: " + this.labelWidth + 'px';
10216 if(this.labelWidth < 13 && this.labelmd == 0){
10217 this.labelmd = this.labelWidth;
10220 if(this.labellg > 0){
10221 labelCfg.cls += ' col-lg-' + this.labellg;
10222 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10225 if(this.labelmd > 0){
10226 labelCfg.cls += ' col-md-' + this.labelmd;
10227 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10230 if(this.labelsm > 0){
10231 labelCfg.cls += ' col-sm-' + this.labelsm;
10232 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10235 if(this.labelxs > 0){
10236 labelCfg.cls += ' col-xs-' + this.labelxs;
10237 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10240 } else if ( this.fieldLabel.length) {
10241 // Roo.log(" label");
10245 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10246 tooltip : 'This field is required'
10250 //cls : 'input-group-addon',
10251 html : this.fieldLabel
10259 if(this.indicatorpos == 'right'){
10267 html : this.fieldLabel
10271 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10272 tooltip : 'This field is required'
10285 // Roo.log(" no label && no align");
10292 ['xs','sm','md','lg'].map(function(size){
10293 if (settings[size]) {
10294 cfg.cls += ' col-' + size + '-' + settings[size];
10305 onResize : function(w, h){
10306 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10307 // if(typeof w == 'number'){
10308 // var x = w - this.trigger.getWidth();
10309 // this.inputEl().setWidth(this.adjustWidth('input', x));
10310 // this.trigger.setStyle('left', x+'px');
10315 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10318 getResizeEl : function(){
10319 return this.inputEl();
10323 getPositionEl : function(){
10324 return this.inputEl();
10328 alignErrorIcon : function(){
10329 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10333 initEvents : function(){
10337 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10338 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10339 if(!this.multiple && this.showToggleBtn){
10340 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10341 if(this.hideTrigger){
10342 this.trigger.setDisplayed(false);
10344 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10348 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10351 if(this.removable && !this.editable && !this.tickable){
10352 var close = this.closeTriggerEl();
10355 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10356 close.on('click', this.removeBtnClick, this, close);
10360 //this.trigger.addClassOnOver('x-form-trigger-over');
10361 //this.trigger.addClassOnClick('x-form-trigger-click');
10364 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10368 closeTriggerEl : function()
10370 var close = this.el.select('.roo-combo-removable-btn', true).first();
10371 return close ? close : false;
10374 removeBtnClick : function(e, h, el)
10376 e.preventDefault();
10378 if(this.fireEvent("remove", this) !== false){
10380 this.fireEvent("afterremove", this)
10384 createList : function()
10386 this.list = Roo.get(document.body).createChild({
10388 cls: 'typeahead typeahead-long dropdown-menu',
10389 style: 'display:none'
10392 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10397 initTrigger : function(){
10402 onDestroy : function(){
10404 this.trigger.removeAllListeners();
10405 // this.trigger.remove();
10408 // this.wrap.remove();
10410 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10414 onFocus : function(){
10415 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10417 if(!this.mimicing){
10418 this.wrap.addClass('x-trigger-wrap-focus');
10419 this.mimicing = true;
10420 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10421 if(this.monitorTab){
10422 this.el.on("keydown", this.checkTab, this);
10429 checkTab : function(e){
10430 if(e.getKey() == e.TAB){
10431 this.triggerBlur();
10436 onBlur : function(){
10441 mimicBlur : function(e, t){
10443 if(!this.wrap.contains(t) && this.validateBlur()){
10444 this.triggerBlur();
10450 triggerBlur : function(){
10451 this.mimicing = false;
10452 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10453 if(this.monitorTab){
10454 this.el.un("keydown", this.checkTab, this);
10456 //this.wrap.removeClass('x-trigger-wrap-focus');
10457 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10461 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10462 validateBlur : function(e, t){
10467 onDisable : function(){
10468 this.inputEl().dom.disabled = true;
10469 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10471 // this.wrap.addClass('x-item-disabled');
10476 onEnable : function(){
10477 this.inputEl().dom.disabled = false;
10478 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10480 // this.el.removeClass('x-item-disabled');
10485 onShow : function(){
10486 var ae = this.getActionEl();
10489 ae.dom.style.display = '';
10490 ae.dom.style.visibility = 'visible';
10496 onHide : function(){
10497 var ae = this.getActionEl();
10498 ae.dom.style.display = 'none';
10502 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10503 * by an implementing function.
10505 * @param {EventObject} e
10507 onTriggerClick : Roo.emptyFn
10511 * Ext JS Library 1.1.1
10512 * Copyright(c) 2006-2007, Ext JS, LLC.
10514 * Originally Released Under LGPL - original licence link has changed is not relivant.
10517 * <script type="text/javascript">
10522 * @class Roo.data.SortTypes
10524 * Defines the default sorting (casting?) comparison functions used when sorting data.
10526 Roo.data.SortTypes = {
10528 * Default sort that does nothing
10529 * @param {Mixed} s The value being converted
10530 * @return {Mixed} The comparison value
10532 none : function(s){
10537 * The regular expression used to strip tags
10541 stripTagsRE : /<\/?[^>]+>/gi,
10544 * Strips all HTML tags to sort on text only
10545 * @param {Mixed} s The value being converted
10546 * @return {String} The comparison value
10548 asText : function(s){
10549 return String(s).replace(this.stripTagsRE, "");
10553 * Strips all HTML tags to sort on text only - Case insensitive
10554 * @param {Mixed} s The value being converted
10555 * @return {String} The comparison value
10557 asUCText : function(s){
10558 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10562 * Case insensitive string
10563 * @param {Mixed} s The value being converted
10564 * @return {String} The comparison value
10566 asUCString : function(s) {
10567 return String(s).toUpperCase();
10572 * @param {Mixed} s The value being converted
10573 * @return {Number} The comparison value
10575 asDate : function(s) {
10579 if(s instanceof Date){
10580 return s.getTime();
10582 return Date.parse(String(s));
10587 * @param {Mixed} s The value being converted
10588 * @return {Float} The comparison value
10590 asFloat : function(s) {
10591 var val = parseFloat(String(s).replace(/,/g, ""));
10600 * @param {Mixed} s The value being converted
10601 * @return {Number} The comparison value
10603 asInt : function(s) {
10604 var val = parseInt(String(s).replace(/,/g, ""));
10612 * Ext JS Library 1.1.1
10613 * Copyright(c) 2006-2007, Ext JS, LLC.
10615 * Originally Released Under LGPL - original licence link has changed is not relivant.
10618 * <script type="text/javascript">
10622 * @class Roo.data.Record
10623 * Instances of this class encapsulate both record <em>definition</em> information, and record
10624 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10625 * to access Records cached in an {@link Roo.data.Store} object.<br>
10627 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10628 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10631 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10633 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10634 * {@link #create}. The parameters are the same.
10635 * @param {Array} data An associative Array of data values keyed by the field name.
10636 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10637 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10638 * not specified an integer id is generated.
10640 Roo.data.Record = function(data, id){
10641 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10646 * Generate a constructor for a specific record layout.
10647 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10648 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10649 * Each field definition object may contain the following properties: <ul>
10650 * <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,
10651 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10652 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10653 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10654 * is being used, then this is a string containing the javascript expression to reference the data relative to
10655 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10656 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10657 * this may be omitted.</p></li>
10658 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10659 * <ul><li>auto (Default, implies no conversion)</li>
10664 * <li>date</li></ul></p></li>
10665 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10666 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10667 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10668 * by the Reader into an object that will be stored in the Record. It is passed the
10669 * following parameters:<ul>
10670 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10672 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10674 * <br>usage:<br><pre><code>
10675 var TopicRecord = Roo.data.Record.create(
10676 {name: 'title', mapping: 'topic_title'},
10677 {name: 'author', mapping: 'username'},
10678 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10679 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10680 {name: 'lastPoster', mapping: 'user2'},
10681 {name: 'excerpt', mapping: 'post_text'}
10684 var myNewRecord = new TopicRecord({
10685 title: 'Do my job please',
10688 lastPost: new Date(),
10689 lastPoster: 'Animal',
10690 excerpt: 'No way dude!'
10692 myStore.add(myNewRecord);
10697 Roo.data.Record.create = function(o){
10698 var f = function(){
10699 f.superclass.constructor.apply(this, arguments);
10701 Roo.extend(f, Roo.data.Record);
10702 var p = f.prototype;
10703 p.fields = new Roo.util.MixedCollection(false, function(field){
10706 for(var i = 0, len = o.length; i < len; i++){
10707 p.fields.add(new Roo.data.Field(o[i]));
10709 f.getField = function(name){
10710 return p.fields.get(name);
10715 Roo.data.Record.AUTO_ID = 1000;
10716 Roo.data.Record.EDIT = 'edit';
10717 Roo.data.Record.REJECT = 'reject';
10718 Roo.data.Record.COMMIT = 'commit';
10720 Roo.data.Record.prototype = {
10722 * Readonly flag - true if this record has been modified.
10731 join : function(store){
10732 this.store = store;
10736 * Set the named field to the specified value.
10737 * @param {String} name The name of the field to set.
10738 * @param {Object} value The value to set the field to.
10740 set : function(name, value){
10741 if(this.data[name] == value){
10745 if(!this.modified){
10746 this.modified = {};
10748 if(typeof this.modified[name] == 'undefined'){
10749 this.modified[name] = this.data[name];
10751 this.data[name] = value;
10752 if(!this.editing && this.store){
10753 this.store.afterEdit(this);
10758 * Get the value of the named field.
10759 * @param {String} name The name of the field to get the value of.
10760 * @return {Object} The value of the field.
10762 get : function(name){
10763 return this.data[name];
10767 beginEdit : function(){
10768 this.editing = true;
10769 this.modified = {};
10773 cancelEdit : function(){
10774 this.editing = false;
10775 delete this.modified;
10779 endEdit : function(){
10780 this.editing = false;
10781 if(this.dirty && this.store){
10782 this.store.afterEdit(this);
10787 * Usually called by the {@link Roo.data.Store} which owns the Record.
10788 * Rejects all changes made to the Record since either creation, or the last commit operation.
10789 * Modified fields are reverted to their original values.
10791 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10792 * of reject operations.
10794 reject : function(){
10795 var m = this.modified;
10797 if(typeof m[n] != "function"){
10798 this.data[n] = m[n];
10801 this.dirty = false;
10802 delete this.modified;
10803 this.editing = false;
10805 this.store.afterReject(this);
10810 * Usually called by the {@link Roo.data.Store} which owns the Record.
10811 * Commits all changes made to the Record since either creation, or the last commit operation.
10813 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10814 * of commit operations.
10816 commit : function(){
10817 this.dirty = false;
10818 delete this.modified;
10819 this.editing = false;
10821 this.store.afterCommit(this);
10826 hasError : function(){
10827 return this.error != null;
10831 clearError : function(){
10836 * Creates a copy of this record.
10837 * @param {String} id (optional) A new record id if you don't want to use this record's id
10840 copy : function(newId) {
10841 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10845 * Ext JS Library 1.1.1
10846 * Copyright(c) 2006-2007, Ext JS, LLC.
10848 * Originally Released Under LGPL - original licence link has changed is not relivant.
10851 * <script type="text/javascript">
10857 * @class Roo.data.Store
10858 * @extends Roo.util.Observable
10859 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10860 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10862 * 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
10863 * has no knowledge of the format of the data returned by the Proxy.<br>
10865 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10866 * instances from the data object. These records are cached and made available through accessor functions.
10868 * Creates a new Store.
10869 * @param {Object} config A config object containing the objects needed for the Store to access data,
10870 * and read the data into Records.
10872 Roo.data.Store = function(config){
10873 this.data = new Roo.util.MixedCollection(false);
10874 this.data.getKey = function(o){
10877 this.baseParams = {};
10879 this.paramNames = {
10884 "multisort" : "_multisort"
10887 if(config && config.data){
10888 this.inlineData = config.data;
10889 delete config.data;
10892 Roo.apply(this, config);
10894 if(this.reader){ // reader passed
10895 this.reader = Roo.factory(this.reader, Roo.data);
10896 this.reader.xmodule = this.xmodule || false;
10897 if(!this.recordType){
10898 this.recordType = this.reader.recordType;
10900 if(this.reader.onMetaChange){
10901 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10905 if(this.recordType){
10906 this.fields = this.recordType.prototype.fields;
10908 this.modified = [];
10912 * @event datachanged
10913 * Fires when the data cache has changed, and a widget which is using this Store
10914 * as a Record cache should refresh its view.
10915 * @param {Store} this
10917 datachanged : true,
10919 * @event metachange
10920 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10921 * @param {Store} this
10922 * @param {Object} meta The JSON metadata
10927 * Fires when Records have been added to the Store
10928 * @param {Store} this
10929 * @param {Roo.data.Record[]} records The array of Records added
10930 * @param {Number} index The index at which the record(s) were added
10935 * Fires when a Record has been removed from the Store
10936 * @param {Store} this
10937 * @param {Roo.data.Record} record The Record that was removed
10938 * @param {Number} index The index at which the record was removed
10943 * Fires when a Record has been updated
10944 * @param {Store} this
10945 * @param {Roo.data.Record} record The Record that was updated
10946 * @param {String} operation The update operation being performed. Value may be one of:
10948 Roo.data.Record.EDIT
10949 Roo.data.Record.REJECT
10950 Roo.data.Record.COMMIT
10956 * Fires when the data cache has been cleared.
10957 * @param {Store} this
10961 * @event beforeload
10962 * Fires before a request is made for a new data object. If the beforeload handler returns false
10963 * the load action will be canceled.
10964 * @param {Store} this
10965 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10969 * @event beforeloadadd
10970 * Fires after a new set of Records has been loaded.
10971 * @param {Store} this
10972 * @param {Roo.data.Record[]} records The Records that were loaded
10973 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10975 beforeloadadd : true,
10978 * Fires after a new set of Records has been loaded, before they are added to the store.
10979 * @param {Store} this
10980 * @param {Roo.data.Record[]} records The Records that were loaded
10981 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10982 * @params {Object} return from reader
10986 * @event loadexception
10987 * Fires if an exception occurs in the Proxy during loading.
10988 * Called with the signature of the Proxy's "loadexception" event.
10989 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10992 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10993 * @param {Object} load options
10994 * @param {Object} jsonData from your request (normally this contains the Exception)
10996 loadexception : true
11000 this.proxy = Roo.factory(this.proxy, Roo.data);
11001 this.proxy.xmodule = this.xmodule || false;
11002 this.relayEvents(this.proxy, ["loadexception"]);
11004 this.sortToggle = {};
11005 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11007 Roo.data.Store.superclass.constructor.call(this);
11009 if(this.inlineData){
11010 this.loadData(this.inlineData);
11011 delete this.inlineData;
11015 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11017 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11018 * without a remote query - used by combo/forms at present.
11022 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11025 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11028 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11029 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11032 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11033 * on any HTTP request
11036 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11039 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11043 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11044 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11046 remoteSort : false,
11049 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11050 * loaded or when a record is removed. (defaults to false).
11052 pruneModifiedRecords : false,
11055 lastOptions : null,
11058 * Add Records to the Store and fires the add event.
11059 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11061 add : function(records){
11062 records = [].concat(records);
11063 for(var i = 0, len = records.length; i < len; i++){
11064 records[i].join(this);
11066 var index = this.data.length;
11067 this.data.addAll(records);
11068 this.fireEvent("add", this, records, index);
11072 * Remove a Record from the Store and fires the remove event.
11073 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11075 remove : function(record){
11076 var index = this.data.indexOf(record);
11077 this.data.removeAt(index);
11078 if(this.pruneModifiedRecords){
11079 this.modified.remove(record);
11081 this.fireEvent("remove", this, record, index);
11085 * Remove all Records from the Store and fires the clear event.
11087 removeAll : function(){
11089 if(this.pruneModifiedRecords){
11090 this.modified = [];
11092 this.fireEvent("clear", this);
11096 * Inserts Records to the Store at the given index and fires the add event.
11097 * @param {Number} index The start index at which to insert the passed Records.
11098 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11100 insert : function(index, records){
11101 records = [].concat(records);
11102 for(var i = 0, len = records.length; i < len; i++){
11103 this.data.insert(index, records[i]);
11104 records[i].join(this);
11106 this.fireEvent("add", this, records, index);
11110 * Get the index within the cache of the passed Record.
11111 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11112 * @return {Number} The index of the passed Record. Returns -1 if not found.
11114 indexOf : function(record){
11115 return this.data.indexOf(record);
11119 * Get the index within the cache of the Record with the passed id.
11120 * @param {String} id The id of the Record to find.
11121 * @return {Number} The index of the Record. Returns -1 if not found.
11123 indexOfId : function(id){
11124 return this.data.indexOfKey(id);
11128 * Get the Record with the specified id.
11129 * @param {String} id The id of the Record to find.
11130 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11132 getById : function(id){
11133 return this.data.key(id);
11137 * Get the Record at the specified index.
11138 * @param {Number} index The index of the Record to find.
11139 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11141 getAt : function(index){
11142 return this.data.itemAt(index);
11146 * Returns a range of Records between specified indices.
11147 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11148 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11149 * @return {Roo.data.Record[]} An array of Records
11151 getRange : function(start, end){
11152 return this.data.getRange(start, end);
11156 storeOptions : function(o){
11157 o = Roo.apply({}, o);
11160 this.lastOptions = o;
11164 * Loads the Record cache from the configured Proxy using the configured Reader.
11166 * If using remote paging, then the first load call must specify the <em>start</em>
11167 * and <em>limit</em> properties in the options.params property to establish the initial
11168 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11170 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11171 * and this call will return before the new data has been loaded. Perform any post-processing
11172 * in a callback function, or in a "load" event handler.</strong>
11174 * @param {Object} options An object containing properties which control loading options:<ul>
11175 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11176 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11177 * passed the following arguments:<ul>
11178 * <li>r : Roo.data.Record[]</li>
11179 * <li>options: Options object from the load call</li>
11180 * <li>success: Boolean success indicator</li></ul></li>
11181 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11182 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11185 load : function(options){
11186 options = options || {};
11187 if(this.fireEvent("beforeload", this, options) !== false){
11188 this.storeOptions(options);
11189 var p = Roo.apply(options.params || {}, this.baseParams);
11190 // if meta was not loaded from remote source.. try requesting it.
11191 if (!this.reader.metaFromRemote) {
11192 p._requestMeta = 1;
11194 if(this.sortInfo && this.remoteSort){
11195 var pn = this.paramNames;
11196 p[pn["sort"]] = this.sortInfo.field;
11197 p[pn["dir"]] = this.sortInfo.direction;
11199 if (this.multiSort) {
11200 var pn = this.paramNames;
11201 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11204 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11209 * Reloads the Record cache from the configured Proxy using the configured Reader and
11210 * the options from the last load operation performed.
11211 * @param {Object} options (optional) An object containing properties which may override the options
11212 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11213 * the most recently used options are reused).
11215 reload : function(options){
11216 this.load(Roo.applyIf(options||{}, this.lastOptions));
11220 // Called as a callback by the Reader during a load operation.
11221 loadRecords : function(o, options, success){
11222 if(!o || success === false){
11223 if(success !== false){
11224 this.fireEvent("load", this, [], options, o);
11226 if(options.callback){
11227 options.callback.call(options.scope || this, [], options, false);
11231 // if data returned failure - throw an exception.
11232 if (o.success === false) {
11233 // show a message if no listener is registered.
11234 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11235 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11237 // loadmask wil be hooked into this..
11238 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11241 var r = o.records, t = o.totalRecords || r.length;
11243 this.fireEvent("beforeloadadd", this, r, options, o);
11245 if(!options || options.add !== true){
11246 if(this.pruneModifiedRecords){
11247 this.modified = [];
11249 for(var i = 0, len = r.length; i < len; i++){
11253 this.data = this.snapshot;
11254 delete this.snapshot;
11257 this.data.addAll(r);
11258 this.totalLength = t;
11260 this.fireEvent("datachanged", this);
11262 this.totalLength = Math.max(t, this.data.length+r.length);
11266 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11268 var e = new Roo.data.Record({});
11270 e.set(this.parent.displayField, this.parent.emptyTitle);
11271 e.set(this.parent.valueField, '');
11276 this.fireEvent("load", this, r, options, o);
11277 if(options.callback){
11278 options.callback.call(options.scope || this, r, options, true);
11284 * Loads data from a passed data block. A Reader which understands the format of the data
11285 * must have been configured in the constructor.
11286 * @param {Object} data The data block from which to read the Records. The format of the data expected
11287 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11288 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11290 loadData : function(o, append){
11291 var r = this.reader.readRecords(o);
11292 this.loadRecords(r, {add: append}, true);
11296 * Gets the number of cached records.
11298 * <em>If using paging, this may not be the total size of the dataset. If the data object
11299 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11300 * the data set size</em>
11302 getCount : function(){
11303 return this.data.length || 0;
11307 * Gets the total number of records in the dataset as returned by the server.
11309 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11310 * the dataset size</em>
11312 getTotalCount : function(){
11313 return this.totalLength || 0;
11317 * Returns the sort state of the Store as an object with two properties:
11319 field {String} The name of the field by which the Records are sorted
11320 direction {String} The sort order, "ASC" or "DESC"
11323 getSortState : function(){
11324 return this.sortInfo;
11328 applySort : function(){
11329 if(this.sortInfo && !this.remoteSort){
11330 var s = this.sortInfo, f = s.field;
11331 var st = this.fields.get(f).sortType;
11332 var fn = function(r1, r2){
11333 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11334 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11336 this.data.sort(s.direction, fn);
11337 if(this.snapshot && this.snapshot != this.data){
11338 this.snapshot.sort(s.direction, fn);
11344 * Sets the default sort column and order to be used by the next load operation.
11345 * @param {String} fieldName The name of the field to sort by.
11346 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11348 setDefaultSort : function(field, dir){
11349 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11353 * Sort the Records.
11354 * If remote sorting is used, the sort is performed on the server, and the cache is
11355 * reloaded. If local sorting is used, the cache is sorted internally.
11356 * @param {String} fieldName The name of the field to sort by.
11357 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11359 sort : function(fieldName, dir){
11360 var f = this.fields.get(fieldName);
11362 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11364 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11365 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11370 this.sortToggle[f.name] = dir;
11371 this.sortInfo = {field: f.name, direction: dir};
11372 if(!this.remoteSort){
11374 this.fireEvent("datachanged", this);
11376 this.load(this.lastOptions);
11381 * Calls the specified function for each of the Records in the cache.
11382 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11383 * Returning <em>false</em> aborts and exits the iteration.
11384 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11386 each : function(fn, scope){
11387 this.data.each(fn, scope);
11391 * Gets all records modified since the last commit. Modified records are persisted across load operations
11392 * (e.g., during paging).
11393 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11395 getModifiedRecords : function(){
11396 return this.modified;
11400 createFilterFn : function(property, value, anyMatch){
11401 if(!value.exec){ // not a regex
11402 value = String(value);
11403 if(value.length == 0){
11406 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11408 return function(r){
11409 return value.test(r.data[property]);
11414 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11415 * @param {String} property A field on your records
11416 * @param {Number} start The record index to start at (defaults to 0)
11417 * @param {Number} end The last record index to include (defaults to length - 1)
11418 * @return {Number} The sum
11420 sum : function(property, start, end){
11421 var rs = this.data.items, v = 0;
11422 start = start || 0;
11423 end = (end || end === 0) ? end : rs.length-1;
11425 for(var i = start; i <= end; i++){
11426 v += (rs[i].data[property] || 0);
11432 * Filter the records by a specified property.
11433 * @param {String} field A field on your records
11434 * @param {String/RegExp} value Either a string that the field
11435 * should start with or a RegExp to test against the field
11436 * @param {Boolean} anyMatch True to match any part not just the beginning
11438 filter : function(property, value, anyMatch){
11439 var fn = this.createFilterFn(property, value, anyMatch);
11440 return fn ? this.filterBy(fn) : this.clearFilter();
11444 * Filter by a function. The specified function will be called with each
11445 * record in this data source. If the function returns true the record is included,
11446 * otherwise it is filtered.
11447 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11448 * @param {Object} scope (optional) The scope of the function (defaults to this)
11450 filterBy : function(fn, scope){
11451 this.snapshot = this.snapshot || this.data;
11452 this.data = this.queryBy(fn, scope||this);
11453 this.fireEvent("datachanged", this);
11457 * Query the records by a specified property.
11458 * @param {String} field A field on your records
11459 * @param {String/RegExp} value Either a string that the field
11460 * should start with or a RegExp to test against the field
11461 * @param {Boolean} anyMatch True to match any part not just the beginning
11462 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11464 query : function(property, value, anyMatch){
11465 var fn = this.createFilterFn(property, value, anyMatch);
11466 return fn ? this.queryBy(fn) : this.data.clone();
11470 * Query by a function. The specified function will be called with each
11471 * record in this data source. If the function returns true the record is included
11473 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11474 * @param {Object} scope (optional) The scope of the function (defaults to this)
11475 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11477 queryBy : function(fn, scope){
11478 var data = this.snapshot || this.data;
11479 return data.filterBy(fn, scope||this);
11483 * Collects unique values for a particular dataIndex from this store.
11484 * @param {String} dataIndex The property to collect
11485 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11486 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11487 * @return {Array} An array of the unique values
11489 collect : function(dataIndex, allowNull, bypassFilter){
11490 var d = (bypassFilter === true && this.snapshot) ?
11491 this.snapshot.items : this.data.items;
11492 var v, sv, r = [], l = {};
11493 for(var i = 0, len = d.length; i < len; i++){
11494 v = d[i].data[dataIndex];
11496 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11505 * Revert to a view of the Record cache with no filtering applied.
11506 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11508 clearFilter : function(suppressEvent){
11509 if(this.snapshot && this.snapshot != this.data){
11510 this.data = this.snapshot;
11511 delete this.snapshot;
11512 if(suppressEvent !== true){
11513 this.fireEvent("datachanged", this);
11519 afterEdit : function(record){
11520 if(this.modified.indexOf(record) == -1){
11521 this.modified.push(record);
11523 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11527 afterReject : function(record){
11528 this.modified.remove(record);
11529 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11533 afterCommit : function(record){
11534 this.modified.remove(record);
11535 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11539 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11540 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11542 commitChanges : function(){
11543 var m = this.modified.slice(0);
11544 this.modified = [];
11545 for(var i = 0, len = m.length; i < len; i++){
11551 * Cancel outstanding changes on all changed records.
11553 rejectChanges : function(){
11554 var m = this.modified.slice(0);
11555 this.modified = [];
11556 for(var i = 0, len = m.length; i < len; i++){
11561 onMetaChange : function(meta, rtype, o){
11562 this.recordType = rtype;
11563 this.fields = rtype.prototype.fields;
11564 delete this.snapshot;
11565 this.sortInfo = meta.sortInfo || this.sortInfo;
11566 this.modified = [];
11567 this.fireEvent('metachange', this, this.reader.meta);
11570 moveIndex : function(data, type)
11572 var index = this.indexOf(data);
11574 var newIndex = index + type;
11578 this.insert(newIndex, data);
11583 * Ext JS Library 1.1.1
11584 * Copyright(c) 2006-2007, Ext JS, LLC.
11586 * Originally Released Under LGPL - original licence link has changed is not relivant.
11589 * <script type="text/javascript">
11593 * @class Roo.data.SimpleStore
11594 * @extends Roo.data.Store
11595 * Small helper class to make creating Stores from Array data easier.
11596 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11597 * @cfg {Array} fields An array of field definition objects, or field name strings.
11598 * @cfg {Array} data The multi-dimensional array of data
11600 * @param {Object} config
11602 Roo.data.SimpleStore = function(config){
11603 Roo.data.SimpleStore.superclass.constructor.call(this, {
11605 reader: new Roo.data.ArrayReader({
11608 Roo.data.Record.create(config.fields)
11610 proxy : new Roo.data.MemoryProxy(config.data)
11614 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11616 * Ext JS Library 1.1.1
11617 * Copyright(c) 2006-2007, Ext JS, LLC.
11619 * Originally Released Under LGPL - original licence link has changed is not relivant.
11622 * <script type="text/javascript">
11627 * @extends Roo.data.Store
11628 * @class Roo.data.JsonStore
11629 * Small helper class to make creating Stores for JSON data easier. <br/>
11631 var store = new Roo.data.JsonStore({
11632 url: 'get-images.php',
11634 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11637 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11638 * JsonReader and HttpProxy (unless inline data is provided).</b>
11639 * @cfg {Array} fields An array of field definition objects, or field name strings.
11641 * @param {Object} config
11643 Roo.data.JsonStore = function(c){
11644 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11645 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11646 reader: new Roo.data.JsonReader(c, c.fields)
11649 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11651 * Ext JS Library 1.1.1
11652 * Copyright(c) 2006-2007, Ext JS, LLC.
11654 * Originally Released Under LGPL - original licence link has changed is not relivant.
11657 * <script type="text/javascript">
11661 Roo.data.Field = function(config){
11662 if(typeof config == "string"){
11663 config = {name: config};
11665 Roo.apply(this, config);
11668 this.type = "auto";
11671 var st = Roo.data.SortTypes;
11672 // named sortTypes are supported, here we look them up
11673 if(typeof this.sortType == "string"){
11674 this.sortType = st[this.sortType];
11677 // set default sortType for strings and dates
11678 if(!this.sortType){
11681 this.sortType = st.asUCString;
11684 this.sortType = st.asDate;
11687 this.sortType = st.none;
11692 var stripRe = /[\$,%]/g;
11694 // prebuilt conversion function for this field, instead of
11695 // switching every time we're reading a value
11697 var cv, dateFormat = this.dateFormat;
11702 cv = function(v){ return v; };
11705 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11709 return v !== undefined && v !== null && v !== '' ?
11710 parseInt(String(v).replace(stripRe, ""), 10) : '';
11715 return v !== undefined && v !== null && v !== '' ?
11716 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11721 cv = function(v){ return v === true || v === "true" || v == 1; };
11728 if(v instanceof Date){
11732 if(dateFormat == "timestamp"){
11733 return new Date(v*1000);
11735 return Date.parseDate(v, dateFormat);
11737 var parsed = Date.parse(v);
11738 return parsed ? new Date(parsed) : null;
11747 Roo.data.Field.prototype = {
11755 * Ext JS Library 1.1.1
11756 * Copyright(c) 2006-2007, Ext JS, LLC.
11758 * Originally Released Under LGPL - original licence link has changed is not relivant.
11761 * <script type="text/javascript">
11764 // Base class for reading structured data from a data source. This class is intended to be
11765 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11768 * @class Roo.data.DataReader
11769 * Base class for reading structured data from a data source. This class is intended to be
11770 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11773 Roo.data.DataReader = function(meta, recordType){
11777 this.recordType = recordType instanceof Array ?
11778 Roo.data.Record.create(recordType) : recordType;
11781 Roo.data.DataReader.prototype = {
11783 * Create an empty record
11784 * @param {Object} data (optional) - overlay some values
11785 * @return {Roo.data.Record} record created.
11787 newRow : function(d) {
11789 this.recordType.prototype.fields.each(function(c) {
11791 case 'int' : da[c.name] = 0; break;
11792 case 'date' : da[c.name] = new Date(); break;
11793 case 'float' : da[c.name] = 0.0; break;
11794 case 'boolean' : da[c.name] = false; break;
11795 default : da[c.name] = ""; break;
11799 return new this.recordType(Roo.apply(da, d));
11804 * Ext JS Library 1.1.1
11805 * Copyright(c) 2006-2007, Ext JS, LLC.
11807 * Originally Released Under LGPL - original licence link has changed is not relivant.
11810 * <script type="text/javascript">
11814 * @class Roo.data.DataProxy
11815 * @extends Roo.data.Observable
11816 * This class is an abstract base class for implementations which provide retrieval of
11817 * unformatted data objects.<br>
11819 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11820 * (of the appropriate type which knows how to parse the data object) to provide a block of
11821 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11823 * Custom implementations must implement the load method as described in
11824 * {@link Roo.data.HttpProxy#load}.
11826 Roo.data.DataProxy = function(){
11829 * @event beforeload
11830 * Fires before a network request is made to retrieve a data object.
11831 * @param {Object} This DataProxy object.
11832 * @param {Object} params The params parameter to the load function.
11837 * Fires before the load method's callback is called.
11838 * @param {Object} This DataProxy object.
11839 * @param {Object} o The data object.
11840 * @param {Object} arg The callback argument object passed to the load function.
11844 * @event loadexception
11845 * Fires if an Exception occurs during data retrieval.
11846 * @param {Object} This DataProxy object.
11847 * @param {Object} o The data object.
11848 * @param {Object} arg The callback argument object passed to the load function.
11849 * @param {Object} e The Exception.
11851 loadexception : true
11853 Roo.data.DataProxy.superclass.constructor.call(this);
11856 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11859 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11863 * Ext JS Library 1.1.1
11864 * Copyright(c) 2006-2007, Ext JS, LLC.
11866 * Originally Released Under LGPL - original licence link has changed is not relivant.
11869 * <script type="text/javascript">
11872 * @class Roo.data.MemoryProxy
11873 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11874 * to the Reader when its load method is called.
11876 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11878 Roo.data.MemoryProxy = function(data){
11882 Roo.data.MemoryProxy.superclass.constructor.call(this);
11886 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11889 * Load data from the requested source (in this case an in-memory
11890 * data object passed to the constructor), read the data object into
11891 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11892 * process that block using the passed callback.
11893 * @param {Object} params This parameter is not used by the MemoryProxy class.
11894 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11895 * object into a block of Roo.data.Records.
11896 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11897 * The function must be passed <ul>
11898 * <li>The Record block object</li>
11899 * <li>The "arg" argument from the load function</li>
11900 * <li>A boolean success indicator</li>
11902 * @param {Object} scope The scope in which to call the callback
11903 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11905 load : function(params, reader, callback, scope, arg){
11906 params = params || {};
11909 result = reader.readRecords(this.data);
11911 this.fireEvent("loadexception", this, arg, null, e);
11912 callback.call(scope, null, arg, false);
11915 callback.call(scope, result, arg, true);
11919 update : function(params, records){
11924 * Ext JS Library 1.1.1
11925 * Copyright(c) 2006-2007, Ext JS, LLC.
11927 * Originally Released Under LGPL - original licence link has changed is not relivant.
11930 * <script type="text/javascript">
11933 * @class Roo.data.HttpProxy
11934 * @extends Roo.data.DataProxy
11935 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11936 * configured to reference a certain URL.<br><br>
11938 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11939 * from which the running page was served.<br><br>
11941 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11943 * Be aware that to enable the browser to parse an XML document, the server must set
11944 * the Content-Type header in the HTTP response to "text/xml".
11946 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11947 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11948 * will be used to make the request.
11950 Roo.data.HttpProxy = function(conn){
11951 Roo.data.HttpProxy.superclass.constructor.call(this);
11952 // is conn a conn config or a real conn?
11954 this.useAjax = !conn || !conn.events;
11958 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11959 // thse are take from connection...
11962 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11965 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11966 * extra parameters to each request made by this object. (defaults to undefined)
11969 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11970 * to each request made by this object. (defaults to undefined)
11973 * @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)
11976 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11979 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11985 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11989 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11990 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11991 * a finer-grained basis than the DataProxy events.
11993 getConnection : function(){
11994 return this.useAjax ? Roo.Ajax : this.conn;
11998 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11999 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12000 * process that block using the passed callback.
12001 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12002 * for the request to the remote server.
12003 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12004 * object into a block of Roo.data.Records.
12005 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12006 * The function must be passed <ul>
12007 * <li>The Record block object</li>
12008 * <li>The "arg" argument from the load function</li>
12009 * <li>A boolean success indicator</li>
12011 * @param {Object} scope The scope in which to call the callback
12012 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12014 load : function(params, reader, callback, scope, arg){
12015 if(this.fireEvent("beforeload", this, params) !== false){
12017 params : params || {},
12019 callback : callback,
12024 callback : this.loadResponse,
12028 Roo.applyIf(o, this.conn);
12029 if(this.activeRequest){
12030 Roo.Ajax.abort(this.activeRequest);
12032 this.activeRequest = Roo.Ajax.request(o);
12034 this.conn.request(o);
12037 callback.call(scope||this, null, arg, false);
12042 loadResponse : function(o, success, response){
12043 delete this.activeRequest;
12045 this.fireEvent("loadexception", this, o, response);
12046 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12051 result = o.reader.read(response);
12053 this.fireEvent("loadexception", this, o, response, e);
12054 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12058 this.fireEvent("load", this, o, o.request.arg);
12059 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12063 update : function(dataSet){
12068 updateResponse : function(dataSet){
12073 * Ext JS Library 1.1.1
12074 * Copyright(c) 2006-2007, Ext JS, LLC.
12076 * Originally Released Under LGPL - original licence link has changed is not relivant.
12079 * <script type="text/javascript">
12083 * @class Roo.data.ScriptTagProxy
12084 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12085 * other than the originating domain of the running page.<br><br>
12087 * <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
12088 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12090 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12091 * source code that is used as the source inside a <script> tag.<br><br>
12093 * In order for the browser to process the returned data, the server must wrap the data object
12094 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12095 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12096 * depending on whether the callback name was passed:
12099 boolean scriptTag = false;
12100 String cb = request.getParameter("callback");
12103 response.setContentType("text/javascript");
12105 response.setContentType("application/x-json");
12107 Writer out = response.getWriter();
12109 out.write(cb + "(");
12111 out.print(dataBlock.toJsonString());
12118 * @param {Object} config A configuration object.
12120 Roo.data.ScriptTagProxy = function(config){
12121 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12122 Roo.apply(this, config);
12123 this.head = document.getElementsByTagName("head")[0];
12126 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12128 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12130 * @cfg {String} url The URL from which to request the data object.
12133 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12137 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12138 * the server the name of the callback function set up by the load call to process the returned data object.
12139 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12140 * javascript output which calls this named function passing the data object as its only parameter.
12142 callbackParam : "callback",
12144 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12145 * name to the request.
12150 * Load data from the configured URL, read the data object into
12151 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12152 * process that block using the passed callback.
12153 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12154 * for the request to the remote server.
12155 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12156 * object into a block of Roo.data.Records.
12157 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12158 * The function must be passed <ul>
12159 * <li>The Record block object</li>
12160 * <li>The "arg" argument from the load function</li>
12161 * <li>A boolean success indicator</li>
12163 * @param {Object} scope The scope in which to call the callback
12164 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12166 load : function(params, reader, callback, scope, arg){
12167 if(this.fireEvent("beforeload", this, params) !== false){
12169 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12171 var url = this.url;
12172 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12174 url += "&_dc=" + (new Date().getTime());
12176 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12179 cb : "stcCallback"+transId,
12180 scriptId : "stcScript"+transId,
12184 callback : callback,
12190 window[trans.cb] = function(o){
12191 conn.handleResponse(o, trans);
12194 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12196 if(this.autoAbort !== false){
12200 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12202 var script = document.createElement("script");
12203 script.setAttribute("src", url);
12204 script.setAttribute("type", "text/javascript");
12205 script.setAttribute("id", trans.scriptId);
12206 this.head.appendChild(script);
12208 this.trans = trans;
12210 callback.call(scope||this, null, arg, false);
12215 isLoading : function(){
12216 return this.trans ? true : false;
12220 * Abort the current server request.
12222 abort : function(){
12223 if(this.isLoading()){
12224 this.destroyTrans(this.trans);
12229 destroyTrans : function(trans, isLoaded){
12230 this.head.removeChild(document.getElementById(trans.scriptId));
12231 clearTimeout(trans.timeoutId);
12233 window[trans.cb] = undefined;
12235 delete window[trans.cb];
12238 // if hasn't been loaded, wait for load to remove it to prevent script error
12239 window[trans.cb] = function(){
12240 window[trans.cb] = undefined;
12242 delete window[trans.cb];
12249 handleResponse : function(o, trans){
12250 this.trans = false;
12251 this.destroyTrans(trans, true);
12254 result = trans.reader.readRecords(o);
12256 this.fireEvent("loadexception", this, o, trans.arg, e);
12257 trans.callback.call(trans.scope||window, null, trans.arg, false);
12260 this.fireEvent("load", this, o, trans.arg);
12261 trans.callback.call(trans.scope||window, result, trans.arg, true);
12265 handleFailure : function(trans){
12266 this.trans = false;
12267 this.destroyTrans(trans, false);
12268 this.fireEvent("loadexception", this, null, trans.arg);
12269 trans.callback.call(trans.scope||window, null, trans.arg, false);
12273 * Ext JS Library 1.1.1
12274 * Copyright(c) 2006-2007, Ext JS, LLC.
12276 * Originally Released Under LGPL - original licence link has changed is not relivant.
12279 * <script type="text/javascript">
12283 * @class Roo.data.JsonReader
12284 * @extends Roo.data.DataReader
12285 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12286 * based on mappings in a provided Roo.data.Record constructor.
12288 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12289 * in the reply previously.
12294 var RecordDef = Roo.data.Record.create([
12295 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12296 {name: 'occupation'} // This field will use "occupation" as the mapping.
12298 var myReader = new Roo.data.JsonReader({
12299 totalProperty: "results", // The property which contains the total dataset size (optional)
12300 root: "rows", // The property which contains an Array of row objects
12301 id: "id" // The property within each row object that provides an ID for the record (optional)
12305 * This would consume a JSON file like this:
12307 { 'results': 2, 'rows': [
12308 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12309 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12312 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12313 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12314 * paged from the remote server.
12315 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12316 * @cfg {String} root name of the property which contains the Array of row objects.
12317 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12318 * @cfg {Array} fields Array of field definition objects
12320 * Create a new JsonReader
12321 * @param {Object} meta Metadata configuration options
12322 * @param {Object} recordType Either an Array of field definition objects,
12323 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12325 Roo.data.JsonReader = function(meta, recordType){
12328 // set some defaults:
12329 Roo.applyIf(meta, {
12330 totalProperty: 'total',
12331 successProperty : 'success',
12336 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12338 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12341 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12342 * Used by Store query builder to append _requestMeta to params.
12345 metaFromRemote : false,
12347 * This method is only used by a DataProxy which has retrieved data from a remote server.
12348 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12349 * @return {Object} data A data block which is used by an Roo.data.Store object as
12350 * a cache of Roo.data.Records.
12352 read : function(response){
12353 var json = response.responseText;
12355 var o = /* eval:var:o */ eval("("+json+")");
12357 throw {message: "JsonReader.read: Json object not found"};
12363 this.metaFromRemote = true;
12364 this.meta = o.metaData;
12365 this.recordType = Roo.data.Record.create(o.metaData.fields);
12366 this.onMetaChange(this.meta, this.recordType, o);
12368 return this.readRecords(o);
12371 // private function a store will implement
12372 onMetaChange : function(meta, recordType, o){
12379 simpleAccess: function(obj, subsc) {
12386 getJsonAccessor: function(){
12388 return function(expr) {
12390 return(re.test(expr))
12391 ? new Function("obj", "return obj." + expr)
12396 return Roo.emptyFn;
12401 * Create a data block containing Roo.data.Records from an XML document.
12402 * @param {Object} o An object which contains an Array of row objects in the property specified
12403 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12404 * which contains the total size of the dataset.
12405 * @return {Object} data A data block which is used by an Roo.data.Store object as
12406 * a cache of Roo.data.Records.
12408 readRecords : function(o){
12410 * After any data loads, the raw JSON data is available for further custom processing.
12414 var s = this.meta, Record = this.recordType,
12415 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12417 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12419 if(s.totalProperty) {
12420 this.getTotal = this.getJsonAccessor(s.totalProperty);
12422 if(s.successProperty) {
12423 this.getSuccess = this.getJsonAccessor(s.successProperty);
12425 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12427 var g = this.getJsonAccessor(s.id);
12428 this.getId = function(rec) {
12430 return (r === undefined || r === "") ? null : r;
12433 this.getId = function(){return null;};
12436 for(var jj = 0; jj < fl; jj++){
12438 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12439 this.ef[jj] = this.getJsonAccessor(map);
12443 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12444 if(s.totalProperty){
12445 var vt = parseInt(this.getTotal(o), 10);
12450 if(s.successProperty){
12451 var vs = this.getSuccess(o);
12452 if(vs === false || vs === 'false'){
12457 for(var i = 0; i < c; i++){
12460 var id = this.getId(n);
12461 for(var j = 0; j < fl; j++){
12463 var v = this.ef[j](n);
12465 Roo.log('missing convert for ' + f.name);
12469 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12471 var record = new Record(values, id);
12473 records[i] = record;
12479 totalRecords : totalRecords
12484 * Ext JS Library 1.1.1
12485 * Copyright(c) 2006-2007, Ext JS, LLC.
12487 * Originally Released Under LGPL - original licence link has changed is not relivant.
12490 * <script type="text/javascript">
12494 * @class Roo.data.ArrayReader
12495 * @extends Roo.data.DataReader
12496 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12497 * Each element of that Array represents a row of data fields. The
12498 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12499 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12503 var RecordDef = Roo.data.Record.create([
12504 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12505 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12507 var myReader = new Roo.data.ArrayReader({
12508 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12512 * This would consume an Array like this:
12514 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12516 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12518 * Create a new JsonReader
12519 * @param {Object} meta Metadata configuration options.
12520 * @param {Object} recordType Either an Array of field definition objects
12521 * as specified to {@link Roo.data.Record#create},
12522 * or an {@link Roo.data.Record} object
12523 * created using {@link Roo.data.Record#create}.
12525 Roo.data.ArrayReader = function(meta, recordType){
12526 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12529 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12531 * Create a data block containing Roo.data.Records from an XML document.
12532 * @param {Object} o An Array of row objects which represents the dataset.
12533 * @return {Object} data A data block which is used by an Roo.data.Store object as
12534 * a cache of Roo.data.Records.
12536 readRecords : function(o){
12537 var sid = this.meta ? this.meta.id : null;
12538 var recordType = this.recordType, fields = recordType.prototype.fields;
12541 for(var i = 0; i < root.length; i++){
12544 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12545 for(var j = 0, jlen = fields.length; j < jlen; j++){
12546 var f = fields.items[j];
12547 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12548 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12550 values[f.name] = v;
12552 var record = new recordType(values, id);
12554 records[records.length] = record;
12558 totalRecords : records.length
12567 * @class Roo.bootstrap.ComboBox
12568 * @extends Roo.bootstrap.TriggerField
12569 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12570 * @cfg {Boolean} append (true|false) default false
12571 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12572 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12573 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12574 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12575 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12576 * @cfg {Boolean} animate default true
12577 * @cfg {Boolean} emptyResultText only for touch device
12578 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12579 * @cfg {String} emptyTitle default ''
12581 * Create a new ComboBox.
12582 * @param {Object} config Configuration options
12584 Roo.bootstrap.ComboBox = function(config){
12585 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12589 * Fires when the dropdown list is expanded
12590 * @param {Roo.bootstrap.ComboBox} combo This combo box
12595 * Fires when the dropdown list is collapsed
12596 * @param {Roo.bootstrap.ComboBox} combo This combo box
12600 * @event beforeselect
12601 * Fires before a list item is selected. Return false to cancel the selection.
12602 * @param {Roo.bootstrap.ComboBox} combo This combo box
12603 * @param {Roo.data.Record} record The data record returned from the underlying store
12604 * @param {Number} index The index of the selected item in the dropdown list
12606 'beforeselect' : true,
12609 * Fires when a list item is selected
12610 * @param {Roo.bootstrap.ComboBox} combo This combo box
12611 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12612 * @param {Number} index The index of the selected item in the dropdown list
12616 * @event beforequery
12617 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12618 * The event object passed has these properties:
12619 * @param {Roo.bootstrap.ComboBox} combo This combo box
12620 * @param {String} query The query
12621 * @param {Boolean} forceAll true to force "all" query
12622 * @param {Boolean} cancel true to cancel the query
12623 * @param {Object} e The query event object
12625 'beforequery': true,
12628 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12629 * @param {Roo.bootstrap.ComboBox} combo This combo box
12634 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12635 * @param {Roo.bootstrap.ComboBox} combo This combo box
12636 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12641 * Fires when the remove value from the combobox array
12642 * @param {Roo.bootstrap.ComboBox} combo This combo box
12646 * @event afterremove
12647 * Fires when the remove value from the combobox array
12648 * @param {Roo.bootstrap.ComboBox} combo This combo box
12650 'afterremove' : true,
12652 * @event specialfilter
12653 * Fires when specialfilter
12654 * @param {Roo.bootstrap.ComboBox} combo This combo box
12656 'specialfilter' : true,
12659 * Fires when tick the element
12660 * @param {Roo.bootstrap.ComboBox} combo This combo box
12664 * @event touchviewdisplay
12665 * Fires when touch view require special display (default is using displayField)
12666 * @param {Roo.bootstrap.ComboBox} combo This combo box
12667 * @param {Object} cfg set html .
12669 'touchviewdisplay' : true
12674 this.tickItems = [];
12676 this.selectedIndex = -1;
12677 if(this.mode == 'local'){
12678 if(config.queryDelay === undefined){
12679 this.queryDelay = 10;
12681 if(config.minChars === undefined){
12687 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12690 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12691 * rendering into an Roo.Editor, defaults to false)
12694 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12695 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12698 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12701 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12702 * the dropdown list (defaults to undefined, with no header element)
12706 * @cfg {String/Roo.Template} tpl The template to use to render the output
12710 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12712 listWidth: undefined,
12714 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12715 * mode = 'remote' or 'text' if mode = 'local')
12717 displayField: undefined,
12720 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12721 * mode = 'remote' or 'value' if mode = 'local').
12722 * Note: use of a valueField requires the user make a selection
12723 * in order for a value to be mapped.
12725 valueField: undefined,
12727 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12732 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12733 * field's data value (defaults to the underlying DOM element's name)
12735 hiddenName: undefined,
12737 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12741 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12743 selectedClass: 'active',
12746 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12750 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12751 * anchor positions (defaults to 'tl-bl')
12753 listAlign: 'tl-bl?',
12755 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12759 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12760 * query specified by the allQuery config option (defaults to 'query')
12762 triggerAction: 'query',
12764 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12765 * (defaults to 4, does not apply if editable = false)
12769 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12770 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12774 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12775 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12779 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12780 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12784 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12785 * when editable = true (defaults to false)
12787 selectOnFocus:false,
12789 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12791 queryParam: 'query',
12793 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12794 * when mode = 'remote' (defaults to 'Loading...')
12796 loadingText: 'Loading...',
12798 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12802 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12806 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12807 * traditional select (defaults to true)
12811 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12815 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12819 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12820 * listWidth has a higher value)
12824 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12825 * allow the user to set arbitrary text into the field (defaults to false)
12827 forceSelection:false,
12829 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12830 * if typeAhead = true (defaults to 250)
12832 typeAheadDelay : 250,
12834 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12835 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12837 valueNotFoundText : undefined,
12839 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12841 blockFocus : false,
12844 * @cfg {Boolean} disableClear Disable showing of clear button.
12846 disableClear : false,
12848 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12850 alwaysQuery : false,
12853 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12858 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12860 invalidClass : "has-warning",
12863 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12865 validClass : "has-success",
12868 * @cfg {Boolean} specialFilter (true|false) special filter default false
12870 specialFilter : false,
12873 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12875 mobileTouchView : true,
12878 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12880 useNativeIOS : false,
12882 ios_options : false,
12894 btnPosition : 'right',
12895 triggerList : true,
12896 showToggleBtn : true,
12898 emptyResultText: 'Empty',
12899 triggerText : 'Select',
12902 // element that contains real text value.. (when hidden is used..)
12904 getAutoCreate : function()
12909 * Render classic select for iso
12912 if(Roo.isIOS && this.useNativeIOS){
12913 cfg = this.getAutoCreateNativeIOS();
12921 if(Roo.isTouch && this.mobileTouchView){
12922 cfg = this.getAutoCreateTouchView();
12929 if(!this.tickable){
12930 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12935 * ComboBox with tickable selections
12938 var align = this.labelAlign || this.parentLabelAlign();
12941 cls : 'form-group roo-combobox-tickable' //input-group
12944 var btn_text_select = '';
12945 var btn_text_done = '';
12946 var btn_text_cancel = '';
12948 if (this.btn_text_show) {
12949 btn_text_select = 'Select';
12950 btn_text_done = 'Done';
12951 btn_text_cancel = 'Cancel';
12956 cls : 'tickable-buttons',
12961 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12962 //html : this.triggerText
12963 html: btn_text_select
12969 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12971 html: btn_text_done
12977 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12979 html: btn_text_cancel
12985 buttons.cn.unshift({
12987 cls: 'roo-select2-search-field-input'
12993 Roo.each(buttons.cn, function(c){
12995 c.cls += ' btn-' + _this.size;
12998 if (_this.disabled) {
13009 cls: 'form-hidden-field'
13013 cls: 'roo-select2-choices',
13017 cls: 'roo-select2-search-field',
13028 cls: 'roo-select2-container input-group roo-select2-container-multi',
13033 // cls: 'typeahead typeahead-long dropdown-menu',
13034 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13039 if(this.hasFeedback && !this.allowBlank){
13043 cls: 'glyphicon form-control-feedback'
13046 combobox.cn.push(feedback);
13050 if (align ==='left' && this.fieldLabel.length) {
13052 cfg.cls += ' roo-form-group-label-left';
13057 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13058 tooltip : 'This field is required'
13063 cls : 'control-label',
13064 html : this.fieldLabel
13076 var labelCfg = cfg.cn[1];
13077 var contentCfg = cfg.cn[2];
13080 if(this.indicatorpos == 'right'){
13086 cls : 'control-label',
13090 html : this.fieldLabel
13094 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13095 tooltip : 'This field is required'
13110 labelCfg = cfg.cn[0];
13111 contentCfg = cfg.cn[1];
13115 if(this.labelWidth > 12){
13116 labelCfg.style = "width: " + this.labelWidth + 'px';
13119 if(this.labelWidth < 13 && this.labelmd == 0){
13120 this.labelmd = this.labelWidth;
13123 if(this.labellg > 0){
13124 labelCfg.cls += ' col-lg-' + this.labellg;
13125 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13128 if(this.labelmd > 0){
13129 labelCfg.cls += ' col-md-' + this.labelmd;
13130 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13133 if(this.labelsm > 0){
13134 labelCfg.cls += ' col-sm-' + this.labelsm;
13135 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13138 if(this.labelxs > 0){
13139 labelCfg.cls += ' col-xs-' + this.labelxs;
13140 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13144 } else if ( this.fieldLabel.length) {
13145 // Roo.log(" label");
13149 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13150 tooltip : 'This field is required'
13154 //cls : 'input-group-addon',
13155 html : this.fieldLabel
13160 if(this.indicatorpos == 'right'){
13164 //cls : 'input-group-addon',
13165 html : this.fieldLabel
13169 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13170 tooltip : 'This field is required'
13179 // Roo.log(" no label && no align");
13186 ['xs','sm','md','lg'].map(function(size){
13187 if (settings[size]) {
13188 cfg.cls += ' col-' + size + '-' + settings[size];
13196 _initEventsCalled : false,
13199 initEvents: function()
13201 if (this._initEventsCalled) { // as we call render... prevent looping...
13204 this._initEventsCalled = true;
13207 throw "can not find store for combo";
13210 this.indicator = this.indicatorEl();
13212 this.store = Roo.factory(this.store, Roo.data);
13213 this.store.parent = this;
13215 // if we are building from html. then this element is so complex, that we can not really
13216 // use the rendered HTML.
13217 // so we have to trash and replace the previous code.
13218 if (Roo.XComponent.build_from_html) {
13219 // remove this element....
13220 var e = this.el.dom, k=0;
13221 while (e ) { e = e.previousSibling; ++k;}
13226 this.rendered = false;
13228 this.render(this.parent().getChildContainer(true), k);
13231 if(Roo.isIOS && this.useNativeIOS){
13232 this.initIOSView();
13240 if(Roo.isTouch && this.mobileTouchView){
13241 this.initTouchView();
13246 this.initTickableEvents();
13250 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13252 if(this.hiddenName){
13254 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13256 this.hiddenField.dom.value =
13257 this.hiddenValue !== undefined ? this.hiddenValue :
13258 this.value !== undefined ? this.value : '';
13260 // prevent input submission
13261 this.el.dom.removeAttribute('name');
13262 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13267 // this.el.dom.setAttribute('autocomplete', 'off');
13270 var cls = 'x-combo-list';
13272 //this.list = new Roo.Layer({
13273 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13279 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13280 _this.list.setWidth(lw);
13283 this.list.on('mouseover', this.onViewOver, this);
13284 this.list.on('mousemove', this.onViewMove, this);
13285 this.list.on('scroll', this.onViewScroll, this);
13288 this.list.swallowEvent('mousewheel');
13289 this.assetHeight = 0;
13292 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13293 this.assetHeight += this.header.getHeight();
13296 this.innerList = this.list.createChild({cls:cls+'-inner'});
13297 this.innerList.on('mouseover', this.onViewOver, this);
13298 this.innerList.on('mousemove', this.onViewMove, this);
13299 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13301 if(this.allowBlank && !this.pageSize && !this.disableClear){
13302 this.footer = this.list.createChild({cls:cls+'-ft'});
13303 this.pageTb = new Roo.Toolbar(this.footer);
13307 this.footer = this.list.createChild({cls:cls+'-ft'});
13308 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13309 {pageSize: this.pageSize});
13313 if (this.pageTb && this.allowBlank && !this.disableClear) {
13315 this.pageTb.add(new Roo.Toolbar.Fill(), {
13316 cls: 'x-btn-icon x-btn-clear',
13318 handler: function()
13321 _this.clearValue();
13322 _this.onSelect(false, -1);
13327 this.assetHeight += this.footer.getHeight();
13332 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13335 this.view = new Roo.View(this.list, this.tpl, {
13336 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13338 //this.view.wrapEl.setDisplayed(false);
13339 this.view.on('click', this.onViewClick, this);
13342 this.store.on('beforeload', this.onBeforeLoad, this);
13343 this.store.on('load', this.onLoad, this);
13344 this.store.on('loadexception', this.onLoadException, this);
13346 if(this.resizable){
13347 this.resizer = new Roo.Resizable(this.list, {
13348 pinned:true, handles:'se'
13350 this.resizer.on('resize', function(r, w, h){
13351 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13352 this.listWidth = w;
13353 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13354 this.restrictHeight();
13356 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13359 if(!this.editable){
13360 this.editable = true;
13361 this.setEditable(false);
13366 if (typeof(this.events.add.listeners) != 'undefined') {
13368 this.addicon = this.wrap.createChild(
13369 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13371 this.addicon.on('click', function(e) {
13372 this.fireEvent('add', this);
13375 if (typeof(this.events.edit.listeners) != 'undefined') {
13377 this.editicon = this.wrap.createChild(
13378 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13379 if (this.addicon) {
13380 this.editicon.setStyle('margin-left', '40px');
13382 this.editicon.on('click', function(e) {
13384 // we fire even if inothing is selected..
13385 this.fireEvent('edit', this, this.lastData );
13391 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13392 "up" : function(e){
13393 this.inKeyMode = true;
13397 "down" : function(e){
13398 if(!this.isExpanded()){
13399 this.onTriggerClick();
13401 this.inKeyMode = true;
13406 "enter" : function(e){
13407 // this.onViewClick();
13411 if(this.fireEvent("specialkey", this, e)){
13412 this.onViewClick(false);
13418 "esc" : function(e){
13422 "tab" : function(e){
13425 if(this.fireEvent("specialkey", this, e)){
13426 this.onViewClick(false);
13434 doRelay : function(foo, bar, hname){
13435 if(hname == 'down' || this.scope.isExpanded()){
13436 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13445 this.queryDelay = Math.max(this.queryDelay || 10,
13446 this.mode == 'local' ? 10 : 250);
13449 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13451 if(this.typeAhead){
13452 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13454 if(this.editable !== false){
13455 this.inputEl().on("keyup", this.onKeyUp, this);
13457 if(this.forceSelection){
13458 this.inputEl().on('blur', this.doForce, this);
13462 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13463 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13467 initTickableEvents: function()
13471 if(this.hiddenName){
13473 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13475 this.hiddenField.dom.value =
13476 this.hiddenValue !== undefined ? this.hiddenValue :
13477 this.value !== undefined ? this.value : '';
13479 // prevent input submission
13480 this.el.dom.removeAttribute('name');
13481 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13486 // this.list = this.el.select('ul.dropdown-menu',true).first();
13488 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13489 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13490 if(this.triggerList){
13491 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13494 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13495 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13497 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13498 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13500 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13501 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13503 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13504 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13505 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13508 this.cancelBtn.hide();
13513 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13514 _this.list.setWidth(lw);
13517 this.list.on('mouseover', this.onViewOver, this);
13518 this.list.on('mousemove', this.onViewMove, this);
13520 this.list.on('scroll', this.onViewScroll, this);
13523 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>';
13526 this.view = new Roo.View(this.list, this.tpl, {
13527 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13530 //this.view.wrapEl.setDisplayed(false);
13531 this.view.on('click', this.onViewClick, this);
13535 this.store.on('beforeload', this.onBeforeLoad, this);
13536 this.store.on('load', this.onLoad, this);
13537 this.store.on('loadexception', this.onLoadException, this);
13540 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13541 "up" : function(e){
13542 this.inKeyMode = true;
13546 "down" : function(e){
13547 this.inKeyMode = true;
13551 "enter" : function(e){
13552 if(this.fireEvent("specialkey", this, e)){
13553 this.onViewClick(false);
13559 "esc" : function(e){
13560 this.onTickableFooterButtonClick(e, false, false);
13563 "tab" : function(e){
13564 this.fireEvent("specialkey", this, e);
13566 this.onTickableFooterButtonClick(e, false, false);
13573 doRelay : function(e, fn, key){
13574 if(this.scope.isExpanded()){
13575 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13584 this.queryDelay = Math.max(this.queryDelay || 10,
13585 this.mode == 'local' ? 10 : 250);
13588 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13590 if(this.typeAhead){
13591 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13594 if(this.editable !== false){
13595 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13598 this.indicator = this.indicatorEl();
13600 if(this.indicator){
13601 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13602 this.indicator.hide();
13607 onDestroy : function(){
13609 this.view.setStore(null);
13610 this.view.el.removeAllListeners();
13611 this.view.el.remove();
13612 this.view.purgeListeners();
13615 this.list.dom.innerHTML = '';
13619 this.store.un('beforeload', this.onBeforeLoad, this);
13620 this.store.un('load', this.onLoad, this);
13621 this.store.un('loadexception', this.onLoadException, this);
13623 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13627 fireKey : function(e){
13628 if(e.isNavKeyPress() && !this.list.isVisible()){
13629 this.fireEvent("specialkey", this, e);
13634 onResize: function(w, h){
13635 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13637 // if(typeof w != 'number'){
13638 // // we do not handle it!?!?
13641 // var tw = this.trigger.getWidth();
13642 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13643 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13645 // this.inputEl().setWidth( this.adjustWidth('input', x));
13647 // //this.trigger.setStyle('left', x+'px');
13649 // if(this.list && this.listWidth === undefined){
13650 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13651 // this.list.setWidth(lw);
13652 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13660 * Allow or prevent the user from directly editing the field text. If false is passed,
13661 * the user will only be able to select from the items defined in the dropdown list. This method
13662 * is the runtime equivalent of setting the 'editable' config option at config time.
13663 * @param {Boolean} value True to allow the user to directly edit the field text
13665 setEditable : function(value){
13666 if(value == this.editable){
13669 this.editable = value;
13671 this.inputEl().dom.setAttribute('readOnly', true);
13672 this.inputEl().on('mousedown', this.onTriggerClick, this);
13673 this.inputEl().addClass('x-combo-noedit');
13675 this.inputEl().dom.setAttribute('readOnly', false);
13676 this.inputEl().un('mousedown', this.onTriggerClick, this);
13677 this.inputEl().removeClass('x-combo-noedit');
13683 onBeforeLoad : function(combo,opts){
13684 if(!this.hasFocus){
13688 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13690 this.restrictHeight();
13691 this.selectedIndex = -1;
13695 onLoad : function(){
13697 this.hasQuery = false;
13699 if(!this.hasFocus){
13703 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13704 this.loading.hide();
13707 if(this.store.getCount() > 0){
13710 this.restrictHeight();
13711 if(this.lastQuery == this.allQuery){
13712 if(this.editable && !this.tickable){
13713 this.inputEl().dom.select();
13717 !this.selectByValue(this.value, true) &&
13720 !this.store.lastOptions ||
13721 typeof(this.store.lastOptions.add) == 'undefined' ||
13722 this.store.lastOptions.add != true
13725 this.select(0, true);
13728 if(this.autoFocus){
13731 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13732 this.taTask.delay(this.typeAheadDelay);
13736 this.onEmptyResults();
13742 onLoadException : function()
13744 this.hasQuery = false;
13746 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13747 this.loading.hide();
13750 if(this.tickable && this.editable){
13755 // only causes errors at present
13756 //Roo.log(this.store.reader.jsonData);
13757 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13759 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13765 onTypeAhead : function(){
13766 if(this.store.getCount() > 0){
13767 var r = this.store.getAt(0);
13768 var newValue = r.data[this.displayField];
13769 var len = newValue.length;
13770 var selStart = this.getRawValue().length;
13772 if(selStart != len){
13773 this.setRawValue(newValue);
13774 this.selectText(selStart, newValue.length);
13780 onSelect : function(record, index){
13782 if(this.fireEvent('beforeselect', this, record, index) !== false){
13784 this.setFromData(index > -1 ? record.data : false);
13787 this.fireEvent('select', this, record, index);
13792 * Returns the currently selected field value or empty string if no value is set.
13793 * @return {String} value The selected value
13795 getValue : function()
13797 if(Roo.isIOS && this.useNativeIOS){
13798 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13802 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13805 if(this.valueField){
13806 return typeof this.value != 'undefined' ? this.value : '';
13808 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13812 getRawValue : function()
13814 if(Roo.isIOS && this.useNativeIOS){
13815 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13818 var v = this.inputEl().getValue();
13824 * Clears any text/value currently set in the field
13826 clearValue : function(){
13828 if(this.hiddenField){
13829 this.hiddenField.dom.value = '';
13832 this.setRawValue('');
13833 this.lastSelectionText = '';
13834 this.lastData = false;
13836 var close = this.closeTriggerEl();
13847 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13848 * will be displayed in the field. If the value does not match the data value of an existing item,
13849 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13850 * Otherwise the field will be blank (although the value will still be set).
13851 * @param {String} value The value to match
13853 setValue : function(v)
13855 if(Roo.isIOS && this.useNativeIOS){
13856 this.setIOSValue(v);
13866 if(this.valueField){
13867 var r = this.findRecord(this.valueField, v);
13869 text = r.data[this.displayField];
13870 }else if(this.valueNotFoundText !== undefined){
13871 text = this.valueNotFoundText;
13874 this.lastSelectionText = text;
13875 if(this.hiddenField){
13876 this.hiddenField.dom.value = v;
13878 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13881 var close = this.closeTriggerEl();
13884 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13890 * @property {Object} the last set data for the element
13895 * Sets the value of the field based on a object which is related to the record format for the store.
13896 * @param {Object} value the value to set as. or false on reset?
13898 setFromData : function(o){
13905 var dv = ''; // display value
13906 var vv = ''; // value value..
13908 if (this.displayField) {
13909 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13911 // this is an error condition!!!
13912 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13915 if(this.valueField){
13916 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13919 var close = this.closeTriggerEl();
13922 if(dv.length || vv * 1 > 0){
13924 this.blockFocus=true;
13930 if(this.hiddenField){
13931 this.hiddenField.dom.value = vv;
13933 this.lastSelectionText = dv;
13934 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13938 // no hidden field.. - we store the value in 'value', but still display
13939 // display field!!!!
13940 this.lastSelectionText = dv;
13941 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13948 reset : function(){
13949 // overridden so that last data is reset..
13956 this.setValue(this.originalValue);
13957 //this.clearInvalid();
13958 this.lastData = false;
13960 this.view.clearSelections();
13966 findRecord : function(prop, value){
13968 if(this.store.getCount() > 0){
13969 this.store.each(function(r){
13970 if(r.data[prop] == value){
13980 getName: function()
13982 // returns hidden if it's set..
13983 if (!this.rendered) {return ''};
13984 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13988 onViewMove : function(e, t){
13989 this.inKeyMode = false;
13993 onViewOver : function(e, t){
13994 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13997 var item = this.view.findItemFromChild(t);
14000 var index = this.view.indexOf(item);
14001 this.select(index, false);
14006 onViewClick : function(view, doFocus, el, e)
14008 var index = this.view.getSelectedIndexes()[0];
14010 var r = this.store.getAt(index);
14014 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14021 Roo.each(this.tickItems, function(v,k){
14023 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14025 _this.tickItems.splice(k, 1);
14027 if(typeof(e) == 'undefined' && view == false){
14028 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14040 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14041 this.tickItems.push(r.data);
14044 if(typeof(e) == 'undefined' && view == false){
14045 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14052 this.onSelect(r, index);
14054 if(doFocus !== false && !this.blockFocus){
14055 this.inputEl().focus();
14060 restrictHeight : function(){
14061 //this.innerList.dom.style.height = '';
14062 //var inner = this.innerList.dom;
14063 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14064 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14065 //this.list.beginUpdate();
14066 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14067 this.list.alignTo(this.inputEl(), this.listAlign);
14068 this.list.alignTo(this.inputEl(), this.listAlign);
14069 //this.list.endUpdate();
14073 onEmptyResults : function(){
14075 if(this.tickable && this.editable){
14076 this.hasFocus = false;
14077 this.restrictHeight();
14085 * Returns true if the dropdown list is expanded, else false.
14087 isExpanded : function(){
14088 return this.list.isVisible();
14092 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14093 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14094 * @param {String} value The data value of the item to select
14095 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14096 * selected item if it is not currently in view (defaults to true)
14097 * @return {Boolean} True if the value matched an item in the list, else false
14099 selectByValue : function(v, scrollIntoView){
14100 if(v !== undefined && v !== null){
14101 var r = this.findRecord(this.valueField || this.displayField, v);
14103 this.select(this.store.indexOf(r), scrollIntoView);
14111 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14112 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14113 * @param {Number} index The zero-based index of the list item to select
14114 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14115 * selected item if it is not currently in view (defaults to true)
14117 select : function(index, scrollIntoView){
14118 this.selectedIndex = index;
14119 this.view.select(index);
14120 if(scrollIntoView !== false){
14121 var el = this.view.getNode(index);
14123 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14126 this.list.scrollChildIntoView(el, false);
14132 selectNext : function(){
14133 var ct = this.store.getCount();
14135 if(this.selectedIndex == -1){
14137 }else if(this.selectedIndex < ct-1){
14138 this.select(this.selectedIndex+1);
14144 selectPrev : function(){
14145 var ct = this.store.getCount();
14147 if(this.selectedIndex == -1){
14149 }else if(this.selectedIndex != 0){
14150 this.select(this.selectedIndex-1);
14156 onKeyUp : function(e){
14157 if(this.editable !== false && !e.isSpecialKey()){
14158 this.lastKey = e.getKey();
14159 this.dqTask.delay(this.queryDelay);
14164 validateBlur : function(){
14165 return !this.list || !this.list.isVisible();
14169 initQuery : function(){
14171 var v = this.getRawValue();
14173 if(this.tickable && this.editable){
14174 v = this.tickableInputEl().getValue();
14181 doForce : function(){
14182 if(this.inputEl().dom.value.length > 0){
14183 this.inputEl().dom.value =
14184 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14190 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14191 * query allowing the query action to be canceled if needed.
14192 * @param {String} query The SQL query to execute
14193 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14194 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14195 * saved in the current store (defaults to false)
14197 doQuery : function(q, forceAll){
14199 if(q === undefined || q === null){
14204 forceAll: forceAll,
14208 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14213 forceAll = qe.forceAll;
14214 if(forceAll === true || (q.length >= this.minChars)){
14216 this.hasQuery = true;
14218 if(this.lastQuery != q || this.alwaysQuery){
14219 this.lastQuery = q;
14220 if(this.mode == 'local'){
14221 this.selectedIndex = -1;
14223 this.store.clearFilter();
14226 if(this.specialFilter){
14227 this.fireEvent('specialfilter', this);
14232 this.store.filter(this.displayField, q);
14235 this.store.fireEvent("datachanged", this.store);
14242 this.store.baseParams[this.queryParam] = q;
14244 var options = {params : this.getParams(q)};
14247 options.add = true;
14248 options.params.start = this.page * this.pageSize;
14251 this.store.load(options);
14254 * this code will make the page width larger, at the beginning, the list not align correctly,
14255 * we should expand the list on onLoad
14256 * so command out it
14261 this.selectedIndex = -1;
14266 this.loadNext = false;
14270 getParams : function(q){
14272 //p[this.queryParam] = q;
14276 p.limit = this.pageSize;
14282 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14284 collapse : function(){
14285 if(!this.isExpanded()){
14291 this.hasFocus = false;
14295 this.cancelBtn.hide();
14296 this.trigger.show();
14299 this.tickableInputEl().dom.value = '';
14300 this.tickableInputEl().blur();
14305 Roo.get(document).un('mousedown', this.collapseIf, this);
14306 Roo.get(document).un('mousewheel', this.collapseIf, this);
14307 if (!this.editable) {
14308 Roo.get(document).un('keydown', this.listKeyPress, this);
14310 this.fireEvent('collapse', this);
14316 collapseIf : function(e){
14317 var in_combo = e.within(this.el);
14318 var in_list = e.within(this.list);
14319 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14321 if (in_combo || in_list || is_list) {
14322 //e.stopPropagation();
14327 this.onTickableFooterButtonClick(e, false, false);
14335 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14337 expand : function(){
14339 if(this.isExpanded() || !this.hasFocus){
14343 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14344 this.list.setWidth(lw);
14350 this.restrictHeight();
14354 this.tickItems = Roo.apply([], this.item);
14357 this.cancelBtn.show();
14358 this.trigger.hide();
14361 this.tickableInputEl().focus();
14366 Roo.get(document).on('mousedown', this.collapseIf, this);
14367 Roo.get(document).on('mousewheel', this.collapseIf, this);
14368 if (!this.editable) {
14369 Roo.get(document).on('keydown', this.listKeyPress, this);
14372 this.fireEvent('expand', this);
14376 // Implements the default empty TriggerField.onTriggerClick function
14377 onTriggerClick : function(e)
14379 Roo.log('trigger click');
14381 if(this.disabled || !this.triggerList){
14386 this.loadNext = false;
14388 if(this.isExpanded()){
14390 if (!this.blockFocus) {
14391 this.inputEl().focus();
14395 this.hasFocus = true;
14396 if(this.triggerAction == 'all') {
14397 this.doQuery(this.allQuery, true);
14399 this.doQuery(this.getRawValue());
14401 if (!this.blockFocus) {
14402 this.inputEl().focus();
14407 onTickableTriggerClick : function(e)
14414 this.loadNext = false;
14415 this.hasFocus = true;
14417 if(this.triggerAction == 'all') {
14418 this.doQuery(this.allQuery, true);
14420 this.doQuery(this.getRawValue());
14424 onSearchFieldClick : function(e)
14426 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14427 this.onTickableFooterButtonClick(e, false, false);
14431 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14436 this.loadNext = false;
14437 this.hasFocus = true;
14439 if(this.triggerAction == 'all') {
14440 this.doQuery(this.allQuery, true);
14442 this.doQuery(this.getRawValue());
14446 listKeyPress : function(e)
14448 //Roo.log('listkeypress');
14449 // scroll to first matching element based on key pres..
14450 if (e.isSpecialKey()) {
14453 var k = String.fromCharCode(e.getKey()).toUpperCase();
14456 var csel = this.view.getSelectedNodes();
14457 var cselitem = false;
14459 var ix = this.view.indexOf(csel[0]);
14460 cselitem = this.store.getAt(ix);
14461 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14467 this.store.each(function(v) {
14469 // start at existing selection.
14470 if (cselitem.id == v.id) {
14476 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14477 match = this.store.indexOf(v);
14483 if (match === false) {
14484 return true; // no more action?
14487 this.view.select(match);
14488 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14489 sn.scrollIntoView(sn.dom.parentNode, false);
14492 onViewScroll : function(e, t){
14494 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){
14498 this.hasQuery = true;
14500 this.loading = this.list.select('.loading', true).first();
14502 if(this.loading === null){
14503 this.list.createChild({
14505 cls: 'loading roo-select2-more-results roo-select2-active',
14506 html: 'Loading more results...'
14509 this.loading = this.list.select('.loading', true).first();
14511 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14513 this.loading.hide();
14516 this.loading.show();
14521 this.loadNext = true;
14523 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14528 addItem : function(o)
14530 var dv = ''; // display value
14532 if (this.displayField) {
14533 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14535 // this is an error condition!!!
14536 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14543 var choice = this.choices.createChild({
14545 cls: 'roo-select2-search-choice',
14554 cls: 'roo-select2-search-choice-close fa fa-times',
14559 }, this.searchField);
14561 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14563 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14571 this.inputEl().dom.value = '';
14576 onRemoveItem : function(e, _self, o)
14578 e.preventDefault();
14580 this.lastItem = Roo.apply([], this.item);
14582 var index = this.item.indexOf(o.data) * 1;
14585 Roo.log('not this item?!');
14589 this.item.splice(index, 1);
14594 this.fireEvent('remove', this, e);
14600 syncValue : function()
14602 if(!this.item.length){
14609 Roo.each(this.item, function(i){
14610 if(_this.valueField){
14611 value.push(i[_this.valueField]);
14618 this.value = value.join(',');
14620 if(this.hiddenField){
14621 this.hiddenField.dom.value = this.value;
14624 this.store.fireEvent("datachanged", this.store);
14629 clearItem : function()
14631 if(!this.multiple){
14637 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14645 if(this.tickable && !Roo.isTouch){
14646 this.view.refresh();
14650 inputEl: function ()
14652 if(Roo.isIOS && this.useNativeIOS){
14653 return this.el.select('select.roo-ios-select', true).first();
14656 if(Roo.isTouch && this.mobileTouchView){
14657 return this.el.select('input.form-control',true).first();
14661 return this.searchField;
14664 return this.el.select('input.form-control',true).first();
14667 onTickableFooterButtonClick : function(e, btn, el)
14669 e.preventDefault();
14671 this.lastItem = Roo.apply([], this.item);
14673 if(btn && btn.name == 'cancel'){
14674 this.tickItems = Roo.apply([], this.item);
14683 Roo.each(this.tickItems, function(o){
14691 validate : function()
14693 if(this.getEl().hasClass('hidden')){
14697 var v = this.getRawValue();
14700 v = this.getValue();
14703 if(this.disabled || this.allowBlank || v.length){
14708 this.markInvalid();
14712 tickableInputEl : function()
14714 if(!this.tickable || !this.editable){
14715 return this.inputEl();
14718 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14722 getAutoCreateTouchView : function()
14727 cls: 'form-group' //input-group
14733 type : this.inputType,
14734 cls : 'form-control x-combo-noedit',
14735 autocomplete: 'new-password',
14736 placeholder : this.placeholder || '',
14741 input.name = this.name;
14745 input.cls += ' input-' + this.size;
14748 if (this.disabled) {
14749 input.disabled = true;
14760 inputblock.cls += ' input-group';
14762 inputblock.cn.unshift({
14764 cls : 'input-group-addon',
14769 if(this.removable && !this.multiple){
14770 inputblock.cls += ' roo-removable';
14772 inputblock.cn.push({
14775 cls : 'roo-combo-removable-btn close'
14779 if(this.hasFeedback && !this.allowBlank){
14781 inputblock.cls += ' has-feedback';
14783 inputblock.cn.push({
14785 cls: 'glyphicon form-control-feedback'
14792 inputblock.cls += (this.before) ? '' : ' input-group';
14794 inputblock.cn.push({
14796 cls : 'input-group-addon',
14807 cls: 'form-hidden-field'
14821 cls: 'form-hidden-field'
14825 cls: 'roo-select2-choices',
14829 cls: 'roo-select2-search-field',
14842 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14848 if(!this.multiple && this.showToggleBtn){
14855 if (this.caret != false) {
14858 cls: 'fa fa-' + this.caret
14865 cls : 'input-group-addon btn dropdown-toggle',
14870 cls: 'combobox-clear',
14884 combobox.cls += ' roo-select2-container-multi';
14887 var align = this.labelAlign || this.parentLabelAlign();
14889 if (align ==='left' && this.fieldLabel.length) {
14894 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14895 tooltip : 'This field is required'
14899 cls : 'control-label',
14900 html : this.fieldLabel
14911 var labelCfg = cfg.cn[1];
14912 var contentCfg = cfg.cn[2];
14915 if(this.indicatorpos == 'right'){
14920 cls : 'control-label',
14924 html : this.fieldLabel
14928 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14929 tooltip : 'This field is required'
14942 labelCfg = cfg.cn[0];
14943 contentCfg = cfg.cn[1];
14948 if(this.labelWidth > 12){
14949 labelCfg.style = "width: " + this.labelWidth + 'px';
14952 if(this.labelWidth < 13 && this.labelmd == 0){
14953 this.labelmd = this.labelWidth;
14956 if(this.labellg > 0){
14957 labelCfg.cls += ' col-lg-' + this.labellg;
14958 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14961 if(this.labelmd > 0){
14962 labelCfg.cls += ' col-md-' + this.labelmd;
14963 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14966 if(this.labelsm > 0){
14967 labelCfg.cls += ' col-sm-' + this.labelsm;
14968 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14971 if(this.labelxs > 0){
14972 labelCfg.cls += ' col-xs-' + this.labelxs;
14973 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14977 } else if ( this.fieldLabel.length) {
14981 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14982 tooltip : 'This field is required'
14986 cls : 'control-label',
14987 html : this.fieldLabel
14998 if(this.indicatorpos == 'right'){
15002 cls : 'control-label',
15003 html : this.fieldLabel,
15007 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15008 tooltip : 'This field is required'
15025 var settings = this;
15027 ['xs','sm','md','lg'].map(function(size){
15028 if (settings[size]) {
15029 cfg.cls += ' col-' + size + '-' + settings[size];
15036 initTouchView : function()
15038 this.renderTouchView();
15040 this.touchViewEl.on('scroll', function(){
15041 this.el.dom.scrollTop = 0;
15044 this.originalValue = this.getValue();
15046 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15048 this.inputEl().on("click", this.showTouchView, this);
15049 if (this.triggerEl) {
15050 this.triggerEl.on("click", this.showTouchView, this);
15054 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15055 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15057 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15059 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15060 this.store.on('load', this.onTouchViewLoad, this);
15061 this.store.on('loadexception', this.onTouchViewLoadException, this);
15063 if(this.hiddenName){
15065 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15067 this.hiddenField.dom.value =
15068 this.hiddenValue !== undefined ? this.hiddenValue :
15069 this.value !== undefined ? this.value : '';
15071 this.el.dom.removeAttribute('name');
15072 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15076 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15077 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15080 if(this.removable && !this.multiple){
15081 var close = this.closeTriggerEl();
15083 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15084 close.on('click', this.removeBtnClick, this, close);
15088 * fix the bug in Safari iOS8
15090 this.inputEl().on("focus", function(e){
15091 document.activeElement.blur();
15099 renderTouchView : function()
15101 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15102 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15104 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15105 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15107 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15108 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15109 this.touchViewBodyEl.setStyle('overflow', 'auto');
15111 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15112 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15114 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15115 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15119 showTouchView : function()
15125 this.touchViewHeaderEl.hide();
15127 if(this.modalTitle.length){
15128 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15129 this.touchViewHeaderEl.show();
15132 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15133 this.touchViewEl.show();
15135 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15137 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15138 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15140 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15142 if(this.modalTitle.length){
15143 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15146 this.touchViewBodyEl.setHeight(bodyHeight);
15150 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15152 this.touchViewEl.addClass('in');
15155 this.doTouchViewQuery();
15159 hideTouchView : function()
15161 this.touchViewEl.removeClass('in');
15165 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15167 this.touchViewEl.setStyle('display', 'none');
15172 setTouchViewValue : function()
15179 Roo.each(this.tickItems, function(o){
15184 this.hideTouchView();
15187 doTouchViewQuery : function()
15196 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15200 if(!this.alwaysQuery || this.mode == 'local'){
15201 this.onTouchViewLoad();
15208 onTouchViewBeforeLoad : function(combo,opts)
15214 onTouchViewLoad : function()
15216 if(this.store.getCount() < 1){
15217 this.onTouchViewEmptyResults();
15221 this.clearTouchView();
15223 var rawValue = this.getRawValue();
15225 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15227 this.tickItems = [];
15229 this.store.data.each(function(d, rowIndex){
15230 var row = this.touchViewListGroup.createChild(template);
15232 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15233 row.addClass(d.data.cls);
15236 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15239 html : d.data[this.displayField]
15242 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15243 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15246 row.removeClass('selected');
15247 if(!this.multiple && this.valueField &&
15248 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15251 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15252 row.addClass('selected');
15255 if(this.multiple && this.valueField &&
15256 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15260 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15261 this.tickItems.push(d.data);
15264 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15268 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15270 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15272 if(this.modalTitle.length){
15273 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15276 var listHeight = this.touchViewListGroup.getHeight();
15280 if(firstChecked && listHeight > bodyHeight){
15281 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15286 onTouchViewLoadException : function()
15288 this.hideTouchView();
15291 onTouchViewEmptyResults : function()
15293 this.clearTouchView();
15295 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15297 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15301 clearTouchView : function()
15303 this.touchViewListGroup.dom.innerHTML = '';
15306 onTouchViewClick : function(e, el, o)
15308 e.preventDefault();
15311 var rowIndex = o.rowIndex;
15313 var r = this.store.getAt(rowIndex);
15315 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15317 if(!this.multiple){
15318 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15319 c.dom.removeAttribute('checked');
15322 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15324 this.setFromData(r.data);
15326 var close = this.closeTriggerEl();
15332 this.hideTouchView();
15334 this.fireEvent('select', this, r, rowIndex);
15339 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15340 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15341 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15345 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15346 this.addItem(r.data);
15347 this.tickItems.push(r.data);
15351 getAutoCreateNativeIOS : function()
15354 cls: 'form-group' //input-group,
15359 cls : 'roo-ios-select'
15363 combobox.name = this.name;
15366 if (this.disabled) {
15367 combobox.disabled = true;
15370 var settings = this;
15372 ['xs','sm','md','lg'].map(function(size){
15373 if (settings[size]) {
15374 cfg.cls += ' col-' + size + '-' + settings[size];
15384 initIOSView : function()
15386 this.store.on('load', this.onIOSViewLoad, this);
15391 onIOSViewLoad : function()
15393 if(this.store.getCount() < 1){
15397 this.clearIOSView();
15399 if(this.allowBlank) {
15401 var default_text = '-- SELECT --';
15403 if(this.placeholder.length){
15404 default_text = this.placeholder;
15407 if(this.emptyTitle.length){
15408 default_text += ' - ' + this.emptyTitle + ' -';
15411 var opt = this.inputEl().createChild({
15414 html : default_text
15418 o[this.valueField] = 0;
15419 o[this.displayField] = default_text;
15421 this.ios_options.push({
15428 this.store.data.each(function(d, rowIndex){
15432 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15433 html = d.data[this.displayField];
15438 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15439 value = d.data[this.valueField];
15448 if(this.value == d.data[this.valueField]){
15449 option['selected'] = true;
15452 var opt = this.inputEl().createChild(option);
15454 this.ios_options.push({
15461 this.inputEl().on('change', function(){
15462 this.fireEvent('select', this);
15467 clearIOSView: function()
15469 this.inputEl().dom.innerHTML = '';
15471 this.ios_options = [];
15474 setIOSValue: function(v)
15478 if(!this.ios_options){
15482 Roo.each(this.ios_options, function(opts){
15484 opts.el.dom.removeAttribute('selected');
15486 if(opts.data[this.valueField] != v){
15490 opts.el.dom.setAttribute('selected', true);
15496 * @cfg {Boolean} grow
15500 * @cfg {Number} growMin
15504 * @cfg {Number} growMax
15513 Roo.apply(Roo.bootstrap.ComboBox, {
15517 cls: 'modal-header',
15539 cls: 'list-group-item',
15543 cls: 'roo-combobox-list-group-item-value'
15547 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15561 listItemCheckbox : {
15563 cls: 'list-group-item',
15567 cls: 'roo-combobox-list-group-item-value'
15571 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15587 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15592 cls: 'modal-footer',
15600 cls: 'col-xs-6 text-left',
15603 cls: 'btn btn-danger roo-touch-view-cancel',
15609 cls: 'col-xs-6 text-right',
15612 cls: 'btn btn-success roo-touch-view-ok',
15623 Roo.apply(Roo.bootstrap.ComboBox, {
15625 touchViewTemplate : {
15627 cls: 'modal fade roo-combobox-touch-view',
15631 cls: 'modal-dialog',
15632 style : 'position:fixed', // we have to fix position....
15636 cls: 'modal-content',
15638 Roo.bootstrap.ComboBox.header,
15639 Roo.bootstrap.ComboBox.body,
15640 Roo.bootstrap.ComboBox.footer
15649 * Ext JS Library 1.1.1
15650 * Copyright(c) 2006-2007, Ext JS, LLC.
15652 * Originally Released Under LGPL - original licence link has changed is not relivant.
15655 * <script type="text/javascript">
15660 * @extends Roo.util.Observable
15661 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15662 * This class also supports single and multi selection modes. <br>
15663 * Create a data model bound view:
15665 var store = new Roo.data.Store(...);
15667 var view = new Roo.View({
15669 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15671 singleSelect: true,
15672 selectedClass: "ydataview-selected",
15676 // listen for node click?
15677 view.on("click", function(vw, index, node, e){
15678 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15682 dataModel.load("foobar.xml");
15684 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15686 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15687 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15689 * Note: old style constructor is still suported (container, template, config)
15692 * Create a new View
15693 * @param {Object} config The config object
15696 Roo.View = function(config, depreciated_tpl, depreciated_config){
15698 this.parent = false;
15700 if (typeof(depreciated_tpl) == 'undefined') {
15701 // new way.. - universal constructor.
15702 Roo.apply(this, config);
15703 this.el = Roo.get(this.el);
15706 this.el = Roo.get(config);
15707 this.tpl = depreciated_tpl;
15708 Roo.apply(this, depreciated_config);
15710 this.wrapEl = this.el.wrap().wrap();
15711 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15714 if(typeof(this.tpl) == "string"){
15715 this.tpl = new Roo.Template(this.tpl);
15717 // support xtype ctors..
15718 this.tpl = new Roo.factory(this.tpl, Roo);
15722 this.tpl.compile();
15727 * @event beforeclick
15728 * Fires before a click is processed. Returns false to cancel the default action.
15729 * @param {Roo.View} this
15730 * @param {Number} index The index of the target node
15731 * @param {HTMLElement} node The target node
15732 * @param {Roo.EventObject} e The raw event object
15734 "beforeclick" : true,
15737 * Fires when a template node is clicked.
15738 * @param {Roo.View} this
15739 * @param {Number} index The index of the target node
15740 * @param {HTMLElement} node The target node
15741 * @param {Roo.EventObject} e The raw event object
15746 * Fires when a template node is double clicked.
15747 * @param {Roo.View} this
15748 * @param {Number} index The index of the target node
15749 * @param {HTMLElement} node The target node
15750 * @param {Roo.EventObject} e The raw event object
15754 * @event contextmenu
15755 * Fires when a template node is right clicked.
15756 * @param {Roo.View} this
15757 * @param {Number} index The index of the target node
15758 * @param {HTMLElement} node The target node
15759 * @param {Roo.EventObject} e The raw event object
15761 "contextmenu" : true,
15763 * @event selectionchange
15764 * Fires when the selected nodes change.
15765 * @param {Roo.View} this
15766 * @param {Array} selections Array of the selected nodes
15768 "selectionchange" : true,
15771 * @event beforeselect
15772 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15773 * @param {Roo.View} this
15774 * @param {HTMLElement} node The node to be selected
15775 * @param {Array} selections Array of currently selected nodes
15777 "beforeselect" : true,
15779 * @event preparedata
15780 * Fires on every row to render, to allow you to change the data.
15781 * @param {Roo.View} this
15782 * @param {Object} data to be rendered (change this)
15784 "preparedata" : true
15792 "click": this.onClick,
15793 "dblclick": this.onDblClick,
15794 "contextmenu": this.onContextMenu,
15798 this.selections = [];
15800 this.cmp = new Roo.CompositeElementLite([]);
15802 this.store = Roo.factory(this.store, Roo.data);
15803 this.setStore(this.store, true);
15806 if ( this.footer && this.footer.xtype) {
15808 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15810 this.footer.dataSource = this.store;
15811 this.footer.container = fctr;
15812 this.footer = Roo.factory(this.footer, Roo);
15813 fctr.insertFirst(this.el);
15815 // this is a bit insane - as the paging toolbar seems to detach the el..
15816 // dom.parentNode.parentNode.parentNode
15817 // they get detached?
15821 Roo.View.superclass.constructor.call(this);
15826 Roo.extend(Roo.View, Roo.util.Observable, {
15829 * @cfg {Roo.data.Store} store Data store to load data from.
15834 * @cfg {String|Roo.Element} el The container element.
15839 * @cfg {String|Roo.Template} tpl The template used by this View
15843 * @cfg {String} dataName the named area of the template to use as the data area
15844 * Works with domtemplates roo-name="name"
15848 * @cfg {String} selectedClass The css class to add to selected nodes
15850 selectedClass : "x-view-selected",
15852 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15857 * @cfg {String} text to display on mask (default Loading)
15861 * @cfg {Boolean} multiSelect Allow multiple selection
15863 multiSelect : false,
15865 * @cfg {Boolean} singleSelect Allow single selection
15867 singleSelect: false,
15870 * @cfg {Boolean} toggleSelect - selecting
15872 toggleSelect : false,
15875 * @cfg {Boolean} tickable - selecting
15880 * Returns the element this view is bound to.
15881 * @return {Roo.Element}
15883 getEl : function(){
15884 return this.wrapEl;
15890 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15892 refresh : function(){
15893 //Roo.log('refresh');
15896 // if we are using something like 'domtemplate', then
15897 // the what gets used is:
15898 // t.applySubtemplate(NAME, data, wrapping data..)
15899 // the outer template then get' applied with
15900 // the store 'extra data'
15901 // and the body get's added to the
15902 // roo-name="data" node?
15903 // <span class='roo-tpl-{name}'></span> ?????
15907 this.clearSelections();
15908 this.el.update("");
15910 var records = this.store.getRange();
15911 if(records.length < 1) {
15913 // is this valid?? = should it render a template??
15915 this.el.update(this.emptyText);
15919 if (this.dataName) {
15920 this.el.update(t.apply(this.store.meta)); //????
15921 el = this.el.child('.roo-tpl-' + this.dataName);
15924 for(var i = 0, len = records.length; i < len; i++){
15925 var data = this.prepareData(records[i].data, i, records[i]);
15926 this.fireEvent("preparedata", this, data, i, records[i]);
15928 var d = Roo.apply({}, data);
15931 Roo.apply(d, {'roo-id' : Roo.id()});
15935 Roo.each(this.parent.item, function(item){
15936 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15939 Roo.apply(d, {'roo-data-checked' : 'checked'});
15943 html[html.length] = Roo.util.Format.trim(
15945 t.applySubtemplate(this.dataName, d, this.store.meta) :
15952 el.update(html.join(""));
15953 this.nodes = el.dom.childNodes;
15954 this.updateIndexes(0);
15959 * Function to override to reformat the data that is sent to
15960 * the template for each node.
15961 * DEPRICATED - use the preparedata event handler.
15962 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15963 * a JSON object for an UpdateManager bound view).
15965 prepareData : function(data, index, record)
15967 this.fireEvent("preparedata", this, data, index, record);
15971 onUpdate : function(ds, record){
15972 // Roo.log('on update');
15973 this.clearSelections();
15974 var index = this.store.indexOf(record);
15975 var n = this.nodes[index];
15976 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15977 n.parentNode.removeChild(n);
15978 this.updateIndexes(index, index);
15984 onAdd : function(ds, records, index)
15986 //Roo.log(['on Add', ds, records, index] );
15987 this.clearSelections();
15988 if(this.nodes.length == 0){
15992 var n = this.nodes[index];
15993 for(var i = 0, len = records.length; i < len; i++){
15994 var d = this.prepareData(records[i].data, i, records[i]);
15996 this.tpl.insertBefore(n, d);
15999 this.tpl.append(this.el, d);
16002 this.updateIndexes(index);
16005 onRemove : function(ds, record, index){
16006 // Roo.log('onRemove');
16007 this.clearSelections();
16008 var el = this.dataName ?
16009 this.el.child('.roo-tpl-' + this.dataName) :
16012 el.dom.removeChild(this.nodes[index]);
16013 this.updateIndexes(index);
16017 * Refresh an individual node.
16018 * @param {Number} index
16020 refreshNode : function(index){
16021 this.onUpdate(this.store, this.store.getAt(index));
16024 updateIndexes : function(startIndex, endIndex){
16025 var ns = this.nodes;
16026 startIndex = startIndex || 0;
16027 endIndex = endIndex || ns.length - 1;
16028 for(var i = startIndex; i <= endIndex; i++){
16029 ns[i].nodeIndex = i;
16034 * Changes the data store this view uses and refresh the view.
16035 * @param {Store} store
16037 setStore : function(store, initial){
16038 if(!initial && this.store){
16039 this.store.un("datachanged", this.refresh);
16040 this.store.un("add", this.onAdd);
16041 this.store.un("remove", this.onRemove);
16042 this.store.un("update", this.onUpdate);
16043 this.store.un("clear", this.refresh);
16044 this.store.un("beforeload", this.onBeforeLoad);
16045 this.store.un("load", this.onLoad);
16046 this.store.un("loadexception", this.onLoad);
16050 store.on("datachanged", this.refresh, this);
16051 store.on("add", this.onAdd, this);
16052 store.on("remove", this.onRemove, this);
16053 store.on("update", this.onUpdate, this);
16054 store.on("clear", this.refresh, this);
16055 store.on("beforeload", this.onBeforeLoad, this);
16056 store.on("load", this.onLoad, this);
16057 store.on("loadexception", this.onLoad, this);
16065 * onbeforeLoad - masks the loading area.
16068 onBeforeLoad : function(store,opts)
16070 //Roo.log('onBeforeLoad');
16072 this.el.update("");
16074 this.el.mask(this.mask ? this.mask : "Loading" );
16076 onLoad : function ()
16083 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16084 * @param {HTMLElement} node
16085 * @return {HTMLElement} The template node
16087 findItemFromChild : function(node){
16088 var el = this.dataName ?
16089 this.el.child('.roo-tpl-' + this.dataName,true) :
16092 if(!node || node.parentNode == el){
16095 var p = node.parentNode;
16096 while(p && p != el){
16097 if(p.parentNode == el){
16106 onClick : function(e){
16107 var item = this.findItemFromChild(e.getTarget());
16109 var index = this.indexOf(item);
16110 if(this.onItemClick(item, index, e) !== false){
16111 this.fireEvent("click", this, index, item, e);
16114 this.clearSelections();
16119 onContextMenu : function(e){
16120 var item = this.findItemFromChild(e.getTarget());
16122 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16127 onDblClick : function(e){
16128 var item = this.findItemFromChild(e.getTarget());
16130 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16134 onItemClick : function(item, index, e)
16136 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16139 if (this.toggleSelect) {
16140 var m = this.isSelected(item) ? 'unselect' : 'select';
16143 _t[m](item, true, false);
16146 if(this.multiSelect || this.singleSelect){
16147 if(this.multiSelect && e.shiftKey && this.lastSelection){
16148 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16150 this.select(item, this.multiSelect && e.ctrlKey);
16151 this.lastSelection = item;
16154 if(!this.tickable){
16155 e.preventDefault();
16163 * Get the number of selected nodes.
16166 getSelectionCount : function(){
16167 return this.selections.length;
16171 * Get the currently selected nodes.
16172 * @return {Array} An array of HTMLElements
16174 getSelectedNodes : function(){
16175 return this.selections;
16179 * Get the indexes of the selected nodes.
16182 getSelectedIndexes : function(){
16183 var indexes = [], s = this.selections;
16184 for(var i = 0, len = s.length; i < len; i++){
16185 indexes.push(s[i].nodeIndex);
16191 * Clear all selections
16192 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16194 clearSelections : function(suppressEvent){
16195 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16196 this.cmp.elements = this.selections;
16197 this.cmp.removeClass(this.selectedClass);
16198 this.selections = [];
16199 if(!suppressEvent){
16200 this.fireEvent("selectionchange", this, this.selections);
16206 * Returns true if the passed node is selected
16207 * @param {HTMLElement/Number} node The node or node index
16208 * @return {Boolean}
16210 isSelected : function(node){
16211 var s = this.selections;
16215 node = this.getNode(node);
16216 return s.indexOf(node) !== -1;
16221 * @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
16222 * @param {Boolean} keepExisting (optional) true to keep existing selections
16223 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16225 select : function(nodeInfo, keepExisting, suppressEvent){
16226 if(nodeInfo instanceof Array){
16228 this.clearSelections(true);
16230 for(var i = 0, len = nodeInfo.length; i < len; i++){
16231 this.select(nodeInfo[i], true, true);
16235 var node = this.getNode(nodeInfo);
16236 if(!node || this.isSelected(node)){
16237 return; // already selected.
16240 this.clearSelections(true);
16243 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16244 Roo.fly(node).addClass(this.selectedClass);
16245 this.selections.push(node);
16246 if(!suppressEvent){
16247 this.fireEvent("selectionchange", this, this.selections);
16255 * @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
16256 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16257 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16259 unselect : function(nodeInfo, keepExisting, suppressEvent)
16261 if(nodeInfo instanceof Array){
16262 Roo.each(this.selections, function(s) {
16263 this.unselect(s, nodeInfo);
16267 var node = this.getNode(nodeInfo);
16268 if(!node || !this.isSelected(node)){
16269 //Roo.log("not selected");
16270 return; // not selected.
16274 Roo.each(this.selections, function(s) {
16276 Roo.fly(node).removeClass(this.selectedClass);
16283 this.selections= ns;
16284 this.fireEvent("selectionchange", this, this.selections);
16288 * Gets a template node.
16289 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16290 * @return {HTMLElement} The node or null if it wasn't found
16292 getNode : function(nodeInfo){
16293 if(typeof nodeInfo == "string"){
16294 return document.getElementById(nodeInfo);
16295 }else if(typeof nodeInfo == "number"){
16296 return this.nodes[nodeInfo];
16302 * Gets a range template nodes.
16303 * @param {Number} startIndex
16304 * @param {Number} endIndex
16305 * @return {Array} An array of nodes
16307 getNodes : function(start, end){
16308 var ns = this.nodes;
16309 start = start || 0;
16310 end = typeof end == "undefined" ? ns.length - 1 : end;
16313 for(var i = start; i <= end; i++){
16317 for(var i = start; i >= end; i--){
16325 * Finds the index of the passed node
16326 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16327 * @return {Number} The index of the node or -1
16329 indexOf : function(node){
16330 node = this.getNode(node);
16331 if(typeof node.nodeIndex == "number"){
16332 return node.nodeIndex;
16334 var ns = this.nodes;
16335 for(var i = 0, len = ns.length; i < len; i++){
16346 * based on jquery fullcalendar
16350 Roo.bootstrap = Roo.bootstrap || {};
16352 * @class Roo.bootstrap.Calendar
16353 * @extends Roo.bootstrap.Component
16354 * Bootstrap Calendar class
16355 * @cfg {Boolean} loadMask (true|false) default false
16356 * @cfg {Object} header generate the user specific header of the calendar, default false
16359 * Create a new Container
16360 * @param {Object} config The config object
16365 Roo.bootstrap.Calendar = function(config){
16366 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16370 * Fires when a date is selected
16371 * @param {DatePicker} this
16372 * @param {Date} date The selected date
16376 * @event monthchange
16377 * Fires when the displayed month changes
16378 * @param {DatePicker} this
16379 * @param {Date} date The selected month
16381 'monthchange': true,
16383 * @event evententer
16384 * Fires when mouse over an event
16385 * @param {Calendar} this
16386 * @param {event} Event
16388 'evententer': true,
16390 * @event eventleave
16391 * Fires when the mouse leaves an
16392 * @param {Calendar} this
16395 'eventleave': true,
16397 * @event eventclick
16398 * Fires when the mouse click an
16399 * @param {Calendar} this
16408 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16411 * @cfg {Number} startDay
16412 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16420 getAutoCreate : function(){
16423 var fc_button = function(name, corner, style, content ) {
16424 return Roo.apply({},{
16426 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16428 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16431 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16442 style : 'width:100%',
16449 cls : 'fc-header-left',
16451 fc_button('prev', 'left', 'arrow', '‹' ),
16452 fc_button('next', 'right', 'arrow', '›' ),
16453 { tag: 'span', cls: 'fc-header-space' },
16454 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16462 cls : 'fc-header-center',
16466 cls: 'fc-header-title',
16469 html : 'month / year'
16477 cls : 'fc-header-right',
16479 /* fc_button('month', 'left', '', 'month' ),
16480 fc_button('week', '', '', 'week' ),
16481 fc_button('day', 'right', '', 'day' )
16493 header = this.header;
16496 var cal_heads = function() {
16498 // fixme - handle this.
16500 for (var i =0; i < Date.dayNames.length; i++) {
16501 var d = Date.dayNames[i];
16504 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16505 html : d.substring(0,3)
16509 ret[0].cls += ' fc-first';
16510 ret[6].cls += ' fc-last';
16513 var cal_cell = function(n) {
16516 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16521 cls: 'fc-day-number',
16525 cls: 'fc-day-content',
16529 style: 'position: relative;' // height: 17px;
16541 var cal_rows = function() {
16544 for (var r = 0; r < 6; r++) {
16551 for (var i =0; i < Date.dayNames.length; i++) {
16552 var d = Date.dayNames[i];
16553 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16556 row.cn[0].cls+=' fc-first';
16557 row.cn[0].cn[0].style = 'min-height:90px';
16558 row.cn[6].cls+=' fc-last';
16562 ret[0].cls += ' fc-first';
16563 ret[4].cls += ' fc-prev-last';
16564 ret[5].cls += ' fc-last';
16571 cls: 'fc-border-separate',
16572 style : 'width:100%',
16580 cls : 'fc-first fc-last',
16598 cls : 'fc-content',
16599 style : "position: relative;",
16602 cls : 'fc-view fc-view-month fc-grid',
16603 style : 'position: relative',
16604 unselectable : 'on',
16607 cls : 'fc-event-container',
16608 style : 'position:absolute;z-index:8;top:0;left:0;'
16626 initEvents : function()
16629 throw "can not find store for calendar";
16635 style: "text-align:center",
16639 style: "background-color:white;width:50%;margin:250 auto",
16643 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16654 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16656 var size = this.el.select('.fc-content', true).first().getSize();
16657 this.maskEl.setSize(size.width, size.height);
16658 this.maskEl.enableDisplayMode("block");
16659 if(!this.loadMask){
16660 this.maskEl.hide();
16663 this.store = Roo.factory(this.store, Roo.data);
16664 this.store.on('load', this.onLoad, this);
16665 this.store.on('beforeload', this.onBeforeLoad, this);
16669 this.cells = this.el.select('.fc-day',true);
16670 //Roo.log(this.cells);
16671 this.textNodes = this.el.query('.fc-day-number');
16672 this.cells.addClassOnOver('fc-state-hover');
16674 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16675 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16676 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16677 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16679 this.on('monthchange', this.onMonthChange, this);
16681 this.update(new Date().clearTime());
16684 resize : function() {
16685 var sz = this.el.getSize();
16687 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16688 this.el.select('.fc-day-content div',true).setHeight(34);
16693 showPrevMonth : function(e){
16694 this.update(this.activeDate.add("mo", -1));
16696 showToday : function(e){
16697 this.update(new Date().clearTime());
16700 showNextMonth : function(e){
16701 this.update(this.activeDate.add("mo", 1));
16705 showPrevYear : function(){
16706 this.update(this.activeDate.add("y", -1));
16710 showNextYear : function(){
16711 this.update(this.activeDate.add("y", 1));
16716 update : function(date)
16718 var vd = this.activeDate;
16719 this.activeDate = date;
16720 // if(vd && this.el){
16721 // var t = date.getTime();
16722 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16723 // Roo.log('using add remove');
16725 // this.fireEvent('monthchange', this, date);
16727 // this.cells.removeClass("fc-state-highlight");
16728 // this.cells.each(function(c){
16729 // if(c.dateValue == t){
16730 // c.addClass("fc-state-highlight");
16731 // setTimeout(function(){
16732 // try{c.dom.firstChild.focus();}catch(e){}
16742 var days = date.getDaysInMonth();
16744 var firstOfMonth = date.getFirstDateOfMonth();
16745 var startingPos = firstOfMonth.getDay()-this.startDay;
16747 if(startingPos < this.startDay){
16751 var pm = date.add(Date.MONTH, -1);
16752 var prevStart = pm.getDaysInMonth()-startingPos;
16754 this.cells = this.el.select('.fc-day',true);
16755 this.textNodes = this.el.query('.fc-day-number');
16756 this.cells.addClassOnOver('fc-state-hover');
16758 var cells = this.cells.elements;
16759 var textEls = this.textNodes;
16761 Roo.each(cells, function(cell){
16762 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16765 days += startingPos;
16767 // convert everything to numbers so it's fast
16768 var day = 86400000;
16769 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16772 //Roo.log(prevStart);
16774 var today = new Date().clearTime().getTime();
16775 var sel = date.clearTime().getTime();
16776 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16777 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16778 var ddMatch = this.disabledDatesRE;
16779 var ddText = this.disabledDatesText;
16780 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16781 var ddaysText = this.disabledDaysText;
16782 var format = this.format;
16784 var setCellClass = function(cal, cell){
16788 //Roo.log('set Cell Class');
16790 var t = d.getTime();
16794 cell.dateValue = t;
16796 cell.className += " fc-today";
16797 cell.className += " fc-state-highlight";
16798 cell.title = cal.todayText;
16801 // disable highlight in other month..
16802 //cell.className += " fc-state-highlight";
16807 cell.className = " fc-state-disabled";
16808 cell.title = cal.minText;
16812 cell.className = " fc-state-disabled";
16813 cell.title = cal.maxText;
16817 if(ddays.indexOf(d.getDay()) != -1){
16818 cell.title = ddaysText;
16819 cell.className = " fc-state-disabled";
16822 if(ddMatch && format){
16823 var fvalue = d.dateFormat(format);
16824 if(ddMatch.test(fvalue)){
16825 cell.title = ddText.replace("%0", fvalue);
16826 cell.className = " fc-state-disabled";
16830 if (!cell.initialClassName) {
16831 cell.initialClassName = cell.dom.className;
16834 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16839 for(; i < startingPos; i++) {
16840 textEls[i].innerHTML = (++prevStart);
16841 d.setDate(d.getDate()+1);
16843 cells[i].className = "fc-past fc-other-month";
16844 setCellClass(this, cells[i]);
16849 for(; i < days; i++){
16850 intDay = i - startingPos + 1;
16851 textEls[i].innerHTML = (intDay);
16852 d.setDate(d.getDate()+1);
16854 cells[i].className = ''; // "x-date-active";
16855 setCellClass(this, cells[i]);
16859 for(; i < 42; i++) {
16860 textEls[i].innerHTML = (++extraDays);
16861 d.setDate(d.getDate()+1);
16863 cells[i].className = "fc-future fc-other-month";
16864 setCellClass(this, cells[i]);
16867 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16869 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16871 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16872 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16874 if(totalRows != 6){
16875 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16876 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16879 this.fireEvent('monthchange', this, date);
16883 if(!this.internalRender){
16884 var main = this.el.dom.firstChild;
16885 var w = main.offsetWidth;
16886 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16887 Roo.fly(main).setWidth(w);
16888 this.internalRender = true;
16889 // opera does not respect the auto grow header center column
16890 // then, after it gets a width opera refuses to recalculate
16891 // without a second pass
16892 if(Roo.isOpera && !this.secondPass){
16893 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16894 this.secondPass = true;
16895 this.update.defer(10, this, [date]);
16902 findCell : function(dt) {
16903 dt = dt.clearTime().getTime();
16905 this.cells.each(function(c){
16906 //Roo.log("check " +c.dateValue + '?=' + dt);
16907 if(c.dateValue == dt){
16917 findCells : function(ev) {
16918 var s = ev.start.clone().clearTime().getTime();
16920 var e= ev.end.clone().clearTime().getTime();
16923 this.cells.each(function(c){
16924 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16926 if(c.dateValue > e){
16929 if(c.dateValue < s){
16938 // findBestRow: function(cells)
16942 // for (var i =0 ; i < cells.length;i++) {
16943 // ret = Math.max(cells[i].rows || 0,ret);
16950 addItem : function(ev)
16952 // look for vertical location slot in
16953 var cells = this.findCells(ev);
16955 // ev.row = this.findBestRow(cells);
16957 // work out the location.
16961 for(var i =0; i < cells.length; i++) {
16963 cells[i].row = cells[0].row;
16966 cells[i].row = cells[i].row + 1;
16976 if (crow.start.getY() == cells[i].getY()) {
16978 crow.end = cells[i];
16995 cells[0].events.push(ev);
16997 this.calevents.push(ev);
17000 clearEvents: function() {
17002 if(!this.calevents){
17006 Roo.each(this.cells.elements, function(c){
17012 Roo.each(this.calevents, function(e) {
17013 Roo.each(e.els, function(el) {
17014 el.un('mouseenter' ,this.onEventEnter, this);
17015 el.un('mouseleave' ,this.onEventLeave, this);
17020 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17026 renderEvents: function()
17030 this.cells.each(function(c) {
17039 if(c.row != c.events.length){
17040 r = 4 - (4 - (c.row - c.events.length));
17043 c.events = ev.slice(0, r);
17044 c.more = ev.slice(r);
17046 if(c.more.length && c.more.length == 1){
17047 c.events.push(c.more.pop());
17050 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17054 this.cells.each(function(c) {
17056 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17059 for (var e = 0; e < c.events.length; e++){
17060 var ev = c.events[e];
17061 var rows = ev.rows;
17063 for(var i = 0; i < rows.length; i++) {
17065 // how many rows should it span..
17068 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17069 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17071 unselectable : "on",
17074 cls: 'fc-event-inner',
17078 // cls: 'fc-event-time',
17079 // html : cells.length > 1 ? '' : ev.time
17083 cls: 'fc-event-title',
17084 html : String.format('{0}', ev.title)
17091 cls: 'ui-resizable-handle ui-resizable-e',
17092 html : '  '
17099 cfg.cls += ' fc-event-start';
17101 if ((i+1) == rows.length) {
17102 cfg.cls += ' fc-event-end';
17105 var ctr = _this.el.select('.fc-event-container',true).first();
17106 var cg = ctr.createChild(cfg);
17108 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17109 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17111 var r = (c.more.length) ? 1 : 0;
17112 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17113 cg.setWidth(ebox.right - sbox.x -2);
17115 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17116 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17117 cg.on('click', _this.onEventClick, _this, ev);
17128 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17129 style : 'position: absolute',
17130 unselectable : "on",
17133 cls: 'fc-event-inner',
17137 cls: 'fc-event-title',
17145 cls: 'ui-resizable-handle ui-resizable-e',
17146 html : '  '
17152 var ctr = _this.el.select('.fc-event-container',true).first();
17153 var cg = ctr.createChild(cfg);
17155 var sbox = c.select('.fc-day-content',true).first().getBox();
17156 var ebox = c.select('.fc-day-content',true).first().getBox();
17158 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17159 cg.setWidth(ebox.right - sbox.x -2);
17161 cg.on('click', _this.onMoreEventClick, _this, c.more);
17171 onEventEnter: function (e, el,event,d) {
17172 this.fireEvent('evententer', this, el, event);
17175 onEventLeave: function (e, el,event,d) {
17176 this.fireEvent('eventleave', this, el, event);
17179 onEventClick: function (e, el,event,d) {
17180 this.fireEvent('eventclick', this, el, event);
17183 onMonthChange: function () {
17187 onMoreEventClick: function(e, el, more)
17191 this.calpopover.placement = 'right';
17192 this.calpopover.setTitle('More');
17194 this.calpopover.setContent('');
17196 var ctr = this.calpopover.el.select('.popover-content', true).first();
17198 Roo.each(more, function(m){
17200 cls : 'fc-event-hori fc-event-draggable',
17203 var cg = ctr.createChild(cfg);
17205 cg.on('click', _this.onEventClick, _this, m);
17208 this.calpopover.show(el);
17213 onLoad: function ()
17215 this.calevents = [];
17218 if(this.store.getCount() > 0){
17219 this.store.data.each(function(d){
17222 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17223 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17224 time : d.data.start_time,
17225 title : d.data.title,
17226 description : d.data.description,
17227 venue : d.data.venue
17232 this.renderEvents();
17234 if(this.calevents.length && this.loadMask){
17235 this.maskEl.hide();
17239 onBeforeLoad: function()
17241 this.clearEvents();
17243 this.maskEl.show();
17257 * @class Roo.bootstrap.Popover
17258 * @extends Roo.bootstrap.Component
17259 * Bootstrap Popover class
17260 * @cfg {String} html contents of the popover (or false to use children..)
17261 * @cfg {String} title of popover (or false to hide)
17262 * @cfg {String} placement how it is placed
17263 * @cfg {String} trigger click || hover (or false to trigger manually)
17264 * @cfg {String} over what (parent or false to trigger manually.)
17265 * @cfg {Number} delay - delay before showing
17268 * Create a new Popover
17269 * @param {Object} config The config object
17272 Roo.bootstrap.Popover = function(config){
17273 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17279 * After the popover show
17281 * @param {Roo.bootstrap.Popover} this
17286 * After the popover hide
17288 * @param {Roo.bootstrap.Popover} this
17294 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17296 title: 'Fill in a title',
17299 placement : 'right',
17300 trigger : 'hover', // hover
17306 can_build_overlaid : false,
17308 getChildContainer : function()
17310 return this.el.select('.popover-content',true).first();
17313 getAutoCreate : function(){
17316 cls : 'popover roo-dynamic',
17317 style: 'display:block',
17323 cls : 'popover-inner',
17327 cls: 'popover-title',
17331 cls : 'popover-content',
17342 setTitle: function(str)
17345 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17347 setContent: function(str)
17350 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17352 // as it get's added to the bottom of the page.
17353 onRender : function(ct, position)
17355 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17357 var cfg = Roo.apply({}, this.getAutoCreate());
17361 cfg.cls += ' ' + this.cls;
17364 cfg.style = this.style;
17366 //Roo.log("adding to ");
17367 this.el = Roo.get(document.body).createChild(cfg, position);
17368 // Roo.log(this.el);
17373 initEvents : function()
17375 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17376 this.el.enableDisplayMode('block');
17378 if (this.over === false) {
17381 if (this.triggers === false) {
17384 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17385 var triggers = this.trigger ? this.trigger.split(' ') : [];
17386 Roo.each(triggers, function(trigger) {
17388 if (trigger == 'click') {
17389 on_el.on('click', this.toggle, this);
17390 } else if (trigger != 'manual') {
17391 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17392 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17394 on_el.on(eventIn ,this.enter, this);
17395 on_el.on(eventOut, this.leave, this);
17406 toggle : function () {
17407 this.hoverState == 'in' ? this.leave() : this.enter();
17410 enter : function () {
17412 clearTimeout(this.timeout);
17414 this.hoverState = 'in';
17416 if (!this.delay || !this.delay.show) {
17421 this.timeout = setTimeout(function () {
17422 if (_t.hoverState == 'in') {
17425 }, this.delay.show)
17428 leave : function() {
17429 clearTimeout(this.timeout);
17431 this.hoverState = 'out';
17433 if (!this.delay || !this.delay.hide) {
17438 this.timeout = setTimeout(function () {
17439 if (_t.hoverState == 'out') {
17442 }, this.delay.hide)
17445 show : function (on_el)
17448 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17452 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17453 if (this.html !== false) {
17454 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17456 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17457 if (!this.title.length) {
17458 this.el.select('.popover-title',true).hide();
17461 var placement = typeof this.placement == 'function' ?
17462 this.placement.call(this, this.el, on_el) :
17465 var autoToken = /\s?auto?\s?/i;
17466 var autoPlace = autoToken.test(placement);
17468 placement = placement.replace(autoToken, '') || 'top';
17472 //this.el.setXY([0,0]);
17474 this.el.dom.style.display='block';
17475 this.el.addClass(placement);
17477 //this.el.appendTo(on_el);
17479 var p = this.getPosition();
17480 var box = this.el.getBox();
17485 var align = Roo.bootstrap.Popover.alignment[placement];
17488 this.el.alignTo(on_el, align[0],align[1]);
17489 //var arrow = this.el.select('.arrow',true).first();
17490 //arrow.set(align[2],
17492 this.el.addClass('in');
17495 if (this.el.hasClass('fade')) {
17499 this.hoverState = 'in';
17501 this.fireEvent('show', this);
17506 this.el.setXY([0,0]);
17507 this.el.removeClass('in');
17509 this.hoverState = null;
17511 this.fireEvent('hide', this);
17516 Roo.bootstrap.Popover.alignment = {
17517 'left' : ['r-l', [-10,0], 'right'],
17518 'right' : ['l-r', [10,0], 'left'],
17519 'bottom' : ['t-b', [0,10], 'top'],
17520 'top' : [ 'b-t', [0,-10], 'bottom']
17531 * @class Roo.bootstrap.Progress
17532 * @extends Roo.bootstrap.Component
17533 * Bootstrap Progress class
17534 * @cfg {Boolean} striped striped of the progress bar
17535 * @cfg {Boolean} active animated of the progress bar
17539 * Create a new Progress
17540 * @param {Object} config The config object
17543 Roo.bootstrap.Progress = function(config){
17544 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17547 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17552 getAutoCreate : function(){
17560 cfg.cls += ' progress-striped';
17564 cfg.cls += ' active';
17583 * @class Roo.bootstrap.ProgressBar
17584 * @extends Roo.bootstrap.Component
17585 * Bootstrap ProgressBar class
17586 * @cfg {Number} aria_valuenow aria-value now
17587 * @cfg {Number} aria_valuemin aria-value min
17588 * @cfg {Number} aria_valuemax aria-value max
17589 * @cfg {String} label label for the progress bar
17590 * @cfg {String} panel (success | info | warning | danger )
17591 * @cfg {String} role role of the progress bar
17592 * @cfg {String} sr_only text
17596 * Create a new ProgressBar
17597 * @param {Object} config The config object
17600 Roo.bootstrap.ProgressBar = function(config){
17601 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17604 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17608 aria_valuemax : 100,
17614 getAutoCreate : function()
17619 cls: 'progress-bar',
17620 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17632 cfg.role = this.role;
17635 if(this.aria_valuenow){
17636 cfg['aria-valuenow'] = this.aria_valuenow;
17639 if(this.aria_valuemin){
17640 cfg['aria-valuemin'] = this.aria_valuemin;
17643 if(this.aria_valuemax){
17644 cfg['aria-valuemax'] = this.aria_valuemax;
17647 if(this.label && !this.sr_only){
17648 cfg.html = this.label;
17652 cfg.cls += ' progress-bar-' + this.panel;
17658 update : function(aria_valuenow)
17660 this.aria_valuenow = aria_valuenow;
17662 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17677 * @class Roo.bootstrap.TabGroup
17678 * @extends Roo.bootstrap.Column
17679 * Bootstrap Column class
17680 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17681 * @cfg {Boolean} carousel true to make the group behave like a carousel
17682 * @cfg {Boolean} bullets show bullets for the panels
17683 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17684 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17685 * @cfg {Boolean} showarrow (true|false) show arrow default true
17688 * Create a new TabGroup
17689 * @param {Object} config The config object
17692 Roo.bootstrap.TabGroup = function(config){
17693 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17695 this.navId = Roo.id();
17698 Roo.bootstrap.TabGroup.register(this);
17702 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17705 transition : false,
17710 slideOnTouch : false,
17713 getAutoCreate : function()
17715 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17717 cfg.cls += ' tab-content';
17719 if (this.carousel) {
17720 cfg.cls += ' carousel slide';
17723 cls : 'carousel-inner',
17727 if(this.bullets && !Roo.isTouch){
17730 cls : 'carousel-bullets',
17734 if(this.bullets_cls){
17735 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17742 cfg.cn[0].cn.push(bullets);
17745 if(this.showarrow){
17746 cfg.cn[0].cn.push({
17748 class : 'carousel-arrow',
17752 class : 'carousel-prev',
17756 class : 'fa fa-chevron-left'
17762 class : 'carousel-next',
17766 class : 'fa fa-chevron-right'
17779 initEvents: function()
17781 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17782 // this.el.on("touchstart", this.onTouchStart, this);
17785 if(this.autoslide){
17788 this.slideFn = window.setInterval(function() {
17789 _this.showPanelNext();
17793 if(this.showarrow){
17794 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17795 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17801 // onTouchStart : function(e, el, o)
17803 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17807 // this.showPanelNext();
17811 getChildContainer : function()
17813 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17817 * register a Navigation item
17818 * @param {Roo.bootstrap.NavItem} the navitem to add
17820 register : function(item)
17822 this.tabs.push( item);
17823 item.navId = this.navId; // not really needed..
17828 getActivePanel : function()
17831 Roo.each(this.tabs, function(t) {
17841 getPanelByName : function(n)
17844 Roo.each(this.tabs, function(t) {
17845 if (t.tabId == n) {
17853 indexOfPanel : function(p)
17856 Roo.each(this.tabs, function(t,i) {
17857 if (t.tabId == p.tabId) {
17866 * show a specific panel
17867 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17868 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17870 showPanel : function (pan)
17872 if(this.transition || typeof(pan) == 'undefined'){
17873 Roo.log("waiting for the transitionend");
17877 if (typeof(pan) == 'number') {
17878 pan = this.tabs[pan];
17881 if (typeof(pan) == 'string') {
17882 pan = this.getPanelByName(pan);
17885 var cur = this.getActivePanel();
17888 Roo.log('pan or acitve pan is undefined');
17892 if (pan.tabId == this.getActivePanel().tabId) {
17896 if (false === cur.fireEvent('beforedeactivate')) {
17900 if(this.bullets > 0 && !Roo.isTouch){
17901 this.setActiveBullet(this.indexOfPanel(pan));
17904 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17906 this.transition = true;
17907 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17908 var lr = dir == 'next' ? 'left' : 'right';
17909 pan.el.addClass(dir); // or prev
17910 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17911 cur.el.addClass(lr); // or right
17912 pan.el.addClass(lr);
17915 cur.el.on('transitionend', function() {
17916 Roo.log("trans end?");
17918 pan.el.removeClass([lr,dir]);
17919 pan.setActive(true);
17921 cur.el.removeClass([lr]);
17922 cur.setActive(false);
17924 _this.transition = false;
17926 }, this, { single: true } );
17931 cur.setActive(false);
17932 pan.setActive(true);
17937 showPanelNext : function()
17939 var i = this.indexOfPanel(this.getActivePanel());
17941 if (i >= this.tabs.length - 1 && !this.autoslide) {
17945 if (i >= this.tabs.length - 1 && this.autoslide) {
17949 this.showPanel(this.tabs[i+1]);
17952 showPanelPrev : function()
17954 var i = this.indexOfPanel(this.getActivePanel());
17956 if (i < 1 && !this.autoslide) {
17960 if (i < 1 && this.autoslide) {
17961 i = this.tabs.length;
17964 this.showPanel(this.tabs[i-1]);
17968 addBullet: function()
17970 if(!this.bullets || Roo.isTouch){
17973 var ctr = this.el.select('.carousel-bullets',true).first();
17974 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17975 var bullet = ctr.createChild({
17976 cls : 'bullet bullet-' + i
17977 },ctr.dom.lastChild);
17982 bullet.on('click', (function(e, el, o, ii, t){
17984 e.preventDefault();
17986 this.showPanel(ii);
17988 if(this.autoslide && this.slideFn){
17989 clearInterval(this.slideFn);
17990 this.slideFn = window.setInterval(function() {
17991 _this.showPanelNext();
17995 }).createDelegate(this, [i, bullet], true));
18000 setActiveBullet : function(i)
18006 Roo.each(this.el.select('.bullet', true).elements, function(el){
18007 el.removeClass('selected');
18010 var bullet = this.el.select('.bullet-' + i, true).first();
18016 bullet.addClass('selected');
18027 Roo.apply(Roo.bootstrap.TabGroup, {
18031 * register a Navigation Group
18032 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18034 register : function(navgrp)
18036 this.groups[navgrp.navId] = navgrp;
18040 * fetch a Navigation Group based on the navigation ID
18041 * if one does not exist , it will get created.
18042 * @param {string} the navgroup to add
18043 * @returns {Roo.bootstrap.NavGroup} the navgroup
18045 get: function(navId) {
18046 if (typeof(this.groups[navId]) == 'undefined') {
18047 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18049 return this.groups[navId] ;
18064 * @class Roo.bootstrap.TabPanel
18065 * @extends Roo.bootstrap.Component
18066 * Bootstrap TabPanel class
18067 * @cfg {Boolean} active panel active
18068 * @cfg {String} html panel content
18069 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18070 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18071 * @cfg {String} href click to link..
18075 * Create a new TabPanel
18076 * @param {Object} config The config object
18079 Roo.bootstrap.TabPanel = function(config){
18080 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18084 * Fires when the active status changes
18085 * @param {Roo.bootstrap.TabPanel} this
18086 * @param {Boolean} state the new state
18091 * @event beforedeactivate
18092 * Fires before a tab is de-activated - can be used to do validation on a form.
18093 * @param {Roo.bootstrap.TabPanel} this
18094 * @return {Boolean} false if there is an error
18097 'beforedeactivate': true
18100 this.tabId = this.tabId || Roo.id();
18104 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18112 getAutoCreate : function(){
18115 // item is needed for carousel - not sure if it has any effect otherwise
18116 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18117 html: this.html || ''
18121 cfg.cls += ' active';
18125 cfg.tabId = this.tabId;
18132 initEvents: function()
18134 var p = this.parent();
18136 this.navId = this.navId || p.navId;
18138 if (typeof(this.navId) != 'undefined') {
18139 // not really needed.. but just in case.. parent should be a NavGroup.
18140 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18144 var i = tg.tabs.length - 1;
18146 if(this.active && tg.bullets > 0 && i < tg.bullets){
18147 tg.setActiveBullet(i);
18151 this.el.on('click', this.onClick, this);
18154 this.el.on("touchstart", this.onTouchStart, this);
18155 this.el.on("touchmove", this.onTouchMove, this);
18156 this.el.on("touchend", this.onTouchEnd, this);
18161 onRender : function(ct, position)
18163 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18166 setActive : function(state)
18168 Roo.log("panel - set active " + this.tabId + "=" + state);
18170 this.active = state;
18172 this.el.removeClass('active');
18174 } else if (!this.el.hasClass('active')) {
18175 this.el.addClass('active');
18178 this.fireEvent('changed', this, state);
18181 onClick : function(e)
18183 e.preventDefault();
18185 if(!this.href.length){
18189 window.location.href = this.href;
18198 onTouchStart : function(e)
18200 this.swiping = false;
18202 this.startX = e.browserEvent.touches[0].clientX;
18203 this.startY = e.browserEvent.touches[0].clientY;
18206 onTouchMove : function(e)
18208 this.swiping = true;
18210 this.endX = e.browserEvent.touches[0].clientX;
18211 this.endY = e.browserEvent.touches[0].clientY;
18214 onTouchEnd : function(e)
18221 var tabGroup = this.parent();
18223 if(this.endX > this.startX){ // swiping right
18224 tabGroup.showPanelPrev();
18228 if(this.startX > this.endX){ // swiping left
18229 tabGroup.showPanelNext();
18248 * @class Roo.bootstrap.DateField
18249 * @extends Roo.bootstrap.Input
18250 * Bootstrap DateField class
18251 * @cfg {Number} weekStart default 0
18252 * @cfg {String} viewMode default empty, (months|years)
18253 * @cfg {String} minViewMode default empty, (months|years)
18254 * @cfg {Number} startDate default -Infinity
18255 * @cfg {Number} endDate default Infinity
18256 * @cfg {Boolean} todayHighlight default false
18257 * @cfg {Boolean} todayBtn default false
18258 * @cfg {Boolean} calendarWeeks default false
18259 * @cfg {Object} daysOfWeekDisabled default empty
18260 * @cfg {Boolean} singleMode default false (true | false)
18262 * @cfg {Boolean} keyboardNavigation default true
18263 * @cfg {String} language default en
18266 * Create a new DateField
18267 * @param {Object} config The config object
18270 Roo.bootstrap.DateField = function(config){
18271 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18275 * Fires when this field show.
18276 * @param {Roo.bootstrap.DateField} this
18277 * @param {Mixed} date The date value
18282 * Fires when this field hide.
18283 * @param {Roo.bootstrap.DateField} this
18284 * @param {Mixed} date The date value
18289 * Fires when select a date.
18290 * @param {Roo.bootstrap.DateField} this
18291 * @param {Mixed} date The date value
18295 * @event beforeselect
18296 * Fires when before select a date.
18297 * @param {Roo.bootstrap.DateField} this
18298 * @param {Mixed} date The date value
18300 beforeselect : true
18304 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18307 * @cfg {String} format
18308 * The default date format string which can be overriden for localization support. The format must be
18309 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18313 * @cfg {String} altFormats
18314 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18315 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18317 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18325 todayHighlight : false,
18331 keyboardNavigation: true,
18333 calendarWeeks: false,
18335 startDate: -Infinity,
18339 daysOfWeekDisabled: [],
18343 singleMode : false,
18345 UTCDate: function()
18347 return new Date(Date.UTC.apply(Date, arguments));
18350 UTCToday: function()
18352 var today = new Date();
18353 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18356 getDate: function() {
18357 var d = this.getUTCDate();
18358 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18361 getUTCDate: function() {
18365 setDate: function(d) {
18366 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18369 setUTCDate: function(d) {
18371 this.setValue(this.formatDate(this.date));
18374 onRender: function(ct, position)
18377 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18379 this.language = this.language || 'en';
18380 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18381 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18383 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18384 this.format = this.format || 'm/d/y';
18385 this.isInline = false;
18386 this.isInput = true;
18387 this.component = this.el.select('.add-on', true).first() || false;
18388 this.component = (this.component && this.component.length === 0) ? false : this.component;
18389 this.hasInput = this.component && this.inputEl().length;
18391 if (typeof(this.minViewMode === 'string')) {
18392 switch (this.minViewMode) {
18394 this.minViewMode = 1;
18397 this.minViewMode = 2;
18400 this.minViewMode = 0;
18405 if (typeof(this.viewMode === 'string')) {
18406 switch (this.viewMode) {
18419 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18421 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18423 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18425 this.picker().on('mousedown', this.onMousedown, this);
18426 this.picker().on('click', this.onClick, this);
18428 this.picker().addClass('datepicker-dropdown');
18430 this.startViewMode = this.viewMode;
18432 if(this.singleMode){
18433 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18434 v.setVisibilityMode(Roo.Element.DISPLAY);
18438 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18439 v.setStyle('width', '189px');
18443 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18444 if(!this.calendarWeeks){
18449 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18450 v.attr('colspan', function(i, val){
18451 return parseInt(val) + 1;
18456 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18458 this.setStartDate(this.startDate);
18459 this.setEndDate(this.endDate);
18461 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18468 if(this.isInline) {
18473 picker : function()
18475 return this.pickerEl;
18476 // return this.el.select('.datepicker', true).first();
18479 fillDow: function()
18481 var dowCnt = this.weekStart;
18490 if(this.calendarWeeks){
18498 while (dowCnt < this.weekStart + 7) {
18502 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18506 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18509 fillMonths: function()
18512 var months = this.picker().select('>.datepicker-months td', true).first();
18514 months.dom.innerHTML = '';
18520 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18523 months.createChild(month);
18530 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;
18532 if (this.date < this.startDate) {
18533 this.viewDate = new Date(this.startDate);
18534 } else if (this.date > this.endDate) {
18535 this.viewDate = new Date(this.endDate);
18537 this.viewDate = new Date(this.date);
18545 var d = new Date(this.viewDate),
18546 year = d.getUTCFullYear(),
18547 month = d.getUTCMonth(),
18548 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18549 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18550 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18551 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18552 currentDate = this.date && this.date.valueOf(),
18553 today = this.UTCToday();
18555 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18557 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18559 // this.picker.select('>tfoot th.today').
18560 // .text(dates[this.language].today)
18561 // .toggle(this.todayBtn !== false);
18563 this.updateNavArrows();
18566 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18568 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18570 prevMonth.setUTCDate(day);
18572 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18574 var nextMonth = new Date(prevMonth);
18576 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18578 nextMonth = nextMonth.valueOf();
18580 var fillMonths = false;
18582 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18584 while(prevMonth.valueOf() < nextMonth) {
18587 if (prevMonth.getUTCDay() === this.weekStart) {
18589 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18597 if(this.calendarWeeks){
18598 // ISO 8601: First week contains first thursday.
18599 // ISO also states week starts on Monday, but we can be more abstract here.
18601 // Start of current week: based on weekstart/current date
18602 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18603 // Thursday of this week
18604 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18605 // First Thursday of year, year from thursday
18606 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18607 // Calendar week: ms between thursdays, div ms per day, div 7 days
18608 calWeek = (th - yth) / 864e5 / 7 + 1;
18610 fillMonths.cn.push({
18618 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18620 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18623 if (this.todayHighlight &&
18624 prevMonth.getUTCFullYear() == today.getFullYear() &&
18625 prevMonth.getUTCMonth() == today.getMonth() &&
18626 prevMonth.getUTCDate() == today.getDate()) {
18627 clsName += ' today';
18630 if (currentDate && prevMonth.valueOf() === currentDate) {
18631 clsName += ' active';
18634 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18635 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18636 clsName += ' disabled';
18639 fillMonths.cn.push({
18641 cls: 'day ' + clsName,
18642 html: prevMonth.getDate()
18645 prevMonth.setDate(prevMonth.getDate()+1);
18648 var currentYear = this.date && this.date.getUTCFullYear();
18649 var currentMonth = this.date && this.date.getUTCMonth();
18651 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18653 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18654 v.removeClass('active');
18656 if(currentYear === year && k === currentMonth){
18657 v.addClass('active');
18660 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18661 v.addClass('disabled');
18667 year = parseInt(year/10, 10) * 10;
18669 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18671 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18674 for (var i = -1; i < 11; i++) {
18675 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18677 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18685 showMode: function(dir)
18688 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18691 Roo.each(this.picker().select('>div',true).elements, function(v){
18692 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18695 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18700 if(this.isInline) {
18704 this.picker().removeClass(['bottom', 'top']);
18706 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18708 * place to the top of element!
18712 this.picker().addClass('top');
18713 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18718 this.picker().addClass('bottom');
18720 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18723 parseDate : function(value)
18725 if(!value || value instanceof Date){
18728 var v = Date.parseDate(value, this.format);
18729 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18730 v = Date.parseDate(value, 'Y-m-d');
18732 if(!v && this.altFormats){
18733 if(!this.altFormatsArray){
18734 this.altFormatsArray = this.altFormats.split("|");
18736 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18737 v = Date.parseDate(value, this.altFormatsArray[i]);
18743 formatDate : function(date, fmt)
18745 return (!date || !(date instanceof Date)) ?
18746 date : date.dateFormat(fmt || this.format);
18749 onFocus : function()
18751 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18755 onBlur : function()
18757 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18759 var d = this.inputEl().getValue();
18768 this.picker().show();
18772 this.fireEvent('show', this, this.date);
18777 if(this.isInline) {
18780 this.picker().hide();
18781 this.viewMode = this.startViewMode;
18784 this.fireEvent('hide', this, this.date);
18788 onMousedown: function(e)
18790 e.stopPropagation();
18791 e.preventDefault();
18796 Roo.bootstrap.DateField.superclass.keyup.call(this);
18800 setValue: function(v)
18802 if(this.fireEvent('beforeselect', this, v) !== false){
18803 var d = new Date(this.parseDate(v) ).clearTime();
18805 if(isNaN(d.getTime())){
18806 this.date = this.viewDate = '';
18807 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18811 v = this.formatDate(d);
18813 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18815 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18819 this.fireEvent('select', this, this.date);
18823 getValue: function()
18825 return this.formatDate(this.date);
18828 fireKey: function(e)
18830 if (!this.picker().isVisible()){
18831 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18837 var dateChanged = false,
18839 newDate, newViewDate;
18844 e.preventDefault();
18848 if (!this.keyboardNavigation) {
18851 dir = e.keyCode == 37 ? -1 : 1;
18854 newDate = this.moveYear(this.date, dir);
18855 newViewDate = this.moveYear(this.viewDate, dir);
18856 } else if (e.shiftKey){
18857 newDate = this.moveMonth(this.date, dir);
18858 newViewDate = this.moveMonth(this.viewDate, dir);
18860 newDate = new Date(this.date);
18861 newDate.setUTCDate(this.date.getUTCDate() + dir);
18862 newViewDate = new Date(this.viewDate);
18863 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18865 if (this.dateWithinRange(newDate)){
18866 this.date = newDate;
18867 this.viewDate = newViewDate;
18868 this.setValue(this.formatDate(this.date));
18870 e.preventDefault();
18871 dateChanged = true;
18876 if (!this.keyboardNavigation) {
18879 dir = e.keyCode == 38 ? -1 : 1;
18881 newDate = this.moveYear(this.date, dir);
18882 newViewDate = this.moveYear(this.viewDate, dir);
18883 } else if (e.shiftKey){
18884 newDate = this.moveMonth(this.date, dir);
18885 newViewDate = this.moveMonth(this.viewDate, dir);
18887 newDate = new Date(this.date);
18888 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18889 newViewDate = new Date(this.viewDate);
18890 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18892 if (this.dateWithinRange(newDate)){
18893 this.date = newDate;
18894 this.viewDate = newViewDate;
18895 this.setValue(this.formatDate(this.date));
18897 e.preventDefault();
18898 dateChanged = true;
18902 this.setValue(this.formatDate(this.date));
18904 e.preventDefault();
18907 this.setValue(this.formatDate(this.date));
18921 onClick: function(e)
18923 e.stopPropagation();
18924 e.preventDefault();
18926 var target = e.getTarget();
18928 if(target.nodeName.toLowerCase() === 'i'){
18929 target = Roo.get(target).dom.parentNode;
18932 var nodeName = target.nodeName;
18933 var className = target.className;
18934 var html = target.innerHTML;
18935 //Roo.log(nodeName);
18937 switch(nodeName.toLowerCase()) {
18939 switch(className) {
18945 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18946 switch(this.viewMode){
18948 this.viewDate = this.moveMonth(this.viewDate, dir);
18952 this.viewDate = this.moveYear(this.viewDate, dir);
18958 var date = new Date();
18959 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18961 this.setValue(this.formatDate(this.date));
18968 if (className.indexOf('disabled') < 0) {
18969 this.viewDate.setUTCDate(1);
18970 if (className.indexOf('month') > -1) {
18971 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18973 var year = parseInt(html, 10) || 0;
18974 this.viewDate.setUTCFullYear(year);
18978 if(this.singleMode){
18979 this.setValue(this.formatDate(this.viewDate));
18990 //Roo.log(className);
18991 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18992 var day = parseInt(html, 10) || 1;
18993 var year = this.viewDate.getUTCFullYear(),
18994 month = this.viewDate.getUTCMonth();
18996 if (className.indexOf('old') > -1) {
19003 } else if (className.indexOf('new') > -1) {
19011 //Roo.log([year,month,day]);
19012 this.date = this.UTCDate(year, month, day,0,0,0,0);
19013 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19015 //Roo.log(this.formatDate(this.date));
19016 this.setValue(this.formatDate(this.date));
19023 setStartDate: function(startDate)
19025 this.startDate = startDate || -Infinity;
19026 if (this.startDate !== -Infinity) {
19027 this.startDate = this.parseDate(this.startDate);
19030 this.updateNavArrows();
19033 setEndDate: function(endDate)
19035 this.endDate = endDate || Infinity;
19036 if (this.endDate !== Infinity) {
19037 this.endDate = this.parseDate(this.endDate);
19040 this.updateNavArrows();
19043 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19045 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19046 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19047 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19049 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19050 return parseInt(d, 10);
19053 this.updateNavArrows();
19056 updateNavArrows: function()
19058 if(this.singleMode){
19062 var d = new Date(this.viewDate),
19063 year = d.getUTCFullYear(),
19064 month = d.getUTCMonth();
19066 Roo.each(this.picker().select('.prev', true).elements, function(v){
19068 switch (this.viewMode) {
19071 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19077 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19084 Roo.each(this.picker().select('.next', true).elements, function(v){
19086 switch (this.viewMode) {
19089 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19095 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19103 moveMonth: function(date, dir)
19108 var new_date = new Date(date.valueOf()),
19109 day = new_date.getUTCDate(),
19110 month = new_date.getUTCMonth(),
19111 mag = Math.abs(dir),
19113 dir = dir > 0 ? 1 : -1;
19116 // If going back one month, make sure month is not current month
19117 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19119 return new_date.getUTCMonth() == month;
19121 // If going forward one month, make sure month is as expected
19122 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19124 return new_date.getUTCMonth() != new_month;
19126 new_month = month + dir;
19127 new_date.setUTCMonth(new_month);
19128 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19129 if (new_month < 0 || new_month > 11) {
19130 new_month = (new_month + 12) % 12;
19133 // For magnitudes >1, move one month at a time...
19134 for (var i=0; i<mag; i++) {
19135 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19136 new_date = this.moveMonth(new_date, dir);
19138 // ...then reset the day, keeping it in the new month
19139 new_month = new_date.getUTCMonth();
19140 new_date.setUTCDate(day);
19142 return new_month != new_date.getUTCMonth();
19145 // Common date-resetting loop -- if date is beyond end of month, make it
19148 new_date.setUTCDate(--day);
19149 new_date.setUTCMonth(new_month);
19154 moveYear: function(date, dir)
19156 return this.moveMonth(date, dir*12);
19159 dateWithinRange: function(date)
19161 return date >= this.startDate && date <= this.endDate;
19167 this.picker().remove();
19170 validateValue : function(value)
19172 if(this.getEl().hasClass('hidden')){
19176 if(value.length < 1) {
19177 if(this.allowBlank){
19183 if(value.length < this.minLength){
19186 if(value.length > this.maxLength){
19190 var vt = Roo.form.VTypes;
19191 if(!vt[this.vtype](value, this)){
19195 if(typeof this.validator == "function"){
19196 var msg = this.validator(value);
19202 if(this.regex && !this.regex.test(value)){
19206 if(typeof(this.parseDate(value)) == 'undefined'){
19210 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19214 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19222 setVisible : function(visible)
19228 this.getEl().removeClass('hidden');
19234 this.getEl().addClass('hidden');
19239 Roo.apply(Roo.bootstrap.DateField, {
19250 html: '<i class="fa fa-arrow-left"/>'
19260 html: '<i class="fa fa-arrow-right"/>'
19302 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19303 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19304 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19305 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19306 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19319 navFnc: 'FullYear',
19324 navFnc: 'FullYear',
19329 Roo.apply(Roo.bootstrap.DateField, {
19333 cls: 'datepicker dropdown-menu roo-dynamic',
19337 cls: 'datepicker-days',
19341 cls: 'table-condensed',
19343 Roo.bootstrap.DateField.head,
19347 Roo.bootstrap.DateField.footer
19354 cls: 'datepicker-months',
19358 cls: 'table-condensed',
19360 Roo.bootstrap.DateField.head,
19361 Roo.bootstrap.DateField.content,
19362 Roo.bootstrap.DateField.footer
19369 cls: 'datepicker-years',
19373 cls: 'table-condensed',
19375 Roo.bootstrap.DateField.head,
19376 Roo.bootstrap.DateField.content,
19377 Roo.bootstrap.DateField.footer
19396 * @class Roo.bootstrap.TimeField
19397 * @extends Roo.bootstrap.Input
19398 * Bootstrap DateField class
19402 * Create a new TimeField
19403 * @param {Object} config The config object
19406 Roo.bootstrap.TimeField = function(config){
19407 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19411 * Fires when this field show.
19412 * @param {Roo.bootstrap.DateField} thisthis
19413 * @param {Mixed} date The date value
19418 * Fires when this field hide.
19419 * @param {Roo.bootstrap.DateField} this
19420 * @param {Mixed} date The date value
19425 * Fires when select a date.
19426 * @param {Roo.bootstrap.DateField} this
19427 * @param {Mixed} date The date value
19433 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19436 * @cfg {String} format
19437 * The default time format string which can be overriden for localization support. The format must be
19438 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19442 onRender: function(ct, position)
19445 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19447 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19449 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19451 this.pop = this.picker().select('>.datepicker-time',true).first();
19452 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19454 this.picker().on('mousedown', this.onMousedown, this);
19455 this.picker().on('click', this.onClick, this);
19457 this.picker().addClass('datepicker-dropdown');
19462 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19463 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19464 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19465 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19466 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19467 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19471 fireKey: function(e){
19472 if (!this.picker().isVisible()){
19473 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19479 e.preventDefault();
19487 this.onTogglePeriod();
19490 this.onIncrementMinutes();
19493 this.onDecrementMinutes();
19502 onClick: function(e) {
19503 e.stopPropagation();
19504 e.preventDefault();
19507 picker : function()
19509 return this.el.select('.datepicker', true).first();
19512 fillTime: function()
19514 var time = this.pop.select('tbody', true).first();
19516 time.dom.innerHTML = '';
19531 cls: 'hours-up glyphicon glyphicon-chevron-up'
19551 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19572 cls: 'timepicker-hour',
19587 cls: 'timepicker-minute',
19602 cls: 'btn btn-primary period',
19624 cls: 'hours-down glyphicon glyphicon-chevron-down'
19644 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19662 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19669 var hours = this.time.getHours();
19670 var minutes = this.time.getMinutes();
19683 hours = hours - 12;
19687 hours = '0' + hours;
19691 minutes = '0' + minutes;
19694 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19695 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19696 this.pop.select('button', true).first().dom.innerHTML = period;
19702 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19704 var cls = ['bottom'];
19706 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19713 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19718 this.picker().addClass(cls.join('-'));
19722 Roo.each(cls, function(c){
19724 _this.picker().setTop(_this.inputEl().getHeight());
19728 _this.picker().setTop(0 - _this.picker().getHeight());
19733 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19737 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19744 onFocus : function()
19746 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19750 onBlur : function()
19752 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19758 this.picker().show();
19763 this.fireEvent('show', this, this.date);
19768 this.picker().hide();
19771 this.fireEvent('hide', this, this.date);
19774 setTime : function()
19777 this.setValue(this.time.format(this.format));
19779 this.fireEvent('select', this, this.date);
19784 onMousedown: function(e){
19785 e.stopPropagation();
19786 e.preventDefault();
19789 onIncrementHours: function()
19791 Roo.log('onIncrementHours');
19792 this.time = this.time.add(Date.HOUR, 1);
19797 onDecrementHours: function()
19799 Roo.log('onDecrementHours');
19800 this.time = this.time.add(Date.HOUR, -1);
19804 onIncrementMinutes: function()
19806 Roo.log('onIncrementMinutes');
19807 this.time = this.time.add(Date.MINUTE, 1);
19811 onDecrementMinutes: function()
19813 Roo.log('onDecrementMinutes');
19814 this.time = this.time.add(Date.MINUTE, -1);
19818 onTogglePeriod: function()
19820 Roo.log('onTogglePeriod');
19821 this.time = this.time.add(Date.HOUR, 12);
19828 Roo.apply(Roo.bootstrap.TimeField, {
19858 cls: 'btn btn-info ok',
19870 Roo.apply(Roo.bootstrap.TimeField, {
19874 cls: 'datepicker dropdown-menu',
19878 cls: 'datepicker-time',
19882 cls: 'table-condensed',
19884 Roo.bootstrap.TimeField.content,
19885 Roo.bootstrap.TimeField.footer
19904 * @class Roo.bootstrap.MonthField
19905 * @extends Roo.bootstrap.Input
19906 * Bootstrap MonthField class
19908 * @cfg {String} language default en
19911 * Create a new MonthField
19912 * @param {Object} config The config object
19915 Roo.bootstrap.MonthField = function(config){
19916 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19921 * Fires when this field show.
19922 * @param {Roo.bootstrap.MonthField} this
19923 * @param {Mixed} date The date value
19928 * Fires when this field hide.
19929 * @param {Roo.bootstrap.MonthField} this
19930 * @param {Mixed} date The date value
19935 * Fires when select a date.
19936 * @param {Roo.bootstrap.MonthField} this
19937 * @param {String} oldvalue The old value
19938 * @param {String} newvalue The new value
19944 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19946 onRender: function(ct, position)
19949 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19951 this.language = this.language || 'en';
19952 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19953 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19955 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19956 this.isInline = false;
19957 this.isInput = true;
19958 this.component = this.el.select('.add-on', true).first() || false;
19959 this.component = (this.component && this.component.length === 0) ? false : this.component;
19960 this.hasInput = this.component && this.inputEL().length;
19962 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19964 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19966 this.picker().on('mousedown', this.onMousedown, this);
19967 this.picker().on('click', this.onClick, this);
19969 this.picker().addClass('datepicker-dropdown');
19971 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19972 v.setStyle('width', '189px');
19979 if(this.isInline) {
19985 setValue: function(v, suppressEvent)
19987 var o = this.getValue();
19989 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19993 if(suppressEvent !== true){
19994 this.fireEvent('select', this, o, v);
19999 getValue: function()
20004 onClick: function(e)
20006 e.stopPropagation();
20007 e.preventDefault();
20009 var target = e.getTarget();
20011 if(target.nodeName.toLowerCase() === 'i'){
20012 target = Roo.get(target).dom.parentNode;
20015 var nodeName = target.nodeName;
20016 var className = target.className;
20017 var html = target.innerHTML;
20019 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20023 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20025 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20031 picker : function()
20033 return this.pickerEl;
20036 fillMonths: function()
20039 var months = this.picker().select('>.datepicker-months td', true).first();
20041 months.dom.innerHTML = '';
20047 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20050 months.createChild(month);
20059 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20060 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20063 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20064 e.removeClass('active');
20066 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20067 e.addClass('active');
20074 if(this.isInline) {
20078 this.picker().removeClass(['bottom', 'top']);
20080 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20082 * place to the top of element!
20086 this.picker().addClass('top');
20087 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20092 this.picker().addClass('bottom');
20094 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20097 onFocus : function()
20099 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20103 onBlur : function()
20105 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20107 var d = this.inputEl().getValue();
20116 this.picker().show();
20117 this.picker().select('>.datepicker-months', true).first().show();
20121 this.fireEvent('show', this, this.date);
20126 if(this.isInline) {
20129 this.picker().hide();
20130 this.fireEvent('hide', this, this.date);
20134 onMousedown: function(e)
20136 e.stopPropagation();
20137 e.preventDefault();
20142 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20146 fireKey: function(e)
20148 if (!this.picker().isVisible()){
20149 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20160 e.preventDefault();
20164 dir = e.keyCode == 37 ? -1 : 1;
20166 this.vIndex = this.vIndex + dir;
20168 if(this.vIndex < 0){
20172 if(this.vIndex > 11){
20176 if(isNaN(this.vIndex)){
20180 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20186 dir = e.keyCode == 38 ? -1 : 1;
20188 this.vIndex = this.vIndex + dir * 4;
20190 if(this.vIndex < 0){
20194 if(this.vIndex > 11){
20198 if(isNaN(this.vIndex)){
20202 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20207 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20208 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20212 e.preventDefault();
20215 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20216 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20232 this.picker().remove();
20237 Roo.apply(Roo.bootstrap.MonthField, {
20256 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20257 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20262 Roo.apply(Roo.bootstrap.MonthField, {
20266 cls: 'datepicker dropdown-menu roo-dynamic',
20270 cls: 'datepicker-months',
20274 cls: 'table-condensed',
20276 Roo.bootstrap.DateField.content
20296 * @class Roo.bootstrap.CheckBox
20297 * @extends Roo.bootstrap.Input
20298 * Bootstrap CheckBox class
20300 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20301 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20302 * @cfg {String} boxLabel The text that appears beside the checkbox
20303 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20304 * @cfg {Boolean} checked initnal the element
20305 * @cfg {Boolean} inline inline the element (default false)
20306 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20307 * @cfg {String} tooltip label tooltip
20310 * Create a new CheckBox
20311 * @param {Object} config The config object
20314 Roo.bootstrap.CheckBox = function(config){
20315 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20320 * Fires when the element is checked or unchecked.
20321 * @param {Roo.bootstrap.CheckBox} this This input
20322 * @param {Boolean} checked The new checked value
20327 * Fires when the element is click.
20328 * @param {Roo.bootstrap.CheckBox} this This input
20335 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20337 inputType: 'checkbox',
20346 getAutoCreate : function()
20348 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20354 cfg.cls = 'form-group ' + this.inputType; //input-group
20357 cfg.cls += ' ' + this.inputType + '-inline';
20363 type : this.inputType,
20364 value : this.inputValue,
20365 cls : 'roo-' + this.inputType, //'form-box',
20366 placeholder : this.placeholder || ''
20370 if(this.inputType != 'radio'){
20374 cls : 'roo-hidden-value',
20375 value : this.checked ? this.inputValue : this.valueOff
20380 if (this.weight) { // Validity check?
20381 cfg.cls += " " + this.inputType + "-" + this.weight;
20384 if (this.disabled) {
20385 input.disabled=true;
20389 input.checked = this.checked;
20394 input.name = this.name;
20396 if(this.inputType != 'radio'){
20397 hidden.name = this.name;
20398 input.name = '_hidden_' + this.name;
20403 input.cls += ' input-' + this.size;
20408 ['xs','sm','md','lg'].map(function(size){
20409 if (settings[size]) {
20410 cfg.cls += ' col-' + size + '-' + settings[size];
20414 var inputblock = input;
20416 if (this.before || this.after) {
20419 cls : 'input-group',
20424 inputblock.cn.push({
20426 cls : 'input-group-addon',
20431 inputblock.cn.push(input);
20433 if(this.inputType != 'radio'){
20434 inputblock.cn.push(hidden);
20438 inputblock.cn.push({
20440 cls : 'input-group-addon',
20447 if (align ==='left' && this.fieldLabel.length) {
20448 // Roo.log("left and has label");
20453 cls : 'control-label',
20454 html : this.fieldLabel
20464 if(this.labelWidth > 12){
20465 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20468 if(this.labelWidth < 13 && this.labelmd == 0){
20469 this.labelmd = this.labelWidth;
20472 if(this.labellg > 0){
20473 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20474 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20477 if(this.labelmd > 0){
20478 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20479 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20482 if(this.labelsm > 0){
20483 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20484 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20487 if(this.labelxs > 0){
20488 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20489 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20492 } else if ( this.fieldLabel.length) {
20493 // Roo.log(" label");
20497 tag: this.boxLabel ? 'span' : 'label',
20499 cls: 'control-label box-input-label',
20500 //cls : 'input-group-addon',
20501 html : this.fieldLabel
20510 // Roo.log(" no label && no align");
20511 cfg.cn = [ inputblock ] ;
20517 var boxLabelCfg = {
20519 //'for': id, // box label is handled by onclick - so no for...
20521 html: this.boxLabel
20525 boxLabelCfg.tooltip = this.tooltip;
20528 cfg.cn.push(boxLabelCfg);
20531 if(this.inputType != 'radio'){
20532 cfg.cn.push(hidden);
20540 * return the real input element.
20542 inputEl: function ()
20544 return this.el.select('input.roo-' + this.inputType,true).first();
20546 hiddenEl: function ()
20548 return this.el.select('input.roo-hidden-value',true).first();
20551 labelEl: function()
20553 return this.el.select('label.control-label',true).first();
20555 /* depricated... */
20559 return this.labelEl();
20562 boxLabelEl: function()
20564 return this.el.select('label.box-label',true).first();
20567 initEvents : function()
20569 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20571 this.inputEl().on('click', this.onClick, this);
20573 if (this.boxLabel) {
20574 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20577 this.startValue = this.getValue();
20580 Roo.bootstrap.CheckBox.register(this);
20584 onClick : function(e)
20586 if(this.fireEvent('click', this, e) !== false){
20587 this.setChecked(!this.checked);
20592 setChecked : function(state,suppressEvent)
20594 this.startValue = this.getValue();
20596 if(this.inputType == 'radio'){
20598 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20599 e.dom.checked = false;
20602 this.inputEl().dom.checked = true;
20604 this.inputEl().dom.value = this.inputValue;
20606 if(suppressEvent !== true){
20607 this.fireEvent('check', this, true);
20615 this.checked = state;
20617 this.inputEl().dom.checked = state;
20620 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20622 if(suppressEvent !== true){
20623 this.fireEvent('check', this, state);
20629 getValue : function()
20631 if(this.inputType == 'radio'){
20632 return this.getGroupValue();
20635 return this.hiddenEl().dom.value;
20639 getGroupValue : function()
20641 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20645 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20648 setValue : function(v,suppressEvent)
20650 if(this.inputType == 'radio'){
20651 this.setGroupValue(v, suppressEvent);
20655 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20660 setGroupValue : function(v, suppressEvent)
20662 this.startValue = this.getValue();
20664 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20665 e.dom.checked = false;
20667 if(e.dom.value == v){
20668 e.dom.checked = true;
20672 if(suppressEvent !== true){
20673 this.fireEvent('check', this, true);
20681 validate : function()
20685 (this.inputType == 'radio' && this.validateRadio()) ||
20686 (this.inputType == 'checkbox' && this.validateCheckbox())
20692 this.markInvalid();
20696 validateRadio : function()
20698 if(this.allowBlank){
20704 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20705 if(!e.dom.checked){
20717 validateCheckbox : function()
20720 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20721 //return (this.getValue() == this.inputValue) ? true : false;
20724 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20732 for(var i in group){
20733 if(group[i].el.isVisible(true)){
20741 for(var i in group){
20746 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20753 * Mark this field as valid
20755 markValid : function()
20759 this.fireEvent('valid', this);
20761 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20764 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20771 if(this.inputType == 'radio'){
20772 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20773 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20774 e.findParent('.form-group', false, true).addClass(_this.validClass);
20781 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20782 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20786 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20792 for(var i in group){
20793 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20794 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20799 * Mark this field as invalid
20800 * @param {String} msg The validation message
20802 markInvalid : function(msg)
20804 if(this.allowBlank){
20810 this.fireEvent('invalid', this, msg);
20812 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20815 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20819 label.markInvalid();
20822 if(this.inputType == 'radio'){
20823 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20824 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20825 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20832 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20833 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20837 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20843 for(var i in group){
20844 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20845 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20850 clearInvalid : function()
20852 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20854 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20856 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20858 if (label && label.iconEl) {
20859 label.iconEl.removeClass(label.validClass);
20860 label.iconEl.removeClass(label.invalidClass);
20864 disable : function()
20866 if(this.inputType != 'radio'){
20867 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20874 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20875 _this.getActionEl().addClass(this.disabledClass);
20876 e.dom.disabled = true;
20880 this.disabled = true;
20881 this.fireEvent("disable", this);
20885 enable : function()
20887 if(this.inputType != 'radio'){
20888 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20895 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20896 _this.getActionEl().removeClass(this.disabledClass);
20897 e.dom.disabled = false;
20901 this.disabled = false;
20902 this.fireEvent("enable", this);
20906 setBoxLabel : function(v)
20911 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20917 Roo.apply(Roo.bootstrap.CheckBox, {
20922 * register a CheckBox Group
20923 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20925 register : function(checkbox)
20927 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20928 this.groups[checkbox.groupId] = {};
20931 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20935 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20939 * fetch a CheckBox Group based on the group ID
20940 * @param {string} the group ID
20941 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20943 get: function(groupId) {
20944 if (typeof(this.groups[groupId]) == 'undefined') {
20948 return this.groups[groupId] ;
20961 * @class Roo.bootstrap.Radio
20962 * @extends Roo.bootstrap.Component
20963 * Bootstrap Radio class
20964 * @cfg {String} boxLabel - the label associated
20965 * @cfg {String} value - the value of radio
20968 * Create a new Radio
20969 * @param {Object} config The config object
20971 Roo.bootstrap.Radio = function(config){
20972 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20976 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20982 getAutoCreate : function()
20986 cls : 'form-group radio',
20991 html : this.boxLabel
20999 initEvents : function()
21001 this.parent().register(this);
21003 this.el.on('click', this.onClick, this);
21007 onClick : function(e)
21009 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21010 this.setChecked(true);
21014 setChecked : function(state, suppressEvent)
21016 this.parent().setValue(this.value, suppressEvent);
21020 setBoxLabel : function(v)
21025 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21040 * @class Roo.bootstrap.SecurePass
21041 * @extends Roo.bootstrap.Input
21042 * Bootstrap SecurePass class
21046 * Create a new SecurePass
21047 * @param {Object} config The config object
21050 Roo.bootstrap.SecurePass = function (config) {
21051 // these go here, so the translation tool can replace them..
21053 PwdEmpty: "Please type a password, and then retype it to confirm.",
21054 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21055 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21056 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21057 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21058 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21059 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21060 TooWeak: "Your password is Too Weak."
21062 this.meterLabel = "Password strength:";
21063 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21064 this.meterClass = [
21065 "roo-password-meter-tooweak",
21066 "roo-password-meter-weak",
21067 "roo-password-meter-medium",
21068 "roo-password-meter-strong",
21069 "roo-password-meter-grey"
21074 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21077 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21079 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21081 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21082 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21083 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21084 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21085 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21086 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21087 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21097 * @cfg {String/Object} Label for the strength meter (defaults to
21098 * 'Password strength:')
21103 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21104 * ['Weak', 'Medium', 'Strong'])
21107 pwdStrengths: false,
21120 initEvents: function ()
21122 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21124 if (this.el.is('input[type=password]') && Roo.isSafari) {
21125 this.el.on('keydown', this.SafariOnKeyDown, this);
21128 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21131 onRender: function (ct, position)
21133 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21134 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21135 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21137 this.trigger.createChild({
21142 cls: 'roo-password-meter-grey col-xs-12',
21145 //width: this.meterWidth + 'px'
21149 cls: 'roo-password-meter-text'
21155 if (this.hideTrigger) {
21156 this.trigger.setDisplayed(false);
21158 this.setSize(this.width || '', this.height || '');
21161 onDestroy: function ()
21163 if (this.trigger) {
21164 this.trigger.removeAllListeners();
21165 this.trigger.remove();
21168 this.wrap.remove();
21170 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21173 checkStrength: function ()
21175 var pwd = this.inputEl().getValue();
21176 if (pwd == this._lastPwd) {
21181 if (this.ClientSideStrongPassword(pwd)) {
21183 } else if (this.ClientSideMediumPassword(pwd)) {
21185 } else if (this.ClientSideWeakPassword(pwd)) {
21191 Roo.log('strength1: ' + strength);
21193 //var pm = this.trigger.child('div/div/div').dom;
21194 var pm = this.trigger.child('div/div');
21195 pm.removeClass(this.meterClass);
21196 pm.addClass(this.meterClass[strength]);
21199 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21201 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21203 this._lastPwd = pwd;
21207 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21209 this._lastPwd = '';
21211 var pm = this.trigger.child('div/div');
21212 pm.removeClass(this.meterClass);
21213 pm.addClass('roo-password-meter-grey');
21216 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21219 this.inputEl().dom.type='password';
21222 validateValue: function (value)
21225 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21228 if (value.length == 0) {
21229 if (this.allowBlank) {
21230 this.clearInvalid();
21234 this.markInvalid(this.errors.PwdEmpty);
21235 this.errorMsg = this.errors.PwdEmpty;
21243 if ('[\x21-\x7e]*'.match(value)) {
21244 this.markInvalid(this.errors.PwdBadChar);
21245 this.errorMsg = this.errors.PwdBadChar;
21248 if (value.length < 6) {
21249 this.markInvalid(this.errors.PwdShort);
21250 this.errorMsg = this.errors.PwdShort;
21253 if (value.length > 16) {
21254 this.markInvalid(this.errors.PwdLong);
21255 this.errorMsg = this.errors.PwdLong;
21259 if (this.ClientSideStrongPassword(value)) {
21261 } else if (this.ClientSideMediumPassword(value)) {
21263 } else if (this.ClientSideWeakPassword(value)) {
21270 if (strength < 2) {
21271 //this.markInvalid(this.errors.TooWeak);
21272 this.errorMsg = this.errors.TooWeak;
21277 console.log('strength2: ' + strength);
21279 //var pm = this.trigger.child('div/div/div').dom;
21281 var pm = this.trigger.child('div/div');
21282 pm.removeClass(this.meterClass);
21283 pm.addClass(this.meterClass[strength]);
21285 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21287 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21289 this.errorMsg = '';
21293 CharacterSetChecks: function (type)
21296 this.fResult = false;
21299 isctype: function (character, type)
21302 case this.kCapitalLetter:
21303 if (character >= 'A' && character <= 'Z') {
21308 case this.kSmallLetter:
21309 if (character >= 'a' && character <= 'z') {
21315 if (character >= '0' && character <= '9') {
21320 case this.kPunctuation:
21321 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21332 IsLongEnough: function (pwd, size)
21334 return !(pwd == null || isNaN(size) || pwd.length < size);
21337 SpansEnoughCharacterSets: function (word, nb)
21339 if (!this.IsLongEnough(word, nb))
21344 var characterSetChecks = new Array(
21345 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21346 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21349 for (var index = 0; index < word.length; ++index) {
21350 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21351 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21352 characterSetChecks[nCharSet].fResult = true;
21359 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21360 if (characterSetChecks[nCharSet].fResult) {
21365 if (nCharSets < nb) {
21371 ClientSideStrongPassword: function (pwd)
21373 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21376 ClientSideMediumPassword: function (pwd)
21378 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21381 ClientSideWeakPassword: function (pwd)
21383 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21386 })//<script type="text/javascript">
21389 * Based Ext JS Library 1.1.1
21390 * Copyright(c) 2006-2007, Ext JS, LLC.
21396 * @class Roo.HtmlEditorCore
21397 * @extends Roo.Component
21398 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21400 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21403 Roo.HtmlEditorCore = function(config){
21406 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21411 * @event initialize
21412 * Fires when the editor is fully initialized (including the iframe)
21413 * @param {Roo.HtmlEditorCore} this
21418 * Fires when the editor is first receives the focus. Any insertion must wait
21419 * until after this event.
21420 * @param {Roo.HtmlEditorCore} this
21424 * @event beforesync
21425 * Fires before the textarea is updated with content from the editor iframe. Return false
21426 * to cancel the sync.
21427 * @param {Roo.HtmlEditorCore} this
21428 * @param {String} html
21432 * @event beforepush
21433 * Fires before the iframe editor is updated with content from the textarea. Return false
21434 * to cancel the push.
21435 * @param {Roo.HtmlEditorCore} this
21436 * @param {String} html
21441 * Fires when the textarea is updated with content from the editor iframe.
21442 * @param {Roo.HtmlEditorCore} this
21443 * @param {String} html
21448 * Fires when the iframe editor is updated with content from the textarea.
21449 * @param {Roo.HtmlEditorCore} this
21450 * @param {String} html
21455 * @event editorevent
21456 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21457 * @param {Roo.HtmlEditorCore} this
21463 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21465 // defaults : white / black...
21466 this.applyBlacklists();
21473 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21477 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21483 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21488 * @cfg {Number} height (in pixels)
21492 * @cfg {Number} width (in pixels)
21497 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21500 stylesheets: false,
21505 // private properties
21506 validationEvent : false,
21508 initialized : false,
21510 sourceEditMode : false,
21511 onFocus : Roo.emptyFn,
21513 hideMode:'offsets',
21517 // blacklist + whitelisted elements..
21524 * Protected method that will not generally be called directly. It
21525 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21526 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21528 getDocMarkup : function(){
21532 // inherit styels from page...??
21533 if (this.stylesheets === false) {
21535 Roo.get(document.head).select('style').each(function(node) {
21536 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21539 Roo.get(document.head).select('link').each(function(node) {
21540 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21543 } else if (!this.stylesheets.length) {
21545 st = '<style type="text/css">' +
21546 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21549 st = '<style type="text/css">' +
21554 st += '<style type="text/css">' +
21555 'IMG { cursor: pointer } ' +
21558 var cls = 'roo-htmleditor-body';
21560 if(this.bodyCls.length){
21561 cls += ' ' + this.bodyCls;
21564 return '<html><head>' + st +
21565 //<style type="text/css">' +
21566 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21568 ' </head><body class="' + cls + '"></body></html>';
21572 onRender : function(ct, position)
21575 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21576 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21579 this.el.dom.style.border = '0 none';
21580 this.el.dom.setAttribute('tabIndex', -1);
21581 this.el.addClass('x-hidden hide');
21585 if(Roo.isIE){ // fix IE 1px bogus margin
21586 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21590 this.frameId = Roo.id();
21594 var iframe = this.owner.wrap.createChild({
21596 cls: 'form-control', // bootstrap..
21598 name: this.frameId,
21599 frameBorder : 'no',
21600 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21605 this.iframe = iframe.dom;
21607 this.assignDocWin();
21609 this.doc.designMode = 'on';
21612 this.doc.write(this.getDocMarkup());
21616 var task = { // must defer to wait for browser to be ready
21618 //console.log("run task?" + this.doc.readyState);
21619 this.assignDocWin();
21620 if(this.doc.body || this.doc.readyState == 'complete'){
21622 this.doc.designMode="on";
21626 Roo.TaskMgr.stop(task);
21627 this.initEditor.defer(10, this);
21634 Roo.TaskMgr.start(task);
21639 onResize : function(w, h)
21641 Roo.log('resize: ' +w + ',' + h );
21642 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21646 if(typeof w == 'number'){
21648 this.iframe.style.width = w + 'px';
21650 if(typeof h == 'number'){
21652 this.iframe.style.height = h + 'px';
21654 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21661 * Toggles the editor between standard and source edit mode.
21662 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21664 toggleSourceEdit : function(sourceEditMode){
21666 this.sourceEditMode = sourceEditMode === true;
21668 if(this.sourceEditMode){
21670 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21673 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21674 //this.iframe.className = '';
21677 //this.setSize(this.owner.wrap.getSize());
21678 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21685 * Protected method that will not generally be called directly. If you need/want
21686 * custom HTML cleanup, this is the method you should override.
21687 * @param {String} html The HTML to be cleaned
21688 * return {String} The cleaned HTML
21690 cleanHtml : function(html){
21691 html = String(html);
21692 if(html.length > 5){
21693 if(Roo.isSafari){ // strip safari nonsense
21694 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21697 if(html == ' '){
21704 * HTML Editor -> Textarea
21705 * Protected method that will not generally be called directly. Syncs the contents
21706 * of the editor iframe with the textarea.
21708 syncValue : function(){
21709 if(this.initialized){
21710 var bd = (this.doc.body || this.doc.documentElement);
21711 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21712 var html = bd.innerHTML;
21714 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21715 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21717 html = '<div style="'+m[0]+'">' + html + '</div>';
21720 html = this.cleanHtml(html);
21721 // fix up the special chars.. normaly like back quotes in word...
21722 // however we do not want to do this with chinese..
21723 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21724 var cc = b.charCodeAt();
21726 (cc >= 0x4E00 && cc < 0xA000 ) ||
21727 (cc >= 0x3400 && cc < 0x4E00 ) ||
21728 (cc >= 0xf900 && cc < 0xfb00 )
21734 if(this.owner.fireEvent('beforesync', this, html) !== false){
21735 this.el.dom.value = html;
21736 this.owner.fireEvent('sync', this, html);
21742 * Protected method that will not generally be called directly. Pushes the value of the textarea
21743 * into the iframe editor.
21745 pushValue : function(){
21746 if(this.initialized){
21747 var v = this.el.dom.value.trim();
21749 // if(v.length < 1){
21753 if(this.owner.fireEvent('beforepush', this, v) !== false){
21754 var d = (this.doc.body || this.doc.documentElement);
21756 this.cleanUpPaste();
21757 this.el.dom.value = d.innerHTML;
21758 this.owner.fireEvent('push', this, v);
21764 deferFocus : function(){
21765 this.focus.defer(10, this);
21769 focus : function(){
21770 if(this.win && !this.sourceEditMode){
21777 assignDocWin: function()
21779 var iframe = this.iframe;
21782 this.doc = iframe.contentWindow.document;
21783 this.win = iframe.contentWindow;
21785 // if (!Roo.get(this.frameId)) {
21788 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21789 // this.win = Roo.get(this.frameId).dom.contentWindow;
21791 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21795 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21796 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21801 initEditor : function(){
21802 //console.log("INIT EDITOR");
21803 this.assignDocWin();
21807 this.doc.designMode="on";
21809 this.doc.write(this.getDocMarkup());
21812 var dbody = (this.doc.body || this.doc.documentElement);
21813 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21814 // this copies styles from the containing element into thsi one..
21815 // not sure why we need all of this..
21816 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21818 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21819 //ss['background-attachment'] = 'fixed'; // w3c
21820 dbody.bgProperties = 'fixed'; // ie
21821 //Roo.DomHelper.applyStyles(dbody, ss);
21822 Roo.EventManager.on(this.doc, {
21823 //'mousedown': this.onEditorEvent,
21824 'mouseup': this.onEditorEvent,
21825 'dblclick': this.onEditorEvent,
21826 'click': this.onEditorEvent,
21827 'keyup': this.onEditorEvent,
21832 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21834 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21835 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21837 this.initialized = true;
21839 this.owner.fireEvent('initialize', this);
21844 onDestroy : function(){
21850 //for (var i =0; i < this.toolbars.length;i++) {
21851 // // fixme - ask toolbars for heights?
21852 // this.toolbars[i].onDestroy();
21855 //this.wrap.dom.innerHTML = '';
21856 //this.wrap.remove();
21861 onFirstFocus : function(){
21863 this.assignDocWin();
21866 this.activated = true;
21869 if(Roo.isGecko){ // prevent silly gecko errors
21871 var s = this.win.getSelection();
21872 if(!s.focusNode || s.focusNode.nodeType != 3){
21873 var r = s.getRangeAt(0);
21874 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21879 this.execCmd('useCSS', true);
21880 this.execCmd('styleWithCSS', false);
21883 this.owner.fireEvent('activate', this);
21887 adjustFont: function(btn){
21888 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21889 //if(Roo.isSafari){ // safari
21892 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21893 if(Roo.isSafari){ // safari
21894 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21895 v = (v < 10) ? 10 : v;
21896 v = (v > 48) ? 48 : v;
21897 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21902 v = Math.max(1, v+adjust);
21904 this.execCmd('FontSize', v );
21907 onEditorEvent : function(e)
21909 this.owner.fireEvent('editorevent', this, e);
21910 // this.updateToolbar();
21911 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21914 insertTag : function(tg)
21916 // could be a bit smarter... -> wrap the current selected tRoo..
21917 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21919 range = this.createRange(this.getSelection());
21920 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21921 wrappingNode.appendChild(range.extractContents());
21922 range.insertNode(wrappingNode);
21929 this.execCmd("formatblock", tg);
21933 insertText : function(txt)
21937 var range = this.createRange();
21938 range.deleteContents();
21939 //alert(Sender.getAttribute('label'));
21941 range.insertNode(this.doc.createTextNode(txt));
21947 * Executes a Midas editor command on the editor document and performs necessary focus and
21948 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21949 * @param {String} cmd The Midas command
21950 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21952 relayCmd : function(cmd, value){
21954 this.execCmd(cmd, value);
21955 this.owner.fireEvent('editorevent', this);
21956 //this.updateToolbar();
21957 this.owner.deferFocus();
21961 * Executes a Midas editor command directly on the editor document.
21962 * For visual commands, you should use {@link #relayCmd} instead.
21963 * <b>This should only be called after the editor is initialized.</b>
21964 * @param {String} cmd The Midas command
21965 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21967 execCmd : function(cmd, value){
21968 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21975 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21977 * @param {String} text | dom node..
21979 insertAtCursor : function(text)
21982 if(!this.activated){
21988 var r = this.doc.selection.createRange();
21999 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22003 // from jquery ui (MIT licenced)
22005 var win = this.win;
22007 if (win.getSelection && win.getSelection().getRangeAt) {
22008 range = win.getSelection().getRangeAt(0);
22009 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22010 range.insertNode(node);
22011 } else if (win.document.selection && win.document.selection.createRange) {
22012 // no firefox support
22013 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22014 win.document.selection.createRange().pasteHTML(txt);
22016 // no firefox support
22017 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22018 this.execCmd('InsertHTML', txt);
22027 mozKeyPress : function(e){
22029 var c = e.getCharCode(), cmd;
22032 c = String.fromCharCode(c).toLowerCase();
22046 this.cleanUpPaste.defer(100, this);
22054 e.preventDefault();
22062 fixKeys : function(){ // load time branching for fastest keydown performance
22064 return function(e){
22065 var k = e.getKey(), r;
22068 r = this.doc.selection.createRange();
22071 r.pasteHTML('    ');
22078 r = this.doc.selection.createRange();
22080 var target = r.parentElement();
22081 if(!target || target.tagName.toLowerCase() != 'li'){
22083 r.pasteHTML('<br />');
22089 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22090 this.cleanUpPaste.defer(100, this);
22096 }else if(Roo.isOpera){
22097 return function(e){
22098 var k = e.getKey();
22102 this.execCmd('InsertHTML','    ');
22105 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22106 this.cleanUpPaste.defer(100, this);
22111 }else if(Roo.isSafari){
22112 return function(e){
22113 var k = e.getKey();
22117 this.execCmd('InsertText','\t');
22121 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22122 this.cleanUpPaste.defer(100, this);
22130 getAllAncestors: function()
22132 var p = this.getSelectedNode();
22135 a.push(p); // push blank onto stack..
22136 p = this.getParentElement();
22140 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22144 a.push(this.doc.body);
22148 lastSelNode : false,
22151 getSelection : function()
22153 this.assignDocWin();
22154 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22157 getSelectedNode: function()
22159 // this may only work on Gecko!!!
22161 // should we cache this!!!!
22166 var range = this.createRange(this.getSelection()).cloneRange();
22169 var parent = range.parentElement();
22171 var testRange = range.duplicate();
22172 testRange.moveToElementText(parent);
22173 if (testRange.inRange(range)) {
22176 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22179 parent = parent.parentElement;
22184 // is ancestor a text element.
22185 var ac = range.commonAncestorContainer;
22186 if (ac.nodeType == 3) {
22187 ac = ac.parentNode;
22190 var ar = ac.childNodes;
22193 var other_nodes = [];
22194 var has_other_nodes = false;
22195 for (var i=0;i<ar.length;i++) {
22196 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22199 // fullly contained node.
22201 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22206 // probably selected..
22207 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22208 other_nodes.push(ar[i]);
22212 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22217 has_other_nodes = true;
22219 if (!nodes.length && other_nodes.length) {
22220 nodes= other_nodes;
22222 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22228 createRange: function(sel)
22230 // this has strange effects when using with
22231 // top toolbar - not sure if it's a great idea.
22232 //this.editor.contentWindow.focus();
22233 if (typeof sel != "undefined") {
22235 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22237 return this.doc.createRange();
22240 return this.doc.createRange();
22243 getParentElement: function()
22246 this.assignDocWin();
22247 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22249 var range = this.createRange(sel);
22252 var p = range.commonAncestorContainer;
22253 while (p.nodeType == 3) { // text node
22264 * Range intersection.. the hard stuff...
22268 * [ -- selected range --- ]
22272 * if end is before start or hits it. fail.
22273 * if start is after end or hits it fail.
22275 * if either hits (but other is outside. - then it's not
22281 // @see http://www.thismuchiknow.co.uk/?p=64.
22282 rangeIntersectsNode : function(range, node)
22284 var nodeRange = node.ownerDocument.createRange();
22286 nodeRange.selectNode(node);
22288 nodeRange.selectNodeContents(node);
22291 var rangeStartRange = range.cloneRange();
22292 rangeStartRange.collapse(true);
22294 var rangeEndRange = range.cloneRange();
22295 rangeEndRange.collapse(false);
22297 var nodeStartRange = nodeRange.cloneRange();
22298 nodeStartRange.collapse(true);
22300 var nodeEndRange = nodeRange.cloneRange();
22301 nodeEndRange.collapse(false);
22303 return rangeStartRange.compareBoundaryPoints(
22304 Range.START_TO_START, nodeEndRange) == -1 &&
22305 rangeEndRange.compareBoundaryPoints(
22306 Range.START_TO_START, nodeStartRange) == 1;
22310 rangeCompareNode : function(range, node)
22312 var nodeRange = node.ownerDocument.createRange();
22314 nodeRange.selectNode(node);
22316 nodeRange.selectNodeContents(node);
22320 range.collapse(true);
22322 nodeRange.collapse(true);
22324 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22325 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22327 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22329 var nodeIsBefore = ss == 1;
22330 var nodeIsAfter = ee == -1;
22332 if (nodeIsBefore && nodeIsAfter) {
22335 if (!nodeIsBefore && nodeIsAfter) {
22336 return 1; //right trailed.
22339 if (nodeIsBefore && !nodeIsAfter) {
22340 return 2; // left trailed.
22346 // private? - in a new class?
22347 cleanUpPaste : function()
22349 // cleans up the whole document..
22350 Roo.log('cleanuppaste');
22352 this.cleanUpChildren(this.doc.body);
22353 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22354 if (clean != this.doc.body.innerHTML) {
22355 this.doc.body.innerHTML = clean;
22360 cleanWordChars : function(input) {// change the chars to hex code
22361 var he = Roo.HtmlEditorCore;
22363 var output = input;
22364 Roo.each(he.swapCodes, function(sw) {
22365 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22367 output = output.replace(swapper, sw[1]);
22374 cleanUpChildren : function (n)
22376 if (!n.childNodes.length) {
22379 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22380 this.cleanUpChild(n.childNodes[i]);
22387 cleanUpChild : function (node)
22390 //console.log(node);
22391 if (node.nodeName == "#text") {
22392 // clean up silly Windows -- stuff?
22395 if (node.nodeName == "#comment") {
22396 node.parentNode.removeChild(node);
22397 // clean up silly Windows -- stuff?
22400 var lcname = node.tagName.toLowerCase();
22401 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22402 // whitelist of tags..
22404 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22406 node.parentNode.removeChild(node);
22411 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22413 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22414 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22416 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22417 // remove_keep_children = true;
22420 if (remove_keep_children) {
22421 this.cleanUpChildren(node);
22422 // inserts everything just before this node...
22423 while (node.childNodes.length) {
22424 var cn = node.childNodes[0];
22425 node.removeChild(cn);
22426 node.parentNode.insertBefore(cn, node);
22428 node.parentNode.removeChild(node);
22432 if (!node.attributes || !node.attributes.length) {
22433 this.cleanUpChildren(node);
22437 function cleanAttr(n,v)
22440 if (v.match(/^\./) || v.match(/^\//)) {
22443 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22446 if (v.match(/^#/)) {
22449 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22450 node.removeAttribute(n);
22454 var cwhite = this.cwhite;
22455 var cblack = this.cblack;
22457 function cleanStyle(n,v)
22459 if (v.match(/expression/)) { //XSS?? should we even bother..
22460 node.removeAttribute(n);
22464 var parts = v.split(/;/);
22467 Roo.each(parts, function(p) {
22468 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22472 var l = p.split(':').shift().replace(/\s+/g,'');
22473 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22475 if ( cwhite.length && cblack.indexOf(l) > -1) {
22476 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22477 //node.removeAttribute(n);
22481 // only allow 'c whitelisted system attributes'
22482 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22483 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22484 //node.removeAttribute(n);
22494 if (clean.length) {
22495 node.setAttribute(n, clean.join(';'));
22497 node.removeAttribute(n);
22503 for (var i = node.attributes.length-1; i > -1 ; i--) {
22504 var a = node.attributes[i];
22507 if (a.name.toLowerCase().substr(0,2)=='on') {
22508 node.removeAttribute(a.name);
22511 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22512 node.removeAttribute(a.name);
22515 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22516 cleanAttr(a.name,a.value); // fixme..
22519 if (a.name == 'style') {
22520 cleanStyle(a.name,a.value);
22523 /// clean up MS crap..
22524 // tecnically this should be a list of valid class'es..
22527 if (a.name == 'class') {
22528 if (a.value.match(/^Mso/)) {
22529 node.className = '';
22532 if (a.value.match(/^body$/)) {
22533 node.className = '';
22544 this.cleanUpChildren(node);
22550 * Clean up MS wordisms...
22552 cleanWord : function(node)
22557 this.cleanWord(this.doc.body);
22560 if (node.nodeName == "#text") {
22561 // clean up silly Windows -- stuff?
22564 if (node.nodeName == "#comment") {
22565 node.parentNode.removeChild(node);
22566 // clean up silly Windows -- stuff?
22570 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22571 node.parentNode.removeChild(node);
22575 // remove - but keep children..
22576 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22577 while (node.childNodes.length) {
22578 var cn = node.childNodes[0];
22579 node.removeChild(cn);
22580 node.parentNode.insertBefore(cn, node);
22582 node.parentNode.removeChild(node);
22583 this.iterateChildren(node, this.cleanWord);
22587 if (node.className.length) {
22589 var cn = node.className.split(/\W+/);
22591 Roo.each(cn, function(cls) {
22592 if (cls.match(/Mso[a-zA-Z]+/)) {
22597 node.className = cna.length ? cna.join(' ') : '';
22599 node.removeAttribute("class");
22603 if (node.hasAttribute("lang")) {
22604 node.removeAttribute("lang");
22607 if (node.hasAttribute("style")) {
22609 var styles = node.getAttribute("style").split(";");
22611 Roo.each(styles, function(s) {
22612 if (!s.match(/:/)) {
22615 var kv = s.split(":");
22616 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22619 // what ever is left... we allow.
22622 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22623 if (!nstyle.length) {
22624 node.removeAttribute('style');
22627 this.iterateChildren(node, this.cleanWord);
22633 * iterateChildren of a Node, calling fn each time, using this as the scole..
22634 * @param {DomNode} node node to iterate children of.
22635 * @param {Function} fn method of this class to call on each item.
22637 iterateChildren : function(node, fn)
22639 if (!node.childNodes.length) {
22642 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22643 fn.call(this, node.childNodes[i])
22649 * cleanTableWidths.
22651 * Quite often pasting from word etc.. results in tables with column and widths.
22652 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22655 cleanTableWidths : function(node)
22660 this.cleanTableWidths(this.doc.body);
22665 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22668 Roo.log(node.tagName);
22669 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22670 this.iterateChildren(node, this.cleanTableWidths);
22673 if (node.hasAttribute('width')) {
22674 node.removeAttribute('width');
22678 if (node.hasAttribute("style")) {
22681 var styles = node.getAttribute("style").split(";");
22683 Roo.each(styles, function(s) {
22684 if (!s.match(/:/)) {
22687 var kv = s.split(":");
22688 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22691 // what ever is left... we allow.
22694 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22695 if (!nstyle.length) {
22696 node.removeAttribute('style');
22700 this.iterateChildren(node, this.cleanTableWidths);
22708 domToHTML : function(currentElement, depth, nopadtext) {
22710 depth = depth || 0;
22711 nopadtext = nopadtext || false;
22713 if (!currentElement) {
22714 return this.domToHTML(this.doc.body);
22717 //Roo.log(currentElement);
22719 var allText = false;
22720 var nodeName = currentElement.nodeName;
22721 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22723 if (nodeName == '#text') {
22725 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22730 if (nodeName != 'BODY') {
22733 // Prints the node tagName, such as <A>, <IMG>, etc
22736 for(i = 0; i < currentElement.attributes.length;i++) {
22738 var aname = currentElement.attributes.item(i).name;
22739 if (!currentElement.attributes.item(i).value.length) {
22742 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22745 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22754 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22757 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22762 // Traverse the tree
22764 var currentElementChild = currentElement.childNodes.item(i);
22765 var allText = true;
22766 var innerHTML = '';
22768 while (currentElementChild) {
22769 // Formatting code (indent the tree so it looks nice on the screen)
22770 var nopad = nopadtext;
22771 if (lastnode == 'SPAN') {
22775 if (currentElementChild.nodeName == '#text') {
22776 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22777 toadd = nopadtext ? toadd : toadd.trim();
22778 if (!nopad && toadd.length > 80) {
22779 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22781 innerHTML += toadd;
22784 currentElementChild = currentElement.childNodes.item(i);
22790 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22792 // Recursively traverse the tree structure of the child node
22793 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22794 lastnode = currentElementChild.nodeName;
22796 currentElementChild=currentElement.childNodes.item(i);
22802 // The remaining code is mostly for formatting the tree
22803 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22808 ret+= "</"+tagName+">";
22814 applyBlacklists : function()
22816 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22817 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22821 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22822 if (b.indexOf(tag) > -1) {
22825 this.white.push(tag);
22829 Roo.each(w, function(tag) {
22830 if (b.indexOf(tag) > -1) {
22833 if (this.white.indexOf(tag) > -1) {
22836 this.white.push(tag);
22841 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22842 if (w.indexOf(tag) > -1) {
22845 this.black.push(tag);
22849 Roo.each(b, function(tag) {
22850 if (w.indexOf(tag) > -1) {
22853 if (this.black.indexOf(tag) > -1) {
22856 this.black.push(tag);
22861 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22862 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22866 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22867 if (b.indexOf(tag) > -1) {
22870 this.cwhite.push(tag);
22874 Roo.each(w, function(tag) {
22875 if (b.indexOf(tag) > -1) {
22878 if (this.cwhite.indexOf(tag) > -1) {
22881 this.cwhite.push(tag);
22886 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22887 if (w.indexOf(tag) > -1) {
22890 this.cblack.push(tag);
22894 Roo.each(b, function(tag) {
22895 if (w.indexOf(tag) > -1) {
22898 if (this.cblack.indexOf(tag) > -1) {
22901 this.cblack.push(tag);
22906 setStylesheets : function(stylesheets)
22908 if(typeof(stylesheets) == 'string'){
22909 Roo.get(this.iframe.contentDocument.head).createChild({
22911 rel : 'stylesheet',
22920 Roo.each(stylesheets, function(s) {
22925 Roo.get(_this.iframe.contentDocument.head).createChild({
22927 rel : 'stylesheet',
22936 removeStylesheets : function()
22940 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22945 setStyle : function(style)
22947 Roo.get(this.iframe.contentDocument.head).createChild({
22956 // hide stuff that is not compatible
22970 * @event specialkey
22974 * @cfg {String} fieldClass @hide
22977 * @cfg {String} focusClass @hide
22980 * @cfg {String} autoCreate @hide
22983 * @cfg {String} inputType @hide
22986 * @cfg {String} invalidClass @hide
22989 * @cfg {String} invalidText @hide
22992 * @cfg {String} msgFx @hide
22995 * @cfg {String} validateOnBlur @hide
22999 Roo.HtmlEditorCore.white = [
23000 'area', 'br', 'img', 'input', 'hr', 'wbr',
23002 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23003 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23004 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23005 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23006 'table', 'ul', 'xmp',
23008 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23011 'dir', 'menu', 'ol', 'ul', 'dl',
23017 Roo.HtmlEditorCore.black = [
23018 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23020 'base', 'basefont', 'bgsound', 'blink', 'body',
23021 'frame', 'frameset', 'head', 'html', 'ilayer',
23022 'iframe', 'layer', 'link', 'meta', 'object',
23023 'script', 'style' ,'title', 'xml' // clean later..
23025 Roo.HtmlEditorCore.clean = [
23026 'script', 'style', 'title', 'xml'
23028 Roo.HtmlEditorCore.remove = [
23033 Roo.HtmlEditorCore.ablack = [
23037 Roo.HtmlEditorCore.aclean = [
23038 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23042 Roo.HtmlEditorCore.pwhite= [
23043 'http', 'https', 'mailto'
23046 // white listed style attributes.
23047 Roo.HtmlEditorCore.cwhite= [
23048 // 'text-align', /// default is to allow most things..
23054 // black listed style attributes.
23055 Roo.HtmlEditorCore.cblack= [
23056 // 'font-size' -- this can be set by the project
23060 Roo.HtmlEditorCore.swapCodes =[
23079 * @class Roo.bootstrap.HtmlEditor
23080 * @extends Roo.bootstrap.TextArea
23081 * Bootstrap HtmlEditor class
23084 * Create a new HtmlEditor
23085 * @param {Object} config The config object
23088 Roo.bootstrap.HtmlEditor = function(config){
23089 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23090 if (!this.toolbars) {
23091 this.toolbars = [];
23094 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23097 * @event initialize
23098 * Fires when the editor is fully initialized (including the iframe)
23099 * @param {HtmlEditor} this
23104 * Fires when the editor is first receives the focus. Any insertion must wait
23105 * until after this event.
23106 * @param {HtmlEditor} this
23110 * @event beforesync
23111 * Fires before the textarea is updated with content from the editor iframe. Return false
23112 * to cancel the sync.
23113 * @param {HtmlEditor} this
23114 * @param {String} html
23118 * @event beforepush
23119 * Fires before the iframe editor is updated with content from the textarea. Return false
23120 * to cancel the push.
23121 * @param {HtmlEditor} this
23122 * @param {String} html
23127 * Fires when the textarea is updated with content from the editor iframe.
23128 * @param {HtmlEditor} this
23129 * @param {String} html
23134 * Fires when the iframe editor is updated with content from the textarea.
23135 * @param {HtmlEditor} this
23136 * @param {String} html
23140 * @event editmodechange
23141 * Fires when the editor switches edit modes
23142 * @param {HtmlEditor} this
23143 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23145 editmodechange: true,
23147 * @event editorevent
23148 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23149 * @param {HtmlEditor} this
23153 * @event firstfocus
23154 * Fires when on first focus - needed by toolbars..
23155 * @param {HtmlEditor} this
23160 * Auto save the htmlEditor value as a file into Events
23161 * @param {HtmlEditor} this
23165 * @event savedpreview
23166 * preview the saved version of htmlEditor
23167 * @param {HtmlEditor} this
23174 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23178 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23183 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23188 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23193 * @cfg {Number} height (in pixels)
23197 * @cfg {Number} width (in pixels)
23202 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23205 stylesheets: false,
23210 // private properties
23211 validationEvent : false,
23213 initialized : false,
23216 onFocus : Roo.emptyFn,
23218 hideMode:'offsets',
23220 tbContainer : false,
23224 toolbarContainer :function() {
23225 return this.wrap.select('.x-html-editor-tb',true).first();
23229 * Protected method that will not generally be called directly. It
23230 * is called when the editor creates its toolbar. Override this method if you need to
23231 * add custom toolbar buttons.
23232 * @param {HtmlEditor} editor
23234 createToolbar : function(){
23235 Roo.log('renewing');
23236 Roo.log("create toolbars");
23238 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23239 this.toolbars[0].render(this.toolbarContainer());
23243 // if (!editor.toolbars || !editor.toolbars.length) {
23244 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23247 // for (var i =0 ; i < editor.toolbars.length;i++) {
23248 // editor.toolbars[i] = Roo.factory(
23249 // typeof(editor.toolbars[i]) == 'string' ?
23250 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23251 // Roo.bootstrap.HtmlEditor);
23252 // editor.toolbars[i].init(editor);
23258 onRender : function(ct, position)
23260 // Roo.log("Call onRender: " + this.xtype);
23262 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23264 this.wrap = this.inputEl().wrap({
23265 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23268 this.editorcore.onRender(ct, position);
23270 if (this.resizable) {
23271 this.resizeEl = new Roo.Resizable(this.wrap, {
23275 minHeight : this.height,
23276 height: this.height,
23277 handles : this.resizable,
23280 resize : function(r, w, h) {
23281 _t.onResize(w,h); // -something
23287 this.createToolbar(this);
23290 if(!this.width && this.resizable){
23291 this.setSize(this.wrap.getSize());
23293 if (this.resizeEl) {
23294 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23295 // should trigger onReize..
23301 onResize : function(w, h)
23303 Roo.log('resize: ' +w + ',' + h );
23304 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23308 if(this.inputEl() ){
23309 if(typeof w == 'number'){
23310 var aw = w - this.wrap.getFrameWidth('lr');
23311 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23314 if(typeof h == 'number'){
23315 var tbh = -11; // fixme it needs to tool bar size!
23316 for (var i =0; i < this.toolbars.length;i++) {
23317 // fixme - ask toolbars for heights?
23318 tbh += this.toolbars[i].el.getHeight();
23319 //if (this.toolbars[i].footer) {
23320 // tbh += this.toolbars[i].footer.el.getHeight();
23328 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23329 ah -= 5; // knock a few pixes off for look..
23330 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23334 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23335 this.editorcore.onResize(ew,eh);
23340 * Toggles the editor between standard and source edit mode.
23341 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23343 toggleSourceEdit : function(sourceEditMode)
23345 this.editorcore.toggleSourceEdit(sourceEditMode);
23347 if(this.editorcore.sourceEditMode){
23348 Roo.log('editor - showing textarea');
23351 // Roo.log(this.syncValue());
23353 this.inputEl().removeClass(['hide', 'x-hidden']);
23354 this.inputEl().dom.removeAttribute('tabIndex');
23355 this.inputEl().focus();
23357 Roo.log('editor - hiding textarea');
23359 // Roo.log(this.pushValue());
23362 this.inputEl().addClass(['hide', 'x-hidden']);
23363 this.inputEl().dom.setAttribute('tabIndex', -1);
23364 //this.deferFocus();
23367 if(this.resizable){
23368 this.setSize(this.wrap.getSize());
23371 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23374 // private (for BoxComponent)
23375 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23377 // private (for BoxComponent)
23378 getResizeEl : function(){
23382 // private (for BoxComponent)
23383 getPositionEl : function(){
23388 initEvents : function(){
23389 this.originalValue = this.getValue();
23393 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23396 // markInvalid : Roo.emptyFn,
23398 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23401 // clearInvalid : Roo.emptyFn,
23403 setValue : function(v){
23404 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23405 this.editorcore.pushValue();
23410 deferFocus : function(){
23411 this.focus.defer(10, this);
23415 focus : function(){
23416 this.editorcore.focus();
23422 onDestroy : function(){
23428 for (var i =0; i < this.toolbars.length;i++) {
23429 // fixme - ask toolbars for heights?
23430 this.toolbars[i].onDestroy();
23433 this.wrap.dom.innerHTML = '';
23434 this.wrap.remove();
23439 onFirstFocus : function(){
23440 //Roo.log("onFirstFocus");
23441 this.editorcore.onFirstFocus();
23442 for (var i =0; i < this.toolbars.length;i++) {
23443 this.toolbars[i].onFirstFocus();
23449 syncValue : function()
23451 this.editorcore.syncValue();
23454 pushValue : function()
23456 this.editorcore.pushValue();
23460 // hide stuff that is not compatible
23474 * @event specialkey
23478 * @cfg {String} fieldClass @hide
23481 * @cfg {String} focusClass @hide
23484 * @cfg {String} autoCreate @hide
23487 * @cfg {String} inputType @hide
23490 * @cfg {String} invalidClass @hide
23493 * @cfg {String} invalidText @hide
23496 * @cfg {String} msgFx @hide
23499 * @cfg {String} validateOnBlur @hide
23508 Roo.namespace('Roo.bootstrap.htmleditor');
23510 * @class Roo.bootstrap.HtmlEditorToolbar1
23515 new Roo.bootstrap.HtmlEditor({
23518 new Roo.bootstrap.HtmlEditorToolbar1({
23519 disable : { fonts: 1 , format: 1, ..., ... , ...],
23525 * @cfg {Object} disable List of elements to disable..
23526 * @cfg {Array} btns List of additional buttons.
23530 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23533 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23536 Roo.apply(this, config);
23538 // default disabled, based on 'good practice'..
23539 this.disable = this.disable || {};
23540 Roo.applyIf(this.disable, {
23543 specialElements : true
23545 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23547 this.editor = config.editor;
23548 this.editorcore = config.editor.editorcore;
23550 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23552 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23553 // dont call parent... till later.
23555 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23560 editorcore : false,
23565 "h1","h2","h3","h4","h5","h6",
23567 "abbr", "acronym", "address", "cite", "samp", "var",
23571 onRender : function(ct, position)
23573 // Roo.log("Call onRender: " + this.xtype);
23575 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23577 this.el.dom.style.marginBottom = '0';
23579 var editorcore = this.editorcore;
23580 var editor= this.editor;
23583 var btn = function(id,cmd , toggle, handler, html){
23585 var event = toggle ? 'toggle' : 'click';
23590 xns: Roo.bootstrap,
23593 enableToggle:toggle !== false,
23595 pressed : toggle ? false : null,
23598 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23599 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23605 // var cb_box = function...
23610 xns: Roo.bootstrap,
23611 glyphicon : 'font',
23615 xns: Roo.bootstrap,
23619 Roo.each(this.formats, function(f) {
23620 style.menu.items.push({
23622 xns: Roo.bootstrap,
23623 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23628 editorcore.insertTag(this.tagname);
23635 children.push(style);
23637 btn('bold',false,true);
23638 btn('italic',false,true);
23639 btn('align-left', 'justifyleft',true);
23640 btn('align-center', 'justifycenter',true);
23641 btn('align-right' , 'justifyright',true);
23642 btn('link', false, false, function(btn) {
23643 //Roo.log("create link?");
23644 var url = prompt(this.createLinkText, this.defaultLinkValue);
23645 if(url && url != 'http:/'+'/'){
23646 this.editorcore.relayCmd('createlink', url);
23649 btn('list','insertunorderedlist',true);
23650 btn('pencil', false,true, function(btn){
23652 this.toggleSourceEdit(btn.pressed);
23655 if (this.editor.btns.length > 0) {
23656 for (var i = 0; i<this.editor.btns.length; i++) {
23657 children.push(this.editor.btns[i]);
23665 xns: Roo.bootstrap,
23670 xns: Roo.bootstrap,
23675 cog.menu.items.push({
23677 xns: Roo.bootstrap,
23678 html : Clean styles,
23683 editorcore.insertTag(this.tagname);
23692 this.xtype = 'NavSimplebar';
23694 for(var i=0;i< children.length;i++) {
23696 this.buttons.add(this.addxtypeChild(children[i]));
23700 editor.on('editorevent', this.updateToolbar, this);
23702 onBtnClick : function(id)
23704 this.editorcore.relayCmd(id);
23705 this.editorcore.focus();
23709 * Protected method that will not generally be called directly. It triggers
23710 * a toolbar update by reading the markup state of the current selection in the editor.
23712 updateToolbar: function(){
23714 if(!this.editorcore.activated){
23715 this.editor.onFirstFocus(); // is this neeed?
23719 var btns = this.buttons;
23720 var doc = this.editorcore.doc;
23721 btns.get('bold').setActive(doc.queryCommandState('bold'));
23722 btns.get('italic').setActive(doc.queryCommandState('italic'));
23723 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23725 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23726 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23727 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23729 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23730 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23733 var ans = this.editorcore.getAllAncestors();
23734 if (this.formatCombo) {
23737 var store = this.formatCombo.store;
23738 this.formatCombo.setValue("");
23739 for (var i =0; i < ans.length;i++) {
23740 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23742 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23750 // hides menus... - so this cant be on a menu...
23751 Roo.bootstrap.MenuMgr.hideAll();
23753 Roo.bootstrap.MenuMgr.hideAll();
23754 //this.editorsyncValue();
23756 onFirstFocus: function() {
23757 this.buttons.each(function(item){
23761 toggleSourceEdit : function(sourceEditMode){
23764 if(sourceEditMode){
23765 Roo.log("disabling buttons");
23766 this.buttons.each( function(item){
23767 if(item.cmd != 'pencil'){
23773 Roo.log("enabling buttons");
23774 if(this.editorcore.initialized){
23775 this.buttons.each( function(item){
23781 Roo.log("calling toggole on editor");
23782 // tell the editor that it's been pressed..
23783 this.editor.toggleSourceEdit(sourceEditMode);
23793 * @class Roo.bootstrap.Table.AbstractSelectionModel
23794 * @extends Roo.util.Observable
23795 * Abstract base class for grid SelectionModels. It provides the interface that should be
23796 * implemented by descendant classes. This class should not be directly instantiated.
23799 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23800 this.locked = false;
23801 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23805 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23806 /** @ignore Called by the grid automatically. Do not call directly. */
23807 init : function(grid){
23813 * Locks the selections.
23816 this.locked = true;
23820 * Unlocks the selections.
23822 unlock : function(){
23823 this.locked = false;
23827 * Returns true if the selections are locked.
23828 * @return {Boolean}
23830 isLocked : function(){
23831 return this.locked;
23835 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23836 * @class Roo.bootstrap.Table.RowSelectionModel
23837 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23838 * It supports multiple selections and keyboard selection/navigation.
23840 * @param {Object} config
23843 Roo.bootstrap.Table.RowSelectionModel = function(config){
23844 Roo.apply(this, config);
23845 this.selections = new Roo.util.MixedCollection(false, function(o){
23850 this.lastActive = false;
23854 * @event selectionchange
23855 * Fires when the selection changes
23856 * @param {SelectionModel} this
23858 "selectionchange" : true,
23860 * @event afterselectionchange
23861 * Fires after the selection changes (eg. by key press or clicking)
23862 * @param {SelectionModel} this
23864 "afterselectionchange" : true,
23866 * @event beforerowselect
23867 * Fires when a row is selected being selected, return false to cancel.
23868 * @param {SelectionModel} this
23869 * @param {Number} rowIndex The selected index
23870 * @param {Boolean} keepExisting False if other selections will be cleared
23872 "beforerowselect" : true,
23875 * Fires when a row is selected.
23876 * @param {SelectionModel} this
23877 * @param {Number} rowIndex The selected index
23878 * @param {Roo.data.Record} r The record
23880 "rowselect" : true,
23882 * @event rowdeselect
23883 * Fires when a row is deselected.
23884 * @param {SelectionModel} this
23885 * @param {Number} rowIndex The selected index
23887 "rowdeselect" : true
23889 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23890 this.locked = false;
23893 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23895 * @cfg {Boolean} singleSelect
23896 * True to allow selection of only one row at a time (defaults to false)
23898 singleSelect : false,
23901 initEvents : function()
23904 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23905 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23906 //}else{ // allow click to work like normal
23907 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23909 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23910 this.grid.on("rowclick", this.handleMouseDown, this);
23912 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23913 "up" : function(e){
23915 this.selectPrevious(e.shiftKey);
23916 }else if(this.last !== false && this.lastActive !== false){
23917 var last = this.last;
23918 this.selectRange(this.last, this.lastActive-1);
23919 this.grid.getView().focusRow(this.lastActive);
23920 if(last !== false){
23924 this.selectFirstRow();
23926 this.fireEvent("afterselectionchange", this);
23928 "down" : function(e){
23930 this.selectNext(e.shiftKey);
23931 }else if(this.last !== false && this.lastActive !== false){
23932 var last = this.last;
23933 this.selectRange(this.last, this.lastActive+1);
23934 this.grid.getView().focusRow(this.lastActive);
23935 if(last !== false){
23939 this.selectFirstRow();
23941 this.fireEvent("afterselectionchange", this);
23945 this.grid.store.on('load', function(){
23946 this.selections.clear();
23949 var view = this.grid.view;
23950 view.on("refresh", this.onRefresh, this);
23951 view.on("rowupdated", this.onRowUpdated, this);
23952 view.on("rowremoved", this.onRemove, this);
23957 onRefresh : function()
23959 var ds = this.grid.store, i, v = this.grid.view;
23960 var s = this.selections;
23961 s.each(function(r){
23962 if((i = ds.indexOfId(r.id)) != -1){
23971 onRemove : function(v, index, r){
23972 this.selections.remove(r);
23976 onRowUpdated : function(v, index, r){
23977 if(this.isSelected(r)){
23978 v.onRowSelect(index);
23984 * @param {Array} records The records to select
23985 * @param {Boolean} keepExisting (optional) True to keep existing selections
23987 selectRecords : function(records, keepExisting)
23990 this.clearSelections();
23992 var ds = this.grid.store;
23993 for(var i = 0, len = records.length; i < len; i++){
23994 this.selectRow(ds.indexOf(records[i]), true);
23999 * Gets the number of selected rows.
24002 getCount : function(){
24003 return this.selections.length;
24007 * Selects the first row in the grid.
24009 selectFirstRow : function(){
24014 * Select the last row.
24015 * @param {Boolean} keepExisting (optional) True to keep existing selections
24017 selectLastRow : function(keepExisting){
24018 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24019 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24023 * Selects the row immediately following the last selected row.
24024 * @param {Boolean} keepExisting (optional) True to keep existing selections
24026 selectNext : function(keepExisting)
24028 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24029 this.selectRow(this.last+1, keepExisting);
24030 this.grid.getView().focusRow(this.last);
24035 * Selects the row that precedes the last selected row.
24036 * @param {Boolean} keepExisting (optional) True to keep existing selections
24038 selectPrevious : function(keepExisting){
24040 this.selectRow(this.last-1, keepExisting);
24041 this.grid.getView().focusRow(this.last);
24046 * Returns the selected records
24047 * @return {Array} Array of selected records
24049 getSelections : function(){
24050 return [].concat(this.selections.items);
24054 * Returns the first selected record.
24057 getSelected : function(){
24058 return this.selections.itemAt(0);
24063 * Clears all selections.
24065 clearSelections : function(fast)
24071 var ds = this.grid.store;
24072 var s = this.selections;
24073 s.each(function(r){
24074 this.deselectRow(ds.indexOfId(r.id));
24078 this.selections.clear();
24085 * Selects all rows.
24087 selectAll : function(){
24091 this.selections.clear();
24092 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24093 this.selectRow(i, true);
24098 * Returns True if there is a selection.
24099 * @return {Boolean}
24101 hasSelection : function(){
24102 return this.selections.length > 0;
24106 * Returns True if the specified row is selected.
24107 * @param {Number/Record} record The record or index of the record to check
24108 * @return {Boolean}
24110 isSelected : function(index){
24111 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24112 return (r && this.selections.key(r.id) ? true : false);
24116 * Returns True if the specified record id is selected.
24117 * @param {String} id The id of record to check
24118 * @return {Boolean}
24120 isIdSelected : function(id){
24121 return (this.selections.key(id) ? true : false);
24126 handleMouseDBClick : function(e, t){
24130 handleMouseDown : function(e, t)
24132 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24133 if(this.isLocked() || rowIndex < 0 ){
24136 if(e.shiftKey && this.last !== false){
24137 var last = this.last;
24138 this.selectRange(last, rowIndex, e.ctrlKey);
24139 this.last = last; // reset the last
24143 var isSelected = this.isSelected(rowIndex);
24144 //Roo.log("select row:" + rowIndex);
24146 this.deselectRow(rowIndex);
24148 this.selectRow(rowIndex, true);
24152 if(e.button !== 0 && isSelected){
24153 alert('rowIndex 2: ' + rowIndex);
24154 view.focusRow(rowIndex);
24155 }else if(e.ctrlKey && isSelected){
24156 this.deselectRow(rowIndex);
24157 }else if(!isSelected){
24158 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24159 view.focusRow(rowIndex);
24163 this.fireEvent("afterselectionchange", this);
24166 handleDragableRowClick : function(grid, rowIndex, e)
24168 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24169 this.selectRow(rowIndex, false);
24170 grid.view.focusRow(rowIndex);
24171 this.fireEvent("afterselectionchange", this);
24176 * Selects multiple rows.
24177 * @param {Array} rows Array of the indexes of the row to select
24178 * @param {Boolean} keepExisting (optional) True to keep existing selections
24180 selectRows : function(rows, keepExisting){
24182 this.clearSelections();
24184 for(var i = 0, len = rows.length; i < len; i++){
24185 this.selectRow(rows[i], true);
24190 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24191 * @param {Number} startRow The index of the first row in the range
24192 * @param {Number} endRow The index of the last row in the range
24193 * @param {Boolean} keepExisting (optional) True to retain existing selections
24195 selectRange : function(startRow, endRow, keepExisting){
24200 this.clearSelections();
24202 if(startRow <= endRow){
24203 for(var i = startRow; i <= endRow; i++){
24204 this.selectRow(i, true);
24207 for(var i = startRow; i >= endRow; i--){
24208 this.selectRow(i, true);
24214 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24215 * @param {Number} startRow The index of the first row in the range
24216 * @param {Number} endRow The index of the last row in the range
24218 deselectRange : function(startRow, endRow, preventViewNotify){
24222 for(var i = startRow; i <= endRow; i++){
24223 this.deselectRow(i, preventViewNotify);
24229 * @param {Number} row The index of the row to select
24230 * @param {Boolean} keepExisting (optional) True to keep existing selections
24232 selectRow : function(index, keepExisting, preventViewNotify)
24234 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24237 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24238 if(!keepExisting || this.singleSelect){
24239 this.clearSelections();
24242 var r = this.grid.store.getAt(index);
24243 //console.log('selectRow - record id :' + r.id);
24245 this.selections.add(r);
24246 this.last = this.lastActive = index;
24247 if(!preventViewNotify){
24248 var proxy = new Roo.Element(
24249 this.grid.getRowDom(index)
24251 proxy.addClass('bg-info info');
24253 this.fireEvent("rowselect", this, index, r);
24254 this.fireEvent("selectionchange", this);
24260 * @param {Number} row The index of the row to deselect
24262 deselectRow : function(index, preventViewNotify)
24267 if(this.last == index){
24270 if(this.lastActive == index){
24271 this.lastActive = false;
24274 var r = this.grid.store.getAt(index);
24279 this.selections.remove(r);
24280 //.console.log('deselectRow - record id :' + r.id);
24281 if(!preventViewNotify){
24283 var proxy = new Roo.Element(
24284 this.grid.getRowDom(index)
24286 proxy.removeClass('bg-info info');
24288 this.fireEvent("rowdeselect", this, index);
24289 this.fireEvent("selectionchange", this);
24293 restoreLast : function(){
24295 this.last = this._last;
24300 acceptsNav : function(row, col, cm){
24301 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24305 onEditorKey : function(field, e){
24306 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24311 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24313 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24315 }else if(k == e.ENTER && !e.ctrlKey){
24319 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24321 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24323 }else if(k == e.ESC){
24327 g.startEditing(newCell[0], newCell[1]);
24333 * Ext JS Library 1.1.1
24334 * Copyright(c) 2006-2007, Ext JS, LLC.
24336 * Originally Released Under LGPL - original licence link has changed is not relivant.
24339 * <script type="text/javascript">
24343 * @class Roo.bootstrap.PagingToolbar
24344 * @extends Roo.bootstrap.NavSimplebar
24345 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24347 * Create a new PagingToolbar
24348 * @param {Object} config The config object
24349 * @param {Roo.data.Store} store
24351 Roo.bootstrap.PagingToolbar = function(config)
24353 // old args format still supported... - xtype is prefered..
24354 // created from xtype...
24356 this.ds = config.dataSource;
24358 if (config.store && !this.ds) {
24359 this.store= Roo.factory(config.store, Roo.data);
24360 this.ds = this.store;
24361 this.ds.xmodule = this.xmodule || false;
24364 this.toolbarItems = [];
24365 if (config.items) {
24366 this.toolbarItems = config.items;
24369 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24374 this.bind(this.ds);
24377 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24381 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24383 * @cfg {Roo.data.Store} dataSource
24384 * The underlying data store providing the paged data
24387 * @cfg {String/HTMLElement/Element} container
24388 * container The id or element that will contain the toolbar
24391 * @cfg {Boolean} displayInfo
24392 * True to display the displayMsg (defaults to false)
24395 * @cfg {Number} pageSize
24396 * The number of records to display per page (defaults to 20)
24400 * @cfg {String} displayMsg
24401 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24403 displayMsg : 'Displaying {0} - {1} of {2}',
24405 * @cfg {String} emptyMsg
24406 * The message to display when no records are found (defaults to "No data to display")
24408 emptyMsg : 'No data to display',
24410 * Customizable piece of the default paging text (defaults to "Page")
24413 beforePageText : "Page",
24415 * Customizable piece of the default paging text (defaults to "of %0")
24418 afterPageText : "of {0}",
24420 * Customizable piece of the default paging text (defaults to "First Page")
24423 firstText : "First Page",
24425 * Customizable piece of the default paging text (defaults to "Previous Page")
24428 prevText : "Previous Page",
24430 * Customizable piece of the default paging text (defaults to "Next Page")
24433 nextText : "Next Page",
24435 * Customizable piece of the default paging text (defaults to "Last Page")
24438 lastText : "Last Page",
24440 * Customizable piece of the default paging text (defaults to "Refresh")
24443 refreshText : "Refresh",
24447 onRender : function(ct, position)
24449 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24450 this.navgroup.parentId = this.id;
24451 this.navgroup.onRender(this.el, null);
24452 // add the buttons to the navgroup
24454 if(this.displayInfo){
24455 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24456 this.displayEl = this.el.select('.x-paging-info', true).first();
24457 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24458 // this.displayEl = navel.el.select('span',true).first();
24464 Roo.each(_this.buttons, function(e){ // this might need to use render????
24465 Roo.factory(e).onRender(_this.el, null);
24469 Roo.each(_this.toolbarItems, function(e) {
24470 _this.navgroup.addItem(e);
24474 this.first = this.navgroup.addItem({
24475 tooltip: this.firstText,
24477 icon : 'fa fa-backward',
24479 preventDefault: true,
24480 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24483 this.prev = this.navgroup.addItem({
24484 tooltip: this.prevText,
24486 icon : 'fa fa-step-backward',
24488 preventDefault: true,
24489 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24491 //this.addSeparator();
24494 var field = this.navgroup.addItem( {
24496 cls : 'x-paging-position',
24498 html : this.beforePageText +
24499 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24500 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24503 this.field = field.el.select('input', true).first();
24504 this.field.on("keydown", this.onPagingKeydown, this);
24505 this.field.on("focus", function(){this.dom.select();});
24508 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24509 //this.field.setHeight(18);
24510 //this.addSeparator();
24511 this.next = this.navgroup.addItem({
24512 tooltip: this.nextText,
24514 html : ' <i class="fa fa-step-forward">',
24516 preventDefault: true,
24517 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24519 this.last = this.navgroup.addItem({
24520 tooltip: this.lastText,
24521 icon : 'fa fa-forward',
24524 preventDefault: true,
24525 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24527 //this.addSeparator();
24528 this.loading = this.navgroup.addItem({
24529 tooltip: this.refreshText,
24530 icon: 'fa fa-refresh',
24531 preventDefault: true,
24532 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24538 updateInfo : function(){
24539 if(this.displayEl){
24540 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24541 var msg = count == 0 ?
24545 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24547 this.displayEl.update(msg);
24552 onLoad : function(ds, r, o)
24554 this.cursor = o.params.start ? o.params.start : 0;
24556 var d = this.getPageData(),
24561 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24562 this.field.dom.value = ap;
24563 this.first.setDisabled(ap == 1);
24564 this.prev.setDisabled(ap == 1);
24565 this.next.setDisabled(ap == ps);
24566 this.last.setDisabled(ap == ps);
24567 this.loading.enable();
24572 getPageData : function(){
24573 var total = this.ds.getTotalCount();
24576 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24577 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24582 onLoadError : function(){
24583 this.loading.enable();
24587 onPagingKeydown : function(e){
24588 var k = e.getKey();
24589 var d = this.getPageData();
24591 var v = this.field.dom.value, pageNum;
24592 if(!v || isNaN(pageNum = parseInt(v, 10))){
24593 this.field.dom.value = d.activePage;
24596 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24597 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24600 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))
24602 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24603 this.field.dom.value = pageNum;
24604 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24607 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24609 var v = this.field.dom.value, pageNum;
24610 var increment = (e.shiftKey) ? 10 : 1;
24611 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24614 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24615 this.field.dom.value = d.activePage;
24618 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24620 this.field.dom.value = parseInt(v, 10) + increment;
24621 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24622 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24629 beforeLoad : function(){
24631 this.loading.disable();
24636 onClick : function(which){
24645 ds.load({params:{start: 0, limit: this.pageSize}});
24648 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24651 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24654 var total = ds.getTotalCount();
24655 var extra = total % this.pageSize;
24656 var lastStart = extra ? (total - extra) : total-this.pageSize;
24657 ds.load({params:{start: lastStart, limit: this.pageSize}});
24660 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24666 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24667 * @param {Roo.data.Store} store The data store to unbind
24669 unbind : function(ds){
24670 ds.un("beforeload", this.beforeLoad, this);
24671 ds.un("load", this.onLoad, this);
24672 ds.un("loadexception", this.onLoadError, this);
24673 ds.un("remove", this.updateInfo, this);
24674 ds.un("add", this.updateInfo, this);
24675 this.ds = undefined;
24679 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24680 * @param {Roo.data.Store} store The data store to bind
24682 bind : function(ds){
24683 ds.on("beforeload", this.beforeLoad, this);
24684 ds.on("load", this.onLoad, this);
24685 ds.on("loadexception", this.onLoadError, this);
24686 ds.on("remove", this.updateInfo, this);
24687 ds.on("add", this.updateInfo, this);
24698 * @class Roo.bootstrap.MessageBar
24699 * @extends Roo.bootstrap.Component
24700 * Bootstrap MessageBar class
24701 * @cfg {String} html contents of the MessageBar
24702 * @cfg {String} weight (info | success | warning | danger) default info
24703 * @cfg {String} beforeClass insert the bar before the given class
24704 * @cfg {Boolean} closable (true | false) default false
24705 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24708 * Create a new Element
24709 * @param {Object} config The config object
24712 Roo.bootstrap.MessageBar = function(config){
24713 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24716 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24722 beforeClass: 'bootstrap-sticky-wrap',
24724 getAutoCreate : function(){
24728 cls: 'alert alert-dismissable alert-' + this.weight,
24733 html: this.html || ''
24739 cfg.cls += ' alert-messages-fixed';
24753 onRender : function(ct, position)
24755 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24758 var cfg = Roo.apply({}, this.getAutoCreate());
24762 cfg.cls += ' ' + this.cls;
24765 cfg.style = this.style;
24767 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24769 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24772 this.el.select('>button.close').on('click', this.hide, this);
24778 if (!this.rendered) {
24784 this.fireEvent('show', this);
24790 if (!this.rendered) {
24796 this.fireEvent('hide', this);
24799 update : function()
24801 // var e = this.el.dom.firstChild;
24803 // if(this.closable){
24804 // e = e.nextSibling;
24807 // e.data = this.html || '';
24809 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24825 * @class Roo.bootstrap.Graph
24826 * @extends Roo.bootstrap.Component
24827 * Bootstrap Graph class
24831 @cfg {String} graphtype bar | vbar | pie
24832 @cfg {number} g_x coodinator | centre x (pie)
24833 @cfg {number} g_y coodinator | centre y (pie)
24834 @cfg {number} g_r radius (pie)
24835 @cfg {number} g_height height of the chart (respected by all elements in the set)
24836 @cfg {number} g_width width of the chart (respected by all elements in the set)
24837 @cfg {Object} title The title of the chart
24840 -opts (object) options for the chart
24842 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24843 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24845 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.
24846 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24848 o stretch (boolean)
24850 -opts (object) options for the pie
24853 o startAngle (number)
24854 o endAngle (number)
24858 * Create a new Input
24859 * @param {Object} config The config object
24862 Roo.bootstrap.Graph = function(config){
24863 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24869 * The img click event for the img.
24870 * @param {Roo.EventObject} e
24876 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24887 //g_colors: this.colors,
24894 getAutoCreate : function(){
24905 onRender : function(ct,position){
24908 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24910 if (typeof(Raphael) == 'undefined') {
24911 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24915 this.raphael = Raphael(this.el.dom);
24917 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24918 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24919 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24920 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24922 r.text(160, 10, "Single Series Chart").attr(txtattr);
24923 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24924 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24925 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24927 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24928 r.barchart(330, 10, 300, 220, data1);
24929 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24930 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24933 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24934 // r.barchart(30, 30, 560, 250, xdata, {
24935 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24936 // axis : "0 0 1 1",
24937 // axisxlabels : xdata
24938 // //yvalues : cols,
24941 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24943 // this.load(null,xdata,{
24944 // axis : "0 0 1 1",
24945 // axisxlabels : xdata
24950 load : function(graphtype,xdata,opts)
24952 this.raphael.clear();
24954 graphtype = this.graphtype;
24959 var r = this.raphael,
24960 fin = function () {
24961 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24963 fout = function () {
24964 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24966 pfin = function() {
24967 this.sector.stop();
24968 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24971 this.label[0].stop();
24972 this.label[0].attr({ r: 7.5 });
24973 this.label[1].attr({ "font-weight": 800 });
24976 pfout = function() {
24977 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24980 this.label[0].animate({ r: 5 }, 500, "bounce");
24981 this.label[1].attr({ "font-weight": 400 });
24987 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24990 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24993 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24994 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24996 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25003 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25008 setTitle: function(o)
25013 initEvents: function() {
25016 this.el.on('click', this.onClick, this);
25020 onClick : function(e)
25022 Roo.log('img onclick');
25023 this.fireEvent('click', this, e);
25035 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25038 * @class Roo.bootstrap.dash.NumberBox
25039 * @extends Roo.bootstrap.Component
25040 * Bootstrap NumberBox class
25041 * @cfg {String} headline Box headline
25042 * @cfg {String} content Box content
25043 * @cfg {String} icon Box icon
25044 * @cfg {String} footer Footer text
25045 * @cfg {String} fhref Footer href
25048 * Create a new NumberBox
25049 * @param {Object} config The config object
25053 Roo.bootstrap.dash.NumberBox = function(config){
25054 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25058 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25067 getAutoCreate : function(){
25071 cls : 'small-box ',
25079 cls : 'roo-headline',
25080 html : this.headline
25084 cls : 'roo-content',
25085 html : this.content
25099 cls : 'ion ' + this.icon
25108 cls : 'small-box-footer',
25109 href : this.fhref || '#',
25113 cfg.cn.push(footer);
25120 onRender : function(ct,position){
25121 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25128 setHeadline: function (value)
25130 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25133 setFooter: function (value, href)
25135 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25138 this.el.select('a.small-box-footer',true).first().attr('href', href);
25143 setContent: function (value)
25145 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25148 initEvents: function()
25162 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25165 * @class Roo.bootstrap.dash.TabBox
25166 * @extends Roo.bootstrap.Component
25167 * Bootstrap TabBox class
25168 * @cfg {String} title Title of the TabBox
25169 * @cfg {String} icon Icon of the TabBox
25170 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25171 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25174 * Create a new TabBox
25175 * @param {Object} config The config object
25179 Roo.bootstrap.dash.TabBox = function(config){
25180 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25185 * When a pane is added
25186 * @param {Roo.bootstrap.dash.TabPane} pane
25190 * @event activatepane
25191 * When a pane is activated
25192 * @param {Roo.bootstrap.dash.TabPane} pane
25194 "activatepane" : true
25202 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25207 tabScrollable : false,
25209 getChildContainer : function()
25211 return this.el.select('.tab-content', true).first();
25214 getAutoCreate : function(){
25218 cls: 'pull-left header',
25226 cls: 'fa ' + this.icon
25232 cls: 'nav nav-tabs pull-right',
25238 if(this.tabScrollable){
25245 cls: 'nav nav-tabs pull-right',
25256 cls: 'nav-tabs-custom',
25261 cls: 'tab-content no-padding',
25269 initEvents : function()
25271 //Roo.log('add add pane handler');
25272 this.on('addpane', this.onAddPane, this);
25275 * Updates the box title
25276 * @param {String} html to set the title to.
25278 setTitle : function(value)
25280 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25282 onAddPane : function(pane)
25284 this.panes.push(pane);
25285 //Roo.log('addpane');
25287 // tabs are rendere left to right..
25288 if(!this.showtabs){
25292 var ctr = this.el.select('.nav-tabs', true).first();
25295 var existing = ctr.select('.nav-tab',true);
25296 var qty = existing.getCount();;
25299 var tab = ctr.createChild({
25301 cls : 'nav-tab' + (qty ? '' : ' active'),
25309 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25312 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25314 pane.el.addClass('active');
25319 onTabClick : function(ev,un,ob,pane)
25321 //Roo.log('tab - prev default');
25322 ev.preventDefault();
25325 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25326 pane.tab.addClass('active');
25327 //Roo.log(pane.title);
25328 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25329 // technically we should have a deactivate event.. but maybe add later.
25330 // and it should not de-activate the selected tab...
25331 this.fireEvent('activatepane', pane);
25332 pane.el.addClass('active');
25333 pane.fireEvent('activate');
25338 getActivePane : function()
25341 Roo.each(this.panes, function(p) {
25342 if(p.el.hasClass('active')){
25363 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25365 * @class Roo.bootstrap.TabPane
25366 * @extends Roo.bootstrap.Component
25367 * Bootstrap TabPane class
25368 * @cfg {Boolean} active (false | true) Default false
25369 * @cfg {String} title title of panel
25373 * Create a new TabPane
25374 * @param {Object} config The config object
25377 Roo.bootstrap.dash.TabPane = function(config){
25378 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25384 * When a pane is activated
25385 * @param {Roo.bootstrap.dash.TabPane} pane
25392 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25397 // the tabBox that this is attached to.
25400 getAutoCreate : function()
25408 cfg.cls += ' active';
25413 initEvents : function()
25415 //Roo.log('trigger add pane handler');
25416 this.parent().fireEvent('addpane', this)
25420 * Updates the tab title
25421 * @param {String} html to set the title to.
25423 setTitle: function(str)
25429 this.tab.select('a', true).first().dom.innerHTML = str;
25446 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25449 * @class Roo.bootstrap.menu.Menu
25450 * @extends Roo.bootstrap.Component
25451 * Bootstrap Menu class - container for Menu
25452 * @cfg {String} html Text of the menu
25453 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25454 * @cfg {String} icon Font awesome icon
25455 * @cfg {String} pos Menu align to (top | bottom) default bottom
25459 * Create a new Menu
25460 * @param {Object} config The config object
25464 Roo.bootstrap.menu.Menu = function(config){
25465 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25469 * @event beforeshow
25470 * Fires before this menu is displayed
25471 * @param {Roo.bootstrap.menu.Menu} this
25475 * @event beforehide
25476 * Fires before this menu is hidden
25477 * @param {Roo.bootstrap.menu.Menu} this
25482 * Fires after this menu is displayed
25483 * @param {Roo.bootstrap.menu.Menu} this
25488 * Fires after this menu is hidden
25489 * @param {Roo.bootstrap.menu.Menu} this
25494 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25495 * @param {Roo.bootstrap.menu.Menu} this
25496 * @param {Roo.EventObject} e
25503 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25507 weight : 'default',
25512 getChildContainer : function() {
25513 if(this.isSubMenu){
25517 return this.el.select('ul.dropdown-menu', true).first();
25520 getAutoCreate : function()
25525 cls : 'roo-menu-text',
25533 cls : 'fa ' + this.icon
25544 cls : 'dropdown-button btn btn-' + this.weight,
25549 cls : 'dropdown-toggle btn btn-' + this.weight,
25559 cls : 'dropdown-menu'
25565 if(this.pos == 'top'){
25566 cfg.cls += ' dropup';
25569 if(this.isSubMenu){
25572 cls : 'dropdown-menu'
25579 onRender : function(ct, position)
25581 this.isSubMenu = ct.hasClass('dropdown-submenu');
25583 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25586 initEvents : function()
25588 if(this.isSubMenu){
25592 this.hidden = true;
25594 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25595 this.triggerEl.on('click', this.onTriggerPress, this);
25597 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25598 this.buttonEl.on('click', this.onClick, this);
25604 if(this.isSubMenu){
25608 return this.el.select('ul.dropdown-menu', true).first();
25611 onClick : function(e)
25613 this.fireEvent("click", this, e);
25616 onTriggerPress : function(e)
25618 if (this.isVisible()) {
25625 isVisible : function(){
25626 return !this.hidden;
25631 this.fireEvent("beforeshow", this);
25633 this.hidden = false;
25634 this.el.addClass('open');
25636 Roo.get(document).on("mouseup", this.onMouseUp, this);
25638 this.fireEvent("show", this);
25645 this.fireEvent("beforehide", this);
25647 this.hidden = true;
25648 this.el.removeClass('open');
25650 Roo.get(document).un("mouseup", this.onMouseUp);
25652 this.fireEvent("hide", this);
25655 onMouseUp : function()
25669 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25672 * @class Roo.bootstrap.menu.Item
25673 * @extends Roo.bootstrap.Component
25674 * Bootstrap MenuItem class
25675 * @cfg {Boolean} submenu (true | false) default false
25676 * @cfg {String} html text of the item
25677 * @cfg {String} href the link
25678 * @cfg {Boolean} disable (true | false) default false
25679 * @cfg {Boolean} preventDefault (true | false) default true
25680 * @cfg {String} icon Font awesome icon
25681 * @cfg {String} pos Submenu align to (left | right) default right
25685 * Create a new Item
25686 * @param {Object} config The config object
25690 Roo.bootstrap.menu.Item = function(config){
25691 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25695 * Fires when the mouse is hovering over this menu
25696 * @param {Roo.bootstrap.menu.Item} this
25697 * @param {Roo.EventObject} e
25702 * Fires when the mouse exits this menu
25703 * @param {Roo.bootstrap.menu.Item} this
25704 * @param {Roo.EventObject} e
25710 * The raw click event for the entire grid.
25711 * @param {Roo.EventObject} e
25717 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25722 preventDefault: true,
25727 getAutoCreate : function()
25732 cls : 'roo-menu-item-text',
25740 cls : 'fa ' + this.icon
25749 href : this.href || '#',
25756 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25760 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25762 if(this.pos == 'left'){
25763 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25770 initEvents : function()
25772 this.el.on('mouseover', this.onMouseOver, this);
25773 this.el.on('mouseout', this.onMouseOut, this);
25775 this.el.select('a', true).first().on('click', this.onClick, this);
25779 onClick : function(e)
25781 if(this.preventDefault){
25782 e.preventDefault();
25785 this.fireEvent("click", this, e);
25788 onMouseOver : function(e)
25790 if(this.submenu && this.pos == 'left'){
25791 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25794 this.fireEvent("mouseover", this, e);
25797 onMouseOut : function(e)
25799 this.fireEvent("mouseout", this, e);
25811 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25814 * @class Roo.bootstrap.menu.Separator
25815 * @extends Roo.bootstrap.Component
25816 * Bootstrap Separator class
25819 * Create a new Separator
25820 * @param {Object} config The config object
25824 Roo.bootstrap.menu.Separator = function(config){
25825 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25828 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25830 getAutoCreate : function(){
25851 * @class Roo.bootstrap.Tooltip
25852 * Bootstrap Tooltip class
25853 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25854 * to determine which dom element triggers the tooltip.
25856 * It needs to add support for additional attributes like tooltip-position
25859 * Create a new Toolti
25860 * @param {Object} config The config object
25863 Roo.bootstrap.Tooltip = function(config){
25864 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25866 this.alignment = Roo.bootstrap.Tooltip.alignment;
25868 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25869 this.alignment = config.alignment;
25874 Roo.apply(Roo.bootstrap.Tooltip, {
25876 * @function init initialize tooltip monitoring.
25880 currentTip : false,
25881 currentRegion : false,
25887 Roo.get(document).on('mouseover', this.enter ,this);
25888 Roo.get(document).on('mouseout', this.leave, this);
25891 this.currentTip = new Roo.bootstrap.Tooltip();
25894 enter : function(ev)
25896 var dom = ev.getTarget();
25898 //Roo.log(['enter',dom]);
25899 var el = Roo.fly(dom);
25900 if (this.currentEl) {
25902 //Roo.log(this.currentEl);
25903 //Roo.log(this.currentEl.contains(dom));
25904 if (this.currentEl == el) {
25907 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25913 if (this.currentTip.el) {
25914 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25918 if(!el || el.dom == document){
25924 // you can not look for children, as if el is the body.. then everythign is the child..
25925 if (!el.attr('tooltip')) { //
25926 if (!el.select("[tooltip]").elements.length) {
25929 // is the mouse over this child...?
25930 bindEl = el.select("[tooltip]").first();
25931 var xy = ev.getXY();
25932 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25933 //Roo.log("not in region.");
25936 //Roo.log("child element over..");
25939 this.currentEl = bindEl;
25940 this.currentTip.bind(bindEl);
25941 this.currentRegion = Roo.lib.Region.getRegion(dom);
25942 this.currentTip.enter();
25945 leave : function(ev)
25947 var dom = ev.getTarget();
25948 //Roo.log(['leave',dom]);
25949 if (!this.currentEl) {
25954 if (dom != this.currentEl.dom) {
25957 var xy = ev.getXY();
25958 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25961 // only activate leave if mouse cursor is outside... bounding box..
25966 if (this.currentTip) {
25967 this.currentTip.leave();
25969 //Roo.log('clear currentEl');
25970 this.currentEl = false;
25975 'left' : ['r-l', [-2,0], 'right'],
25976 'right' : ['l-r', [2,0], 'left'],
25977 'bottom' : ['t-b', [0,2], 'top'],
25978 'top' : [ 'b-t', [0,-2], 'bottom']
25984 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25989 delay : null, // can be { show : 300 , hide: 500}
25993 hoverState : null, //???
25995 placement : 'bottom',
25999 getAutoCreate : function(){
26006 cls : 'tooltip-arrow'
26009 cls : 'tooltip-inner'
26016 bind : function(el)
26022 enter : function () {
26024 if (this.timeout != null) {
26025 clearTimeout(this.timeout);
26028 this.hoverState = 'in';
26029 //Roo.log("enter - show");
26030 if (!this.delay || !this.delay.show) {
26035 this.timeout = setTimeout(function () {
26036 if (_t.hoverState == 'in') {
26039 }, this.delay.show);
26043 clearTimeout(this.timeout);
26045 this.hoverState = 'out';
26046 if (!this.delay || !this.delay.hide) {
26052 this.timeout = setTimeout(function () {
26053 //Roo.log("leave - timeout");
26055 if (_t.hoverState == 'out') {
26057 Roo.bootstrap.Tooltip.currentEl = false;
26062 show : function (msg)
26065 this.render(document.body);
26068 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26070 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26072 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26074 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26076 var placement = typeof this.placement == 'function' ?
26077 this.placement.call(this, this.el, on_el) :
26080 var autoToken = /\s?auto?\s?/i;
26081 var autoPlace = autoToken.test(placement);
26083 placement = placement.replace(autoToken, '') || 'top';
26087 //this.el.setXY([0,0]);
26089 //this.el.dom.style.display='block';
26091 //this.el.appendTo(on_el);
26093 var p = this.getPosition();
26094 var box = this.el.getBox();
26100 var align = this.alignment[placement];
26102 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26104 if(placement == 'top' || placement == 'bottom'){
26106 placement = 'right';
26109 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26110 placement = 'left';
26113 var scroll = Roo.select('body', true).first().getScroll();
26115 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26121 this.el.alignTo(this.bindEl, align[0],align[1]);
26122 //var arrow = this.el.select('.arrow',true).first();
26123 //arrow.set(align[2],
26125 this.el.addClass(placement);
26127 this.el.addClass('in fade');
26129 this.hoverState = null;
26131 if (this.el.hasClass('fade')) {
26142 //this.el.setXY([0,0]);
26143 this.el.removeClass('in');
26159 * @class Roo.bootstrap.LocationPicker
26160 * @extends Roo.bootstrap.Component
26161 * Bootstrap LocationPicker class
26162 * @cfg {Number} latitude Position when init default 0
26163 * @cfg {Number} longitude Position when init default 0
26164 * @cfg {Number} zoom default 15
26165 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26166 * @cfg {Boolean} mapTypeControl default false
26167 * @cfg {Boolean} disableDoubleClickZoom default false
26168 * @cfg {Boolean} scrollwheel default true
26169 * @cfg {Boolean} streetViewControl default false
26170 * @cfg {Number} radius default 0
26171 * @cfg {String} locationName
26172 * @cfg {Boolean} draggable default true
26173 * @cfg {Boolean} enableAutocomplete default false
26174 * @cfg {Boolean} enableReverseGeocode default true
26175 * @cfg {String} markerTitle
26178 * Create a new LocationPicker
26179 * @param {Object} config The config object
26183 Roo.bootstrap.LocationPicker = function(config){
26185 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26190 * Fires when the picker initialized.
26191 * @param {Roo.bootstrap.LocationPicker} this
26192 * @param {Google Location} location
26196 * @event positionchanged
26197 * Fires when the picker position changed.
26198 * @param {Roo.bootstrap.LocationPicker} this
26199 * @param {Google Location} location
26201 positionchanged : true,
26204 * Fires when the map resize.
26205 * @param {Roo.bootstrap.LocationPicker} this
26210 * Fires when the map show.
26211 * @param {Roo.bootstrap.LocationPicker} this
26216 * Fires when the map hide.
26217 * @param {Roo.bootstrap.LocationPicker} this
26222 * Fires when click the map.
26223 * @param {Roo.bootstrap.LocationPicker} this
26224 * @param {Map event} e
26228 * @event mapRightClick
26229 * Fires when right click the map.
26230 * @param {Roo.bootstrap.LocationPicker} this
26231 * @param {Map event} e
26233 mapRightClick : true,
26235 * @event markerClick
26236 * Fires when click the marker.
26237 * @param {Roo.bootstrap.LocationPicker} this
26238 * @param {Map event} e
26240 markerClick : true,
26242 * @event markerRightClick
26243 * Fires when right click the marker.
26244 * @param {Roo.bootstrap.LocationPicker} this
26245 * @param {Map event} e
26247 markerRightClick : true,
26249 * @event OverlayViewDraw
26250 * Fires when OverlayView Draw
26251 * @param {Roo.bootstrap.LocationPicker} this
26253 OverlayViewDraw : true,
26255 * @event OverlayViewOnAdd
26256 * Fires when OverlayView Draw
26257 * @param {Roo.bootstrap.LocationPicker} this
26259 OverlayViewOnAdd : true,
26261 * @event OverlayViewOnRemove
26262 * Fires when OverlayView Draw
26263 * @param {Roo.bootstrap.LocationPicker} this
26265 OverlayViewOnRemove : true,
26267 * @event OverlayViewShow
26268 * Fires when OverlayView Draw
26269 * @param {Roo.bootstrap.LocationPicker} this
26270 * @param {Pixel} cpx
26272 OverlayViewShow : true,
26274 * @event OverlayViewHide
26275 * Fires when OverlayView Draw
26276 * @param {Roo.bootstrap.LocationPicker} this
26278 OverlayViewHide : true,
26280 * @event loadexception
26281 * Fires when load google lib failed.
26282 * @param {Roo.bootstrap.LocationPicker} this
26284 loadexception : true
26289 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26291 gMapContext: false,
26297 mapTypeControl: false,
26298 disableDoubleClickZoom: false,
26300 streetViewControl: false,
26304 enableAutocomplete: false,
26305 enableReverseGeocode: true,
26308 getAutoCreate: function()
26313 cls: 'roo-location-picker'
26319 initEvents: function(ct, position)
26321 if(!this.el.getWidth() || this.isApplied()){
26325 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26330 initial: function()
26332 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26333 this.fireEvent('loadexception', this);
26337 if(!this.mapTypeId){
26338 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26341 this.gMapContext = this.GMapContext();
26343 this.initOverlayView();
26345 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26349 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26350 _this.setPosition(_this.gMapContext.marker.position);
26353 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26354 _this.fireEvent('mapClick', this, event);
26358 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26359 _this.fireEvent('mapRightClick', this, event);
26363 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26364 _this.fireEvent('markerClick', this, event);
26368 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26369 _this.fireEvent('markerRightClick', this, event);
26373 this.setPosition(this.gMapContext.location);
26375 this.fireEvent('initial', this, this.gMapContext.location);
26378 initOverlayView: function()
26382 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26386 _this.fireEvent('OverlayViewDraw', _this);
26391 _this.fireEvent('OverlayViewOnAdd', _this);
26394 onRemove: function()
26396 _this.fireEvent('OverlayViewOnRemove', _this);
26399 show: function(cpx)
26401 _this.fireEvent('OverlayViewShow', _this, cpx);
26406 _this.fireEvent('OverlayViewHide', _this);
26412 fromLatLngToContainerPixel: function(event)
26414 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26417 isApplied: function()
26419 return this.getGmapContext() == false ? false : true;
26422 getGmapContext: function()
26424 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26427 GMapContext: function()
26429 var position = new google.maps.LatLng(this.latitude, this.longitude);
26431 var _map = new google.maps.Map(this.el.dom, {
26434 mapTypeId: this.mapTypeId,
26435 mapTypeControl: this.mapTypeControl,
26436 disableDoubleClickZoom: this.disableDoubleClickZoom,
26437 scrollwheel: this.scrollwheel,
26438 streetViewControl: this.streetViewControl,
26439 locationName: this.locationName,
26440 draggable: this.draggable,
26441 enableAutocomplete: this.enableAutocomplete,
26442 enableReverseGeocode: this.enableReverseGeocode
26445 var _marker = new google.maps.Marker({
26446 position: position,
26448 title: this.markerTitle,
26449 draggable: this.draggable
26456 location: position,
26457 radius: this.radius,
26458 locationName: this.locationName,
26459 addressComponents: {
26460 formatted_address: null,
26461 addressLine1: null,
26462 addressLine2: null,
26464 streetNumber: null,
26468 stateOrProvince: null
26471 domContainer: this.el.dom,
26472 geodecoder: new google.maps.Geocoder()
26476 drawCircle: function(center, radius, options)
26478 if (this.gMapContext.circle != null) {
26479 this.gMapContext.circle.setMap(null);
26483 options = Roo.apply({}, options, {
26484 strokeColor: "#0000FF",
26485 strokeOpacity: .35,
26487 fillColor: "#0000FF",
26491 options.map = this.gMapContext.map;
26492 options.radius = radius;
26493 options.center = center;
26494 this.gMapContext.circle = new google.maps.Circle(options);
26495 return this.gMapContext.circle;
26501 setPosition: function(location)
26503 this.gMapContext.location = location;
26504 this.gMapContext.marker.setPosition(location);
26505 this.gMapContext.map.panTo(location);
26506 this.drawCircle(location, this.gMapContext.radius, {});
26510 if (this.gMapContext.settings.enableReverseGeocode) {
26511 this.gMapContext.geodecoder.geocode({
26512 latLng: this.gMapContext.location
26513 }, function(results, status) {
26515 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26516 _this.gMapContext.locationName = results[0].formatted_address;
26517 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26519 _this.fireEvent('positionchanged', this, location);
26526 this.fireEvent('positionchanged', this, location);
26531 google.maps.event.trigger(this.gMapContext.map, "resize");
26533 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26535 this.fireEvent('resize', this);
26538 setPositionByLatLng: function(latitude, longitude)
26540 this.setPosition(new google.maps.LatLng(latitude, longitude));
26543 getCurrentPosition: function()
26546 latitude: this.gMapContext.location.lat(),
26547 longitude: this.gMapContext.location.lng()
26551 getAddressName: function()
26553 return this.gMapContext.locationName;
26556 getAddressComponents: function()
26558 return this.gMapContext.addressComponents;
26561 address_component_from_google_geocode: function(address_components)
26565 for (var i = 0; i < address_components.length; i++) {
26566 var component = address_components[i];
26567 if (component.types.indexOf("postal_code") >= 0) {
26568 result.postalCode = component.short_name;
26569 } else if (component.types.indexOf("street_number") >= 0) {
26570 result.streetNumber = component.short_name;
26571 } else if (component.types.indexOf("route") >= 0) {
26572 result.streetName = component.short_name;
26573 } else if (component.types.indexOf("neighborhood") >= 0) {
26574 result.city = component.short_name;
26575 } else if (component.types.indexOf("locality") >= 0) {
26576 result.city = component.short_name;
26577 } else if (component.types.indexOf("sublocality") >= 0) {
26578 result.district = component.short_name;
26579 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26580 result.stateOrProvince = component.short_name;
26581 } else if (component.types.indexOf("country") >= 0) {
26582 result.country = component.short_name;
26586 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26587 result.addressLine2 = "";
26591 setZoomLevel: function(zoom)
26593 this.gMapContext.map.setZoom(zoom);
26606 this.fireEvent('show', this);
26617 this.fireEvent('hide', this);
26622 Roo.apply(Roo.bootstrap.LocationPicker, {
26624 OverlayView : function(map, options)
26626 options = options || {};
26640 * @class Roo.bootstrap.Alert
26641 * @extends Roo.bootstrap.Component
26642 * Bootstrap Alert class
26643 * @cfg {String} title The title of alert
26644 * @cfg {String} html The content of alert
26645 * @cfg {String} weight ( success | info | warning | danger )
26646 * @cfg {String} faicon font-awesomeicon
26649 * Create a new alert
26650 * @param {Object} config The config object
26654 Roo.bootstrap.Alert = function(config){
26655 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26659 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26666 getAutoCreate : function()
26675 cls : 'roo-alert-icon'
26680 cls : 'roo-alert-title',
26685 cls : 'roo-alert-text',
26692 cfg.cn[0].cls += ' fa ' + this.faicon;
26696 cfg.cls += ' alert-' + this.weight;
26702 initEvents: function()
26704 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26707 setTitle : function(str)
26709 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26712 setText : function(str)
26714 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26717 setWeight : function(weight)
26720 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26723 this.weight = weight;
26725 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26728 setIcon : function(icon)
26731 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26734 this.faicon = icon;
26736 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26757 * @class Roo.bootstrap.UploadCropbox
26758 * @extends Roo.bootstrap.Component
26759 * Bootstrap UploadCropbox class
26760 * @cfg {String} emptyText show when image has been loaded
26761 * @cfg {String} rotateNotify show when image too small to rotate
26762 * @cfg {Number} errorTimeout default 3000
26763 * @cfg {Number} minWidth default 300
26764 * @cfg {Number} minHeight default 300
26765 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26766 * @cfg {Boolean} isDocument (true|false) default false
26767 * @cfg {String} url action url
26768 * @cfg {String} paramName default 'imageUpload'
26769 * @cfg {String} method default POST
26770 * @cfg {Boolean} loadMask (true|false) default true
26771 * @cfg {Boolean} loadingText default 'Loading...'
26774 * Create a new UploadCropbox
26775 * @param {Object} config The config object
26778 Roo.bootstrap.UploadCropbox = function(config){
26779 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26783 * @event beforeselectfile
26784 * Fire before select file
26785 * @param {Roo.bootstrap.UploadCropbox} this
26787 "beforeselectfile" : true,
26790 * Fire after initEvent
26791 * @param {Roo.bootstrap.UploadCropbox} this
26796 * Fire after initEvent
26797 * @param {Roo.bootstrap.UploadCropbox} this
26798 * @param {String} data
26803 * Fire when preparing the file data
26804 * @param {Roo.bootstrap.UploadCropbox} this
26805 * @param {Object} file
26810 * Fire when get exception
26811 * @param {Roo.bootstrap.UploadCropbox} this
26812 * @param {XMLHttpRequest} xhr
26814 "exception" : true,
26816 * @event beforeloadcanvas
26817 * Fire before load the canvas
26818 * @param {Roo.bootstrap.UploadCropbox} this
26819 * @param {String} src
26821 "beforeloadcanvas" : true,
26824 * Fire when trash image
26825 * @param {Roo.bootstrap.UploadCropbox} this
26830 * Fire when download the image
26831 * @param {Roo.bootstrap.UploadCropbox} this
26835 * @event footerbuttonclick
26836 * Fire when footerbuttonclick
26837 * @param {Roo.bootstrap.UploadCropbox} this
26838 * @param {String} type
26840 "footerbuttonclick" : true,
26844 * @param {Roo.bootstrap.UploadCropbox} this
26849 * Fire when rotate the image
26850 * @param {Roo.bootstrap.UploadCropbox} this
26851 * @param {String} pos
26856 * Fire when inspect the file
26857 * @param {Roo.bootstrap.UploadCropbox} this
26858 * @param {Object} file
26863 * Fire when xhr upload the file
26864 * @param {Roo.bootstrap.UploadCropbox} this
26865 * @param {Object} data
26870 * Fire when arrange the file data
26871 * @param {Roo.bootstrap.UploadCropbox} this
26872 * @param {Object} formData
26877 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26880 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26882 emptyText : 'Click to upload image',
26883 rotateNotify : 'Image is too small to rotate',
26884 errorTimeout : 3000,
26898 cropType : 'image/jpeg',
26900 canvasLoaded : false,
26901 isDocument : false,
26903 paramName : 'imageUpload',
26905 loadingText : 'Loading...',
26908 getAutoCreate : function()
26912 cls : 'roo-upload-cropbox',
26916 cls : 'roo-upload-cropbox-selector',
26921 cls : 'roo-upload-cropbox-body',
26922 style : 'cursor:pointer',
26926 cls : 'roo-upload-cropbox-preview'
26930 cls : 'roo-upload-cropbox-thumb'
26934 cls : 'roo-upload-cropbox-empty-notify',
26935 html : this.emptyText
26939 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26940 html : this.rotateNotify
26946 cls : 'roo-upload-cropbox-footer',
26949 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26959 onRender : function(ct, position)
26961 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26963 if (this.buttons.length) {
26965 Roo.each(this.buttons, function(bb) {
26967 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26969 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26975 this.maskEl = this.el;
26979 initEvents : function()
26981 this.urlAPI = (window.createObjectURL && window) ||
26982 (window.URL && URL.revokeObjectURL && URL) ||
26983 (window.webkitURL && webkitURL);
26985 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26986 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26988 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26989 this.selectorEl.hide();
26991 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26992 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26994 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26995 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26996 this.thumbEl.hide();
26998 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26999 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27001 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27002 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27003 this.errorEl.hide();
27005 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27006 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27007 this.footerEl.hide();
27009 this.setThumbBoxSize();
27015 this.fireEvent('initial', this);
27022 window.addEventListener("resize", function() { _this.resize(); } );
27024 this.bodyEl.on('click', this.beforeSelectFile, this);
27027 this.bodyEl.on('touchstart', this.onTouchStart, this);
27028 this.bodyEl.on('touchmove', this.onTouchMove, this);
27029 this.bodyEl.on('touchend', this.onTouchEnd, this);
27033 this.bodyEl.on('mousedown', this.onMouseDown, this);
27034 this.bodyEl.on('mousemove', this.onMouseMove, this);
27035 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27036 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27037 Roo.get(document).on('mouseup', this.onMouseUp, this);
27040 this.selectorEl.on('change', this.onFileSelected, this);
27046 this.baseScale = 1;
27048 this.baseRotate = 1;
27049 this.dragable = false;
27050 this.pinching = false;
27053 this.cropData = false;
27054 this.notifyEl.dom.innerHTML = this.emptyText;
27056 this.selectorEl.dom.value = '';
27060 resize : function()
27062 if(this.fireEvent('resize', this) != false){
27063 this.setThumbBoxPosition();
27064 this.setCanvasPosition();
27068 onFooterButtonClick : function(e, el, o, type)
27071 case 'rotate-left' :
27072 this.onRotateLeft(e);
27074 case 'rotate-right' :
27075 this.onRotateRight(e);
27078 this.beforeSelectFile(e);
27093 this.fireEvent('footerbuttonclick', this, type);
27096 beforeSelectFile : function(e)
27098 e.preventDefault();
27100 if(this.fireEvent('beforeselectfile', this) != false){
27101 this.selectorEl.dom.click();
27105 onFileSelected : function(e)
27107 e.preventDefault();
27109 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27113 var file = this.selectorEl.dom.files[0];
27115 if(this.fireEvent('inspect', this, file) != false){
27116 this.prepare(file);
27121 trash : function(e)
27123 this.fireEvent('trash', this);
27126 download : function(e)
27128 this.fireEvent('download', this);
27131 loadCanvas : function(src)
27133 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27137 this.imageEl = document.createElement('img');
27141 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27143 this.imageEl.src = src;
27147 onLoadCanvas : function()
27149 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27150 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27152 this.bodyEl.un('click', this.beforeSelectFile, this);
27154 this.notifyEl.hide();
27155 this.thumbEl.show();
27156 this.footerEl.show();
27158 this.baseRotateLevel();
27160 if(this.isDocument){
27161 this.setThumbBoxSize();
27164 this.setThumbBoxPosition();
27166 this.baseScaleLevel();
27172 this.canvasLoaded = true;
27175 this.maskEl.unmask();
27180 setCanvasPosition : function()
27182 if(!this.canvasEl){
27186 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27187 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27189 this.previewEl.setLeft(pw);
27190 this.previewEl.setTop(ph);
27194 onMouseDown : function(e)
27198 this.dragable = true;
27199 this.pinching = false;
27201 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27202 this.dragable = false;
27206 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27207 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27211 onMouseMove : function(e)
27215 if(!this.canvasLoaded){
27219 if (!this.dragable){
27223 var minX = Math.ceil(this.thumbEl.getLeft(true));
27224 var minY = Math.ceil(this.thumbEl.getTop(true));
27226 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27227 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27229 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27230 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27232 x = x - this.mouseX;
27233 y = y - this.mouseY;
27235 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27236 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27238 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27239 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27241 this.previewEl.setLeft(bgX);
27242 this.previewEl.setTop(bgY);
27244 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27245 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27248 onMouseUp : function(e)
27252 this.dragable = false;
27255 onMouseWheel : function(e)
27259 this.startScale = this.scale;
27261 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27263 if(!this.zoomable()){
27264 this.scale = this.startScale;
27273 zoomable : function()
27275 var minScale = this.thumbEl.getWidth() / this.minWidth;
27277 if(this.minWidth < this.minHeight){
27278 minScale = this.thumbEl.getHeight() / this.minHeight;
27281 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27282 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27286 (this.rotate == 0 || this.rotate == 180) &&
27288 width > this.imageEl.OriginWidth ||
27289 height > this.imageEl.OriginHeight ||
27290 (width < this.minWidth && height < this.minHeight)
27298 (this.rotate == 90 || this.rotate == 270) &&
27300 width > this.imageEl.OriginWidth ||
27301 height > this.imageEl.OriginHeight ||
27302 (width < this.minHeight && height < this.minWidth)
27309 !this.isDocument &&
27310 (this.rotate == 0 || this.rotate == 180) &&
27312 width < this.minWidth ||
27313 width > this.imageEl.OriginWidth ||
27314 height < this.minHeight ||
27315 height > this.imageEl.OriginHeight
27322 !this.isDocument &&
27323 (this.rotate == 90 || this.rotate == 270) &&
27325 width < this.minHeight ||
27326 width > this.imageEl.OriginWidth ||
27327 height < this.minWidth ||
27328 height > this.imageEl.OriginHeight
27338 onRotateLeft : function(e)
27340 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27342 var minScale = this.thumbEl.getWidth() / this.minWidth;
27344 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27345 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27347 this.startScale = this.scale;
27349 while (this.getScaleLevel() < minScale){
27351 this.scale = this.scale + 1;
27353 if(!this.zoomable()){
27358 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27359 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27364 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27371 this.scale = this.startScale;
27373 this.onRotateFail();
27378 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27380 if(this.isDocument){
27381 this.setThumbBoxSize();
27382 this.setThumbBoxPosition();
27383 this.setCanvasPosition();
27388 this.fireEvent('rotate', this, 'left');
27392 onRotateRight : function(e)
27394 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27396 var minScale = this.thumbEl.getWidth() / this.minWidth;
27398 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27399 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27401 this.startScale = this.scale;
27403 while (this.getScaleLevel() < minScale){
27405 this.scale = this.scale + 1;
27407 if(!this.zoomable()){
27412 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27413 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27418 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27425 this.scale = this.startScale;
27427 this.onRotateFail();
27432 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27434 if(this.isDocument){
27435 this.setThumbBoxSize();
27436 this.setThumbBoxPosition();
27437 this.setCanvasPosition();
27442 this.fireEvent('rotate', this, 'right');
27445 onRotateFail : function()
27447 this.errorEl.show(true);
27451 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27456 this.previewEl.dom.innerHTML = '';
27458 var canvasEl = document.createElement("canvas");
27460 var contextEl = canvasEl.getContext("2d");
27462 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27463 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27464 var center = this.imageEl.OriginWidth / 2;
27466 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27467 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27468 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27469 center = this.imageEl.OriginHeight / 2;
27472 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27474 contextEl.translate(center, center);
27475 contextEl.rotate(this.rotate * Math.PI / 180);
27477 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27479 this.canvasEl = document.createElement("canvas");
27481 this.contextEl = this.canvasEl.getContext("2d");
27483 switch (this.rotate) {
27486 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27487 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27489 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27494 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27495 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27497 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27498 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);
27502 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27507 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27508 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27510 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27511 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);
27515 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);
27520 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27521 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27523 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27524 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27528 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);
27535 this.previewEl.appendChild(this.canvasEl);
27537 this.setCanvasPosition();
27542 if(!this.canvasLoaded){
27546 var imageCanvas = document.createElement("canvas");
27548 var imageContext = imageCanvas.getContext("2d");
27550 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27551 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27553 var center = imageCanvas.width / 2;
27555 imageContext.translate(center, center);
27557 imageContext.rotate(this.rotate * Math.PI / 180);
27559 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27561 var canvas = document.createElement("canvas");
27563 var context = canvas.getContext("2d");
27565 canvas.width = this.minWidth;
27566 canvas.height = this.minHeight;
27568 switch (this.rotate) {
27571 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27572 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27574 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27575 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27577 var targetWidth = this.minWidth - 2 * x;
27578 var targetHeight = this.minHeight - 2 * y;
27582 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27583 scale = targetWidth / width;
27586 if(x > 0 && y == 0){
27587 scale = targetHeight / height;
27590 if(x > 0 && y > 0){
27591 scale = targetWidth / width;
27593 if(width < height){
27594 scale = targetHeight / height;
27598 context.scale(scale, scale);
27600 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27601 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27603 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27604 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27606 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27611 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27612 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27614 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27615 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27617 var targetWidth = this.minWidth - 2 * x;
27618 var targetHeight = this.minHeight - 2 * y;
27622 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27623 scale = targetWidth / width;
27626 if(x > 0 && y == 0){
27627 scale = targetHeight / height;
27630 if(x > 0 && y > 0){
27631 scale = targetWidth / width;
27633 if(width < height){
27634 scale = targetHeight / height;
27638 context.scale(scale, scale);
27640 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27641 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27643 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27644 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27646 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27648 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27653 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27654 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27656 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27657 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27659 var targetWidth = this.minWidth - 2 * x;
27660 var targetHeight = this.minHeight - 2 * y;
27664 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27665 scale = targetWidth / width;
27668 if(x > 0 && y == 0){
27669 scale = targetHeight / height;
27672 if(x > 0 && y > 0){
27673 scale = targetWidth / width;
27675 if(width < height){
27676 scale = targetHeight / height;
27680 context.scale(scale, scale);
27682 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27683 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27685 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27686 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27688 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27689 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27691 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27696 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27697 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27699 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27700 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27702 var targetWidth = this.minWidth - 2 * x;
27703 var targetHeight = this.minHeight - 2 * y;
27707 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27708 scale = targetWidth / width;
27711 if(x > 0 && y == 0){
27712 scale = targetHeight / height;
27715 if(x > 0 && y > 0){
27716 scale = targetWidth / width;
27718 if(width < height){
27719 scale = targetHeight / height;
27723 context.scale(scale, scale);
27725 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27726 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27728 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27729 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27731 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27733 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27740 this.cropData = canvas.toDataURL(this.cropType);
27742 if(this.fireEvent('crop', this, this.cropData) !== false){
27743 this.process(this.file, this.cropData);
27750 setThumbBoxSize : function()
27754 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27755 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27756 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27758 this.minWidth = width;
27759 this.minHeight = height;
27761 if(this.rotate == 90 || this.rotate == 270){
27762 this.minWidth = height;
27763 this.minHeight = width;
27768 width = Math.ceil(this.minWidth * height / this.minHeight);
27770 if(this.minWidth > this.minHeight){
27772 height = Math.ceil(this.minHeight * width / this.minWidth);
27775 this.thumbEl.setStyle({
27776 width : width + 'px',
27777 height : height + 'px'
27784 setThumbBoxPosition : function()
27786 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27787 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27789 this.thumbEl.setLeft(x);
27790 this.thumbEl.setTop(y);
27794 baseRotateLevel : function()
27796 this.baseRotate = 1;
27799 typeof(this.exif) != 'undefined' &&
27800 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27801 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27803 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27806 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27810 baseScaleLevel : function()
27814 if(this.isDocument){
27816 if(this.baseRotate == 6 || this.baseRotate == 8){
27818 height = this.thumbEl.getHeight();
27819 this.baseScale = height / this.imageEl.OriginWidth;
27821 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27822 width = this.thumbEl.getWidth();
27823 this.baseScale = width / this.imageEl.OriginHeight;
27829 height = this.thumbEl.getHeight();
27830 this.baseScale = height / this.imageEl.OriginHeight;
27832 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27833 width = this.thumbEl.getWidth();
27834 this.baseScale = width / this.imageEl.OriginWidth;
27840 if(this.baseRotate == 6 || this.baseRotate == 8){
27842 width = this.thumbEl.getHeight();
27843 this.baseScale = width / this.imageEl.OriginHeight;
27845 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27846 height = this.thumbEl.getWidth();
27847 this.baseScale = height / this.imageEl.OriginHeight;
27850 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27851 height = this.thumbEl.getWidth();
27852 this.baseScale = height / this.imageEl.OriginHeight;
27854 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27855 width = this.thumbEl.getHeight();
27856 this.baseScale = width / this.imageEl.OriginWidth;
27863 width = this.thumbEl.getWidth();
27864 this.baseScale = width / this.imageEl.OriginWidth;
27866 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27867 height = this.thumbEl.getHeight();
27868 this.baseScale = height / this.imageEl.OriginHeight;
27871 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27873 height = this.thumbEl.getHeight();
27874 this.baseScale = height / this.imageEl.OriginHeight;
27876 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27877 width = this.thumbEl.getWidth();
27878 this.baseScale = width / this.imageEl.OriginWidth;
27886 getScaleLevel : function()
27888 return this.baseScale * Math.pow(1.1, this.scale);
27891 onTouchStart : function(e)
27893 if(!this.canvasLoaded){
27894 this.beforeSelectFile(e);
27898 var touches = e.browserEvent.touches;
27904 if(touches.length == 1){
27905 this.onMouseDown(e);
27909 if(touches.length != 2){
27915 for(var i = 0, finger; finger = touches[i]; i++){
27916 coords.push(finger.pageX, finger.pageY);
27919 var x = Math.pow(coords[0] - coords[2], 2);
27920 var y = Math.pow(coords[1] - coords[3], 2);
27922 this.startDistance = Math.sqrt(x + y);
27924 this.startScale = this.scale;
27926 this.pinching = true;
27927 this.dragable = false;
27931 onTouchMove : function(e)
27933 if(!this.pinching && !this.dragable){
27937 var touches = e.browserEvent.touches;
27944 this.onMouseMove(e);
27950 for(var i = 0, finger; finger = touches[i]; i++){
27951 coords.push(finger.pageX, finger.pageY);
27954 var x = Math.pow(coords[0] - coords[2], 2);
27955 var y = Math.pow(coords[1] - coords[3], 2);
27957 this.endDistance = Math.sqrt(x + y);
27959 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27961 if(!this.zoomable()){
27962 this.scale = this.startScale;
27970 onTouchEnd : function(e)
27972 this.pinching = false;
27973 this.dragable = false;
27977 process : function(file, crop)
27980 this.maskEl.mask(this.loadingText);
27983 this.xhr = new XMLHttpRequest();
27985 file.xhr = this.xhr;
27987 this.xhr.open(this.method, this.url, true);
27990 "Accept": "application/json",
27991 "Cache-Control": "no-cache",
27992 "X-Requested-With": "XMLHttpRequest"
27995 for (var headerName in headers) {
27996 var headerValue = headers[headerName];
27998 this.xhr.setRequestHeader(headerName, headerValue);
28004 this.xhr.onload = function()
28006 _this.xhrOnLoad(_this.xhr);
28009 this.xhr.onerror = function()
28011 _this.xhrOnError(_this.xhr);
28014 var formData = new FormData();
28016 formData.append('returnHTML', 'NO');
28019 formData.append('crop', crop);
28022 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28023 formData.append(this.paramName, file, file.name);
28026 if(typeof(file.filename) != 'undefined'){
28027 formData.append('filename', file.filename);
28030 if(typeof(file.mimetype) != 'undefined'){
28031 formData.append('mimetype', file.mimetype);
28034 if(this.fireEvent('arrange', this, formData) != false){
28035 this.xhr.send(formData);
28039 xhrOnLoad : function(xhr)
28042 this.maskEl.unmask();
28045 if (xhr.readyState !== 4) {
28046 this.fireEvent('exception', this, xhr);
28050 var response = Roo.decode(xhr.responseText);
28052 if(!response.success){
28053 this.fireEvent('exception', this, xhr);
28057 var response = Roo.decode(xhr.responseText);
28059 this.fireEvent('upload', this, response);
28063 xhrOnError : function()
28066 this.maskEl.unmask();
28069 Roo.log('xhr on error');
28071 var response = Roo.decode(xhr.responseText);
28077 prepare : function(file)
28080 this.maskEl.mask(this.loadingText);
28086 if(typeof(file) === 'string'){
28087 this.loadCanvas(file);
28091 if(!file || !this.urlAPI){
28096 this.cropType = file.type;
28100 if(this.fireEvent('prepare', this, this.file) != false){
28102 var reader = new FileReader();
28104 reader.onload = function (e) {
28105 if (e.target.error) {
28106 Roo.log(e.target.error);
28110 var buffer = e.target.result,
28111 dataView = new DataView(buffer),
28113 maxOffset = dataView.byteLength - 4,
28117 if (dataView.getUint16(0) === 0xffd8) {
28118 while (offset < maxOffset) {
28119 markerBytes = dataView.getUint16(offset);
28121 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28122 markerLength = dataView.getUint16(offset + 2) + 2;
28123 if (offset + markerLength > dataView.byteLength) {
28124 Roo.log('Invalid meta data: Invalid segment size.');
28128 if(markerBytes == 0xffe1){
28129 _this.parseExifData(
28136 offset += markerLength;
28146 var url = _this.urlAPI.createObjectURL(_this.file);
28148 _this.loadCanvas(url);
28153 reader.readAsArrayBuffer(this.file);
28159 parseExifData : function(dataView, offset, length)
28161 var tiffOffset = offset + 10,
28165 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28166 // No Exif data, might be XMP data instead
28170 // Check for the ASCII code for "Exif" (0x45786966):
28171 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28172 // No Exif data, might be XMP data instead
28175 if (tiffOffset + 8 > dataView.byteLength) {
28176 Roo.log('Invalid Exif data: Invalid segment size.');
28179 // Check for the two null bytes:
28180 if (dataView.getUint16(offset + 8) !== 0x0000) {
28181 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28184 // Check the byte alignment:
28185 switch (dataView.getUint16(tiffOffset)) {
28187 littleEndian = true;
28190 littleEndian = false;
28193 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28196 // Check for the TIFF tag marker (0x002A):
28197 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28198 Roo.log('Invalid Exif data: Missing TIFF marker.');
28201 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28202 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28204 this.parseExifTags(
28207 tiffOffset + dirOffset,
28212 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28217 if (dirOffset + 6 > dataView.byteLength) {
28218 Roo.log('Invalid Exif data: Invalid directory offset.');
28221 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28222 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28223 if (dirEndOffset + 4 > dataView.byteLength) {
28224 Roo.log('Invalid Exif data: Invalid directory size.');
28227 for (i = 0; i < tagsNumber; i += 1) {
28231 dirOffset + 2 + 12 * i, // tag offset
28235 // Return the offset to the next directory:
28236 return dataView.getUint32(dirEndOffset, littleEndian);
28239 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28241 var tag = dataView.getUint16(offset, littleEndian);
28243 this.exif[tag] = this.getExifValue(
28247 dataView.getUint16(offset + 2, littleEndian), // tag type
28248 dataView.getUint32(offset + 4, littleEndian), // tag length
28253 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28255 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28264 Roo.log('Invalid Exif data: Invalid tag type.');
28268 tagSize = tagType.size * length;
28269 // Determine if the value is contained in the dataOffset bytes,
28270 // or if the value at the dataOffset is a pointer to the actual data:
28271 dataOffset = tagSize > 4 ?
28272 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28273 if (dataOffset + tagSize > dataView.byteLength) {
28274 Roo.log('Invalid Exif data: Invalid data offset.');
28277 if (length === 1) {
28278 return tagType.getValue(dataView, dataOffset, littleEndian);
28281 for (i = 0; i < length; i += 1) {
28282 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28285 if (tagType.ascii) {
28287 // Concatenate the chars:
28288 for (i = 0; i < values.length; i += 1) {
28290 // Ignore the terminating NULL byte(s):
28291 if (c === '\u0000') {
28303 Roo.apply(Roo.bootstrap.UploadCropbox, {
28305 'Orientation': 0x0112
28309 1: 0, //'top-left',
28311 3: 180, //'bottom-right',
28312 // 4: 'bottom-left',
28314 6: 90, //'right-top',
28315 // 7: 'right-bottom',
28316 8: 270 //'left-bottom'
28320 // byte, 8-bit unsigned int:
28322 getValue: function (dataView, dataOffset) {
28323 return dataView.getUint8(dataOffset);
28327 // ascii, 8-bit byte:
28329 getValue: function (dataView, dataOffset) {
28330 return String.fromCharCode(dataView.getUint8(dataOffset));
28335 // short, 16 bit int:
28337 getValue: function (dataView, dataOffset, littleEndian) {
28338 return dataView.getUint16(dataOffset, littleEndian);
28342 // long, 32 bit int:
28344 getValue: function (dataView, dataOffset, littleEndian) {
28345 return dataView.getUint32(dataOffset, littleEndian);
28349 // rational = two long values, first is numerator, second is denominator:
28351 getValue: function (dataView, dataOffset, littleEndian) {
28352 return dataView.getUint32(dataOffset, littleEndian) /
28353 dataView.getUint32(dataOffset + 4, littleEndian);
28357 // slong, 32 bit signed int:
28359 getValue: function (dataView, dataOffset, littleEndian) {
28360 return dataView.getInt32(dataOffset, littleEndian);
28364 // srational, two slongs, first is numerator, second is denominator:
28366 getValue: function (dataView, dataOffset, littleEndian) {
28367 return dataView.getInt32(dataOffset, littleEndian) /
28368 dataView.getInt32(dataOffset + 4, littleEndian);
28378 cls : 'btn-group roo-upload-cropbox-rotate-left',
28379 action : 'rotate-left',
28383 cls : 'btn btn-default',
28384 html : '<i class="fa fa-undo"></i>'
28390 cls : 'btn-group roo-upload-cropbox-picture',
28391 action : 'picture',
28395 cls : 'btn btn-default',
28396 html : '<i class="fa fa-picture-o"></i>'
28402 cls : 'btn-group roo-upload-cropbox-rotate-right',
28403 action : 'rotate-right',
28407 cls : 'btn btn-default',
28408 html : '<i class="fa fa-repeat"></i>'
28416 cls : 'btn-group roo-upload-cropbox-rotate-left',
28417 action : 'rotate-left',
28421 cls : 'btn btn-default',
28422 html : '<i class="fa fa-undo"></i>'
28428 cls : 'btn-group roo-upload-cropbox-download',
28429 action : 'download',
28433 cls : 'btn btn-default',
28434 html : '<i class="fa fa-download"></i>'
28440 cls : 'btn-group roo-upload-cropbox-crop',
28445 cls : 'btn btn-default',
28446 html : '<i class="fa fa-crop"></i>'
28452 cls : 'btn-group roo-upload-cropbox-trash',
28457 cls : 'btn btn-default',
28458 html : '<i class="fa fa-trash"></i>'
28464 cls : 'btn-group roo-upload-cropbox-rotate-right',
28465 action : 'rotate-right',
28469 cls : 'btn btn-default',
28470 html : '<i class="fa fa-repeat"></i>'
28478 cls : 'btn-group roo-upload-cropbox-rotate-left',
28479 action : 'rotate-left',
28483 cls : 'btn btn-default',
28484 html : '<i class="fa fa-undo"></i>'
28490 cls : 'btn-group roo-upload-cropbox-rotate-right',
28491 action : 'rotate-right',
28495 cls : 'btn btn-default',
28496 html : '<i class="fa fa-repeat"></i>'
28509 * @class Roo.bootstrap.DocumentManager
28510 * @extends Roo.bootstrap.Component
28511 * Bootstrap DocumentManager class
28512 * @cfg {String} paramName default 'imageUpload'
28513 * @cfg {String} toolTipName default 'filename'
28514 * @cfg {String} method default POST
28515 * @cfg {String} url action url
28516 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28517 * @cfg {Boolean} multiple multiple upload default true
28518 * @cfg {Number} thumbSize default 300
28519 * @cfg {String} fieldLabel
28520 * @cfg {Number} labelWidth default 4
28521 * @cfg {String} labelAlign (left|top) default left
28522 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28523 * @cfg {Number} labellg set the width of label (1-12)
28524 * @cfg {Number} labelmd set the width of label (1-12)
28525 * @cfg {Number} labelsm set the width of label (1-12)
28526 * @cfg {Number} labelxs set the width of label (1-12)
28529 * Create a new DocumentManager
28530 * @param {Object} config The config object
28533 Roo.bootstrap.DocumentManager = function(config){
28534 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28537 this.delegates = [];
28542 * Fire when initial the DocumentManager
28543 * @param {Roo.bootstrap.DocumentManager} this
28548 * inspect selected file
28549 * @param {Roo.bootstrap.DocumentManager} this
28550 * @param {File} file
28555 * Fire when xhr load exception
28556 * @param {Roo.bootstrap.DocumentManager} this
28557 * @param {XMLHttpRequest} xhr
28559 "exception" : true,
28561 * @event afterupload
28562 * Fire when xhr load exception
28563 * @param {Roo.bootstrap.DocumentManager} this
28564 * @param {XMLHttpRequest} xhr
28566 "afterupload" : true,
28569 * prepare the form data
28570 * @param {Roo.bootstrap.DocumentManager} this
28571 * @param {Object} formData
28576 * Fire when remove the file
28577 * @param {Roo.bootstrap.DocumentManager} this
28578 * @param {Object} file
28583 * Fire after refresh the file
28584 * @param {Roo.bootstrap.DocumentManager} this
28589 * Fire after click the image
28590 * @param {Roo.bootstrap.DocumentManager} this
28591 * @param {Object} file
28596 * Fire when upload a image and editable set to true
28597 * @param {Roo.bootstrap.DocumentManager} this
28598 * @param {Object} file
28602 * @event beforeselectfile
28603 * Fire before select file
28604 * @param {Roo.bootstrap.DocumentManager} this
28606 "beforeselectfile" : true,
28609 * Fire before process file
28610 * @param {Roo.bootstrap.DocumentManager} this
28611 * @param {Object} file
28615 * @event previewrendered
28616 * Fire when preview rendered
28617 * @param {Roo.bootstrap.DocumentManager} this
28618 * @param {Object} file
28620 "previewrendered" : true
28625 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28634 paramName : 'imageUpload',
28635 toolTipName : 'filename',
28638 labelAlign : 'left',
28648 getAutoCreate : function()
28650 var managerWidget = {
28652 cls : 'roo-document-manager',
28656 cls : 'roo-document-manager-selector',
28661 cls : 'roo-document-manager-uploader',
28665 cls : 'roo-document-manager-upload-btn',
28666 html : '<i class="fa fa-plus"></i>'
28677 cls : 'column col-md-12',
28682 if(this.fieldLabel.length){
28687 cls : 'column col-md-12',
28688 html : this.fieldLabel
28692 cls : 'column col-md-12',
28697 if(this.labelAlign == 'left'){
28702 html : this.fieldLabel
28711 if(this.labelWidth > 12){
28712 content[0].style = "width: " + this.labelWidth + 'px';
28715 if(this.labelWidth < 13 && this.labelmd == 0){
28716 this.labelmd = this.labelWidth;
28719 if(this.labellg > 0){
28720 content[0].cls += ' col-lg-' + this.labellg;
28721 content[1].cls += ' col-lg-' + (12 - this.labellg);
28724 if(this.labelmd > 0){
28725 content[0].cls += ' col-md-' + this.labelmd;
28726 content[1].cls += ' col-md-' + (12 - this.labelmd);
28729 if(this.labelsm > 0){
28730 content[0].cls += ' col-sm-' + this.labelsm;
28731 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28734 if(this.labelxs > 0){
28735 content[0].cls += ' col-xs-' + this.labelxs;
28736 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28744 cls : 'row clearfix',
28752 initEvents : function()
28754 this.managerEl = this.el.select('.roo-document-manager', true).first();
28755 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28757 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28758 this.selectorEl.hide();
28761 this.selectorEl.attr('multiple', 'multiple');
28764 this.selectorEl.on('change', this.onFileSelected, this);
28766 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28767 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28769 this.uploader.on('click', this.onUploaderClick, this);
28771 this.renderProgressDialog();
28775 window.addEventListener("resize", function() { _this.refresh(); } );
28777 this.fireEvent('initial', this);
28780 renderProgressDialog : function()
28784 this.progressDialog = new Roo.bootstrap.Modal({
28785 cls : 'roo-document-manager-progress-dialog',
28786 allow_close : false,
28796 btnclick : function() {
28797 _this.uploadCancel();
28803 this.progressDialog.render(Roo.get(document.body));
28805 this.progress = new Roo.bootstrap.Progress({
28806 cls : 'roo-document-manager-progress',
28811 this.progress.render(this.progressDialog.getChildContainer());
28813 this.progressBar = new Roo.bootstrap.ProgressBar({
28814 cls : 'roo-document-manager-progress-bar',
28817 aria_valuemax : 12,
28821 this.progressBar.render(this.progress.getChildContainer());
28824 onUploaderClick : function(e)
28826 e.preventDefault();
28828 if(this.fireEvent('beforeselectfile', this) != false){
28829 this.selectorEl.dom.click();
28834 onFileSelected : function(e)
28836 e.preventDefault();
28838 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28842 Roo.each(this.selectorEl.dom.files, function(file){
28843 if(this.fireEvent('inspect', this, file) != false){
28844 this.files.push(file);
28854 this.selectorEl.dom.value = '';
28856 if(!this.files || !this.files.length){
28860 if(this.boxes > 0 && this.files.length > this.boxes){
28861 this.files = this.files.slice(0, this.boxes);
28864 this.uploader.show();
28866 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28867 this.uploader.hide();
28876 Roo.each(this.files, function(file){
28878 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28879 var f = this.renderPreview(file);
28884 if(file.type.indexOf('image') != -1){
28885 this.delegates.push(
28887 _this.process(file);
28888 }).createDelegate(this)
28896 _this.process(file);
28897 }).createDelegate(this)
28902 this.files = files;
28904 this.delegates = this.delegates.concat(docs);
28906 if(!this.delegates.length){
28911 this.progressBar.aria_valuemax = this.delegates.length;
28918 arrange : function()
28920 if(!this.delegates.length){
28921 this.progressDialog.hide();
28926 var delegate = this.delegates.shift();
28928 this.progressDialog.show();
28930 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28932 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28937 refresh : function()
28939 this.uploader.show();
28941 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28942 this.uploader.hide();
28945 Roo.isTouch ? this.closable(false) : this.closable(true);
28947 this.fireEvent('refresh', this);
28950 onRemove : function(e, el, o)
28952 e.preventDefault();
28954 this.fireEvent('remove', this, o);
28958 remove : function(o)
28962 Roo.each(this.files, function(file){
28963 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28972 this.files = files;
28979 Roo.each(this.files, function(file){
28984 file.target.remove();
28993 onClick : function(e, el, o)
28995 e.preventDefault();
28997 this.fireEvent('click', this, o);
29001 closable : function(closable)
29003 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29005 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29017 xhrOnLoad : function(xhr)
29019 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29023 if (xhr.readyState !== 4) {
29025 this.fireEvent('exception', this, xhr);
29029 var response = Roo.decode(xhr.responseText);
29031 if(!response.success){
29033 this.fireEvent('exception', this, xhr);
29037 var file = this.renderPreview(response.data);
29039 this.files.push(file);
29043 this.fireEvent('afterupload', this, xhr);
29047 xhrOnError : function(xhr)
29049 Roo.log('xhr on error');
29051 var response = Roo.decode(xhr.responseText);
29058 process : function(file)
29060 if(this.fireEvent('process', this, file) !== false){
29061 if(this.editable && file.type.indexOf('image') != -1){
29062 this.fireEvent('edit', this, file);
29066 this.uploadStart(file, false);
29073 uploadStart : function(file, crop)
29075 this.xhr = new XMLHttpRequest();
29077 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29082 file.xhr = this.xhr;
29084 this.managerEl.createChild({
29086 cls : 'roo-document-manager-loading',
29090 tooltip : file.name,
29091 cls : 'roo-document-manager-thumb',
29092 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29098 this.xhr.open(this.method, this.url, true);
29101 "Accept": "application/json",
29102 "Cache-Control": "no-cache",
29103 "X-Requested-With": "XMLHttpRequest"
29106 for (var headerName in headers) {
29107 var headerValue = headers[headerName];
29109 this.xhr.setRequestHeader(headerName, headerValue);
29115 this.xhr.onload = function()
29117 _this.xhrOnLoad(_this.xhr);
29120 this.xhr.onerror = function()
29122 _this.xhrOnError(_this.xhr);
29125 var formData = new FormData();
29127 formData.append('returnHTML', 'NO');
29130 formData.append('crop', crop);
29133 formData.append(this.paramName, file, file.name);
29140 if(this.fireEvent('prepare', this, formData, options) != false){
29142 if(options.manually){
29146 this.xhr.send(formData);
29150 this.uploadCancel();
29153 uploadCancel : function()
29159 this.delegates = [];
29161 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29168 renderPreview : function(file)
29170 if(typeof(file.target) != 'undefined' && file.target){
29174 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29176 var previewEl = this.managerEl.createChild({
29178 cls : 'roo-document-manager-preview',
29182 tooltip : file[this.toolTipName],
29183 cls : 'roo-document-manager-thumb',
29184 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29189 html : '<i class="fa fa-times-circle"></i>'
29194 var close = previewEl.select('button.close', true).first();
29196 close.on('click', this.onRemove, this, file);
29198 file.target = previewEl;
29200 var image = previewEl.select('img', true).first();
29204 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29206 image.on('click', this.onClick, this, file);
29208 this.fireEvent('previewrendered', this, file);
29214 onPreviewLoad : function(file, image)
29216 if(typeof(file.target) == 'undefined' || !file.target){
29220 var width = image.dom.naturalWidth || image.dom.width;
29221 var height = image.dom.naturalHeight || image.dom.height;
29223 if(width > height){
29224 file.target.addClass('wide');
29228 file.target.addClass('tall');
29233 uploadFromSource : function(file, crop)
29235 this.xhr = new XMLHttpRequest();
29237 this.managerEl.createChild({
29239 cls : 'roo-document-manager-loading',
29243 tooltip : file.name,
29244 cls : 'roo-document-manager-thumb',
29245 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29251 this.xhr.open(this.method, this.url, true);
29254 "Accept": "application/json",
29255 "Cache-Control": "no-cache",
29256 "X-Requested-With": "XMLHttpRequest"
29259 for (var headerName in headers) {
29260 var headerValue = headers[headerName];
29262 this.xhr.setRequestHeader(headerName, headerValue);
29268 this.xhr.onload = function()
29270 _this.xhrOnLoad(_this.xhr);
29273 this.xhr.onerror = function()
29275 _this.xhrOnError(_this.xhr);
29278 var formData = new FormData();
29280 formData.append('returnHTML', 'NO');
29282 formData.append('crop', crop);
29284 if(typeof(file.filename) != 'undefined'){
29285 formData.append('filename', file.filename);
29288 if(typeof(file.mimetype) != 'undefined'){
29289 formData.append('mimetype', file.mimetype);
29294 if(this.fireEvent('prepare', this, formData) != false){
29295 this.xhr.send(formData);
29305 * @class Roo.bootstrap.DocumentViewer
29306 * @extends Roo.bootstrap.Component
29307 * Bootstrap DocumentViewer class
29308 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29309 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29312 * Create a new DocumentViewer
29313 * @param {Object} config The config object
29316 Roo.bootstrap.DocumentViewer = function(config){
29317 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29322 * Fire after initEvent
29323 * @param {Roo.bootstrap.DocumentViewer} this
29329 * @param {Roo.bootstrap.DocumentViewer} this
29334 * Fire after download button
29335 * @param {Roo.bootstrap.DocumentViewer} this
29340 * Fire after trash button
29341 * @param {Roo.bootstrap.DocumentViewer} this
29348 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29350 showDownload : true,
29354 getAutoCreate : function()
29358 cls : 'roo-document-viewer',
29362 cls : 'roo-document-viewer-body',
29366 cls : 'roo-document-viewer-thumb',
29370 cls : 'roo-document-viewer-image'
29378 cls : 'roo-document-viewer-footer',
29381 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29385 cls : 'btn-group roo-document-viewer-download',
29389 cls : 'btn btn-default',
29390 html : '<i class="fa fa-download"></i>'
29396 cls : 'btn-group roo-document-viewer-trash',
29400 cls : 'btn btn-default',
29401 html : '<i class="fa fa-trash"></i>'
29414 initEvents : function()
29416 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29417 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29419 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29420 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29422 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29423 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29425 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29426 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29428 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29429 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29431 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29432 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29434 this.bodyEl.on('click', this.onClick, this);
29435 this.downloadBtn.on('click', this.onDownload, this);
29436 this.trashBtn.on('click', this.onTrash, this);
29438 this.downloadBtn.hide();
29439 this.trashBtn.hide();
29441 if(this.showDownload){
29442 this.downloadBtn.show();
29445 if(this.showTrash){
29446 this.trashBtn.show();
29449 if(!this.showDownload && !this.showTrash) {
29450 this.footerEl.hide();
29455 initial : function()
29457 this.fireEvent('initial', this);
29461 onClick : function(e)
29463 e.preventDefault();
29465 this.fireEvent('click', this);
29468 onDownload : function(e)
29470 e.preventDefault();
29472 this.fireEvent('download', this);
29475 onTrash : function(e)
29477 e.preventDefault();
29479 this.fireEvent('trash', this);
29491 * @class Roo.bootstrap.NavProgressBar
29492 * @extends Roo.bootstrap.Component
29493 * Bootstrap NavProgressBar class
29496 * Create a new nav progress bar
29497 * @param {Object} config The config object
29500 Roo.bootstrap.NavProgressBar = function(config){
29501 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29503 this.bullets = this.bullets || [];
29505 // Roo.bootstrap.NavProgressBar.register(this);
29509 * Fires when the active item changes
29510 * @param {Roo.bootstrap.NavProgressBar} this
29511 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29512 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29519 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29524 getAutoCreate : function()
29526 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29530 cls : 'roo-navigation-bar-group',
29534 cls : 'roo-navigation-top-bar'
29538 cls : 'roo-navigation-bullets-bar',
29542 cls : 'roo-navigation-bar'
29549 cls : 'roo-navigation-bottom-bar'
29559 initEvents: function()
29564 onRender : function(ct, position)
29566 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29568 if(this.bullets.length){
29569 Roo.each(this.bullets, function(b){
29578 addItem : function(cfg)
29580 var item = new Roo.bootstrap.NavProgressItem(cfg);
29582 item.parentId = this.id;
29583 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29586 var top = new Roo.bootstrap.Element({
29588 cls : 'roo-navigation-bar-text'
29591 var bottom = new Roo.bootstrap.Element({
29593 cls : 'roo-navigation-bar-text'
29596 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29597 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29599 var topText = new Roo.bootstrap.Element({
29601 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29604 var bottomText = new Roo.bootstrap.Element({
29606 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29609 topText.onRender(top.el, null);
29610 bottomText.onRender(bottom.el, null);
29613 item.bottomEl = bottom;
29616 this.barItems.push(item);
29621 getActive : function()
29623 var active = false;
29625 Roo.each(this.barItems, function(v){
29627 if (!v.isActive()) {
29639 setActiveItem : function(item)
29643 Roo.each(this.barItems, function(v){
29644 if (v.rid == item.rid) {
29648 if (v.isActive()) {
29649 v.setActive(false);
29654 item.setActive(true);
29656 this.fireEvent('changed', this, item, prev);
29659 getBarItem: function(rid)
29663 Roo.each(this.barItems, function(e) {
29664 if (e.rid != rid) {
29675 indexOfItem : function(item)
29679 Roo.each(this.barItems, function(v, i){
29681 if (v.rid != item.rid) {
29692 setActiveNext : function()
29694 var i = this.indexOfItem(this.getActive());
29696 if (i > this.barItems.length) {
29700 this.setActiveItem(this.barItems[i+1]);
29703 setActivePrev : function()
29705 var i = this.indexOfItem(this.getActive());
29711 this.setActiveItem(this.barItems[i-1]);
29714 format : function()
29716 if(!this.barItems.length){
29720 var width = 100 / this.barItems.length;
29722 Roo.each(this.barItems, function(i){
29723 i.el.setStyle('width', width + '%');
29724 i.topEl.el.setStyle('width', width + '%');
29725 i.bottomEl.el.setStyle('width', width + '%');
29734 * Nav Progress Item
29739 * @class Roo.bootstrap.NavProgressItem
29740 * @extends Roo.bootstrap.Component
29741 * Bootstrap NavProgressItem class
29742 * @cfg {String} rid the reference id
29743 * @cfg {Boolean} active (true|false) Is item active default false
29744 * @cfg {Boolean} disabled (true|false) Is item active default false
29745 * @cfg {String} html
29746 * @cfg {String} position (top|bottom) text position default bottom
29747 * @cfg {String} icon show icon instead of number
29750 * Create a new NavProgressItem
29751 * @param {Object} config The config object
29753 Roo.bootstrap.NavProgressItem = function(config){
29754 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29759 * The raw click event for the entire grid.
29760 * @param {Roo.bootstrap.NavProgressItem} this
29761 * @param {Roo.EventObject} e
29768 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29774 position : 'bottom',
29777 getAutoCreate : function()
29779 var iconCls = 'roo-navigation-bar-item-icon';
29781 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29785 cls: 'roo-navigation-bar-item',
29795 cfg.cls += ' active';
29798 cfg.cls += ' disabled';
29804 disable : function()
29806 this.setDisabled(true);
29809 enable : function()
29811 this.setDisabled(false);
29814 initEvents: function()
29816 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29818 this.iconEl.on('click', this.onClick, this);
29821 onClick : function(e)
29823 e.preventDefault();
29829 if(this.fireEvent('click', this, e) === false){
29833 this.parent().setActiveItem(this);
29836 isActive: function ()
29838 return this.active;
29841 setActive : function(state)
29843 if(this.active == state){
29847 this.active = state;
29850 this.el.addClass('active');
29854 this.el.removeClass('active');
29859 setDisabled : function(state)
29861 if(this.disabled == state){
29865 this.disabled = state;
29868 this.el.addClass('disabled');
29872 this.el.removeClass('disabled');
29875 tooltipEl : function()
29877 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29890 * @class Roo.bootstrap.FieldLabel
29891 * @extends Roo.bootstrap.Component
29892 * Bootstrap FieldLabel class
29893 * @cfg {String} html contents of the element
29894 * @cfg {String} tag tag of the element default label
29895 * @cfg {String} cls class of the element
29896 * @cfg {String} target label target
29897 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29898 * @cfg {String} invalidClass default "text-warning"
29899 * @cfg {String} validClass default "text-success"
29900 * @cfg {String} iconTooltip default "This field is required"
29901 * @cfg {String} indicatorpos (left|right) default left
29904 * Create a new FieldLabel
29905 * @param {Object} config The config object
29908 Roo.bootstrap.FieldLabel = function(config){
29909 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29914 * Fires after the field has been marked as invalid.
29915 * @param {Roo.form.FieldLabel} this
29916 * @param {String} msg The validation message
29921 * Fires after the field has been validated with no errors.
29922 * @param {Roo.form.FieldLabel} this
29928 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29935 invalidClass : 'has-warning',
29936 validClass : 'has-success',
29937 iconTooltip : 'This field is required',
29938 indicatorpos : 'left',
29940 getAutoCreate : function(){
29944 cls : 'roo-bootstrap-field-label ' + this.cls,
29949 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29950 tooltip : this.iconTooltip
29959 if(this.indicatorpos == 'right'){
29962 cls : 'roo-bootstrap-field-label ' + this.cls,
29971 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29972 tooltip : this.iconTooltip
29981 initEvents: function()
29983 Roo.bootstrap.Element.superclass.initEvents.call(this);
29985 this.indicator = this.indicatorEl();
29987 if(this.indicator){
29988 this.indicator.removeClass('visible');
29989 this.indicator.addClass('invisible');
29992 Roo.bootstrap.FieldLabel.register(this);
29995 indicatorEl : function()
29997 var indicator = this.el.select('i.roo-required-indicator',true).first();
30008 * Mark this field as valid
30010 markValid : function()
30012 if(this.indicator){
30013 this.indicator.removeClass('visible');
30014 this.indicator.addClass('invisible');
30017 this.el.removeClass(this.invalidClass);
30019 this.el.addClass(this.validClass);
30021 this.fireEvent('valid', this);
30025 * Mark this field as invalid
30026 * @param {String} msg The validation message
30028 markInvalid : function(msg)
30030 if(this.indicator){
30031 this.indicator.removeClass('invisible');
30032 this.indicator.addClass('visible');
30035 this.el.removeClass(this.validClass);
30037 this.el.addClass(this.invalidClass);
30039 this.fireEvent('invalid', this, msg);
30045 Roo.apply(Roo.bootstrap.FieldLabel, {
30050 * register a FieldLabel Group
30051 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30053 register : function(label)
30055 if(this.groups.hasOwnProperty(label.target)){
30059 this.groups[label.target] = label;
30063 * fetch a FieldLabel Group based on the target
30064 * @param {string} target
30065 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30067 get: function(target) {
30068 if (typeof(this.groups[target]) == 'undefined') {
30072 return this.groups[target] ;
30081 * page DateSplitField.
30087 * @class Roo.bootstrap.DateSplitField
30088 * @extends Roo.bootstrap.Component
30089 * Bootstrap DateSplitField class
30090 * @cfg {string} fieldLabel - the label associated
30091 * @cfg {Number} labelWidth set the width of label (0-12)
30092 * @cfg {String} labelAlign (top|left)
30093 * @cfg {Boolean} dayAllowBlank (true|false) default false
30094 * @cfg {Boolean} monthAllowBlank (true|false) default false
30095 * @cfg {Boolean} yearAllowBlank (true|false) default false
30096 * @cfg {string} dayPlaceholder
30097 * @cfg {string} monthPlaceholder
30098 * @cfg {string} yearPlaceholder
30099 * @cfg {string} dayFormat default 'd'
30100 * @cfg {string} monthFormat default 'm'
30101 * @cfg {string} yearFormat default 'Y'
30102 * @cfg {Number} labellg set the width of label (1-12)
30103 * @cfg {Number} labelmd set the width of label (1-12)
30104 * @cfg {Number} labelsm set the width of label (1-12)
30105 * @cfg {Number} labelxs set the width of label (1-12)
30109 * Create a new DateSplitField
30110 * @param {Object} config The config object
30113 Roo.bootstrap.DateSplitField = function(config){
30114 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30120 * getting the data of years
30121 * @param {Roo.bootstrap.DateSplitField} this
30122 * @param {Object} years
30127 * getting the data of days
30128 * @param {Roo.bootstrap.DateSplitField} this
30129 * @param {Object} days
30134 * Fires after the field has been marked as invalid.
30135 * @param {Roo.form.Field} this
30136 * @param {String} msg The validation message
30141 * Fires after the field has been validated with no errors.
30142 * @param {Roo.form.Field} this
30148 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30151 labelAlign : 'top',
30153 dayAllowBlank : false,
30154 monthAllowBlank : false,
30155 yearAllowBlank : false,
30156 dayPlaceholder : '',
30157 monthPlaceholder : '',
30158 yearPlaceholder : '',
30162 isFormField : true,
30168 getAutoCreate : function()
30172 cls : 'row roo-date-split-field-group',
30177 cls : 'form-hidden-field roo-date-split-field-group-value',
30183 var labelCls = 'col-md-12';
30184 var contentCls = 'col-md-4';
30186 if(this.fieldLabel){
30190 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30194 html : this.fieldLabel
30199 if(this.labelAlign == 'left'){
30201 if(this.labelWidth > 12){
30202 label.style = "width: " + this.labelWidth + 'px';
30205 if(this.labelWidth < 13 && this.labelmd == 0){
30206 this.labelmd = this.labelWidth;
30209 if(this.labellg > 0){
30210 labelCls = ' col-lg-' + this.labellg;
30211 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30214 if(this.labelmd > 0){
30215 labelCls = ' col-md-' + this.labelmd;
30216 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30219 if(this.labelsm > 0){
30220 labelCls = ' col-sm-' + this.labelsm;
30221 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30224 if(this.labelxs > 0){
30225 labelCls = ' col-xs-' + this.labelxs;
30226 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30230 label.cls += ' ' + labelCls;
30232 cfg.cn.push(label);
30235 Roo.each(['day', 'month', 'year'], function(t){
30238 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30245 inputEl: function ()
30247 return this.el.select('.roo-date-split-field-group-value', true).first();
30250 onRender : function(ct, position)
30254 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30256 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30258 this.dayField = new Roo.bootstrap.ComboBox({
30259 allowBlank : this.dayAllowBlank,
30260 alwaysQuery : true,
30261 displayField : 'value',
30264 forceSelection : true,
30266 placeholder : this.dayPlaceholder,
30267 selectOnFocus : true,
30268 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30269 triggerAction : 'all',
30271 valueField : 'value',
30272 store : new Roo.data.SimpleStore({
30273 data : (function() {
30275 _this.fireEvent('days', _this, days);
30278 fields : [ 'value' ]
30281 select : function (_self, record, index)
30283 _this.setValue(_this.getValue());
30288 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30290 this.monthField = new Roo.bootstrap.MonthField({
30291 after : '<i class=\"fa fa-calendar\"></i>',
30292 allowBlank : this.monthAllowBlank,
30293 placeholder : this.monthPlaceholder,
30296 render : function (_self)
30298 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30299 e.preventDefault();
30303 select : function (_self, oldvalue, newvalue)
30305 _this.setValue(_this.getValue());
30310 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30312 this.yearField = new Roo.bootstrap.ComboBox({
30313 allowBlank : this.yearAllowBlank,
30314 alwaysQuery : true,
30315 displayField : 'value',
30318 forceSelection : true,
30320 placeholder : this.yearPlaceholder,
30321 selectOnFocus : true,
30322 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30323 triggerAction : 'all',
30325 valueField : 'value',
30326 store : new Roo.data.SimpleStore({
30327 data : (function() {
30329 _this.fireEvent('years', _this, years);
30332 fields : [ 'value' ]
30335 select : function (_self, record, index)
30337 _this.setValue(_this.getValue());
30342 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30345 setValue : function(v, format)
30347 this.inputEl.dom.value = v;
30349 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30351 var d = Date.parseDate(v, f);
30358 this.setDay(d.format(this.dayFormat));
30359 this.setMonth(d.format(this.monthFormat));
30360 this.setYear(d.format(this.yearFormat));
30367 setDay : function(v)
30369 this.dayField.setValue(v);
30370 this.inputEl.dom.value = this.getValue();
30375 setMonth : function(v)
30377 this.monthField.setValue(v, true);
30378 this.inputEl.dom.value = this.getValue();
30383 setYear : function(v)
30385 this.yearField.setValue(v);
30386 this.inputEl.dom.value = this.getValue();
30391 getDay : function()
30393 return this.dayField.getValue();
30396 getMonth : function()
30398 return this.monthField.getValue();
30401 getYear : function()
30403 return this.yearField.getValue();
30406 getValue : function()
30408 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30410 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30420 this.inputEl.dom.value = '';
30425 validate : function()
30427 var d = this.dayField.validate();
30428 var m = this.monthField.validate();
30429 var y = this.yearField.validate();
30434 (!this.dayAllowBlank && !d) ||
30435 (!this.monthAllowBlank && !m) ||
30436 (!this.yearAllowBlank && !y)
30441 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30450 this.markInvalid();
30455 markValid : function()
30458 var label = this.el.select('label', true).first();
30459 var icon = this.el.select('i.fa-star', true).first();
30465 this.fireEvent('valid', this);
30469 * Mark this field as invalid
30470 * @param {String} msg The validation message
30472 markInvalid : function(msg)
30475 var label = this.el.select('label', true).first();
30476 var icon = this.el.select('i.fa-star', true).first();
30478 if(label && !icon){
30479 this.el.select('.roo-date-split-field-label', true).createChild({
30481 cls : 'text-danger fa fa-lg fa-star',
30482 tooltip : 'This field is required',
30483 style : 'margin-right:5px;'
30487 this.fireEvent('invalid', this, msg);
30490 clearInvalid : function()
30492 var label = this.el.select('label', true).first();
30493 var icon = this.el.select('i.fa-star', true).first();
30499 this.fireEvent('valid', this);
30502 getName: function()
30512 * http://masonry.desandro.com
30514 * The idea is to render all the bricks based on vertical width...
30516 * The original code extends 'outlayer' - we might need to use that....
30522 * @class Roo.bootstrap.LayoutMasonry
30523 * @extends Roo.bootstrap.Component
30524 * Bootstrap Layout Masonry class
30527 * Create a new Element
30528 * @param {Object} config The config object
30531 Roo.bootstrap.LayoutMasonry = function(config){
30533 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30537 Roo.bootstrap.LayoutMasonry.register(this);
30543 * Fire after layout the items
30544 * @param {Roo.bootstrap.LayoutMasonry} this
30545 * @param {Roo.EventObject} e
30552 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30555 * @cfg {Boolean} isLayoutInstant = no animation?
30557 isLayoutInstant : false, // needed?
30560 * @cfg {Number} boxWidth width of the columns
30565 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30570 * @cfg {Number} padWidth padding below box..
30575 * @cfg {Number} gutter gutter width..
30580 * @cfg {Number} maxCols maximum number of columns
30586 * @cfg {Boolean} isAutoInitial defalut true
30588 isAutoInitial : true,
30593 * @cfg {Boolean} isHorizontal defalut false
30595 isHorizontal : false,
30597 currentSize : null,
30603 bricks: null, //CompositeElement
30607 _isLayoutInited : false,
30609 // isAlternative : false, // only use for vertical layout...
30612 * @cfg {Number} alternativePadWidth padding below box..
30614 alternativePadWidth : 50,
30616 selectedBrick : [],
30618 getAutoCreate : function(){
30620 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30624 cls: 'blog-masonary-wrapper ' + this.cls,
30626 cls : 'mas-boxes masonary'
30633 getChildContainer: function( )
30635 if (this.boxesEl) {
30636 return this.boxesEl;
30639 this.boxesEl = this.el.select('.mas-boxes').first();
30641 return this.boxesEl;
30645 initEvents : function()
30649 if(this.isAutoInitial){
30650 Roo.log('hook children rendered');
30651 this.on('childrenrendered', function() {
30652 Roo.log('children rendered');
30658 initial : function()
30660 this.selectedBrick = [];
30662 this.currentSize = this.el.getBox(true);
30664 Roo.EventManager.onWindowResize(this.resize, this);
30666 if(!this.isAutoInitial){
30674 //this.layout.defer(500,this);
30678 resize : function()
30680 var cs = this.el.getBox(true);
30683 this.currentSize.width == cs.width &&
30684 this.currentSize.x == cs.x &&
30685 this.currentSize.height == cs.height &&
30686 this.currentSize.y == cs.y
30688 Roo.log("no change in with or X or Y");
30692 this.currentSize = cs;
30698 layout : function()
30700 this._resetLayout();
30702 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30704 this.layoutItems( isInstant );
30706 this._isLayoutInited = true;
30708 this.fireEvent('layout', this);
30712 _resetLayout : function()
30714 if(this.isHorizontal){
30715 this.horizontalMeasureColumns();
30719 this.verticalMeasureColumns();
30723 verticalMeasureColumns : function()
30725 this.getContainerWidth();
30727 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30728 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30732 var boxWidth = this.boxWidth + this.padWidth;
30734 if(this.containerWidth < this.boxWidth){
30735 boxWidth = this.containerWidth
30738 var containerWidth = this.containerWidth;
30740 var cols = Math.floor(containerWidth / boxWidth);
30742 this.cols = Math.max( cols, 1 );
30744 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30746 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30748 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30750 this.colWidth = boxWidth + avail - this.padWidth;
30752 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30753 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30756 horizontalMeasureColumns : function()
30758 this.getContainerWidth();
30760 var boxWidth = this.boxWidth;
30762 if(this.containerWidth < boxWidth){
30763 boxWidth = this.containerWidth;
30766 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30768 this.el.setHeight(boxWidth);
30772 getContainerWidth : function()
30774 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30777 layoutItems : function( isInstant )
30779 Roo.log(this.bricks);
30781 var items = Roo.apply([], this.bricks);
30783 if(this.isHorizontal){
30784 this._horizontalLayoutItems( items , isInstant );
30788 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30789 // this._verticalAlternativeLayoutItems( items , isInstant );
30793 this._verticalLayoutItems( items , isInstant );
30797 _verticalLayoutItems : function ( items , isInstant)
30799 if ( !items || !items.length ) {
30804 ['xs', 'xs', 'xs', 'tall'],
30805 ['xs', 'xs', 'tall'],
30806 ['xs', 'xs', 'sm'],
30807 ['xs', 'xs', 'xs'],
30813 ['sm', 'xs', 'xs'],
30817 ['tall', 'xs', 'xs', 'xs'],
30818 ['tall', 'xs', 'xs'],
30830 Roo.each(items, function(item, k){
30832 switch (item.size) {
30833 // these layouts take up a full box,
30844 boxes.push([item]);
30867 var filterPattern = function(box, length)
30875 var pattern = box.slice(0, length);
30879 Roo.each(pattern, function(i){
30880 format.push(i.size);
30883 Roo.each(standard, function(s){
30885 if(String(s) != String(format)){
30894 if(!match && length == 1){
30899 filterPattern(box, length - 1);
30903 queue.push(pattern);
30905 box = box.slice(length, box.length);
30907 filterPattern(box, 4);
30913 Roo.each(boxes, function(box, k){
30919 if(box.length == 1){
30924 filterPattern(box, 4);
30928 this._processVerticalLayoutQueue( queue, isInstant );
30932 // _verticalAlternativeLayoutItems : function( items , isInstant )
30934 // if ( !items || !items.length ) {
30938 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30942 _horizontalLayoutItems : function ( items , isInstant)
30944 if ( !items || !items.length || items.length < 3) {
30950 var eItems = items.slice(0, 3);
30952 items = items.slice(3, items.length);
30955 ['xs', 'xs', 'xs', 'wide'],
30956 ['xs', 'xs', 'wide'],
30957 ['xs', 'xs', 'sm'],
30958 ['xs', 'xs', 'xs'],
30964 ['sm', 'xs', 'xs'],
30968 ['wide', 'xs', 'xs', 'xs'],
30969 ['wide', 'xs', 'xs'],
30982 Roo.each(items, function(item, k){
30984 switch (item.size) {
30995 boxes.push([item]);
31019 var filterPattern = function(box, length)
31027 var pattern = box.slice(0, length);
31031 Roo.each(pattern, function(i){
31032 format.push(i.size);
31035 Roo.each(standard, function(s){
31037 if(String(s) != String(format)){
31046 if(!match && length == 1){
31051 filterPattern(box, length - 1);
31055 queue.push(pattern);
31057 box = box.slice(length, box.length);
31059 filterPattern(box, 4);
31065 Roo.each(boxes, function(box, k){
31071 if(box.length == 1){
31076 filterPattern(box, 4);
31083 var pos = this.el.getBox(true);
31087 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31089 var hit_end = false;
31091 Roo.each(queue, function(box){
31095 Roo.each(box, function(b){
31097 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31107 Roo.each(box, function(b){
31109 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31112 mx = Math.max(mx, b.x);
31116 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31120 Roo.each(box, function(b){
31122 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31136 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31139 /** Sets position of item in DOM
31140 * @param {Element} item
31141 * @param {Number} x - horizontal position
31142 * @param {Number} y - vertical position
31143 * @param {Boolean} isInstant - disables transitions
31145 _processVerticalLayoutQueue : function( queue, isInstant )
31147 var pos = this.el.getBox(true);
31152 for (var i = 0; i < this.cols; i++){
31156 Roo.each(queue, function(box, k){
31158 var col = k % this.cols;
31160 Roo.each(box, function(b,kk){
31162 b.el.position('absolute');
31164 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31165 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31167 if(b.size == 'md-left' || b.size == 'md-right'){
31168 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31169 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31172 b.el.setWidth(width);
31173 b.el.setHeight(height);
31175 b.el.select('iframe',true).setSize(width,height);
31179 for (var i = 0; i < this.cols; i++){
31181 if(maxY[i] < maxY[col]){
31186 col = Math.min(col, i);
31190 x = pos.x + col * (this.colWidth + this.padWidth);
31194 var positions = [];
31196 switch (box.length){
31198 positions = this.getVerticalOneBoxColPositions(x, y, box);
31201 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31204 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31207 positions = this.getVerticalFourBoxColPositions(x, y, box);
31213 Roo.each(box, function(b,kk){
31215 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31217 var sz = b.el.getSize();
31219 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31227 for (var i = 0; i < this.cols; i++){
31228 mY = Math.max(mY, maxY[i]);
31231 this.el.setHeight(mY - pos.y);
31235 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31237 // var pos = this.el.getBox(true);
31240 // var maxX = pos.right;
31242 // var maxHeight = 0;
31244 // Roo.each(items, function(item, k){
31248 // item.el.position('absolute');
31250 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31252 // item.el.setWidth(width);
31254 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31256 // item.el.setHeight(height);
31259 // item.el.setXY([x, y], isInstant ? false : true);
31261 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31264 // y = y + height + this.alternativePadWidth;
31266 // maxHeight = maxHeight + height + this.alternativePadWidth;
31270 // this.el.setHeight(maxHeight);
31274 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31276 var pos = this.el.getBox(true);
31281 var maxX = pos.right;
31283 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31285 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31287 Roo.each(queue, function(box, k){
31289 Roo.each(box, function(b, kk){
31291 b.el.position('absolute');
31293 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31294 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31296 if(b.size == 'md-left' || b.size == 'md-right'){
31297 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31298 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31301 b.el.setWidth(width);
31302 b.el.setHeight(height);
31310 var positions = [];
31312 switch (box.length){
31314 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31317 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31320 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31323 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31329 Roo.each(box, function(b,kk){
31331 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31333 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31341 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31343 Roo.each(eItems, function(b,k){
31345 b.size = (k == 0) ? 'sm' : 'xs';
31346 b.x = (k == 0) ? 2 : 1;
31347 b.y = (k == 0) ? 2 : 1;
31349 b.el.position('absolute');
31351 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31353 b.el.setWidth(width);
31355 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31357 b.el.setHeight(height);
31361 var positions = [];
31364 x : maxX - this.unitWidth * 2 - this.gutter,
31369 x : maxX - this.unitWidth,
31370 y : minY + (this.unitWidth + this.gutter) * 2
31374 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31378 Roo.each(eItems, function(b,k){
31380 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31386 getVerticalOneBoxColPositions : function(x, y, box)
31390 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31392 if(box[0].size == 'md-left'){
31396 if(box[0].size == 'md-right'){
31401 x : x + (this.unitWidth + this.gutter) * rand,
31408 getVerticalTwoBoxColPositions : function(x, y, box)
31412 if(box[0].size == 'xs'){
31416 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31420 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31434 x : x + (this.unitWidth + this.gutter) * 2,
31435 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31442 getVerticalThreeBoxColPositions : function(x, y, box)
31446 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31454 x : x + (this.unitWidth + this.gutter) * 1,
31459 x : x + (this.unitWidth + this.gutter) * 2,
31467 if(box[0].size == 'xs' && box[1].size == 'xs'){
31476 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31480 x : x + (this.unitWidth + this.gutter) * 1,
31494 x : x + (this.unitWidth + this.gutter) * 2,
31499 x : x + (this.unitWidth + this.gutter) * 2,
31500 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31507 getVerticalFourBoxColPositions : function(x, y, box)
31511 if(box[0].size == 'xs'){
31520 y : y + (this.unitHeight + this.gutter) * 1
31525 y : y + (this.unitHeight + this.gutter) * 2
31529 x : x + (this.unitWidth + this.gutter) * 1,
31543 x : x + (this.unitWidth + this.gutter) * 2,
31548 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31549 y : y + (this.unitHeight + this.gutter) * 1
31553 x : x + (this.unitWidth + this.gutter) * 2,
31554 y : y + (this.unitWidth + this.gutter) * 2
31561 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31565 if(box[0].size == 'md-left'){
31567 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31574 if(box[0].size == 'md-right'){
31576 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31577 y : minY + (this.unitWidth + this.gutter) * 1
31583 var rand = Math.floor(Math.random() * (4 - box[0].y));
31586 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31587 y : minY + (this.unitWidth + this.gutter) * rand
31594 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31598 if(box[0].size == 'xs'){
31601 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31606 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31607 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31615 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31620 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31621 y : minY + (this.unitWidth + this.gutter) * 2
31628 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31632 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31635 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31640 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31641 y : minY + (this.unitWidth + this.gutter) * 1
31645 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31646 y : minY + (this.unitWidth + this.gutter) * 2
31653 if(box[0].size == 'xs' && box[1].size == 'xs'){
31656 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31661 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31666 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31667 y : minY + (this.unitWidth + this.gutter) * 1
31675 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31680 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31681 y : minY + (this.unitWidth + this.gutter) * 2
31685 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31686 y : minY + (this.unitWidth + this.gutter) * 2
31693 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31697 if(box[0].size == 'xs'){
31700 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31705 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31710 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),
31715 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31716 y : minY + (this.unitWidth + this.gutter) * 1
31724 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31729 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31730 y : minY + (this.unitWidth + this.gutter) * 2
31734 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31735 y : minY + (this.unitWidth + this.gutter) * 2
31739 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),
31740 y : minY + (this.unitWidth + this.gutter) * 2
31748 * remove a Masonry Brick
31749 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31751 removeBrick : function(brick_id)
31757 for (var i = 0; i<this.bricks.length; i++) {
31758 if (this.bricks[i].id == brick_id) {
31759 this.bricks.splice(i,1);
31760 this.el.dom.removeChild(Roo.get(brick_id).dom);
31767 * adds a Masonry Brick
31768 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31770 addBrick : function(cfg)
31772 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31773 //this.register(cn);
31774 cn.parentId = this.id;
31775 cn.onRender(this.el, null);
31780 * register a Masonry Brick
31781 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31784 register : function(brick)
31786 this.bricks.push(brick);
31787 brick.masonryId = this.id;
31791 * clear all the Masonry Brick
31793 clearAll : function()
31796 //this.getChildContainer().dom.innerHTML = "";
31797 this.el.dom.innerHTML = '';
31800 getSelected : function()
31802 if (!this.selectedBrick) {
31806 return this.selectedBrick;
31810 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31814 * register a Masonry Layout
31815 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31818 register : function(layout)
31820 this.groups[layout.id] = layout;
31823 * fetch a Masonry Layout based on the masonry layout ID
31824 * @param {string} the masonry layout to add
31825 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31828 get: function(layout_id) {
31829 if (typeof(this.groups[layout_id]) == 'undefined') {
31832 return this.groups[layout_id] ;
31844 * http://masonry.desandro.com
31846 * The idea is to render all the bricks based on vertical width...
31848 * The original code extends 'outlayer' - we might need to use that....
31854 * @class Roo.bootstrap.LayoutMasonryAuto
31855 * @extends Roo.bootstrap.Component
31856 * Bootstrap Layout Masonry class
31859 * Create a new Element
31860 * @param {Object} config The config object
31863 Roo.bootstrap.LayoutMasonryAuto = function(config){
31864 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31867 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31870 * @cfg {Boolean} isFitWidth - resize the width..
31872 isFitWidth : false, // options..
31874 * @cfg {Boolean} isOriginLeft = left align?
31876 isOriginLeft : true,
31878 * @cfg {Boolean} isOriginTop = top align?
31880 isOriginTop : false,
31882 * @cfg {Boolean} isLayoutInstant = no animation?
31884 isLayoutInstant : false, // needed?
31886 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31888 isResizingContainer : true,
31890 * @cfg {Number} columnWidth width of the columns
31896 * @cfg {Number} maxCols maximum number of columns
31901 * @cfg {Number} padHeight padding below box..
31907 * @cfg {Boolean} isAutoInitial defalut true
31910 isAutoInitial : true,
31916 initialColumnWidth : 0,
31917 currentSize : null,
31919 colYs : null, // array.
31926 bricks: null, //CompositeElement
31927 cols : 0, // array?
31928 // element : null, // wrapped now this.el
31929 _isLayoutInited : null,
31932 getAutoCreate : function(){
31936 cls: 'blog-masonary-wrapper ' + this.cls,
31938 cls : 'mas-boxes masonary'
31945 getChildContainer: function( )
31947 if (this.boxesEl) {
31948 return this.boxesEl;
31951 this.boxesEl = this.el.select('.mas-boxes').first();
31953 return this.boxesEl;
31957 initEvents : function()
31961 if(this.isAutoInitial){
31962 Roo.log('hook children rendered');
31963 this.on('childrenrendered', function() {
31964 Roo.log('children rendered');
31971 initial : function()
31973 this.reloadItems();
31975 this.currentSize = this.el.getBox(true);
31977 /// was window resize... - let's see if this works..
31978 Roo.EventManager.onWindowResize(this.resize, this);
31980 if(!this.isAutoInitial){
31985 this.layout.defer(500,this);
31988 reloadItems: function()
31990 this.bricks = this.el.select('.masonry-brick', true);
31992 this.bricks.each(function(b) {
31993 //Roo.log(b.getSize());
31994 if (!b.attr('originalwidth')) {
31995 b.attr('originalwidth', b.getSize().width);
32000 Roo.log(this.bricks.elements.length);
32003 resize : function()
32006 var cs = this.el.getBox(true);
32008 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32009 Roo.log("no change in with or X");
32012 this.currentSize = cs;
32016 layout : function()
32019 this._resetLayout();
32020 //this._manageStamps();
32022 // don't animate first layout
32023 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32024 this.layoutItems( isInstant );
32026 // flag for initalized
32027 this._isLayoutInited = true;
32030 layoutItems : function( isInstant )
32032 //var items = this._getItemsForLayout( this.items );
32033 // original code supports filtering layout items.. we just ignore it..
32035 this._layoutItems( this.bricks , isInstant );
32037 this._postLayout();
32039 _layoutItems : function ( items , isInstant)
32041 //this.fireEvent( 'layout', this, items );
32044 if ( !items || !items.elements.length ) {
32045 // no items, emit event with empty array
32050 items.each(function(item) {
32051 Roo.log("layout item");
32053 // get x/y object from method
32054 var position = this._getItemLayoutPosition( item );
32056 position.item = item;
32057 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32058 queue.push( position );
32061 this._processLayoutQueue( queue );
32063 /** Sets position of item in DOM
32064 * @param {Element} item
32065 * @param {Number} x - horizontal position
32066 * @param {Number} y - vertical position
32067 * @param {Boolean} isInstant - disables transitions
32069 _processLayoutQueue : function( queue )
32071 for ( var i=0, len = queue.length; i < len; i++ ) {
32072 var obj = queue[i];
32073 obj.item.position('absolute');
32074 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32080 * Any logic you want to do after each layout,
32081 * i.e. size the container
32083 _postLayout : function()
32085 this.resizeContainer();
32088 resizeContainer : function()
32090 if ( !this.isResizingContainer ) {
32093 var size = this._getContainerSize();
32095 this.el.setSize(size.width,size.height);
32096 this.boxesEl.setSize(size.width,size.height);
32102 _resetLayout : function()
32104 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32105 this.colWidth = this.el.getWidth();
32106 //this.gutter = this.el.getWidth();
32108 this.measureColumns();
32114 this.colYs.push( 0 );
32120 measureColumns : function()
32122 this.getContainerWidth();
32123 // if columnWidth is 0, default to outerWidth of first item
32124 if ( !this.columnWidth ) {
32125 var firstItem = this.bricks.first();
32126 Roo.log(firstItem);
32127 this.columnWidth = this.containerWidth;
32128 if (firstItem && firstItem.attr('originalwidth') ) {
32129 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32131 // columnWidth fall back to item of first element
32132 Roo.log("set column width?");
32133 this.initialColumnWidth = this.columnWidth ;
32135 // if first elem has no width, default to size of container
32140 if (this.initialColumnWidth) {
32141 this.columnWidth = this.initialColumnWidth;
32146 // column width is fixed at the top - however if container width get's smaller we should
32149 // this bit calcs how man columns..
32151 var columnWidth = this.columnWidth += this.gutter;
32153 // calculate columns
32154 var containerWidth = this.containerWidth + this.gutter;
32156 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32157 // fix rounding errors, typically with gutters
32158 var excess = columnWidth - containerWidth % columnWidth;
32161 // if overshoot is less than a pixel, round up, otherwise floor it
32162 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32163 cols = Math[ mathMethod ]( cols );
32164 this.cols = Math.max( cols, 1 );
32165 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32167 // padding positioning..
32168 var totalColWidth = this.cols * this.columnWidth;
32169 var padavail = this.containerWidth - totalColWidth;
32170 // so for 2 columns - we need 3 'pads'
32172 var padNeeded = (1+this.cols) * this.padWidth;
32174 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32176 this.columnWidth += padExtra
32177 //this.padWidth = Math.floor(padavail / ( this.cols));
32179 // adjust colum width so that padding is fixed??
32181 // we have 3 columns ... total = width * 3
32182 // we have X left over... that should be used by
32184 //if (this.expandC) {
32192 getContainerWidth : function()
32194 /* // container is parent if fit width
32195 var container = this.isFitWidth ? this.element.parentNode : this.element;
32196 // check that this.size and size are there
32197 // IE8 triggers resize on body size change, so they might not be
32199 var size = getSize( container ); //FIXME
32200 this.containerWidth = size && size.innerWidth; //FIXME
32203 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32207 _getItemLayoutPosition : function( item ) // what is item?
32209 // we resize the item to our columnWidth..
32211 item.setWidth(this.columnWidth);
32212 item.autoBoxAdjust = false;
32214 var sz = item.getSize();
32216 // how many columns does this brick span
32217 var remainder = this.containerWidth % this.columnWidth;
32219 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32220 // round if off by 1 pixel, otherwise use ceil
32221 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32222 colSpan = Math.min( colSpan, this.cols );
32224 // normally this should be '1' as we dont' currently allow multi width columns..
32226 var colGroup = this._getColGroup( colSpan );
32227 // get the minimum Y value from the columns
32228 var minimumY = Math.min.apply( Math, colGroup );
32229 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32231 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32233 // position the brick
32235 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32236 y: this.currentSize.y + minimumY + this.padHeight
32240 // apply setHeight to necessary columns
32241 var setHeight = minimumY + sz.height + this.padHeight;
32242 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32244 var setSpan = this.cols + 1 - colGroup.length;
32245 for ( var i = 0; i < setSpan; i++ ) {
32246 this.colYs[ shortColIndex + i ] = setHeight ;
32253 * @param {Number} colSpan - number of columns the element spans
32254 * @returns {Array} colGroup
32256 _getColGroup : function( colSpan )
32258 if ( colSpan < 2 ) {
32259 // if brick spans only one column, use all the column Ys
32264 // how many different places could this brick fit horizontally
32265 var groupCount = this.cols + 1 - colSpan;
32266 // for each group potential horizontal position
32267 for ( var i = 0; i < groupCount; i++ ) {
32268 // make an array of colY values for that one group
32269 var groupColYs = this.colYs.slice( i, i + colSpan );
32270 // and get the max value of the array
32271 colGroup[i] = Math.max.apply( Math, groupColYs );
32276 _manageStamp : function( stamp )
32278 var stampSize = stamp.getSize();
32279 var offset = stamp.getBox();
32280 // get the columns that this stamp affects
32281 var firstX = this.isOriginLeft ? offset.x : offset.right;
32282 var lastX = firstX + stampSize.width;
32283 var firstCol = Math.floor( firstX / this.columnWidth );
32284 firstCol = Math.max( 0, firstCol );
32286 var lastCol = Math.floor( lastX / this.columnWidth );
32287 // lastCol should not go over if multiple of columnWidth #425
32288 lastCol -= lastX % this.columnWidth ? 0 : 1;
32289 lastCol = Math.min( this.cols - 1, lastCol );
32291 // set colYs to bottom of the stamp
32292 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32295 for ( var i = firstCol; i <= lastCol; i++ ) {
32296 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32301 _getContainerSize : function()
32303 this.maxY = Math.max.apply( Math, this.colYs );
32308 if ( this.isFitWidth ) {
32309 size.width = this._getContainerFitWidth();
32315 _getContainerFitWidth : function()
32317 var unusedCols = 0;
32318 // count unused columns
32321 if ( this.colYs[i] !== 0 ) {
32326 // fit container to columns that have been used
32327 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32330 needsResizeLayout : function()
32332 var previousWidth = this.containerWidth;
32333 this.getContainerWidth();
32334 return previousWidth !== this.containerWidth;
32349 * @class Roo.bootstrap.MasonryBrick
32350 * @extends Roo.bootstrap.Component
32351 * Bootstrap MasonryBrick class
32354 * Create a new MasonryBrick
32355 * @param {Object} config The config object
32358 Roo.bootstrap.MasonryBrick = function(config){
32360 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32362 Roo.bootstrap.MasonryBrick.register(this);
32368 * When a MasonryBrick is clcik
32369 * @param {Roo.bootstrap.MasonryBrick} this
32370 * @param {Roo.EventObject} e
32376 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32379 * @cfg {String} title
32383 * @cfg {String} html
32387 * @cfg {String} bgimage
32391 * @cfg {String} videourl
32395 * @cfg {String} cls
32399 * @cfg {String} href
32403 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32408 * @cfg {String} placetitle (center|bottom)
32413 * @cfg {Boolean} isFitContainer defalut true
32415 isFitContainer : true,
32418 * @cfg {Boolean} preventDefault defalut false
32420 preventDefault : false,
32423 * @cfg {Boolean} inverse defalut false
32425 maskInverse : false,
32427 getAutoCreate : function()
32429 if(!this.isFitContainer){
32430 return this.getSplitAutoCreate();
32433 var cls = 'masonry-brick masonry-brick-full';
32435 if(this.href.length){
32436 cls += ' masonry-brick-link';
32439 if(this.bgimage.length){
32440 cls += ' masonry-brick-image';
32443 if(this.maskInverse){
32444 cls += ' mask-inverse';
32447 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32448 cls += ' enable-mask';
32452 cls += ' masonry-' + this.size + '-brick';
32455 if(this.placetitle.length){
32457 switch (this.placetitle) {
32459 cls += ' masonry-center-title';
32462 cls += ' masonry-bottom-title';
32469 if(!this.html.length && !this.bgimage.length){
32470 cls += ' masonry-center-title';
32473 if(!this.html.length && this.bgimage.length){
32474 cls += ' masonry-bottom-title';
32479 cls += ' ' + this.cls;
32483 tag: (this.href.length) ? 'a' : 'div',
32488 cls: 'masonry-brick-mask'
32492 cls: 'masonry-brick-paragraph',
32498 if(this.href.length){
32499 cfg.href = this.href;
32502 var cn = cfg.cn[1].cn;
32504 if(this.title.length){
32507 cls: 'masonry-brick-title',
32512 if(this.html.length){
32515 cls: 'masonry-brick-text',
32520 if (!this.title.length && !this.html.length) {
32521 cfg.cn[1].cls += ' hide';
32524 if(this.bgimage.length){
32527 cls: 'masonry-brick-image-view',
32532 if(this.videourl.length){
32533 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32534 // youtube support only?
32537 cls: 'masonry-brick-image-view',
32540 allowfullscreen : true
32548 getSplitAutoCreate : function()
32550 var cls = 'masonry-brick masonry-brick-split';
32552 if(this.href.length){
32553 cls += ' masonry-brick-link';
32556 if(this.bgimage.length){
32557 cls += ' masonry-brick-image';
32561 cls += ' masonry-' + this.size + '-brick';
32564 switch (this.placetitle) {
32566 cls += ' masonry-center-title';
32569 cls += ' masonry-bottom-title';
32572 if(!this.bgimage.length){
32573 cls += ' masonry-center-title';
32576 if(this.bgimage.length){
32577 cls += ' masonry-bottom-title';
32583 cls += ' ' + this.cls;
32587 tag: (this.href.length) ? 'a' : 'div',
32592 cls: 'masonry-brick-split-head',
32596 cls: 'masonry-brick-paragraph',
32603 cls: 'masonry-brick-split-body',
32609 if(this.href.length){
32610 cfg.href = this.href;
32613 if(this.title.length){
32614 cfg.cn[0].cn[0].cn.push({
32616 cls: 'masonry-brick-title',
32621 if(this.html.length){
32622 cfg.cn[1].cn.push({
32624 cls: 'masonry-brick-text',
32629 if(this.bgimage.length){
32630 cfg.cn[0].cn.push({
32632 cls: 'masonry-brick-image-view',
32637 if(this.videourl.length){
32638 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32639 // youtube support only?
32640 cfg.cn[0].cn.cn.push({
32642 cls: 'masonry-brick-image-view',
32645 allowfullscreen : true
32652 initEvents: function()
32654 switch (this.size) {
32687 this.el.on('touchstart', this.onTouchStart, this);
32688 this.el.on('touchmove', this.onTouchMove, this);
32689 this.el.on('touchend', this.onTouchEnd, this);
32690 this.el.on('contextmenu', this.onContextMenu, this);
32692 this.el.on('mouseenter' ,this.enter, this);
32693 this.el.on('mouseleave', this.leave, this);
32694 this.el.on('click', this.onClick, this);
32697 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32698 this.parent().bricks.push(this);
32703 onClick: function(e, el)
32705 var time = this.endTimer - this.startTimer;
32706 // Roo.log(e.preventDefault());
32709 e.preventDefault();
32714 if(!this.preventDefault){
32718 e.preventDefault();
32720 if (this.activcClass != '') {
32721 this.selectBrick();
32724 this.fireEvent('click', this);
32727 enter: function(e, el)
32729 e.preventDefault();
32731 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32735 if(this.bgimage.length && this.html.length){
32736 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32740 leave: function(e, el)
32742 e.preventDefault();
32744 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32748 if(this.bgimage.length && this.html.length){
32749 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32753 onTouchStart: function(e, el)
32755 // e.preventDefault();
32757 this.touchmoved = false;
32759 if(!this.isFitContainer){
32763 if(!this.bgimage.length || !this.html.length){
32767 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32769 this.timer = new Date().getTime();
32773 onTouchMove: function(e, el)
32775 this.touchmoved = true;
32778 onContextMenu : function(e,el)
32780 e.preventDefault();
32781 e.stopPropagation();
32785 onTouchEnd: function(e, el)
32787 // e.preventDefault();
32789 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32796 if(!this.bgimage.length || !this.html.length){
32798 if(this.href.length){
32799 window.location.href = this.href;
32805 if(!this.isFitContainer){
32809 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32811 window.location.href = this.href;
32814 //selection on single brick only
32815 selectBrick : function() {
32817 if (!this.parentId) {
32821 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32822 var index = m.selectedBrick.indexOf(this.id);
32825 m.selectedBrick.splice(index,1);
32826 this.el.removeClass(this.activeClass);
32830 for(var i = 0; i < m.selectedBrick.length; i++) {
32831 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32832 b.el.removeClass(b.activeClass);
32835 m.selectedBrick = [];
32837 m.selectedBrick.push(this.id);
32838 this.el.addClass(this.activeClass);
32844 Roo.apply(Roo.bootstrap.MasonryBrick, {
32847 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32849 * register a Masonry Brick
32850 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32853 register : function(brick)
32855 //this.groups[brick.id] = brick;
32856 this.groups.add(brick.id, brick);
32859 * fetch a masonry brick based on the masonry brick ID
32860 * @param {string} the masonry brick to add
32861 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32864 get: function(brick_id)
32866 // if (typeof(this.groups[brick_id]) == 'undefined') {
32869 // return this.groups[brick_id] ;
32871 if(this.groups.key(brick_id)) {
32872 return this.groups.key(brick_id);
32890 * @class Roo.bootstrap.Brick
32891 * @extends Roo.bootstrap.Component
32892 * Bootstrap Brick class
32895 * Create a new Brick
32896 * @param {Object} config The config object
32899 Roo.bootstrap.Brick = function(config){
32900 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32906 * When a Brick is click
32907 * @param {Roo.bootstrap.Brick} this
32908 * @param {Roo.EventObject} e
32914 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32917 * @cfg {String} title
32921 * @cfg {String} html
32925 * @cfg {String} bgimage
32929 * @cfg {String} cls
32933 * @cfg {String} href
32937 * @cfg {String} video
32941 * @cfg {Boolean} square
32945 getAutoCreate : function()
32947 var cls = 'roo-brick';
32949 if(this.href.length){
32950 cls += ' roo-brick-link';
32953 if(this.bgimage.length){
32954 cls += ' roo-brick-image';
32957 if(!this.html.length && !this.bgimage.length){
32958 cls += ' roo-brick-center-title';
32961 if(!this.html.length && this.bgimage.length){
32962 cls += ' roo-brick-bottom-title';
32966 cls += ' ' + this.cls;
32970 tag: (this.href.length) ? 'a' : 'div',
32975 cls: 'roo-brick-paragraph',
32981 if(this.href.length){
32982 cfg.href = this.href;
32985 var cn = cfg.cn[0].cn;
32987 if(this.title.length){
32990 cls: 'roo-brick-title',
32995 if(this.html.length){
32998 cls: 'roo-brick-text',
33005 if(this.bgimage.length){
33008 cls: 'roo-brick-image-view',
33016 initEvents: function()
33018 if(this.title.length || this.html.length){
33019 this.el.on('mouseenter' ,this.enter, this);
33020 this.el.on('mouseleave', this.leave, this);
33023 Roo.EventManager.onWindowResize(this.resize, this);
33025 if(this.bgimage.length){
33026 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33027 this.imageEl.on('load', this.onImageLoad, this);
33034 onImageLoad : function()
33039 resize : function()
33041 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33043 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33045 if(this.bgimage.length){
33046 var image = this.el.select('.roo-brick-image-view', true).first();
33048 image.setWidth(paragraph.getWidth());
33051 image.setHeight(paragraph.getWidth());
33054 this.el.setHeight(image.getHeight());
33055 paragraph.setHeight(image.getHeight());
33061 enter: function(e, el)
33063 e.preventDefault();
33065 if(this.bgimage.length){
33066 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33067 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33071 leave: function(e, el)
33073 e.preventDefault();
33075 if(this.bgimage.length){
33076 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33077 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33092 * @class Roo.bootstrap.NumberField
33093 * @extends Roo.bootstrap.Input
33094 * Bootstrap NumberField class
33100 * Create a new NumberField
33101 * @param {Object} config The config object
33104 Roo.bootstrap.NumberField = function(config){
33105 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33108 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33111 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33113 allowDecimals : true,
33115 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33117 decimalSeparator : ".",
33119 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33121 decimalPrecision : 2,
33123 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33125 allowNegative : true,
33128 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33132 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33134 minValue : Number.NEGATIVE_INFINITY,
33136 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33138 maxValue : Number.MAX_VALUE,
33140 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33142 minText : "The minimum value for this field is {0}",
33144 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33146 maxText : "The maximum value for this field is {0}",
33148 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33149 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33151 nanText : "{0} is not a valid number",
33153 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33157 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33159 thousandsDelimiter : false,
33161 * @cfg {String} valueAlign alignment of value
33163 valueAlign : "left",
33165 getAutoCreate : function()
33167 var hiddenInput = {
33171 cls: 'hidden-number-input'
33175 hiddenInput.name = this.name;
33180 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33182 this.name = hiddenInput.name;
33184 if(cfg.cn.length > 0) {
33185 cfg.cn.push(hiddenInput);
33192 initEvents : function()
33194 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33196 var allowed = "0123456789";
33198 if(this.allowDecimals){
33199 allowed += this.decimalSeparator;
33202 if(this.allowNegative){
33206 if(this.thousandsDelimiter) {
33210 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33212 var keyPress = function(e){
33214 var k = e.getKey();
33216 var c = e.getCharCode();
33219 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33220 allowed.indexOf(String.fromCharCode(c)) === -1
33226 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33230 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33235 this.el.on("keypress", keyPress, this);
33238 validateValue : function(value)
33241 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33245 var num = this.parseValue(value);
33248 this.markInvalid(String.format(this.nanText, value));
33252 if(num < this.minValue){
33253 this.markInvalid(String.format(this.minText, this.minValue));
33257 if(num > this.maxValue){
33258 this.markInvalid(String.format(this.maxText, this.maxValue));
33265 getValue : function()
33267 var v = this.hiddenEl().getValue();
33269 return this.fixPrecision(this.parseValue(v));
33272 parseValue : function(value)
33274 if(this.thousandsDelimiter) {
33276 r = new RegExp(",", "g");
33277 value = value.replace(r, "");
33280 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33281 return isNaN(value) ? '' : value;
33284 fixPrecision : function(value)
33286 if(this.thousandsDelimiter) {
33288 r = new RegExp(",", "g");
33289 value = value.replace(r, "");
33292 var nan = isNaN(value);
33294 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33295 return nan ? '' : value;
33297 return parseFloat(value).toFixed(this.decimalPrecision);
33300 setValue : function(v)
33302 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33308 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33310 this.inputEl().dom.value = (v == '') ? '' :
33311 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33313 if(!this.allowZero && v === '0') {
33314 this.hiddenEl().dom.value = '';
33315 this.inputEl().dom.value = '';
33322 decimalPrecisionFcn : function(v)
33324 return Math.floor(v);
33327 beforeBlur : function()
33333 var v = this.parseValue(this.getRawValue());
33340 hiddenEl : function()
33342 return this.el.select('input.hidden-number-input',true).first();
33354 * @class Roo.bootstrap.DocumentSlider
33355 * @extends Roo.bootstrap.Component
33356 * Bootstrap DocumentSlider class
33359 * Create a new DocumentViewer
33360 * @param {Object} config The config object
33363 Roo.bootstrap.DocumentSlider = function(config){
33364 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33371 * Fire after initEvent
33372 * @param {Roo.bootstrap.DocumentSlider} this
33377 * Fire after update
33378 * @param {Roo.bootstrap.DocumentSlider} this
33384 * @param {Roo.bootstrap.DocumentSlider} this
33390 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33396 getAutoCreate : function()
33400 cls : 'roo-document-slider',
33404 cls : 'roo-document-slider-header',
33408 cls : 'roo-document-slider-header-title'
33414 cls : 'roo-document-slider-body',
33418 cls : 'roo-document-slider-prev',
33422 cls : 'fa fa-chevron-left'
33428 cls : 'roo-document-slider-thumb',
33432 cls : 'roo-document-slider-image'
33438 cls : 'roo-document-slider-next',
33442 cls : 'fa fa-chevron-right'
33454 initEvents : function()
33456 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33457 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33459 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33460 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33462 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33463 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33465 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33466 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33468 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33469 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33471 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33472 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33474 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33475 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33477 this.thumbEl.on('click', this.onClick, this);
33479 this.prevIndicator.on('click', this.prev, this);
33481 this.nextIndicator.on('click', this.next, this);
33485 initial : function()
33487 if(this.files.length){
33488 this.indicator = 1;
33492 this.fireEvent('initial', this);
33495 update : function()
33497 this.imageEl.attr('src', this.files[this.indicator - 1]);
33499 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33501 this.prevIndicator.show();
33503 if(this.indicator == 1){
33504 this.prevIndicator.hide();
33507 this.nextIndicator.show();
33509 if(this.indicator == this.files.length){
33510 this.nextIndicator.hide();
33513 this.thumbEl.scrollTo('top');
33515 this.fireEvent('update', this);
33518 onClick : function(e)
33520 e.preventDefault();
33522 this.fireEvent('click', this);
33527 e.preventDefault();
33529 this.indicator = Math.max(1, this.indicator - 1);
33536 e.preventDefault();
33538 this.indicator = Math.min(this.files.length, this.indicator + 1);
33552 * @class Roo.bootstrap.RadioSet
33553 * @extends Roo.bootstrap.Input
33554 * Bootstrap RadioSet class
33555 * @cfg {String} indicatorpos (left|right) default left
33556 * @cfg {Boolean} inline (true|false) inline the element (default true)
33557 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33559 * Create a new RadioSet
33560 * @param {Object} config The config object
33563 Roo.bootstrap.RadioSet = function(config){
33565 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33569 Roo.bootstrap.RadioSet.register(this);
33574 * Fires when the element is checked or unchecked.
33575 * @param {Roo.bootstrap.RadioSet} this This radio
33576 * @param {Roo.bootstrap.Radio} item The checked item
33581 * Fires when the element is click.
33582 * @param {Roo.bootstrap.RadioSet} this This radio set
33583 * @param {Roo.bootstrap.Radio} item The checked item
33584 * @param {Roo.EventObject} e The event object
33591 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33599 indicatorpos : 'left',
33601 getAutoCreate : function()
33605 cls : 'roo-radio-set-label',
33609 html : this.fieldLabel
33614 if(this.indicatorpos == 'left'){
33617 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33618 tooltip : 'This field is required'
33623 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33624 tooltip : 'This field is required'
33630 cls : 'roo-radio-set-items'
33633 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33635 if (align === 'left' && this.fieldLabel.length) {
33638 cls : "roo-radio-set-right",
33644 if(this.labelWidth > 12){
33645 label.style = "width: " + this.labelWidth + 'px';
33648 if(this.labelWidth < 13 && this.labelmd == 0){
33649 this.labelmd = this.labelWidth;
33652 if(this.labellg > 0){
33653 label.cls += ' col-lg-' + this.labellg;
33654 items.cls += ' col-lg-' + (12 - this.labellg);
33657 if(this.labelmd > 0){
33658 label.cls += ' col-md-' + this.labelmd;
33659 items.cls += ' col-md-' + (12 - this.labelmd);
33662 if(this.labelsm > 0){
33663 label.cls += ' col-sm-' + this.labelsm;
33664 items.cls += ' col-sm-' + (12 - this.labelsm);
33667 if(this.labelxs > 0){
33668 label.cls += ' col-xs-' + this.labelxs;
33669 items.cls += ' col-xs-' + (12 - this.labelxs);
33675 cls : 'roo-radio-set',
33679 cls : 'roo-radio-set-input',
33682 value : this.value ? this.value : ''
33689 if(this.weight.length){
33690 cfg.cls += ' roo-radio-' + this.weight;
33694 cfg.cls += ' roo-radio-set-inline';
33698 ['xs','sm','md','lg'].map(function(size){
33699 if (settings[size]) {
33700 cfg.cls += ' col-' + size + '-' + settings[size];
33708 initEvents : function()
33710 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33711 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33713 if(!this.fieldLabel.length){
33714 this.labelEl.hide();
33717 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33718 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33720 this.indicatorEl().addClass('invisible');
33722 this.originalValue = this.getValue();
33726 inputEl: function ()
33728 return this.el.select('.roo-radio-set-input', true).first();
33731 getChildContainer : function()
33733 return this.itemsEl;
33736 register : function(item)
33738 this.radioes.push(item);
33742 validate : function()
33744 if(this.getEl().hasClass('hidden')){
33750 Roo.each(this.radioes, function(i){
33759 if(this.allowBlank) {
33763 if(this.disabled || valid){
33768 this.markInvalid();
33773 markValid : function()
33775 if(this.labelEl.isVisible(true)){
33776 this.indicatorEl().removeClass('visible');
33777 this.indicatorEl().addClass('invisible');
33780 this.el.removeClass([this.invalidClass, this.validClass]);
33781 this.el.addClass(this.validClass);
33783 this.fireEvent('valid', this);
33786 markInvalid : function(msg)
33788 if(this.allowBlank || this.disabled){
33792 if(this.labelEl.isVisible(true)){
33793 this.indicatorEl().removeClass('invisible');
33794 this.indicatorEl().addClass('visible');
33797 this.el.removeClass([this.invalidClass, this.validClass]);
33798 this.el.addClass(this.invalidClass);
33800 this.fireEvent('invalid', this, msg);
33804 setValue : function(v, suppressEvent)
33806 if(this.value === v){
33813 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33816 Roo.each(this.radioes, function(i){
33818 i.el.removeClass('checked');
33821 Roo.each(this.radioes, function(i){
33823 if(i.value === v || i.value.toString() === v.toString()){
33825 i.el.addClass('checked');
33827 if(suppressEvent !== true){
33828 this.fireEvent('check', this, i);
33839 clearInvalid : function(){
33841 if(!this.el || this.preventMark){
33845 this.el.removeClass([this.invalidClass]);
33847 this.fireEvent('valid', this);
33852 Roo.apply(Roo.bootstrap.RadioSet, {
33856 register : function(set)
33858 this.groups[set.name] = set;
33861 get: function(name)
33863 if (typeof(this.groups[name]) == 'undefined') {
33867 return this.groups[name] ;
33873 * Ext JS Library 1.1.1
33874 * Copyright(c) 2006-2007, Ext JS, LLC.
33876 * Originally Released Under LGPL - original licence link has changed is not relivant.
33879 * <script type="text/javascript">
33884 * @class Roo.bootstrap.SplitBar
33885 * @extends Roo.util.Observable
33886 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33890 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33891 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33892 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33893 split.minSize = 100;
33894 split.maxSize = 600;
33895 split.animate = true;
33896 split.on('moved', splitterMoved);
33899 * Create a new SplitBar
33900 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33901 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33902 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33903 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33904 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33905 position of the SplitBar).
33907 Roo.bootstrap.SplitBar = function(cfg){
33912 // dragElement : elm
33913 // resizingElement: el,
33915 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33916 // placement : Roo.bootstrap.SplitBar.LEFT ,
33917 // existingProxy ???
33920 this.el = Roo.get(cfg.dragElement, true);
33921 this.el.dom.unselectable = "on";
33923 this.resizingEl = Roo.get(cfg.resizingElement, true);
33927 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33928 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33931 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33934 * The minimum size of the resizing element. (Defaults to 0)
33940 * The maximum size of the resizing element. (Defaults to 2000)
33943 this.maxSize = 2000;
33946 * Whether to animate the transition to the new size
33949 this.animate = false;
33952 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33955 this.useShim = false;
33960 if(!cfg.existingProxy){
33962 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33964 this.proxy = Roo.get(cfg.existingProxy).dom;
33967 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33970 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33973 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33976 this.dragSpecs = {};
33979 * @private The adapter to use to positon and resize elements
33981 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33982 this.adapter.init(this);
33984 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33986 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33987 this.el.addClass("roo-splitbar-h");
33990 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33991 this.el.addClass("roo-splitbar-v");
33997 * Fires when the splitter is moved (alias for {@link #event-moved})
33998 * @param {Roo.bootstrap.SplitBar} this
33999 * @param {Number} newSize the new width or height
34004 * Fires when the splitter is moved
34005 * @param {Roo.bootstrap.SplitBar} this
34006 * @param {Number} newSize the new width or height
34010 * @event beforeresize
34011 * Fires before the splitter is dragged
34012 * @param {Roo.bootstrap.SplitBar} this
34014 "beforeresize" : true,
34016 "beforeapply" : true
34019 Roo.util.Observable.call(this);
34022 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34023 onStartProxyDrag : function(x, y){
34024 this.fireEvent("beforeresize", this);
34026 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34028 o.enableDisplayMode("block");
34029 // all splitbars share the same overlay
34030 Roo.bootstrap.SplitBar.prototype.overlay = o;
34032 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34033 this.overlay.show();
34034 Roo.get(this.proxy).setDisplayed("block");
34035 var size = this.adapter.getElementSize(this);
34036 this.activeMinSize = this.getMinimumSize();;
34037 this.activeMaxSize = this.getMaximumSize();;
34038 var c1 = size - this.activeMinSize;
34039 var c2 = Math.max(this.activeMaxSize - size, 0);
34040 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34041 this.dd.resetConstraints();
34042 this.dd.setXConstraint(
34043 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34044 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34046 this.dd.setYConstraint(0, 0);
34048 this.dd.resetConstraints();
34049 this.dd.setXConstraint(0, 0);
34050 this.dd.setYConstraint(
34051 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34052 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34055 this.dragSpecs.startSize = size;
34056 this.dragSpecs.startPoint = [x, y];
34057 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34061 * @private Called after the drag operation by the DDProxy
34063 onEndProxyDrag : function(e){
34064 Roo.get(this.proxy).setDisplayed(false);
34065 var endPoint = Roo.lib.Event.getXY(e);
34067 this.overlay.hide();
34070 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34071 newSize = this.dragSpecs.startSize +
34072 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34073 endPoint[0] - this.dragSpecs.startPoint[0] :
34074 this.dragSpecs.startPoint[0] - endPoint[0]
34077 newSize = this.dragSpecs.startSize +
34078 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34079 endPoint[1] - this.dragSpecs.startPoint[1] :
34080 this.dragSpecs.startPoint[1] - endPoint[1]
34083 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34084 if(newSize != this.dragSpecs.startSize){
34085 if(this.fireEvent('beforeapply', this, newSize) !== false){
34086 this.adapter.setElementSize(this, newSize);
34087 this.fireEvent("moved", this, newSize);
34088 this.fireEvent("resize", this, newSize);
34094 * Get the adapter this SplitBar uses
34095 * @return The adapter object
34097 getAdapter : function(){
34098 return this.adapter;
34102 * Set the adapter this SplitBar uses
34103 * @param {Object} adapter A SplitBar adapter object
34105 setAdapter : function(adapter){
34106 this.adapter = adapter;
34107 this.adapter.init(this);
34111 * Gets the minimum size for the resizing element
34112 * @return {Number} The minimum size
34114 getMinimumSize : function(){
34115 return this.minSize;
34119 * Sets the minimum size for the resizing element
34120 * @param {Number} minSize The minimum size
34122 setMinimumSize : function(minSize){
34123 this.minSize = minSize;
34127 * Gets the maximum size for the resizing element
34128 * @return {Number} The maximum size
34130 getMaximumSize : function(){
34131 return this.maxSize;
34135 * Sets the maximum size for the resizing element
34136 * @param {Number} maxSize The maximum size
34138 setMaximumSize : function(maxSize){
34139 this.maxSize = maxSize;
34143 * Sets the initialize size for the resizing element
34144 * @param {Number} size The initial size
34146 setCurrentSize : function(size){
34147 var oldAnimate = this.animate;
34148 this.animate = false;
34149 this.adapter.setElementSize(this, size);
34150 this.animate = oldAnimate;
34154 * Destroy this splitbar.
34155 * @param {Boolean} removeEl True to remove the element
34157 destroy : function(removeEl){
34159 this.shim.remove();
34162 this.proxy.parentNode.removeChild(this.proxy);
34170 * @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.
34172 Roo.bootstrap.SplitBar.createProxy = function(dir){
34173 var proxy = new Roo.Element(document.createElement("div"));
34174 proxy.unselectable();
34175 var cls = 'roo-splitbar-proxy';
34176 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34177 document.body.appendChild(proxy.dom);
34182 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34183 * Default Adapter. It assumes the splitter and resizing element are not positioned
34184 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34186 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34189 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34190 // do nothing for now
34191 init : function(s){
34195 * Called before drag operations to get the current size of the resizing element.
34196 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34198 getElementSize : function(s){
34199 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34200 return s.resizingEl.getWidth();
34202 return s.resizingEl.getHeight();
34207 * Called after drag operations to set the size of the resizing element.
34208 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34209 * @param {Number} newSize The new size to set
34210 * @param {Function} onComplete A function to be invoked when resizing is complete
34212 setElementSize : function(s, newSize, onComplete){
34213 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34215 s.resizingEl.setWidth(newSize);
34217 onComplete(s, newSize);
34220 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34225 s.resizingEl.setHeight(newSize);
34227 onComplete(s, newSize);
34230 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34237 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34238 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34239 * Adapter that moves the splitter element to align with the resized sizing element.
34240 * Used with an absolute positioned SplitBar.
34241 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34242 * document.body, make sure you assign an id to the body element.
34244 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34245 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34246 this.container = Roo.get(container);
34249 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34250 init : function(s){
34251 this.basic.init(s);
34254 getElementSize : function(s){
34255 return this.basic.getElementSize(s);
34258 setElementSize : function(s, newSize, onComplete){
34259 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34262 moveSplitter : function(s){
34263 var yes = Roo.bootstrap.SplitBar;
34264 switch(s.placement){
34266 s.el.setX(s.resizingEl.getRight());
34269 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34272 s.el.setY(s.resizingEl.getBottom());
34275 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34282 * Orientation constant - Create a vertical SplitBar
34286 Roo.bootstrap.SplitBar.VERTICAL = 1;
34289 * Orientation constant - Create a horizontal SplitBar
34293 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34296 * Placement constant - The resizing element is to the left of the splitter element
34300 Roo.bootstrap.SplitBar.LEFT = 1;
34303 * Placement constant - The resizing element is to the right of the splitter element
34307 Roo.bootstrap.SplitBar.RIGHT = 2;
34310 * Placement constant - The resizing element is positioned above the splitter element
34314 Roo.bootstrap.SplitBar.TOP = 3;
34317 * Placement constant - The resizing element is positioned under splitter element
34321 Roo.bootstrap.SplitBar.BOTTOM = 4;
34322 Roo.namespace("Roo.bootstrap.layout");/*
34324 * Ext JS Library 1.1.1
34325 * Copyright(c) 2006-2007, Ext JS, LLC.
34327 * Originally Released Under LGPL - original licence link has changed is not relivant.
34330 * <script type="text/javascript">
34334 * @class Roo.bootstrap.layout.Manager
34335 * @extends Roo.bootstrap.Component
34336 * Base class for layout managers.
34338 Roo.bootstrap.layout.Manager = function(config)
34340 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34346 /** false to disable window resize monitoring @type Boolean */
34347 this.monitorWindowResize = true;
34352 * Fires when a layout is performed.
34353 * @param {Roo.LayoutManager} this
34357 * @event regionresized
34358 * Fires when the user resizes a region.
34359 * @param {Roo.LayoutRegion} region The resized region
34360 * @param {Number} newSize The new size (width for east/west, height for north/south)
34362 "regionresized" : true,
34364 * @event regioncollapsed
34365 * Fires when a region is collapsed.
34366 * @param {Roo.LayoutRegion} region The collapsed region
34368 "regioncollapsed" : true,
34370 * @event regionexpanded
34371 * Fires when a region is expanded.
34372 * @param {Roo.LayoutRegion} region The expanded region
34374 "regionexpanded" : true
34376 this.updating = false;
34379 this.el = Roo.get(config.el);
34385 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34390 monitorWindowResize : true,
34396 onRender : function(ct, position)
34399 this.el = Roo.get(ct);
34402 //this.fireEvent('render',this);
34406 initEvents: function()
34410 // ie scrollbar fix
34411 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34412 document.body.scroll = "no";
34413 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34414 this.el.position('relative');
34416 this.id = this.el.id;
34417 this.el.addClass("roo-layout-container");
34418 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34419 if(this.el.dom != document.body ) {
34420 this.el.on('resize', this.layout,this);
34421 this.el.on('show', this.layout,this);
34427 * Returns true if this layout is currently being updated
34428 * @return {Boolean}
34430 isUpdating : function(){
34431 return this.updating;
34435 * Suspend the LayoutManager from doing auto-layouts while
34436 * making multiple add or remove calls
34438 beginUpdate : function(){
34439 this.updating = true;
34443 * Restore auto-layouts and optionally disable the manager from performing a layout
34444 * @param {Boolean} noLayout true to disable a layout update
34446 endUpdate : function(noLayout){
34447 this.updating = false;
34453 layout: function(){
34457 onRegionResized : function(region, newSize){
34458 this.fireEvent("regionresized", region, newSize);
34462 onRegionCollapsed : function(region){
34463 this.fireEvent("regioncollapsed", region);
34466 onRegionExpanded : function(region){
34467 this.fireEvent("regionexpanded", region);
34471 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34472 * performs box-model adjustments.
34473 * @return {Object} The size as an object {width: (the width), height: (the height)}
34475 getViewSize : function()
34478 if(this.el.dom != document.body){
34479 size = this.el.getSize();
34481 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34483 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34484 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34489 * Returns the Element this layout is bound to.
34490 * @return {Roo.Element}
34492 getEl : function(){
34497 * Returns the specified region.
34498 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34499 * @return {Roo.LayoutRegion}
34501 getRegion : function(target){
34502 return this.regions[target.toLowerCase()];
34505 onWindowResize : function(){
34506 if(this.monitorWindowResize){
34513 * Ext JS Library 1.1.1
34514 * Copyright(c) 2006-2007, Ext JS, LLC.
34516 * Originally Released Under LGPL - original licence link has changed is not relivant.
34519 * <script type="text/javascript">
34522 * @class Roo.bootstrap.layout.Border
34523 * @extends Roo.bootstrap.layout.Manager
34524 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34525 * please see: examples/bootstrap/nested.html<br><br>
34527 <b>The container the layout is rendered into can be either the body element or any other element.
34528 If it is not the body element, the container needs to either be an absolute positioned element,
34529 or you will need to add "position:relative" to the css of the container. You will also need to specify
34530 the container size if it is not the body element.</b>
34533 * Create a new Border
34534 * @param {Object} config Configuration options
34536 Roo.bootstrap.layout.Border = function(config){
34537 config = config || {};
34538 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34542 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34543 if(config[region]){
34544 config[region].region = region;
34545 this.addRegion(config[region]);
34551 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34553 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34555 * Creates and adds a new region if it doesn't already exist.
34556 * @param {String} target The target region key (north, south, east, west or center).
34557 * @param {Object} config The regions config object
34558 * @return {BorderLayoutRegion} The new region
34560 addRegion : function(config)
34562 if(!this.regions[config.region]){
34563 var r = this.factory(config);
34564 this.bindRegion(r);
34566 return this.regions[config.region];
34570 bindRegion : function(r){
34571 this.regions[r.config.region] = r;
34573 r.on("visibilitychange", this.layout, this);
34574 r.on("paneladded", this.layout, this);
34575 r.on("panelremoved", this.layout, this);
34576 r.on("invalidated", this.layout, this);
34577 r.on("resized", this.onRegionResized, this);
34578 r.on("collapsed", this.onRegionCollapsed, this);
34579 r.on("expanded", this.onRegionExpanded, this);
34583 * Performs a layout update.
34585 layout : function()
34587 if(this.updating) {
34591 // render all the rebions if they have not been done alreayd?
34592 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34593 if(this.regions[region] && !this.regions[region].bodyEl){
34594 this.regions[region].onRender(this.el)
34598 var size = this.getViewSize();
34599 var w = size.width;
34600 var h = size.height;
34605 //var x = 0, y = 0;
34607 var rs = this.regions;
34608 var north = rs["north"];
34609 var south = rs["south"];
34610 var west = rs["west"];
34611 var east = rs["east"];
34612 var center = rs["center"];
34613 //if(this.hideOnLayout){ // not supported anymore
34614 //c.el.setStyle("display", "none");
34616 if(north && north.isVisible()){
34617 var b = north.getBox();
34618 var m = north.getMargins();
34619 b.width = w - (m.left+m.right);
34622 centerY = b.height + b.y + m.bottom;
34623 centerH -= centerY;
34624 north.updateBox(this.safeBox(b));
34626 if(south && south.isVisible()){
34627 var b = south.getBox();
34628 var m = south.getMargins();
34629 b.width = w - (m.left+m.right);
34631 var totalHeight = (b.height + m.top + m.bottom);
34632 b.y = h - totalHeight + m.top;
34633 centerH -= totalHeight;
34634 south.updateBox(this.safeBox(b));
34636 if(west && west.isVisible()){
34637 var b = west.getBox();
34638 var m = west.getMargins();
34639 b.height = centerH - (m.top+m.bottom);
34641 b.y = centerY + m.top;
34642 var totalWidth = (b.width + m.left + m.right);
34643 centerX += totalWidth;
34644 centerW -= totalWidth;
34645 west.updateBox(this.safeBox(b));
34647 if(east && east.isVisible()){
34648 var b = east.getBox();
34649 var m = east.getMargins();
34650 b.height = centerH - (m.top+m.bottom);
34651 var totalWidth = (b.width + m.left + m.right);
34652 b.x = w - totalWidth + m.left;
34653 b.y = centerY + m.top;
34654 centerW -= totalWidth;
34655 east.updateBox(this.safeBox(b));
34658 var m = center.getMargins();
34660 x: centerX + m.left,
34661 y: centerY + m.top,
34662 width: centerW - (m.left+m.right),
34663 height: centerH - (m.top+m.bottom)
34665 //if(this.hideOnLayout){
34666 //center.el.setStyle("display", "block");
34668 center.updateBox(this.safeBox(centerBox));
34671 this.fireEvent("layout", this);
34675 safeBox : function(box){
34676 box.width = Math.max(0, box.width);
34677 box.height = Math.max(0, box.height);
34682 * Adds a ContentPanel (or subclass) to this layout.
34683 * @param {String} target The target region key (north, south, east, west or center).
34684 * @param {Roo.ContentPanel} panel The panel to add
34685 * @return {Roo.ContentPanel} The added panel
34687 add : function(target, panel){
34689 target = target.toLowerCase();
34690 return this.regions[target].add(panel);
34694 * Remove a ContentPanel (or subclass) to this layout.
34695 * @param {String} target The target region key (north, south, east, west or center).
34696 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34697 * @return {Roo.ContentPanel} The removed panel
34699 remove : function(target, panel){
34700 target = target.toLowerCase();
34701 return this.regions[target].remove(panel);
34705 * Searches all regions for a panel with the specified id
34706 * @param {String} panelId
34707 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34709 findPanel : function(panelId){
34710 var rs = this.regions;
34711 for(var target in rs){
34712 if(typeof rs[target] != "function"){
34713 var p = rs[target].getPanel(panelId);
34723 * Searches all regions for a panel with the specified id and activates (shows) it.
34724 * @param {String/ContentPanel} panelId The panels id or the panel itself
34725 * @return {Roo.ContentPanel} The shown panel or null
34727 showPanel : function(panelId) {
34728 var rs = this.regions;
34729 for(var target in rs){
34730 var r = rs[target];
34731 if(typeof r != "function"){
34732 if(r.hasPanel(panelId)){
34733 return r.showPanel(panelId);
34741 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34742 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34745 restoreState : function(provider){
34747 provider = Roo.state.Manager;
34749 var sm = new Roo.LayoutStateManager();
34750 sm.init(this, provider);
34756 * Adds a xtype elements to the layout.
34760 xtype : 'ContentPanel',
34767 xtype : 'NestedLayoutPanel',
34773 items : [ ... list of content panels or nested layout panels.. ]
34777 * @param {Object} cfg Xtype definition of item to add.
34779 addxtype : function(cfg)
34781 // basically accepts a pannel...
34782 // can accept a layout region..!?!?
34783 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34786 // theory? children can only be panels??
34788 //if (!cfg.xtype.match(/Panel$/)) {
34793 if (typeof(cfg.region) == 'undefined') {
34794 Roo.log("Failed to add Panel, region was not set");
34798 var region = cfg.region;
34804 xitems = cfg.items;
34811 case 'Content': // ContentPanel (el, cfg)
34812 case 'Scroll': // ContentPanel (el, cfg)
34814 cfg.autoCreate = true;
34815 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34817 // var el = this.el.createChild();
34818 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34821 this.add(region, ret);
34825 case 'TreePanel': // our new panel!
34826 cfg.el = this.el.createChild();
34827 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34828 this.add(region, ret);
34833 // create a new Layout (which is a Border Layout...
34835 var clayout = cfg.layout;
34836 clayout.el = this.el.createChild();
34837 clayout.items = clayout.items || [];
34841 // replace this exitems with the clayout ones..
34842 xitems = clayout.items;
34844 // force background off if it's in center...
34845 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34846 cfg.background = false;
34848 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34851 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34852 //console.log('adding nested layout panel ' + cfg.toSource());
34853 this.add(region, ret);
34854 nb = {}; /// find first...
34859 // needs grid and region
34861 //var el = this.getRegion(region).el.createChild();
34863 *var el = this.el.createChild();
34864 // create the grid first...
34865 cfg.grid.container = el;
34866 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34869 if (region == 'center' && this.active ) {
34870 cfg.background = false;
34873 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34875 this.add(region, ret);
34877 if (cfg.background) {
34878 // render grid on panel activation (if panel background)
34879 ret.on('activate', function(gp) {
34880 if (!gp.grid.rendered) {
34881 // gp.grid.render(el);
34885 // cfg.grid.render(el);
34891 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34892 // it was the old xcomponent building that caused this before.
34893 // espeically if border is the top element in the tree.
34903 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34905 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34906 this.add(region, ret);
34910 throw "Can not add '" + cfg.xtype + "' to Border";
34916 this.beginUpdate();
34920 Roo.each(xitems, function(i) {
34921 region = nb && i.region ? i.region : false;
34923 var add = ret.addxtype(i);
34926 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34927 if (!i.background) {
34928 abn[region] = nb[region] ;
34935 // make the last non-background panel active..
34936 //if (nb) { Roo.log(abn); }
34939 for(var r in abn) {
34940 region = this.getRegion(r);
34942 // tried using nb[r], but it does not work..
34944 region.showPanel(abn[r]);
34955 factory : function(cfg)
34958 var validRegions = Roo.bootstrap.layout.Border.regions;
34960 var target = cfg.region;
34963 var r = Roo.bootstrap.layout;
34967 return new r.North(cfg);
34969 return new r.South(cfg);
34971 return new r.East(cfg);
34973 return new r.West(cfg);
34975 return new r.Center(cfg);
34977 throw 'Layout region "'+target+'" not supported.';
34984 * Ext JS Library 1.1.1
34985 * Copyright(c) 2006-2007, Ext JS, LLC.
34987 * Originally Released Under LGPL - original licence link has changed is not relivant.
34990 * <script type="text/javascript">
34994 * @class Roo.bootstrap.layout.Basic
34995 * @extends Roo.util.Observable
34996 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34997 * and does not have a titlebar, tabs or any other features. All it does is size and position
34998 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34999 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35000 * @cfg {string} region the region that it inhabits..
35001 * @cfg {bool} skipConfig skip config?
35005 Roo.bootstrap.layout.Basic = function(config){
35007 this.mgr = config.mgr;
35009 this.position = config.region;
35011 var skipConfig = config.skipConfig;
35015 * @scope Roo.BasicLayoutRegion
35019 * @event beforeremove
35020 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35021 * @param {Roo.LayoutRegion} this
35022 * @param {Roo.ContentPanel} panel The panel
35023 * @param {Object} e The cancel event object
35025 "beforeremove" : true,
35027 * @event invalidated
35028 * Fires when the layout for this region is changed.
35029 * @param {Roo.LayoutRegion} this
35031 "invalidated" : true,
35033 * @event visibilitychange
35034 * Fires when this region is shown or hidden
35035 * @param {Roo.LayoutRegion} this
35036 * @param {Boolean} visibility true or false
35038 "visibilitychange" : true,
35040 * @event paneladded
35041 * Fires when a panel is added.
35042 * @param {Roo.LayoutRegion} this
35043 * @param {Roo.ContentPanel} panel The panel
35045 "paneladded" : true,
35047 * @event panelremoved
35048 * Fires when a panel is removed.
35049 * @param {Roo.LayoutRegion} this
35050 * @param {Roo.ContentPanel} panel The panel
35052 "panelremoved" : true,
35054 * @event beforecollapse
35055 * Fires when this region before collapse.
35056 * @param {Roo.LayoutRegion} this
35058 "beforecollapse" : true,
35061 * Fires when this region is collapsed.
35062 * @param {Roo.LayoutRegion} this
35064 "collapsed" : true,
35067 * Fires when this region is expanded.
35068 * @param {Roo.LayoutRegion} this
35073 * Fires when this region is slid into view.
35074 * @param {Roo.LayoutRegion} this
35076 "slideshow" : true,
35079 * Fires when this region slides out of view.
35080 * @param {Roo.LayoutRegion} this
35082 "slidehide" : true,
35084 * @event panelactivated
35085 * Fires when a panel is activated.
35086 * @param {Roo.LayoutRegion} this
35087 * @param {Roo.ContentPanel} panel The activated panel
35089 "panelactivated" : true,
35092 * Fires when the user resizes this region.
35093 * @param {Roo.LayoutRegion} this
35094 * @param {Number} newSize The new size (width for east/west, height for north/south)
35098 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35099 this.panels = new Roo.util.MixedCollection();
35100 this.panels.getKey = this.getPanelId.createDelegate(this);
35102 this.activePanel = null;
35103 // ensure listeners are added...
35105 if (config.listeners || config.events) {
35106 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35107 listeners : config.listeners || {},
35108 events : config.events || {}
35112 if(skipConfig !== true){
35113 this.applyConfig(config);
35117 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35119 getPanelId : function(p){
35123 applyConfig : function(config){
35124 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35125 this.config = config;
35130 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35131 * the width, for horizontal (north, south) the height.
35132 * @param {Number} newSize The new width or height
35134 resizeTo : function(newSize){
35135 var el = this.el ? this.el :
35136 (this.activePanel ? this.activePanel.getEl() : null);
35138 switch(this.position){
35141 el.setWidth(newSize);
35142 this.fireEvent("resized", this, newSize);
35146 el.setHeight(newSize);
35147 this.fireEvent("resized", this, newSize);
35153 getBox : function(){
35154 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35157 getMargins : function(){
35158 return this.margins;
35161 updateBox : function(box){
35163 var el = this.activePanel.getEl();
35164 el.dom.style.left = box.x + "px";
35165 el.dom.style.top = box.y + "px";
35166 this.activePanel.setSize(box.width, box.height);
35170 * Returns the container element for this region.
35171 * @return {Roo.Element}
35173 getEl : function(){
35174 return this.activePanel;
35178 * Returns true if this region is currently visible.
35179 * @return {Boolean}
35181 isVisible : function(){
35182 return this.activePanel ? true : false;
35185 setActivePanel : function(panel){
35186 panel = this.getPanel(panel);
35187 if(this.activePanel && this.activePanel != panel){
35188 this.activePanel.setActiveState(false);
35189 this.activePanel.getEl().setLeftTop(-10000,-10000);
35191 this.activePanel = panel;
35192 panel.setActiveState(true);
35194 panel.setSize(this.box.width, this.box.height);
35196 this.fireEvent("panelactivated", this, panel);
35197 this.fireEvent("invalidated");
35201 * Show the specified panel.
35202 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35203 * @return {Roo.ContentPanel} The shown panel or null
35205 showPanel : function(panel){
35206 panel = this.getPanel(panel);
35208 this.setActivePanel(panel);
35214 * Get the active panel for this region.
35215 * @return {Roo.ContentPanel} The active panel or null
35217 getActivePanel : function(){
35218 return this.activePanel;
35222 * Add the passed ContentPanel(s)
35223 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35224 * @return {Roo.ContentPanel} The panel added (if only one was added)
35226 add : function(panel){
35227 if(arguments.length > 1){
35228 for(var i = 0, len = arguments.length; i < len; i++) {
35229 this.add(arguments[i]);
35233 if(this.hasPanel(panel)){
35234 this.showPanel(panel);
35237 var el = panel.getEl();
35238 if(el.dom.parentNode != this.mgr.el.dom){
35239 this.mgr.el.dom.appendChild(el.dom);
35241 if(panel.setRegion){
35242 panel.setRegion(this);
35244 this.panels.add(panel);
35245 el.setStyle("position", "absolute");
35246 if(!panel.background){
35247 this.setActivePanel(panel);
35248 if(this.config.initialSize && this.panels.getCount()==1){
35249 this.resizeTo(this.config.initialSize);
35252 this.fireEvent("paneladded", this, panel);
35257 * Returns true if the panel is in this region.
35258 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35259 * @return {Boolean}
35261 hasPanel : function(panel){
35262 if(typeof panel == "object"){ // must be panel obj
35263 panel = panel.getId();
35265 return this.getPanel(panel) ? true : false;
35269 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35270 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35271 * @param {Boolean} preservePanel Overrides the config preservePanel option
35272 * @return {Roo.ContentPanel} The panel that was removed
35274 remove : function(panel, preservePanel){
35275 panel = this.getPanel(panel);
35280 this.fireEvent("beforeremove", this, panel, e);
35281 if(e.cancel === true){
35284 var panelId = panel.getId();
35285 this.panels.removeKey(panelId);
35290 * Returns the panel specified or null if it's not in this region.
35291 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35292 * @return {Roo.ContentPanel}
35294 getPanel : function(id){
35295 if(typeof id == "object"){ // must be panel obj
35298 return this.panels.get(id);
35302 * Returns this regions position (north/south/east/west/center).
35305 getPosition: function(){
35306 return this.position;
35310 * Ext JS Library 1.1.1
35311 * Copyright(c) 2006-2007, Ext JS, LLC.
35313 * Originally Released Under LGPL - original licence link has changed is not relivant.
35316 * <script type="text/javascript">
35320 * @class Roo.bootstrap.layout.Region
35321 * @extends Roo.bootstrap.layout.Basic
35322 * This class represents a region in a layout manager.
35324 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35325 * @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})
35326 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35327 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35328 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35329 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35330 * @cfg {String} title The title for the region (overrides panel titles)
35331 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35332 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35333 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35334 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35335 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35336 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35337 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35338 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35339 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35340 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35342 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35343 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35344 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35345 * @cfg {Number} width For East/West panels
35346 * @cfg {Number} height For North/South panels
35347 * @cfg {Boolean} split To show the splitter
35348 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35350 * @cfg {string} cls Extra CSS classes to add to region
35352 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35353 * @cfg {string} region the region that it inhabits..
35356 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35357 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35359 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35360 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35361 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35363 Roo.bootstrap.layout.Region = function(config)
35365 this.applyConfig(config);
35367 var mgr = config.mgr;
35368 var pos = config.region;
35369 config.skipConfig = true;
35370 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35373 this.onRender(mgr.el);
35376 this.visible = true;
35377 this.collapsed = false;
35378 this.unrendered_panels = [];
35381 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35383 position: '', // set by wrapper (eg. north/south etc..)
35384 unrendered_panels : null, // unrendered panels.
35385 createBody : function(){
35386 /** This region's body element
35387 * @type Roo.Element */
35388 this.bodyEl = this.el.createChild({
35390 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35394 onRender: function(ctr, pos)
35396 var dh = Roo.DomHelper;
35397 /** This region's container element
35398 * @type Roo.Element */
35399 this.el = dh.append(ctr.dom, {
35401 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35403 /** This region's title element
35404 * @type Roo.Element */
35406 this.titleEl = dh.append(this.el.dom,
35409 unselectable: "on",
35410 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35412 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35413 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35416 this.titleEl.enableDisplayMode();
35417 /** This region's title text element
35418 * @type HTMLElement */
35419 this.titleTextEl = this.titleEl.dom.firstChild;
35420 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35422 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35423 this.closeBtn.enableDisplayMode();
35424 this.closeBtn.on("click", this.closeClicked, this);
35425 this.closeBtn.hide();
35427 this.createBody(this.config);
35428 if(this.config.hideWhenEmpty){
35430 this.on("paneladded", this.validateVisibility, this);
35431 this.on("panelremoved", this.validateVisibility, this);
35433 if(this.autoScroll){
35434 this.bodyEl.setStyle("overflow", "auto");
35436 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35438 //if(c.titlebar !== false){
35439 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35440 this.titleEl.hide();
35442 this.titleEl.show();
35443 if(this.config.title){
35444 this.titleTextEl.innerHTML = this.config.title;
35448 if(this.config.collapsed){
35449 this.collapse(true);
35451 if(this.config.hidden){
35455 if (this.unrendered_panels && this.unrendered_panels.length) {
35456 for (var i =0;i< this.unrendered_panels.length; i++) {
35457 this.add(this.unrendered_panels[i]);
35459 this.unrendered_panels = null;
35465 applyConfig : function(c)
35468 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35469 var dh = Roo.DomHelper;
35470 if(c.titlebar !== false){
35471 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35472 this.collapseBtn.on("click", this.collapse, this);
35473 this.collapseBtn.enableDisplayMode();
35475 if(c.showPin === true || this.showPin){
35476 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35477 this.stickBtn.enableDisplayMode();
35478 this.stickBtn.on("click", this.expand, this);
35479 this.stickBtn.hide();
35484 /** This region's collapsed element
35485 * @type Roo.Element */
35488 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35489 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35492 if(c.floatable !== false){
35493 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35494 this.collapsedEl.on("click", this.collapseClick, this);
35497 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35498 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35499 id: "message", unselectable: "on", style:{"float":"left"}});
35500 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35502 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35503 this.expandBtn.on("click", this.expand, this);
35507 if(this.collapseBtn){
35508 this.collapseBtn.setVisible(c.collapsible == true);
35511 this.cmargins = c.cmargins || this.cmargins ||
35512 (this.position == "west" || this.position == "east" ?
35513 {top: 0, left: 2, right:2, bottom: 0} :
35514 {top: 2, left: 0, right:0, bottom: 2});
35516 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35519 this.bottomTabs = c.tabPosition != "top";
35521 this.autoScroll = c.autoScroll || false;
35526 this.duration = c.duration || .30;
35527 this.slideDuration = c.slideDuration || .45;
35532 * Returns true if this region is currently visible.
35533 * @return {Boolean}
35535 isVisible : function(){
35536 return this.visible;
35540 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35541 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35543 //setCollapsedTitle : function(title){
35544 // title = title || " ";
35545 // if(this.collapsedTitleTextEl){
35546 // this.collapsedTitleTextEl.innerHTML = title;
35550 getBox : function(){
35552 // if(!this.collapsed){
35553 b = this.el.getBox(false, true);
35555 // b = this.collapsedEl.getBox(false, true);
35560 getMargins : function(){
35561 return this.margins;
35562 //return this.collapsed ? this.cmargins : this.margins;
35565 highlight : function(){
35566 this.el.addClass("x-layout-panel-dragover");
35569 unhighlight : function(){
35570 this.el.removeClass("x-layout-panel-dragover");
35573 updateBox : function(box)
35575 if (!this.bodyEl) {
35576 return; // not rendered yet..
35580 if(!this.collapsed){
35581 this.el.dom.style.left = box.x + "px";
35582 this.el.dom.style.top = box.y + "px";
35583 this.updateBody(box.width, box.height);
35585 this.collapsedEl.dom.style.left = box.x + "px";
35586 this.collapsedEl.dom.style.top = box.y + "px";
35587 this.collapsedEl.setSize(box.width, box.height);
35590 this.tabs.autoSizeTabs();
35594 updateBody : function(w, h)
35597 this.el.setWidth(w);
35598 w -= this.el.getBorderWidth("rl");
35599 if(this.config.adjustments){
35600 w += this.config.adjustments[0];
35603 if(h !== null && h > 0){
35604 this.el.setHeight(h);
35605 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35606 h -= this.el.getBorderWidth("tb");
35607 if(this.config.adjustments){
35608 h += this.config.adjustments[1];
35610 this.bodyEl.setHeight(h);
35612 h = this.tabs.syncHeight(h);
35615 if(this.panelSize){
35616 w = w !== null ? w : this.panelSize.width;
35617 h = h !== null ? h : this.panelSize.height;
35619 if(this.activePanel){
35620 var el = this.activePanel.getEl();
35621 w = w !== null ? w : el.getWidth();
35622 h = h !== null ? h : el.getHeight();
35623 this.panelSize = {width: w, height: h};
35624 this.activePanel.setSize(w, h);
35626 if(Roo.isIE && this.tabs){
35627 this.tabs.el.repaint();
35632 * Returns the container element for this region.
35633 * @return {Roo.Element}
35635 getEl : function(){
35640 * Hides this region.
35643 //if(!this.collapsed){
35644 this.el.dom.style.left = "-2000px";
35647 // this.collapsedEl.dom.style.left = "-2000px";
35648 // this.collapsedEl.hide();
35650 this.visible = false;
35651 this.fireEvent("visibilitychange", this, false);
35655 * Shows this region if it was previously hidden.
35658 //if(!this.collapsed){
35661 // this.collapsedEl.show();
35663 this.visible = true;
35664 this.fireEvent("visibilitychange", this, true);
35667 closeClicked : function(){
35668 if(this.activePanel){
35669 this.remove(this.activePanel);
35673 collapseClick : function(e){
35675 e.stopPropagation();
35678 e.stopPropagation();
35684 * Collapses this region.
35685 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35688 collapse : function(skipAnim, skipCheck = false){
35689 if(this.collapsed) {
35693 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35695 this.collapsed = true;
35697 this.split.el.hide();
35699 if(this.config.animate && skipAnim !== true){
35700 this.fireEvent("invalidated", this);
35701 this.animateCollapse();
35703 this.el.setLocation(-20000,-20000);
35705 this.collapsedEl.show();
35706 this.fireEvent("collapsed", this);
35707 this.fireEvent("invalidated", this);
35713 animateCollapse : function(){
35718 * Expands this region if it was previously collapsed.
35719 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35720 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35723 expand : function(e, skipAnim){
35725 e.stopPropagation();
35727 if(!this.collapsed || this.el.hasActiveFx()) {
35731 this.afterSlideIn();
35734 this.collapsed = false;
35735 if(this.config.animate && skipAnim !== true){
35736 this.animateExpand();
35740 this.split.el.show();
35742 this.collapsedEl.setLocation(-2000,-2000);
35743 this.collapsedEl.hide();
35744 this.fireEvent("invalidated", this);
35745 this.fireEvent("expanded", this);
35749 animateExpand : function(){
35753 initTabs : function()
35755 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35757 var ts = new Roo.bootstrap.panel.Tabs({
35758 el: this.bodyEl.dom,
35759 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35760 disableTooltips: this.config.disableTabTips,
35761 toolbar : this.config.toolbar
35764 if(this.config.hideTabs){
35765 ts.stripWrap.setDisplayed(false);
35768 ts.resizeTabs = this.config.resizeTabs === true;
35769 ts.minTabWidth = this.config.minTabWidth || 40;
35770 ts.maxTabWidth = this.config.maxTabWidth || 250;
35771 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35772 ts.monitorResize = false;
35773 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35774 ts.bodyEl.addClass('roo-layout-tabs-body');
35775 this.panels.each(this.initPanelAsTab, this);
35778 initPanelAsTab : function(panel){
35779 var ti = this.tabs.addTab(
35783 this.config.closeOnTab && panel.isClosable(),
35786 if(panel.tabTip !== undefined){
35787 ti.setTooltip(panel.tabTip);
35789 ti.on("activate", function(){
35790 this.setActivePanel(panel);
35793 if(this.config.closeOnTab){
35794 ti.on("beforeclose", function(t, e){
35796 this.remove(panel);
35800 panel.tabItem = ti;
35805 updatePanelTitle : function(panel, title)
35807 if(this.activePanel == panel){
35808 this.updateTitle(title);
35811 var ti = this.tabs.getTab(panel.getEl().id);
35813 if(panel.tabTip !== undefined){
35814 ti.setTooltip(panel.tabTip);
35819 updateTitle : function(title){
35820 if(this.titleTextEl && !this.config.title){
35821 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35825 setActivePanel : function(panel)
35827 panel = this.getPanel(panel);
35828 if(this.activePanel && this.activePanel != panel){
35829 if(this.activePanel.setActiveState(false) === false){
35833 this.activePanel = panel;
35834 panel.setActiveState(true);
35835 if(this.panelSize){
35836 panel.setSize(this.panelSize.width, this.panelSize.height);
35839 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35841 this.updateTitle(panel.getTitle());
35843 this.fireEvent("invalidated", this);
35845 this.fireEvent("panelactivated", this, panel);
35849 * Shows the specified panel.
35850 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35851 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35853 showPanel : function(panel)
35855 panel = this.getPanel(panel);
35858 var tab = this.tabs.getTab(panel.getEl().id);
35859 if(tab.isHidden()){
35860 this.tabs.unhideTab(tab.id);
35864 this.setActivePanel(panel);
35871 * Get the active panel for this region.
35872 * @return {Roo.ContentPanel} The active panel or null
35874 getActivePanel : function(){
35875 return this.activePanel;
35878 validateVisibility : function(){
35879 if(this.panels.getCount() < 1){
35880 this.updateTitle(" ");
35881 this.closeBtn.hide();
35884 if(!this.isVisible()){
35891 * Adds the passed ContentPanel(s) to this region.
35892 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35893 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35895 add : function(panel)
35897 if(arguments.length > 1){
35898 for(var i = 0, len = arguments.length; i < len; i++) {
35899 this.add(arguments[i]);
35904 // if we have not been rendered yet, then we can not really do much of this..
35905 if (!this.bodyEl) {
35906 this.unrendered_panels.push(panel);
35913 if(this.hasPanel(panel)){
35914 this.showPanel(panel);
35917 panel.setRegion(this);
35918 this.panels.add(panel);
35919 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35920 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35921 // and hide them... ???
35922 this.bodyEl.dom.appendChild(panel.getEl().dom);
35923 if(panel.background !== true){
35924 this.setActivePanel(panel);
35926 this.fireEvent("paneladded", this, panel);
35933 this.initPanelAsTab(panel);
35937 if(panel.background !== true){
35938 this.tabs.activate(panel.getEl().id);
35940 this.fireEvent("paneladded", this, panel);
35945 * Hides the tab for the specified panel.
35946 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35948 hidePanel : function(panel){
35949 if(this.tabs && (panel = this.getPanel(panel))){
35950 this.tabs.hideTab(panel.getEl().id);
35955 * Unhides the tab for a previously hidden panel.
35956 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35958 unhidePanel : function(panel){
35959 if(this.tabs && (panel = this.getPanel(panel))){
35960 this.tabs.unhideTab(panel.getEl().id);
35964 clearPanels : function(){
35965 while(this.panels.getCount() > 0){
35966 this.remove(this.panels.first());
35971 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35972 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35973 * @param {Boolean} preservePanel Overrides the config preservePanel option
35974 * @return {Roo.ContentPanel} The panel that was removed
35976 remove : function(panel, preservePanel)
35978 panel = this.getPanel(panel);
35983 this.fireEvent("beforeremove", this, panel, e);
35984 if(e.cancel === true){
35987 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35988 var panelId = panel.getId();
35989 this.panels.removeKey(panelId);
35991 document.body.appendChild(panel.getEl().dom);
35994 this.tabs.removeTab(panel.getEl().id);
35995 }else if (!preservePanel){
35996 this.bodyEl.dom.removeChild(panel.getEl().dom);
35998 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35999 var p = this.panels.first();
36000 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36001 tempEl.appendChild(p.getEl().dom);
36002 this.bodyEl.update("");
36003 this.bodyEl.dom.appendChild(p.getEl().dom);
36005 this.updateTitle(p.getTitle());
36007 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36008 this.setActivePanel(p);
36010 panel.setRegion(null);
36011 if(this.activePanel == panel){
36012 this.activePanel = null;
36014 if(this.config.autoDestroy !== false && preservePanel !== true){
36015 try{panel.destroy();}catch(e){}
36017 this.fireEvent("panelremoved", this, panel);
36022 * Returns the TabPanel component used by this region
36023 * @return {Roo.TabPanel}
36025 getTabs : function(){
36029 createTool : function(parentEl, className){
36030 var btn = Roo.DomHelper.append(parentEl, {
36032 cls: "x-layout-tools-button",
36035 cls: "roo-layout-tools-button-inner " + className,
36039 btn.addClassOnOver("roo-layout-tools-button-over");
36044 * Ext JS Library 1.1.1
36045 * Copyright(c) 2006-2007, Ext JS, LLC.
36047 * Originally Released Under LGPL - original licence link has changed is not relivant.
36050 * <script type="text/javascript">
36056 * @class Roo.SplitLayoutRegion
36057 * @extends Roo.LayoutRegion
36058 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36060 Roo.bootstrap.layout.Split = function(config){
36061 this.cursor = config.cursor;
36062 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36065 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36067 splitTip : "Drag to resize.",
36068 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36069 useSplitTips : false,
36071 applyConfig : function(config){
36072 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36075 onRender : function(ctr,pos) {
36077 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36078 if(!this.config.split){
36083 var splitEl = Roo.DomHelper.append(ctr.dom, {
36085 id: this.el.id + "-split",
36086 cls: "roo-layout-split roo-layout-split-"+this.position,
36089 /** The SplitBar for this region
36090 * @type Roo.SplitBar */
36091 // does not exist yet...
36092 Roo.log([this.position, this.orientation]);
36094 this.split = new Roo.bootstrap.SplitBar({
36095 dragElement : splitEl,
36096 resizingElement: this.el,
36097 orientation : this.orientation
36100 this.split.on("moved", this.onSplitMove, this);
36101 this.split.useShim = this.config.useShim === true;
36102 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36103 if(this.useSplitTips){
36104 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36106 //if(config.collapsible){
36107 // this.split.el.on("dblclick", this.collapse, this);
36110 if(typeof this.config.minSize != "undefined"){
36111 this.split.minSize = this.config.minSize;
36113 if(typeof this.config.maxSize != "undefined"){
36114 this.split.maxSize = this.config.maxSize;
36116 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36117 this.hideSplitter();
36122 getHMaxSize : function(){
36123 var cmax = this.config.maxSize || 10000;
36124 var center = this.mgr.getRegion("center");
36125 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36128 getVMaxSize : function(){
36129 var cmax = this.config.maxSize || 10000;
36130 var center = this.mgr.getRegion("center");
36131 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36134 onSplitMove : function(split, newSize){
36135 this.fireEvent("resized", this, newSize);
36139 * Returns the {@link Roo.SplitBar} for this region.
36140 * @return {Roo.SplitBar}
36142 getSplitBar : function(){
36147 this.hideSplitter();
36148 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36151 hideSplitter : function(){
36153 this.split.el.setLocation(-2000,-2000);
36154 this.split.el.hide();
36160 this.split.el.show();
36162 Roo.bootstrap.layout.Split.superclass.show.call(this);
36165 beforeSlide: function(){
36166 if(Roo.isGecko){// firefox overflow auto bug workaround
36167 this.bodyEl.clip();
36169 this.tabs.bodyEl.clip();
36171 if(this.activePanel){
36172 this.activePanel.getEl().clip();
36174 if(this.activePanel.beforeSlide){
36175 this.activePanel.beforeSlide();
36181 afterSlide : function(){
36182 if(Roo.isGecko){// firefox overflow auto bug workaround
36183 this.bodyEl.unclip();
36185 this.tabs.bodyEl.unclip();
36187 if(this.activePanel){
36188 this.activePanel.getEl().unclip();
36189 if(this.activePanel.afterSlide){
36190 this.activePanel.afterSlide();
36196 initAutoHide : function(){
36197 if(this.autoHide !== false){
36198 if(!this.autoHideHd){
36199 var st = new Roo.util.DelayedTask(this.slideIn, this);
36200 this.autoHideHd = {
36201 "mouseout": function(e){
36202 if(!e.within(this.el, true)){
36206 "mouseover" : function(e){
36212 this.el.on(this.autoHideHd);
36216 clearAutoHide : function(){
36217 if(this.autoHide !== false){
36218 this.el.un("mouseout", this.autoHideHd.mouseout);
36219 this.el.un("mouseover", this.autoHideHd.mouseover);
36223 clearMonitor : function(){
36224 Roo.get(document).un("click", this.slideInIf, this);
36227 // these names are backwards but not changed for compat
36228 slideOut : function(){
36229 if(this.isSlid || this.el.hasActiveFx()){
36232 this.isSlid = true;
36233 if(this.collapseBtn){
36234 this.collapseBtn.hide();
36236 this.closeBtnState = this.closeBtn.getStyle('display');
36237 this.closeBtn.hide();
36239 this.stickBtn.show();
36242 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36243 this.beforeSlide();
36244 this.el.setStyle("z-index", 10001);
36245 this.el.slideIn(this.getSlideAnchor(), {
36246 callback: function(){
36248 this.initAutoHide();
36249 Roo.get(document).on("click", this.slideInIf, this);
36250 this.fireEvent("slideshow", this);
36257 afterSlideIn : function(){
36258 this.clearAutoHide();
36259 this.isSlid = false;
36260 this.clearMonitor();
36261 this.el.setStyle("z-index", "");
36262 if(this.collapseBtn){
36263 this.collapseBtn.show();
36265 this.closeBtn.setStyle('display', this.closeBtnState);
36267 this.stickBtn.hide();
36269 this.fireEvent("slidehide", this);
36272 slideIn : function(cb){
36273 if(!this.isSlid || this.el.hasActiveFx()){
36277 this.isSlid = false;
36278 this.beforeSlide();
36279 this.el.slideOut(this.getSlideAnchor(), {
36280 callback: function(){
36281 this.el.setLeftTop(-10000, -10000);
36283 this.afterSlideIn();
36291 slideInIf : function(e){
36292 if(!e.within(this.el)){
36297 animateCollapse : function(){
36298 this.beforeSlide();
36299 this.el.setStyle("z-index", 20000);
36300 var anchor = this.getSlideAnchor();
36301 this.el.slideOut(anchor, {
36302 callback : function(){
36303 this.el.setStyle("z-index", "");
36304 this.collapsedEl.slideIn(anchor, {duration:.3});
36306 this.el.setLocation(-10000,-10000);
36308 this.fireEvent("collapsed", this);
36315 animateExpand : function(){
36316 this.beforeSlide();
36317 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36318 this.el.setStyle("z-index", 20000);
36319 this.collapsedEl.hide({
36322 this.el.slideIn(this.getSlideAnchor(), {
36323 callback : function(){
36324 this.el.setStyle("z-index", "");
36327 this.split.el.show();
36329 this.fireEvent("invalidated", this);
36330 this.fireEvent("expanded", this);
36358 getAnchor : function(){
36359 return this.anchors[this.position];
36362 getCollapseAnchor : function(){
36363 return this.canchors[this.position];
36366 getSlideAnchor : function(){
36367 return this.sanchors[this.position];
36370 getAlignAdj : function(){
36371 var cm = this.cmargins;
36372 switch(this.position){
36388 getExpandAdj : function(){
36389 var c = this.collapsedEl, cm = this.cmargins;
36390 switch(this.position){
36392 return [-(cm.right+c.getWidth()+cm.left), 0];
36395 return [cm.right+c.getWidth()+cm.left, 0];
36398 return [0, -(cm.top+cm.bottom+c.getHeight())];
36401 return [0, cm.top+cm.bottom+c.getHeight()];
36407 * Ext JS Library 1.1.1
36408 * Copyright(c) 2006-2007, Ext JS, LLC.
36410 * Originally Released Under LGPL - original licence link has changed is not relivant.
36413 * <script type="text/javascript">
36416 * These classes are private internal classes
36418 Roo.bootstrap.layout.Center = function(config){
36419 config.region = "center";
36420 Roo.bootstrap.layout.Region.call(this, config);
36421 this.visible = true;
36422 this.minWidth = config.minWidth || 20;
36423 this.minHeight = config.minHeight || 20;
36426 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36428 // center panel can't be hidden
36432 // center panel can't be hidden
36435 getMinWidth: function(){
36436 return this.minWidth;
36439 getMinHeight: function(){
36440 return this.minHeight;
36453 Roo.bootstrap.layout.North = function(config)
36455 config.region = 'north';
36456 config.cursor = 'n-resize';
36458 Roo.bootstrap.layout.Split.call(this, config);
36462 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36463 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36464 this.split.el.addClass("roo-layout-split-v");
36466 var size = config.initialSize || config.height;
36467 if(typeof size != "undefined"){
36468 this.el.setHeight(size);
36471 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36473 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36477 getBox : function(){
36478 if(this.collapsed){
36479 return this.collapsedEl.getBox();
36481 var box = this.el.getBox();
36483 box.height += this.split.el.getHeight();
36488 updateBox : function(box){
36489 if(this.split && !this.collapsed){
36490 box.height -= this.split.el.getHeight();
36491 this.split.el.setLeft(box.x);
36492 this.split.el.setTop(box.y+box.height);
36493 this.split.el.setWidth(box.width);
36495 if(this.collapsed){
36496 this.updateBody(box.width, null);
36498 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36506 Roo.bootstrap.layout.South = function(config){
36507 config.region = 'south';
36508 config.cursor = 's-resize';
36509 Roo.bootstrap.layout.Split.call(this, config);
36511 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36512 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36513 this.split.el.addClass("roo-layout-split-v");
36515 var size = config.initialSize || config.height;
36516 if(typeof size != "undefined"){
36517 this.el.setHeight(size);
36521 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36522 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36523 getBox : function(){
36524 if(this.collapsed){
36525 return this.collapsedEl.getBox();
36527 var box = this.el.getBox();
36529 var sh = this.split.el.getHeight();
36536 updateBox : function(box){
36537 if(this.split && !this.collapsed){
36538 var sh = this.split.el.getHeight();
36541 this.split.el.setLeft(box.x);
36542 this.split.el.setTop(box.y-sh);
36543 this.split.el.setWidth(box.width);
36545 if(this.collapsed){
36546 this.updateBody(box.width, null);
36548 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36552 Roo.bootstrap.layout.East = function(config){
36553 config.region = "east";
36554 config.cursor = "e-resize";
36555 Roo.bootstrap.layout.Split.call(this, config);
36557 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36558 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36559 this.split.el.addClass("roo-layout-split-h");
36561 var size = config.initialSize || config.width;
36562 if(typeof size != "undefined"){
36563 this.el.setWidth(size);
36566 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36567 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36568 getBox : function(){
36569 if(this.collapsed){
36570 return this.collapsedEl.getBox();
36572 var box = this.el.getBox();
36574 var sw = this.split.el.getWidth();
36581 updateBox : function(box){
36582 if(this.split && !this.collapsed){
36583 var sw = this.split.el.getWidth();
36585 this.split.el.setLeft(box.x);
36586 this.split.el.setTop(box.y);
36587 this.split.el.setHeight(box.height);
36590 if(this.collapsed){
36591 this.updateBody(null, box.height);
36593 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36597 Roo.bootstrap.layout.West = function(config){
36598 config.region = "west";
36599 config.cursor = "w-resize";
36601 Roo.bootstrap.layout.Split.call(this, config);
36603 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36604 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36605 this.split.el.addClass("roo-layout-split-h");
36609 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36610 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36612 onRender: function(ctr, pos)
36614 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36615 var size = this.config.initialSize || this.config.width;
36616 if(typeof size != "undefined"){
36617 this.el.setWidth(size);
36621 getBox : function(){
36622 if(this.collapsed){
36623 return this.collapsedEl.getBox();
36625 var box = this.el.getBox();
36627 box.width += this.split.el.getWidth();
36632 updateBox : function(box){
36633 if(this.split && !this.collapsed){
36634 var sw = this.split.el.getWidth();
36636 this.split.el.setLeft(box.x+box.width);
36637 this.split.el.setTop(box.y);
36638 this.split.el.setHeight(box.height);
36640 if(this.collapsed){
36641 this.updateBody(null, box.height);
36643 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36646 Roo.namespace("Roo.bootstrap.panel");/*
36648 * Ext JS Library 1.1.1
36649 * Copyright(c) 2006-2007, Ext JS, LLC.
36651 * Originally Released Under LGPL - original licence link has changed is not relivant.
36654 * <script type="text/javascript">
36657 * @class Roo.ContentPanel
36658 * @extends Roo.util.Observable
36659 * A basic ContentPanel element.
36660 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36661 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36662 * @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
36663 * @cfg {Boolean} closable True if the panel can be closed/removed
36664 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36665 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36666 * @cfg {Toolbar} toolbar A toolbar for this panel
36667 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36668 * @cfg {String} title The title for this panel
36669 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36670 * @cfg {String} url Calls {@link #setUrl} with this value
36671 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36672 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36673 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36674 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36675 * @cfg {Boolean} badges render the badges
36678 * Create a new ContentPanel.
36679 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36680 * @param {String/Object} config A string to set only the title or a config object
36681 * @param {String} content (optional) Set the HTML content for this panel
36682 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36684 Roo.bootstrap.panel.Content = function( config){
36686 this.tpl = config.tpl || false;
36688 var el = config.el;
36689 var content = config.content;
36691 if(config.autoCreate){ // xtype is available if this is called from factory
36694 this.el = Roo.get(el);
36695 if(!this.el && config && config.autoCreate){
36696 if(typeof config.autoCreate == "object"){
36697 if(!config.autoCreate.id){
36698 config.autoCreate.id = config.id||el;
36700 this.el = Roo.DomHelper.append(document.body,
36701 config.autoCreate, true);
36703 var elcfg = { tag: "div",
36704 cls: "roo-layout-inactive-content",
36708 elcfg.html = config.html;
36712 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36715 this.closable = false;
36716 this.loaded = false;
36717 this.active = false;
36720 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36722 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36724 this.wrapEl = this.el; //this.el.wrap();
36726 if (config.toolbar.items) {
36727 ti = config.toolbar.items ;
36728 delete config.toolbar.items ;
36732 this.toolbar.render(this.wrapEl, 'before');
36733 for(var i =0;i < ti.length;i++) {
36734 // Roo.log(['add child', items[i]]);
36735 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36737 this.toolbar.items = nitems;
36738 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36739 delete config.toolbar;
36743 // xtype created footer. - not sure if will work as we normally have to render first..
36744 if (this.footer && !this.footer.el && this.footer.xtype) {
36745 if (!this.wrapEl) {
36746 this.wrapEl = this.el.wrap();
36749 this.footer.container = this.wrapEl.createChild();
36751 this.footer = Roo.factory(this.footer, Roo);
36756 if(typeof config == "string"){
36757 this.title = config;
36759 Roo.apply(this, config);
36763 this.resizeEl = Roo.get(this.resizeEl, true);
36765 this.resizeEl = this.el;
36767 // handle view.xtype
36775 * Fires when this panel is activated.
36776 * @param {Roo.ContentPanel} this
36780 * @event deactivate
36781 * Fires when this panel is activated.
36782 * @param {Roo.ContentPanel} this
36784 "deactivate" : true,
36788 * Fires when this panel is resized if fitToFrame is true.
36789 * @param {Roo.ContentPanel} this
36790 * @param {Number} width The width after any component adjustments
36791 * @param {Number} height The height after any component adjustments
36797 * Fires when this tab is created
36798 * @param {Roo.ContentPanel} this
36809 if(this.autoScroll){
36810 this.resizeEl.setStyle("overflow", "auto");
36812 // fix randome scrolling
36813 //this.el.on('scroll', function() {
36814 // Roo.log('fix random scolling');
36815 // this.scrollTo('top',0);
36818 content = content || this.content;
36820 this.setContent(content);
36822 if(config && config.url){
36823 this.setUrl(this.url, this.params, this.loadOnce);
36828 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36830 if (this.view && typeof(this.view.xtype) != 'undefined') {
36831 this.view.el = this.el.appendChild(document.createElement("div"));
36832 this.view = Roo.factory(this.view);
36833 this.view.render && this.view.render(false, '');
36837 this.fireEvent('render', this);
36840 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36844 setRegion : function(region){
36845 this.region = region;
36846 this.setActiveClass(region && !this.background);
36850 setActiveClass: function(state)
36853 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36854 this.el.setStyle('position','relative');
36856 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36857 this.el.setStyle('position', 'absolute');
36862 * Returns the toolbar for this Panel if one was configured.
36863 * @return {Roo.Toolbar}
36865 getToolbar : function(){
36866 return this.toolbar;
36869 setActiveState : function(active)
36871 this.active = active;
36872 this.setActiveClass(active);
36874 if(this.fireEvent("deactivate", this) === false){
36879 this.fireEvent("activate", this);
36883 * Updates this panel's element
36884 * @param {String} content The new content
36885 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36887 setContent : function(content, loadScripts){
36888 this.el.update(content, loadScripts);
36891 ignoreResize : function(w, h){
36892 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36895 this.lastSize = {width: w, height: h};
36900 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36901 * @return {Roo.UpdateManager} The UpdateManager
36903 getUpdateManager : function(){
36904 return this.el.getUpdateManager();
36907 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36908 * @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:
36911 url: "your-url.php",
36912 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36913 callback: yourFunction,
36914 scope: yourObject, //(optional scope)
36917 text: "Loading...",
36922 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36923 * 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.
36924 * @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}
36925 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36926 * @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.
36927 * @return {Roo.ContentPanel} this
36930 var um = this.el.getUpdateManager();
36931 um.update.apply(um, arguments);
36937 * 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.
36938 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36939 * @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)
36940 * @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)
36941 * @return {Roo.UpdateManager} The UpdateManager
36943 setUrl : function(url, params, loadOnce){
36944 if(this.refreshDelegate){
36945 this.removeListener("activate", this.refreshDelegate);
36947 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36948 this.on("activate", this.refreshDelegate);
36949 return this.el.getUpdateManager();
36952 _handleRefresh : function(url, params, loadOnce){
36953 if(!loadOnce || !this.loaded){
36954 var updater = this.el.getUpdateManager();
36955 updater.update(url, params, this._setLoaded.createDelegate(this));
36959 _setLoaded : function(){
36960 this.loaded = true;
36964 * Returns this panel's id
36967 getId : function(){
36972 * Returns this panel's element - used by regiosn to add.
36973 * @return {Roo.Element}
36975 getEl : function(){
36976 return this.wrapEl || this.el;
36981 adjustForComponents : function(width, height)
36983 //Roo.log('adjustForComponents ');
36984 if(this.resizeEl != this.el){
36985 width -= this.el.getFrameWidth('lr');
36986 height -= this.el.getFrameWidth('tb');
36989 var te = this.toolbar.getEl();
36990 te.setWidth(width);
36991 height -= te.getHeight();
36994 var te = this.footer.getEl();
36995 te.setWidth(width);
36996 height -= te.getHeight();
37000 if(this.adjustments){
37001 width += this.adjustments[0];
37002 height += this.adjustments[1];
37004 return {"width": width, "height": height};
37007 setSize : function(width, height){
37008 if(this.fitToFrame && !this.ignoreResize(width, height)){
37009 if(this.fitContainer && this.resizeEl != this.el){
37010 this.el.setSize(width, height);
37012 var size = this.adjustForComponents(width, height);
37013 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37014 this.fireEvent('resize', this, size.width, size.height);
37019 * Returns this panel's title
37022 getTitle : function(){
37024 if (typeof(this.title) != 'object') {
37029 for (var k in this.title) {
37030 if (!this.title.hasOwnProperty(k)) {
37034 if (k.indexOf('-') >= 0) {
37035 var s = k.split('-');
37036 for (var i = 0; i<s.length; i++) {
37037 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37040 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37047 * Set this panel's title
37048 * @param {String} title
37050 setTitle : function(title){
37051 this.title = title;
37053 this.region.updatePanelTitle(this, title);
37058 * Returns true is this panel was configured to be closable
37059 * @return {Boolean}
37061 isClosable : function(){
37062 return this.closable;
37065 beforeSlide : function(){
37067 this.resizeEl.clip();
37070 afterSlide : function(){
37072 this.resizeEl.unclip();
37076 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37077 * Will fail silently if the {@link #setUrl} method has not been called.
37078 * This does not activate the panel, just updates its content.
37080 refresh : function(){
37081 if(this.refreshDelegate){
37082 this.loaded = false;
37083 this.refreshDelegate();
37088 * Destroys this panel
37090 destroy : function(){
37091 this.el.removeAllListeners();
37092 var tempEl = document.createElement("span");
37093 tempEl.appendChild(this.el.dom);
37094 tempEl.innerHTML = "";
37100 * form - if the content panel contains a form - this is a reference to it.
37101 * @type {Roo.form.Form}
37105 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37106 * This contains a reference to it.
37112 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37122 * @param {Object} cfg Xtype definition of item to add.
37126 getChildContainer: function () {
37127 return this.getEl();
37132 var ret = new Roo.factory(cfg);
37137 if (cfg.xtype.match(/^Form$/)) {
37140 //if (this.footer) {
37141 // el = this.footer.container.insertSibling(false, 'before');
37143 el = this.el.createChild();
37146 this.form = new Roo.form.Form(cfg);
37149 if ( this.form.allItems.length) {
37150 this.form.render(el.dom);
37154 // should only have one of theses..
37155 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37156 // views.. should not be just added - used named prop 'view''
37158 cfg.el = this.el.appendChild(document.createElement("div"));
37161 var ret = new Roo.factory(cfg);
37163 ret.render && ret.render(false, ''); // render blank..
37173 * @class Roo.bootstrap.panel.Grid
37174 * @extends Roo.bootstrap.panel.Content
37176 * Create a new GridPanel.
37177 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37178 * @param {Object} config A the config object
37184 Roo.bootstrap.panel.Grid = function(config)
37188 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37189 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37191 config.el = this.wrapper;
37192 //this.el = this.wrapper;
37194 if (config.container) {
37195 // ctor'ed from a Border/panel.grid
37198 this.wrapper.setStyle("overflow", "hidden");
37199 this.wrapper.addClass('roo-grid-container');
37204 if(config.toolbar){
37205 var tool_el = this.wrapper.createChild();
37206 this.toolbar = Roo.factory(config.toolbar);
37208 if (config.toolbar.items) {
37209 ti = config.toolbar.items ;
37210 delete config.toolbar.items ;
37214 this.toolbar.render(tool_el);
37215 for(var i =0;i < ti.length;i++) {
37216 // Roo.log(['add child', items[i]]);
37217 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37219 this.toolbar.items = nitems;
37221 delete config.toolbar;
37224 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37225 config.grid.scrollBody = true;;
37226 config.grid.monitorWindowResize = false; // turn off autosizing
37227 config.grid.autoHeight = false;
37228 config.grid.autoWidth = false;
37230 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37232 if (config.background) {
37233 // render grid on panel activation (if panel background)
37234 this.on('activate', function(gp) {
37235 if (!gp.grid.rendered) {
37236 gp.grid.render(this.wrapper);
37237 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37242 this.grid.render(this.wrapper);
37243 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37246 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37247 // ??? needed ??? config.el = this.wrapper;
37252 // xtype created footer. - not sure if will work as we normally have to render first..
37253 if (this.footer && !this.footer.el && this.footer.xtype) {
37255 var ctr = this.grid.getView().getFooterPanel(true);
37256 this.footer.dataSource = this.grid.dataSource;
37257 this.footer = Roo.factory(this.footer, Roo);
37258 this.footer.render(ctr);
37268 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37269 getId : function(){
37270 return this.grid.id;
37274 * Returns the grid for this panel
37275 * @return {Roo.bootstrap.Table}
37277 getGrid : function(){
37281 setSize : function(width, height){
37282 if(!this.ignoreResize(width, height)){
37283 var grid = this.grid;
37284 var size = this.adjustForComponents(width, height);
37285 var gridel = grid.getGridEl();
37286 gridel.setSize(size.width, size.height);
37288 var thd = grid.getGridEl().select('thead',true).first();
37289 var tbd = grid.getGridEl().select('tbody', true).first();
37291 tbd.setSize(width, height - thd.getHeight());
37300 beforeSlide : function(){
37301 this.grid.getView().scroller.clip();
37304 afterSlide : function(){
37305 this.grid.getView().scroller.unclip();
37308 destroy : function(){
37309 this.grid.destroy();
37311 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37316 * @class Roo.bootstrap.panel.Nest
37317 * @extends Roo.bootstrap.panel.Content
37319 * Create a new Panel, that can contain a layout.Border.
37322 * @param {Roo.BorderLayout} layout The layout for this panel
37323 * @param {String/Object} config A string to set only the title or a config object
37325 Roo.bootstrap.panel.Nest = function(config)
37327 // construct with only one argument..
37328 /* FIXME - implement nicer consturctors
37329 if (layout.layout) {
37331 layout = config.layout;
37332 delete config.layout;
37334 if (layout.xtype && !layout.getEl) {
37335 // then layout needs constructing..
37336 layout = Roo.factory(layout, Roo);
37340 config.el = config.layout.getEl();
37342 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37344 config.layout.monitorWindowResize = false; // turn off autosizing
37345 this.layout = config.layout;
37346 this.layout.getEl().addClass("roo-layout-nested-layout");
37353 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37355 setSize : function(width, height){
37356 if(!this.ignoreResize(width, height)){
37357 var size = this.adjustForComponents(width, height);
37358 var el = this.layout.getEl();
37359 if (size.height < 1) {
37360 el.setWidth(size.width);
37362 el.setSize(size.width, size.height);
37364 var touch = el.dom.offsetWidth;
37365 this.layout.layout();
37366 // ie requires a double layout on the first pass
37367 if(Roo.isIE && !this.initialized){
37368 this.initialized = true;
37369 this.layout.layout();
37374 // activate all subpanels if not currently active..
37376 setActiveState : function(active){
37377 this.active = active;
37378 this.setActiveClass(active);
37381 this.fireEvent("deactivate", this);
37385 this.fireEvent("activate", this);
37386 // not sure if this should happen before or after..
37387 if (!this.layout) {
37388 return; // should not happen..
37391 for (var r in this.layout.regions) {
37392 reg = this.layout.getRegion(r);
37393 if (reg.getActivePanel()) {
37394 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37395 reg.setActivePanel(reg.getActivePanel());
37398 if (!reg.panels.length) {
37401 reg.showPanel(reg.getPanel(0));
37410 * Returns the nested BorderLayout for this panel
37411 * @return {Roo.BorderLayout}
37413 getLayout : function(){
37414 return this.layout;
37418 * Adds a xtype elements to the layout of the nested panel
37422 xtype : 'ContentPanel',
37429 xtype : 'NestedLayoutPanel',
37435 items : [ ... list of content panels or nested layout panels.. ]
37439 * @param {Object} cfg Xtype definition of item to add.
37441 addxtype : function(cfg) {
37442 return this.layout.addxtype(cfg);
37447 * Ext JS Library 1.1.1
37448 * Copyright(c) 2006-2007, Ext JS, LLC.
37450 * Originally Released Under LGPL - original licence link has changed is not relivant.
37453 * <script type="text/javascript">
37456 * @class Roo.TabPanel
37457 * @extends Roo.util.Observable
37458 * A lightweight tab container.
37462 // basic tabs 1, built from existing content
37463 var tabs = new Roo.TabPanel("tabs1");
37464 tabs.addTab("script", "View Script");
37465 tabs.addTab("markup", "View Markup");
37466 tabs.activate("script");
37468 // more advanced tabs, built from javascript
37469 var jtabs = new Roo.TabPanel("jtabs");
37470 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37472 // set up the UpdateManager
37473 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37474 var updater = tab2.getUpdateManager();
37475 updater.setDefaultUrl("ajax1.htm");
37476 tab2.on('activate', updater.refresh, updater, true);
37478 // Use setUrl for Ajax loading
37479 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37480 tab3.setUrl("ajax2.htm", null, true);
37483 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37486 jtabs.activate("jtabs-1");
37489 * Create a new TabPanel.
37490 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37491 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37493 Roo.bootstrap.panel.Tabs = function(config){
37495 * The container element for this TabPanel.
37496 * @type Roo.Element
37498 this.el = Roo.get(config.el);
37501 if(typeof config == "boolean"){
37502 this.tabPosition = config ? "bottom" : "top";
37504 Roo.apply(this, config);
37508 if(this.tabPosition == "bottom"){
37509 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37510 this.el.addClass("roo-tabs-bottom");
37512 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37513 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37514 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37516 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37518 if(this.tabPosition != "bottom"){
37519 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37520 * @type Roo.Element
37522 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37523 this.el.addClass("roo-tabs-top");
37527 this.bodyEl.setStyle("position", "relative");
37529 this.active = null;
37530 this.activateDelegate = this.activate.createDelegate(this);
37535 * Fires when the active tab changes
37536 * @param {Roo.TabPanel} this
37537 * @param {Roo.TabPanelItem} activePanel The new active tab
37541 * @event beforetabchange
37542 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37543 * @param {Roo.TabPanel} this
37544 * @param {Object} e Set cancel to true on this object to cancel the tab change
37545 * @param {Roo.TabPanelItem} tab The tab being changed to
37547 "beforetabchange" : true
37550 Roo.EventManager.onWindowResize(this.onResize, this);
37551 this.cpad = this.el.getPadding("lr");
37552 this.hiddenCount = 0;
37555 // toolbar on the tabbar support...
37556 if (this.toolbar) {
37557 alert("no toolbar support yet");
37558 this.toolbar = false;
37560 var tcfg = this.toolbar;
37561 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37562 this.toolbar = new Roo.Toolbar(tcfg);
37563 if (Roo.isSafari) {
37564 var tbl = tcfg.container.child('table', true);
37565 tbl.setAttribute('width', '100%');
37573 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37576 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37578 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37580 tabPosition : "top",
37582 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37584 currentTabWidth : 0,
37586 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37590 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37594 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37596 preferredTabWidth : 175,
37598 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37600 resizeTabs : false,
37602 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37604 monitorResize : true,
37606 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37611 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37612 * @param {String} id The id of the div to use <b>or create</b>
37613 * @param {String} text The text for the tab
37614 * @param {String} content (optional) Content to put in the TabPanelItem body
37615 * @param {Boolean} closable (optional) True to create a close icon on the tab
37616 * @return {Roo.TabPanelItem} The created TabPanelItem
37618 addTab : function(id, text, content, closable, tpl)
37620 var item = new Roo.bootstrap.panel.TabItem({
37624 closable : closable,
37627 this.addTabItem(item);
37629 item.setContent(content);
37635 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37636 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37637 * @return {Roo.TabPanelItem}
37639 getTab : function(id){
37640 return this.items[id];
37644 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37645 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37647 hideTab : function(id){
37648 var t = this.items[id];
37651 this.hiddenCount++;
37652 this.autoSizeTabs();
37657 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37658 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37660 unhideTab : function(id){
37661 var t = this.items[id];
37663 t.setHidden(false);
37664 this.hiddenCount--;
37665 this.autoSizeTabs();
37670 * Adds an existing {@link Roo.TabPanelItem}.
37671 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37673 addTabItem : function(item){
37674 this.items[item.id] = item;
37675 this.items.push(item);
37676 // if(this.resizeTabs){
37677 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37678 // this.autoSizeTabs();
37680 // item.autoSize();
37685 * Removes a {@link Roo.TabPanelItem}.
37686 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37688 removeTab : function(id){
37689 var items = this.items;
37690 var tab = items[id];
37691 if(!tab) { return; }
37692 var index = items.indexOf(tab);
37693 if(this.active == tab && items.length > 1){
37694 var newTab = this.getNextAvailable(index);
37699 this.stripEl.dom.removeChild(tab.pnode.dom);
37700 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37701 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37703 items.splice(index, 1);
37704 delete this.items[tab.id];
37705 tab.fireEvent("close", tab);
37706 tab.purgeListeners();
37707 this.autoSizeTabs();
37710 getNextAvailable : function(start){
37711 var items = this.items;
37713 // look for a next tab that will slide over to
37714 // replace the one being removed
37715 while(index < items.length){
37716 var item = items[++index];
37717 if(item && !item.isHidden()){
37721 // if one isn't found select the previous tab (on the left)
37724 var item = items[--index];
37725 if(item && !item.isHidden()){
37733 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37734 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37736 disableTab : function(id){
37737 var tab = this.items[id];
37738 if(tab && this.active != tab){
37744 * Enables a {@link Roo.TabPanelItem} that is disabled.
37745 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37747 enableTab : function(id){
37748 var tab = this.items[id];
37753 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37754 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37755 * @return {Roo.TabPanelItem} The TabPanelItem.
37757 activate : function(id){
37758 var tab = this.items[id];
37762 if(tab == this.active || tab.disabled){
37766 this.fireEvent("beforetabchange", this, e, tab);
37767 if(e.cancel !== true && !tab.disabled){
37769 this.active.hide();
37771 this.active = this.items[id];
37772 this.active.show();
37773 this.fireEvent("tabchange", this, this.active);
37779 * Gets the active {@link Roo.TabPanelItem}.
37780 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37782 getActiveTab : function(){
37783 return this.active;
37787 * Updates the tab body element to fit the height of the container element
37788 * for overflow scrolling
37789 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37791 syncHeight : function(targetHeight){
37792 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37793 var bm = this.bodyEl.getMargins();
37794 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37795 this.bodyEl.setHeight(newHeight);
37799 onResize : function(){
37800 if(this.monitorResize){
37801 this.autoSizeTabs();
37806 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37808 beginUpdate : function(){
37809 this.updating = true;
37813 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37815 endUpdate : function(){
37816 this.updating = false;
37817 this.autoSizeTabs();
37821 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37823 autoSizeTabs : function(){
37824 var count = this.items.length;
37825 var vcount = count - this.hiddenCount;
37826 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37829 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37830 var availWidth = Math.floor(w / vcount);
37831 var b = this.stripBody;
37832 if(b.getWidth() > w){
37833 var tabs = this.items;
37834 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37835 if(availWidth < this.minTabWidth){
37836 /*if(!this.sleft){ // incomplete scrolling code
37837 this.createScrollButtons();
37840 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37843 if(this.currentTabWidth < this.preferredTabWidth){
37844 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37850 * Returns the number of tabs in this TabPanel.
37853 getCount : function(){
37854 return this.items.length;
37858 * Resizes all the tabs to the passed width
37859 * @param {Number} The new width
37861 setTabWidth : function(width){
37862 this.currentTabWidth = width;
37863 for(var i = 0, len = this.items.length; i < len; i++) {
37864 if(!this.items[i].isHidden()) {
37865 this.items[i].setWidth(width);
37871 * Destroys this TabPanel
37872 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37874 destroy : function(removeEl){
37875 Roo.EventManager.removeResizeListener(this.onResize, this);
37876 for(var i = 0, len = this.items.length; i < len; i++){
37877 this.items[i].purgeListeners();
37879 if(removeEl === true){
37880 this.el.update("");
37885 createStrip : function(container)
37887 var strip = document.createElement("nav");
37888 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37889 container.appendChild(strip);
37893 createStripList : function(strip)
37895 // div wrapper for retard IE
37896 // returns the "tr" element.
37897 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37898 //'<div class="x-tabs-strip-wrap">'+
37899 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37900 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37901 return strip.firstChild; //.firstChild.firstChild.firstChild;
37903 createBody : function(container)
37905 var body = document.createElement("div");
37906 Roo.id(body, "tab-body");
37907 //Roo.fly(body).addClass("x-tabs-body");
37908 Roo.fly(body).addClass("tab-content");
37909 container.appendChild(body);
37912 createItemBody :function(bodyEl, id){
37913 var body = Roo.getDom(id);
37915 body = document.createElement("div");
37918 //Roo.fly(body).addClass("x-tabs-item-body");
37919 Roo.fly(body).addClass("tab-pane");
37920 bodyEl.insertBefore(body, bodyEl.firstChild);
37924 createStripElements : function(stripEl, text, closable, tpl)
37926 var td = document.createElement("li"); // was td..
37929 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37932 stripEl.appendChild(td);
37934 td.className = "x-tabs-closable";
37935 if(!this.closeTpl){
37936 this.closeTpl = new Roo.Template(
37937 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37938 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37939 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37942 var el = this.closeTpl.overwrite(td, {"text": text});
37943 var close = el.getElementsByTagName("div")[0];
37944 var inner = el.getElementsByTagName("em")[0];
37945 return {"el": el, "close": close, "inner": inner};
37948 // not sure what this is..
37949 // if(!this.tabTpl){
37950 //this.tabTpl = new Roo.Template(
37951 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37952 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37954 // this.tabTpl = new Roo.Template(
37955 // '<a href="#">' +
37956 // '<span unselectable="on"' +
37957 // (this.disableTooltips ? '' : ' title="{text}"') +
37958 // ' >{text}</span></a>'
37964 var template = tpl || this.tabTpl || false;
37968 template = new Roo.Template(
37970 '<span unselectable="on"' +
37971 (this.disableTooltips ? '' : ' title="{text}"') +
37972 ' >{text}</span></a>'
37976 switch (typeof(template)) {
37980 template = new Roo.Template(template);
37986 var el = template.overwrite(td, {"text": text});
37988 var inner = el.getElementsByTagName("span")[0];
37990 return {"el": el, "inner": inner};
37998 * @class Roo.TabPanelItem
37999 * @extends Roo.util.Observable
38000 * Represents an individual item (tab plus body) in a TabPanel.
38001 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38002 * @param {String} id The id of this TabPanelItem
38003 * @param {String} text The text for the tab of this TabPanelItem
38004 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38006 Roo.bootstrap.panel.TabItem = function(config){
38008 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38009 * @type Roo.TabPanel
38011 this.tabPanel = config.panel;
38013 * The id for this TabPanelItem
38016 this.id = config.id;
38018 this.disabled = false;
38020 this.text = config.text;
38022 this.loaded = false;
38023 this.closable = config.closable;
38026 * The body element for this TabPanelItem.
38027 * @type Roo.Element
38029 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38030 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38031 this.bodyEl.setStyle("display", "block");
38032 this.bodyEl.setStyle("zoom", "1");
38033 //this.hideAction();
38035 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38037 this.el = Roo.get(els.el);
38038 this.inner = Roo.get(els.inner, true);
38039 this.textEl = Roo.get(this.el.dom.firstChild, true);
38040 this.pnode = Roo.get(els.el.parentNode, true);
38041 // this.el.on("mousedown", this.onTabMouseDown, this);
38042 this.el.on("click", this.onTabClick, this);
38044 if(config.closable){
38045 var c = Roo.get(els.close, true);
38046 c.dom.title = this.closeText;
38047 c.addClassOnOver("close-over");
38048 c.on("click", this.closeClick, this);
38054 * Fires when this tab becomes the active tab.
38055 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38056 * @param {Roo.TabPanelItem} this
38060 * @event beforeclose
38061 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38062 * @param {Roo.TabPanelItem} this
38063 * @param {Object} e Set cancel to true on this object to cancel the close.
38065 "beforeclose": true,
38068 * Fires when this tab is closed.
38069 * @param {Roo.TabPanelItem} this
38073 * @event deactivate
38074 * Fires when this tab is no longer the active tab.
38075 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38076 * @param {Roo.TabPanelItem} this
38078 "deactivate" : true
38080 this.hidden = false;
38082 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38085 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38087 purgeListeners : function(){
38088 Roo.util.Observable.prototype.purgeListeners.call(this);
38089 this.el.removeAllListeners();
38092 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38095 this.pnode.addClass("active");
38098 this.tabPanel.stripWrap.repaint();
38100 this.fireEvent("activate", this.tabPanel, this);
38104 * Returns true if this tab is the active tab.
38105 * @return {Boolean}
38107 isActive : function(){
38108 return this.tabPanel.getActiveTab() == this;
38112 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38115 this.pnode.removeClass("active");
38117 this.fireEvent("deactivate", this.tabPanel, this);
38120 hideAction : function(){
38121 this.bodyEl.hide();
38122 this.bodyEl.setStyle("position", "absolute");
38123 this.bodyEl.setLeft("-20000px");
38124 this.bodyEl.setTop("-20000px");
38127 showAction : function(){
38128 this.bodyEl.setStyle("position", "relative");
38129 this.bodyEl.setTop("");
38130 this.bodyEl.setLeft("");
38131 this.bodyEl.show();
38135 * Set the tooltip for the tab.
38136 * @param {String} tooltip The tab's tooltip
38138 setTooltip : function(text){
38139 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38140 this.textEl.dom.qtip = text;
38141 this.textEl.dom.removeAttribute('title');
38143 this.textEl.dom.title = text;
38147 onTabClick : function(e){
38148 e.preventDefault();
38149 this.tabPanel.activate(this.id);
38152 onTabMouseDown : function(e){
38153 e.preventDefault();
38154 this.tabPanel.activate(this.id);
38157 getWidth : function(){
38158 return this.inner.getWidth();
38161 setWidth : function(width){
38162 var iwidth = width - this.pnode.getPadding("lr");
38163 this.inner.setWidth(iwidth);
38164 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38165 this.pnode.setWidth(width);
38169 * Show or hide the tab
38170 * @param {Boolean} hidden True to hide or false to show.
38172 setHidden : function(hidden){
38173 this.hidden = hidden;
38174 this.pnode.setStyle("display", hidden ? "none" : "");
38178 * Returns true if this tab is "hidden"
38179 * @return {Boolean}
38181 isHidden : function(){
38182 return this.hidden;
38186 * Returns the text for this tab
38189 getText : function(){
38193 autoSize : function(){
38194 //this.el.beginMeasure();
38195 this.textEl.setWidth(1);
38197 * #2804 [new] Tabs in Roojs
38198 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38200 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38201 //this.el.endMeasure();
38205 * Sets the text for the tab (Note: this also sets the tooltip text)
38206 * @param {String} text The tab's text and tooltip
38208 setText : function(text){
38210 this.textEl.update(text);
38211 this.setTooltip(text);
38212 //if(!this.tabPanel.resizeTabs){
38213 // this.autoSize();
38217 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38219 activate : function(){
38220 this.tabPanel.activate(this.id);
38224 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38226 disable : function(){
38227 if(this.tabPanel.active != this){
38228 this.disabled = true;
38229 this.pnode.addClass("disabled");
38234 * Enables this TabPanelItem if it was previously disabled.
38236 enable : function(){
38237 this.disabled = false;
38238 this.pnode.removeClass("disabled");
38242 * Sets the content for this TabPanelItem.
38243 * @param {String} content The content
38244 * @param {Boolean} loadScripts true to look for and load scripts
38246 setContent : function(content, loadScripts){
38247 this.bodyEl.update(content, loadScripts);
38251 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38252 * @return {Roo.UpdateManager} The UpdateManager
38254 getUpdateManager : function(){
38255 return this.bodyEl.getUpdateManager();
38259 * Set a URL to be used to load the content for this TabPanelItem.
38260 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38261 * @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)
38262 * @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)
38263 * @return {Roo.UpdateManager} The UpdateManager
38265 setUrl : function(url, params, loadOnce){
38266 if(this.refreshDelegate){
38267 this.un('activate', this.refreshDelegate);
38269 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38270 this.on("activate", this.refreshDelegate);
38271 return this.bodyEl.getUpdateManager();
38275 _handleRefresh : function(url, params, loadOnce){
38276 if(!loadOnce || !this.loaded){
38277 var updater = this.bodyEl.getUpdateManager();
38278 updater.update(url, params, this._setLoaded.createDelegate(this));
38283 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38284 * Will fail silently if the setUrl method has not been called.
38285 * This does not activate the panel, just updates its content.
38287 refresh : function(){
38288 if(this.refreshDelegate){
38289 this.loaded = false;
38290 this.refreshDelegate();
38295 _setLoaded : function(){
38296 this.loaded = true;
38300 closeClick : function(e){
38303 this.fireEvent("beforeclose", this, o);
38304 if(o.cancel !== true){
38305 this.tabPanel.removeTab(this.id);
38309 * The text displayed in the tooltip for the close icon.
38312 closeText : "Close this tab"
38315 * This script refer to:
38316 * Title: International Telephone Input
38317 * Author: Jack O'Connor
38318 * Code version: v12.1.12
38319 * Availability: https://github.com/jackocnr/intl-tel-input.git
38322 Roo.bootstrap.PhoneInputData = function() {
38325 "Afghanistan (افغانستان)",
38330 "Albania (Shqipëri)",
38335 "Algeria (الجزائر)",
38360 "Antigua and Barbuda",
38370 "Armenia (Հայաստան)",
38386 "Austria (Österreich)",
38391 "Azerbaijan (Azərbaycan)",
38401 "Bahrain (البحرين)",
38406 "Bangladesh (বাংলাদেশ)",
38416 "Belarus (Беларусь)",
38421 "Belgium (België)",
38451 "Bosnia and Herzegovina (Босна и Херцеговина)",
38466 "British Indian Ocean Territory",
38471 "British Virgin Islands",
38481 "Bulgaria (България)",
38491 "Burundi (Uburundi)",
38496 "Cambodia (កម្ពុជា)",
38501 "Cameroon (Cameroun)",
38510 ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38513 "Cape Verde (Kabu Verdi)",
38518 "Caribbean Netherlands",
38529 "Central African Republic (République centrafricaine)",
38549 "Christmas Island",
38555 "Cocos (Keeling) Islands",
38566 "Comoros (جزر القمر)",
38571 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38576 "Congo (Republic) (Congo-Brazzaville)",
38596 "Croatia (Hrvatska)",
38617 "Czech Republic (Česká republika)",
38622 "Denmark (Danmark)",
38637 "Dominican Republic (República Dominicana)",
38641 ["809", "829", "849"]
38659 "Equatorial Guinea (Guinea Ecuatorial)",
38679 "Falkland Islands (Islas Malvinas)",
38684 "Faroe Islands (Føroyar)",
38705 "French Guiana (Guyane française)",
38710 "French Polynesia (Polynésie française)",
38725 "Georgia (საქართველო)",
38730 "Germany (Deutschland)",
38750 "Greenland (Kalaallit Nunaat)",
38787 "Guinea-Bissau (Guiné Bissau)",
38812 "Hungary (Magyarország)",
38817 "Iceland (Ísland)",
38837 "Iraq (العراق)",
38853 "Israel (ישראל)",
38880 "Jordan (الأردن)",
38885 "Kazakhstan (Казахстан)",
38906 "Kuwait (الكويت)",
38911 "Kyrgyzstan (Кыргызстан)",
38921 "Latvia (Latvija)",
38926 "Lebanon (لبنان)",
38941 "Libya (ليبيا)",
38951 "Lithuania (Lietuva)",
38966 "Macedonia (FYROM) (Македонија)",
38971 "Madagascar (Madagasikara)",
39001 "Marshall Islands",
39011 "Mauritania (موريتانيا)",
39016 "Mauritius (Moris)",
39037 "Moldova (Republica Moldova)",
39047 "Mongolia (Монгол)",
39052 "Montenegro (Crna Gora)",
39062 "Morocco (المغرب)",
39068 "Mozambique (Moçambique)",
39073 "Myanmar (Burma) (မြန်မာ)",
39078 "Namibia (Namibië)",
39093 "Netherlands (Nederland)",
39098 "New Caledonia (Nouvelle-Calédonie)",
39133 "North Korea (조선 민주주의 인민 공화국)",
39138 "Northern Mariana Islands",
39154 "Pakistan (پاکستان)",
39164 "Palestine (فلسطين)",
39174 "Papua New Guinea",
39216 "Réunion (La Réunion)",
39222 "Romania (România)",
39238 "Saint Barthélemy",
39249 "Saint Kitts and Nevis",
39259 "Saint Martin (Saint-Martin (partie française))",
39265 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39270 "Saint Vincent and the Grenadines",
39285 "São Tomé and Príncipe (São Tomé e Príncipe)",
39290 "Saudi Arabia (المملكة العربية السعودية)",
39295 "Senegal (Sénégal)",
39325 "Slovakia (Slovensko)",
39330 "Slovenia (Slovenija)",
39340 "Somalia (Soomaaliya)",
39350 "South Korea (대한민국)",
39355 "South Sudan (جنوب السودان)",
39365 "Sri Lanka (ශ්රී ලංකාව)",
39370 "Sudan (السودان)",
39380 "Svalbard and Jan Mayen",
39391 "Sweden (Sverige)",
39396 "Switzerland (Schweiz)",
39401 "Syria (سوريا)",
39446 "Trinidad and Tobago",
39451 "Tunisia (تونس)",
39456 "Turkey (Türkiye)",
39466 "Turks and Caicos Islands",
39476 "U.S. Virgin Islands",
39486 "Ukraine (Україна)",
39491 "United Arab Emirates (الإمارات العربية المتحدة)",
39513 "Uzbekistan (Oʻzbekiston)",
39523 "Vatican City (Città del Vaticano)",
39534 "Vietnam (Việt Nam)",
39539 "Wallis and Futuna (Wallis-et-Futuna)",
39544 "Western Sahara (الصحراء الغربية)",
39550 "Yemen (اليمن)",
39574 * This script refer to:
39575 * Title: International Telephone Input
39576 * Author: Jack O'Connor
39577 * Code version: v12.1.12
39578 * Availability: https://github.com/jackocnr/intl-tel-input.git
39582 * @class Roo.bootstrap.PhoneInput
39583 * @extends Roo.bootstrap.TriggerField
39584 * An input with International dial-code selection
39586 * @cfg {String} defaultDialCode default '+852'
39587 * @cfg {Array} preferedCountries default []
39590 * Create a new PhoneInput.
39591 * @param {Object} config Configuration options
39594 Roo.bootstrap.PhoneInput = function(config) {
39595 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39598 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39600 listWidth: undefined,
39602 selectedClass: 'active',
39604 invalidClass : "has-warning",
39606 validClass: 'has-success',
39608 allowed: '0123456789',
39611 * @cfg {String} defaultDialCode The default dial code when initializing the input
39613 defaultDialCode: '+852',
39616 * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
39618 preferedCountries: false,
39620 getAutoCreate : function()
39622 var data = Roo.bootstrap.PhoneInputData();
39623 var align = this.labelAlign || this.parentLabelAlign();
39626 this.allCountries = [];
39627 this.dialCodeMapping = [];
39629 for (var i = 0; i < data.length; i++) {
39631 this.allCountries[i] = {
39635 priority: c[3] || 0,
39636 areaCodes: c[4] || null
39638 this.dialCodeMapping[c[2]] = {
39641 priority: c[3] || 0,
39642 areaCodes: c[4] || null
39654 cls : 'form-control tel-input',
39655 autocomplete: 'new-password'
39658 var hiddenInput = {
39661 cls: 'hidden-tel-input'
39665 hiddenInput.name = this.name;
39668 if (this.disabled) {
39669 input.disabled = true;
39672 var flag_container = {
39689 cls: this.hasFeedback ? 'has-feedback' : '',
39695 cls: 'dial-code-holder',
39702 cls: 'roo-select2-container input-group',
39709 if (this.fieldLabel.length) {
39712 tooltip: 'This field is required'
39718 cls: 'control-label',
39724 html: this.fieldLabel
39727 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39733 if(this.indicatorpos == 'right') {
39734 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39741 if(align == 'left') {
39749 if(this.labelWidth > 12){
39750 label.style = "width: " + this.labelWidth + 'px';
39752 if(this.labelWidth < 13 && this.labelmd == 0){
39753 this.labelmd = this.labelWidth;
39755 if(this.labellg > 0){
39756 label.cls += ' col-lg-' + this.labellg;
39757 input.cls += ' col-lg-' + (12 - this.labellg);
39759 if(this.labelmd > 0){
39760 label.cls += ' col-md-' + this.labelmd;
39761 container.cls += ' col-md-' + (12 - this.labelmd);
39763 if(this.labelsm > 0){
39764 label.cls += ' col-sm-' + this.labelsm;
39765 container.cls += ' col-sm-' + (12 - this.labelsm);
39767 if(this.labelxs > 0){
39768 label.cls += ' col-xs-' + this.labelxs;
39769 container.cls += ' col-xs-' + (12 - this.labelxs);
39779 var settings = this;
39781 ['xs','sm','md','lg'].map(function(size){
39782 if (settings[size]) {
39783 cfg.cls += ' col-' + size + '-' + settings[size];
39787 this.store = new Roo.data.Store({
39788 proxy : new Roo.data.MemoryProxy({}),
39789 reader : new Roo.data.JsonReader({
39800 'name' : 'dialCode',
39804 'name' : 'priority',
39808 'name' : 'areaCodes',
39815 if(!this.preferedCountries) {
39816 this.preferedCountries = [
39823 var p = this.preferedCountries.reverse();
39826 for (var i = 0; i < p.length; i++) {
39827 for (var j = 0; j < this.allCountries.length; j++) {
39828 if(this.allCountries[j].iso2 == p[i]) {
39829 var t = this.allCountries[j];
39830 this.allCountries.splice(j,1);
39831 this.allCountries.unshift(t);
39837 this.store.proxy.data = {
39839 data: this.allCountries
39845 initEvents : function()
39848 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39850 this.indicator = this.indicatorEl();
39851 this.flag = this.flagEl();
39852 this.dialCodeHolder = this.dialCodeHolderEl();
39854 this.trigger = this.el.select('div.flag-box',true).first();
39855 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39860 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39861 _this.list.setWidth(lw);
39864 this.list.on('mouseover', this.onViewOver, this);
39865 this.list.on('mousemove', this.onViewMove, this);
39866 this.inputEl().on("keyup", this.onKeyUp, this);
39868 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39870 this.view = new Roo.View(this.list, this.tpl, {
39871 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39874 this.view.on('click', this.onViewClick, this);
39875 this.setValue(this.defaultDialCode);
39878 onTriggerClick : function(e)
39880 Roo.log('trigger click');
39885 if(this.isExpanded()){
39887 this.hasFocus = false;
39889 this.store.load({});
39890 this.hasFocus = true;
39895 isExpanded : function()
39897 return this.list.isVisible();
39900 collapse : function()
39902 if(!this.isExpanded()){
39906 Roo.get(document).un('mousedown', this.collapseIf, this);
39907 Roo.get(document).un('mousewheel', this.collapseIf, this);
39908 this.fireEvent('collapse', this);
39912 expand : function()
39916 if(this.isExpanded() || !this.hasFocus){
39920 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39921 this.list.setWidth(lw);
39924 this.restrictHeight();
39926 Roo.get(document).on('mousedown', this.collapseIf, this);
39927 Roo.get(document).on('mousewheel', this.collapseIf, this);
39929 this.fireEvent('expand', this);
39932 restrictHeight : function()
39934 this.list.alignTo(this.inputEl(), this.listAlign);
39935 this.list.alignTo(this.inputEl(), this.listAlign);
39938 onViewOver : function(e, t)
39940 if(this.inKeyMode){
39943 var item = this.view.findItemFromChild(t);
39946 var index = this.view.indexOf(item);
39947 this.select(index, false);
39952 onViewClick : function(view, doFocus, el, e)
39954 var index = this.view.getSelectedIndexes()[0];
39956 var r = this.store.getAt(index);
39959 this.onSelect(r, index);
39961 if(doFocus !== false && !this.blockFocus){
39962 this.inputEl().focus();
39966 onViewMove : function(e, t)
39968 this.inKeyMode = false;
39971 select : function(index, scrollIntoView)
39973 this.selectedIndex = index;
39974 this.view.select(index);
39975 if(scrollIntoView !== false){
39976 var el = this.view.getNode(index);
39978 this.list.scrollChildIntoView(el, false);
39983 createList : function()
39985 this.list = Roo.get(document.body).createChild({
39987 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39988 style: 'display:none'
39990 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39993 collapseIf : function(e)
39995 var in_combo = e.within(this.el);
39996 var in_list = e.within(this.list);
39997 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39999 if (in_combo || in_list || is_list) {
40005 onSelect : function(record, index)
40007 if(this.fireEvent('beforeselect', this, record, index) !== false){
40009 this.setFlagClass(record.data.iso2);
40010 this.setDialCode(record.data.dialCode);
40011 this.hasFocus = false;
40013 this.fireEvent('select', this, record, index);
40017 flagEl : function()
40019 var flag = this.el.select('div.flag',true).first();
40026 dialCodeHolderEl : function()
40028 var d = this.el.select('input.dial-code-holder',true).first();
40035 setDialCode : function(v)
40037 this.dialCodeHolder.dom.value = '+'+v;
40040 setFlagClass : function(n)
40042 this.flag.dom.className = 'flag '+n;
40045 getValue : function()
40047 var v = this.inputEl().getValue();
40048 if(this.dialCodeHolder) {
40049 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40054 setValue : function(v)
40056 var d = this.getDialCode(v);
40058 //invalid dial code
40059 if(v.length == 0 || !d || d.length == 0) {
40061 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40062 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40068 this.setFlagClass(this.dialCodeMapping[d].iso2);
40069 this.setDialCode(d);
40070 this.inputEl().dom.value = v.replace('+'+d,'');
40071 this.hiddenEl().dom.value = this.getValue();
40076 getDialCode : function(v = '')
40078 if (v.length == 0) {
40079 return this.dialCodeHolder.dom.value;
40083 if (v.charAt(0) != "+") {
40086 var numericChars = "";
40087 for (var i = 1; i < v.length; i++) {
40088 var c = v.charAt(i);
40091 if (this.dialCodeMapping[numericChars]) {
40092 dialCode = v.substr(1, i);
40094 if (numericChars.length == 4) {
40104 this.setValue(this.defaultDialCode);
40108 hiddenEl : function()
40110 return this.el.select('input.hidden-tel-input',true).first();
40113 onKeyUp : function(e){
40115 var k = e.getKey();
40116 var c = e.getCharCode();
40119 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40120 this.allowed.indexOf(String.fromCharCode(c)) === -1
40125 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40128 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40132 this.setValue(this.getValue());
40137 * @class Roo.bootstrap.MoneyField
40138 * @extends Roo.bootstrap.ComboBox
40139 * Bootstrap MoneyField class
40142 * Create a new MoneyField.
40143 * @param {Object} config Configuration options
40146 Roo.bootstrap.MoneyField = function(config) {
40148 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40152 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40155 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40157 allowDecimals : true,
40159 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40161 decimalSeparator : ".",
40163 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40165 decimalPrecision : 0,
40167 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40169 allowNegative : true,
40171 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40173 minValue : Number.NEGATIVE_INFINITY,
40175 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40177 maxValue : Number.MAX_VALUE,
40179 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40181 minText : "The minimum value for this field is {0}",
40183 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40185 maxText : "The maximum value for this field is {0}",
40187 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40188 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40190 nanText : "{0} is not a valid number",
40192 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40196 * @cfg {String} defaults currency of the MoneyField
40197 * value should be in lkey
40199 defaultCurrency : false,
40201 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40203 thousandsDelimiter : false,
40213 getAutoCreate : function()
40215 var align = this.labelAlign || this.parentLabelAlign();
40227 cls : 'form-control roo-money-amount-input',
40228 autocomplete: 'new-password'
40231 var hiddenInput = {
40235 cls: 'hidden-number-input'
40239 hiddenInput.name = this.name;
40242 if (this.disabled) {
40243 input.disabled = true;
40246 var clg = 12 - this.inputlg;
40247 var cmd = 12 - this.inputmd;
40248 var csm = 12 - this.inputsm;
40249 var cxs = 12 - this.inputxs;
40253 cls : 'row roo-money-field',
40257 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40261 cls: 'roo-select2-container input-group',
40265 cls : 'form-control roo-money-currency-input',
40266 autocomplete: 'new-password',
40268 name : this.currencyName
40272 cls : 'input-group-addon',
40286 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40290 cls: this.hasFeedback ? 'has-feedback' : '',
40301 if (this.fieldLabel.length) {
40304 tooltip: 'This field is required'
40310 cls: 'control-label',
40316 html: this.fieldLabel
40319 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40325 if(this.indicatorpos == 'right') {
40326 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40333 if(align == 'left') {
40341 if(this.labelWidth > 12){
40342 label.style = "width: " + this.labelWidth + 'px';
40344 if(this.labelWidth < 13 && this.labelmd == 0){
40345 this.labelmd = this.labelWidth;
40347 if(this.labellg > 0){
40348 label.cls += ' col-lg-' + this.labellg;
40349 input.cls += ' col-lg-' + (12 - this.labellg);
40351 if(this.labelmd > 0){
40352 label.cls += ' col-md-' + this.labelmd;
40353 container.cls += ' col-md-' + (12 - this.labelmd);
40355 if(this.labelsm > 0){
40356 label.cls += ' col-sm-' + this.labelsm;
40357 container.cls += ' col-sm-' + (12 - this.labelsm);
40359 if(this.labelxs > 0){
40360 label.cls += ' col-xs-' + this.labelxs;
40361 container.cls += ' col-xs-' + (12 - this.labelxs);
40372 var settings = this;
40374 ['xs','sm','md','lg'].map(function(size){
40375 if (settings[size]) {
40376 cfg.cls += ' col-' + size + '-' + settings[size];
40383 initEvents : function()
40385 this.indicator = this.indicatorEl();
40387 this.initCurrencyEvent();
40389 this.initNumberEvent();
40392 initCurrencyEvent : function()
40395 throw "can not find store for combo";
40398 this.store = Roo.factory(this.store, Roo.data);
40399 this.store.parent = this;
40403 this.triggerEl = this.el.select('.input-group-addon', true).first();
40405 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40410 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40411 _this.list.setWidth(lw);
40414 this.list.on('mouseover', this.onViewOver, this);
40415 this.list.on('mousemove', this.onViewMove, this);
40416 this.list.on('scroll', this.onViewScroll, this);
40419 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40422 this.view = new Roo.View(this.list, this.tpl, {
40423 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40426 this.view.on('click', this.onViewClick, this);
40428 this.store.on('beforeload', this.onBeforeLoad, this);
40429 this.store.on('load', this.onLoad, this);
40430 this.store.on('loadexception', this.onLoadException, this);
40432 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40433 "up" : function(e){
40434 this.inKeyMode = true;
40438 "down" : function(e){
40439 if(!this.isExpanded()){
40440 this.onTriggerClick();
40442 this.inKeyMode = true;
40447 "enter" : function(e){
40450 if(this.fireEvent("specialkey", this, e)){
40451 this.onViewClick(false);
40457 "esc" : function(e){
40461 "tab" : function(e){
40464 if(this.fireEvent("specialkey", this, e)){
40465 this.onViewClick(false);
40473 doRelay : function(foo, bar, hname){
40474 if(hname == 'down' || this.scope.isExpanded()){
40475 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40483 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40487 initNumberEvent : function(e)
40489 this.inputEl().on("keydown" , this.fireKey, this);
40490 this.inputEl().on("focus", this.onFocus, this);
40491 this.inputEl().on("blur", this.onBlur, this);
40493 this.inputEl().relayEvent('keyup', this);
40495 if(this.indicator){
40496 this.indicator.addClass('invisible');
40499 this.originalValue = this.getValue();
40501 if(this.validationEvent == 'keyup'){
40502 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40503 this.inputEl().on('keyup', this.filterValidation, this);
40505 else if(this.validationEvent !== false){
40506 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40509 if(this.selectOnFocus){
40510 this.on("focus", this.preFocus, this);
40513 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40514 this.inputEl().on("keypress", this.filterKeys, this);
40516 this.inputEl().relayEvent('keypress', this);
40519 var allowed = "0123456789";
40521 if(this.allowDecimals){
40522 allowed += this.decimalSeparator;
40525 if(this.allowNegative){
40529 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40531 var keyPress = function(e){
40533 var k = e.getKey();
40535 var c = e.getCharCode();
40538 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40539 allowed.indexOf(String.fromCharCode(c)) === -1
40545 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40549 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40554 this.inputEl().on("keypress", keyPress, this);
40558 onTriggerClick : function(e)
40565 this.loadNext = false;
40567 if(this.isExpanded()){
40572 this.hasFocus = true;
40574 if(this.triggerAction == 'all') {
40575 this.doQuery(this.allQuery, true);
40579 this.doQuery(this.getRawValue());
40582 getCurrency : function()
40584 var v = this.currencyEl().getValue();
40589 restrictHeight : function()
40591 this.list.alignTo(this.currencyEl(), this.listAlign);
40592 this.list.alignTo(this.currencyEl(), this.listAlign);
40595 onViewClick : function(view, doFocus, el, e)
40597 var index = this.view.getSelectedIndexes()[0];
40599 var r = this.store.getAt(index);
40602 this.onSelect(r, index);
40606 onSelect : function(record, index){
40608 if(this.fireEvent('beforeselect', this, record, index) !== false){
40610 this.setFromCurrencyData(index > -1 ? record.data : false);
40614 this.fireEvent('select', this, record, index);
40618 setFromCurrencyData : function(o)
40622 this.lastCurrency = o;
40624 if (this.currencyField) {
40625 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40627 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40630 this.lastSelectionText = currency;
40632 //setting default currency
40633 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40634 this.setCurrency(this.defaultCurrency);
40638 this.setCurrency(currency);
40641 setFromData : function(o)
40645 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40647 this.setFromCurrencyData(c);
40652 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40654 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40657 this.setValue(value);
40661 setCurrency : function(v)
40663 this.currencyValue = v;
40666 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40671 setValue : function(v)
40673 v = this.fixPrecision(v);
40675 v = String(v).replace(".", this.decimalSeparator);
40681 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40683 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40684 this.thousandsDelimiter || ','
40687 if(this.allowBlank && !v) {
40688 this.inputEl().dom.value = '';
40695 getRawValue : function()
40697 var v = this.inputEl().getValue();
40702 getValue : function()
40704 return this.fixPrecision(this.parseValue(this.getRawValue()));
40707 parseValue : function(value)
40709 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40710 return isNaN(value) ? '' : value;
40713 fixPrecision : function(value)
40715 var nan = isNaN(value);
40717 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40718 return nan ? '' : value;
40721 return parseFloat(value).toFixed(this.decimalPrecision);
40724 decimalPrecisionFcn : function(v)
40726 return Math.floor(v);
40729 validateValue : function(value)
40731 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40735 var num = this.parseValue(value);
40738 this.markInvalid(String.format(this.nanText, value));
40742 if(num < this.minValue){
40743 this.markInvalid(String.format(this.minText, this.minValue));
40747 if(num > this.maxValue){
40748 this.markInvalid(String.format(this.maxText, this.maxValue));
40755 validate : function()
40757 if(this.disabled || this.allowBlank){
40762 var currency = this.getCurrency();
40764 if(this.validateValue(this.getRawValue()) && currency.length){
40769 this.markInvalid();
40773 getName: function()
40778 beforeBlur : function()
40784 var v = this.parseValue(this.getRawValue());
40791 onBlur : function()
40795 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40796 //this.el.removeClass(this.focusClass);
40799 this.hasFocus = false;
40801 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40805 var v = this.getValue();
40807 if(String(v) !== String(this.startValue)){
40808 this.fireEvent('change', this, v, this.startValue);
40811 this.fireEvent("blur", this);
40814 inputEl : function()
40816 return this.el.select('.roo-money-amount-input', true).first();
40819 currencyEl : function()
40821 return this.el.select('.roo-money-currency-input', true).first();
40824 hiddenEl : function()
40826 return this.el.select('input.hidden-number-input',true).first();