3 * @class Roo.bootstrap.form.MoneyField
4 * @extends Roo.bootstrap.form.ComboBox
5 * Bootstrap MoneyField class
8 * Create a new MoneyField.
9 * @param {Object} config Configuration options
12 Roo.bootstrap.form.MoneyField = function(config) {
14 Roo.bootstrap.form.MoneyField.superclass.constructor.call(this, config);
18 Roo.extend(Roo.bootstrap.form.MoneyField, Roo.bootstrap.form.ComboBox, {
21 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
25 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
27 decimalSeparator : ".",
29 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
41 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
43 minValue : Number.NEGATIVE_INFINITY,
45 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
47 maxValue : Number.MAX_VALUE,
49 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
51 minText : "The minimum value for this field is {0}",
53 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
55 maxText : "The maximum value for this field is {0}",
57 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
58 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
60 nanText : "{0} is not a valid number",
62 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
66 * @cfg {String} defaults currency of the MoneyField
67 * value should be in lkey
69 defaultCurrency : false,
71 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
73 thousandsDelimiter : false,
75 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
84 * @cfg {Roo.data.Store} store Store to lookup currency??
88 getAutoCreate : function()
90 var align = this.labelAlign || this.parentLabelAlign();
102 cls : 'form-control roo-money-amount-input',
103 autocomplete: 'new-password'
110 cls: 'hidden-number-input'
113 if(this.max_length) {
114 input.maxlength = this.max_length;
118 hiddenInput.name = this.name;
122 input.disabled = true;
125 var clg = 12 - this.inputlg;
126 var cmd = 12 - this.inputmd;
127 var csm = 12 - this.inputsm;
128 var cxs = 12 - this.inputxs;
132 cls : 'row roo-money-field',
136 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
140 cls: 'roo-select2-container input-group',
144 cls : 'form-control roo-money-currency-input',
145 autocomplete: 'new-password',
147 name : this.currencyName
151 cls : 'input-group-addon',
165 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
169 cls: this.hasFeedback ? 'has-feedback' : '',
180 if (this.fieldLabel.length) {
183 tooltip: 'This field is required'
189 cls: 'control-label',
195 html: this.fieldLabel
198 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
204 if(this.indicatorpos == 'right') {
205 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
212 if(align == 'left') {
220 if(this.labelWidth > 12){
221 label.style = "width: " + this.labelWidth + 'px';
223 if(this.labelWidth < 13 && this.labelmd == 0){
224 this.labelmd = this.labelWidth;
226 if(this.labellg > 0){
227 label.cls += ' col-lg-' + this.labellg;
228 input.cls += ' col-lg-' + (12 - this.labellg);
230 if(this.labelmd > 0){
231 label.cls += ' col-md-' + this.labelmd;
232 container.cls += ' col-md-' + (12 - this.labelmd);
234 if(this.labelsm > 0){
235 label.cls += ' col-sm-' + this.labelsm;
236 container.cls += ' col-sm-' + (12 - this.labelsm);
238 if(this.labelxs > 0){
239 label.cls += ' col-xs-' + this.labelxs;
240 container.cls += ' col-xs-' + (12 - this.labelxs);
253 ['xs','sm','md','lg'].map(function(size){
254 if (settings[size]) {
255 cfg.cls += ' col-' + size + '-' + settings[size];
262 initEvents : function()
264 this.indicator = this.indicatorEl();
266 this.initCurrencyEvent();
268 this.initNumberEvent();
271 initCurrencyEvent : function()
274 throw "can not find store for combo";
277 this.store = Roo.factory(this.store, Roo.data);
278 this.store.parent = this;
282 this.triggerEl = this.el.select('.input-group-addon', true).first();
284 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
289 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
290 _this.list.setWidth(lw);
293 this.list.on('mouseover', this.onViewOver, this);
294 this.list.on('mousemove', this.onViewMove, this);
295 this.list.on('scroll', this.onViewScroll, this);
298 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
301 this.view = new Roo.View(this.list, this.tpl, {
302 singleSelect:true, store: this.store, selectedClass: this.selectedClass
305 this.view.on('click', this.onViewClick, this);
307 this.store.on('beforeload', this.onBeforeLoad, this);
308 this.store.on('load', this.onLoad, this);
309 this.store.on('loadexception', this.onLoadException, this);
311 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
313 this.inKeyMode = true;
317 "down" : function(e){
318 if(!this.isExpanded()){
319 this.onTriggerClick();
321 this.inKeyMode = true;
326 "enter" : function(e){
329 if(this.fireEvent("specialkey", this, e)){
330 this.onViewClick(false);
343 if(this.fireEvent("specialkey", this, e)){
344 this.onViewClick(false);
352 doRelay : function(foo, bar, hname){
353 if(hname == 'down' || this.scope.isExpanded()){
354 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
362 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
366 initNumberEvent : function(e)
368 this.inputEl().on("keydown" , this.fireKey, this);
369 this.inputEl().on("focus", this.onFocus, this);
370 this.inputEl().on("blur", this.onBlur, this);
372 this.inputEl().relayEvent('keyup', this);
375 this.indicator.addClass('invisible');
378 this.originalValue = this.getValue();
380 if(this.validationEvent == 'keyup'){
381 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
382 this.inputEl().on('keyup', this.filterValidation, this);
384 else if(this.validationEvent !== false){
385 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
388 if(this.selectOnFocus){
389 this.on("focus", this.preFocus, this);
392 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
393 this.inputEl().on("keypress", this.filterKeys, this);
395 this.inputEl().relayEvent('keypress', this);
398 var allowed = "0123456789";
400 if(this.allowDecimals){
401 allowed += this.decimalSeparator;
404 if(this.allowNegative){
408 if(this.thousandsDelimiter) {
412 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
414 var keyPress = function(e){
418 var c = e.getCharCode();
421 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
422 allowed.indexOf(String.fromCharCode(c)) === -1
428 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
432 if(allowed.indexOf(String.fromCharCode(c)) === -1){
437 this.inputEl().on("keypress", keyPress, this);
441 onTriggerClick : function(e)
448 this.loadNext = false;
450 if(this.isExpanded()){
455 this.hasFocus = true;
457 if(this.triggerAction == 'all') {
458 this.doQuery(this.allQuery, true);
462 this.doQuery(this.getRawValue());
465 getCurrency : function()
467 var v = this.currencyEl().getValue();
472 restrictHeight : function()
474 this.list.alignTo(this.currencyEl(), this.listAlign);
475 this.list.alignTo(this.currencyEl(), this.listAlign);
478 onViewClick : function(view, doFocus, el, e)
480 var index = this.view.getSelectedIndexes()[0];
482 var r = this.store.getAt(index);
485 this.onSelect(r, index);
489 onSelect : function(record, index){
491 if(this.fireEvent('beforeselect', this, record, index) !== false){
493 this.setFromCurrencyData(index > -1 ? record.data : false);
497 this.fireEvent('select', this, record, index);
501 setFromCurrencyData : function(o)
505 this.lastCurrency = o;
507 if (this.currencyField) {
508 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
510 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
513 this.lastSelectionText = currency;
515 //setting default currency
516 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
517 this.setCurrency(this.defaultCurrency);
521 this.setCurrency(currency);
524 setFromData : function(o)
528 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
530 this.setFromCurrencyData(c);
535 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
537 Roo.log('no value set for '+ (this.name ? this.name : this.id));
540 this.setValue(value);
544 setCurrency : function(v)
546 this.currencyValue = v;
549 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
554 setValue : function(v)
556 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
562 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
564 this.inputEl().dom.value = (v == '') ? '' :
565 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
567 if(!this.allowZero && v === '0') {
568 this.hiddenEl().dom.value = '';
569 this.inputEl().dom.value = '';
576 getRawValue : function()
578 var v = this.inputEl().getValue();
583 getValue : function()
585 return this.fixPrecision(this.parseValue(this.getRawValue()));
588 parseValue : function(value)
590 if(this.thousandsDelimiter) {
592 r = new RegExp(",", "g");
593 value = value.replace(r, "");
596 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
597 return isNaN(value) ? '' : value;
601 fixPrecision : function(value)
603 if(this.thousandsDelimiter) {
605 r = new RegExp(",", "g");
606 value = value.replace(r, "");
609 var nan = isNaN(value);
611 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
612 return nan ? '' : value;
614 return parseFloat(value).toFixed(this.decimalPrecision);
617 decimalPrecisionFcn : function(v)
619 return Math.floor(v);
622 validateValue : function(value)
624 if(!Roo.bootstrap.form.MoneyField.superclass.validateValue.call(this, value)){
628 var num = this.parseValue(value);
631 this.markInvalid(String.format(this.nanText, value));
635 if(num < this.minValue){
636 this.markInvalid(String.format(this.minText, this.minValue));
640 if(num > this.maxValue){
641 this.markInvalid(String.format(this.maxText, this.maxValue));
648 validate : function()
650 if(this.disabled || this.allowBlank){
655 var currency = this.getCurrency();
657 if(this.validateValue(this.getRawValue()) && currency.length){
671 beforeBlur : function()
677 var v = this.parseValue(this.getRawValue());
688 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
689 //this.el.removeClass(this.focusClass);
692 this.hasFocus = false;
694 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
698 var v = this.getValue();
700 if(String(v) !== String(this.startValue)){
701 this.fireEvent('change', this, v, this.startValue);
704 this.fireEvent("blur", this);
709 return this.el.select('.roo-money-amount-input', true).first();
712 currencyEl : function()
714 return this.el.select('.roo-money-currency-input', true).first();
717 hiddenEl : function()
719 return this.el.select('input.hidden-number-input',true).first();