/*---
* @xtype ux.numberfield
* @class Ext.ux.form.NumberField
* @extends Ext.form.NumberField
* Numeric text field that provides automatic keystroke filtering and numeric validation
* Also resolves bugs by enforcing allowDecimals (fixed in validation) and allowNegative (fixed by setting minValue if no negatives allowed)
---*/
Ext.ns('Ext.ux.form');
Ext.ux.form.NumberField = Ext.extend(Ext.form.NumberField, {
//=== PUBLIC PROPERTIES ===//
// Defaults
// @cfg {boolean} decorateNumber turns on\off functionality related to applying decoration onblur
// and removing decoration onfocus and before submit
decorateNumber: true,
// Custom
selectOnFocus: true,
// Localization
decimalSeparator: '.',
groupingSymbol: ',',
// Custom
// @cfg {String} allowNegativeText Error text to display if negative values are NOT allowed (see allowNegative)
// and one is FOUND during validation (this happens due to pasting the value or programmatically assigning the value)
allowNegativeText: 'Negative values not allowed',
// Custom
// @cfg {String} allowDecimalsText Error text to display if decimals are NOT allowed (see allowDecimals)
// and they are FOUND during validation (this happens due to pasting the value or programmatically assigning the value)
allowDecimalsText: 'Decimal values not allowed',
// Custom
//=== OVERRIDES ===//
initEvents: function () {
Ext.ux.form.NumberField.superclass.initEvents.call(this);
var basicForm = this.ownerCt.getForm();
basicForm.addListener('beforeaction', function (form, action) {
/*var parsedValue = this.getValue();
if (this.decorateNumber && action.type == 'submit' && parsedValue)
this.setRawValue(parsedValue);*/
if (action.type == 'submit') {
this.setRawValue(this.removeDecoration(this.getRawValue()));
this.setRawValue(this.getRawValue().replace(this.decimalSeparator, '.'));
}
}, this);
},
preFocus: function () {
this.setRawValue(this.removeDecoration(this.getRawValue()));
/*if (this.decorateNumber)
this.setRawValue(this.parseValue(this.getRawValue()));*/
//NOTE: Remove decorations from raw value before calling into base so that select on focus runs properly
Ext.ux.form.NumberField.superclass.preFocus.call(this); //NOTE: Call into base class
},
processValue: function (value) {
//NOTE: Removing decorations before validation, process value is called internally before a call to validate
value = Ext.ux.form.NumberField.superclass.processValue.call(this, this.parseValue(value)); //NOTE: Call into base class
return value;
},
validateValue: function (value) {
if (!Ext.ux.form.NumberField.superclass.validateValue.call(this, value)) return false;
if (value.length < 1) return true; //NOTE: if it's blank and textfield didn't flag it then it's valid
// Validate for presense of negative sign when they are explicitely NOT allowed
// (resolves bug in this only being enforced by keystroke masking)
if (!this.allowNegative) {
regExpDecimals = new RegExp('[-]');
if (regExpDecimals.test(value)) {
this.markInvalid(this.allowNegativeText);
return false;
}
}
// Validate for presense of a decimal separator when they are explicitely not allowed
// (resolves bug in this only being enforced by keystroke masking)
if (!this.allowDecimals) {
regExpDecimals = new RegExp('[' + this.decimalSeparator + ']');
if (regExpDecimals.test(value)) {
this.markInvalid(this.allowDecimalsText);
return false;
}
}
return true;
},
parseValue: function (v) {
v = this.removeDecoration(v);
//NOTE: Non period decimal separators are replaced with periods by base class
return Ext.ux.form.NumberField.superclass.parseValue.call(this, v);
},
postBlur: function () {
Ext.ux.form.NumberField.superclass.postBlur.call(this); //NOTE: Call into base class
if (this.decorateNumber && this.isValid) {
//NOTE: Decorate number value (if present and valid)
var value = this.getValue();
if (value) this.setRawValue(this.numberFormat(value));
}
},
//=== CUSTOM ===//
removeDecoration: function (v) {
// Removes all but digits, negative sign, and specified decimal separator
if (v && this.decorateNumber) {
re = new RegExp('[^0-9\\-\\' + this.decimalSeparator + ']', 'g');
v = String(v).replace(re, '');
}
return v;
},
numberFormat: function (v) {
// Format number with ExtJS number format
var pattern = this.numberPattern();
var format = Ext.util.Format.number(v, pattern);
// Replace comma in format with specified grouping symbol if not specified as '.' or ','
if (this.isI18n() && this.groupingSymbol != '.') {
re = new RegExp('[\\.]', 'g');
format = format.replace(re, this.groupingSymbol);
}
return format;
},
numberPattern: function (decimalSeparator, decimalPrecision, groupingSymbol) {
// Building the number format pattern for use by ExtJS Ext.util.Format.number
var pattern = [];
pattern.push('0');
if (this.groupingSymbol) pattern.push((this.isI18n() && this.groupingSymbol != '.') ? '.000' : this.groupingSymbol + '000');
if (this.allowDecimals && this.decimalPrecision) {
pattern.push(this.decimalSeparator);
for (var i = 0; i < this.decimalPrecision; i++)
pattern.push('0');
}
if (this.isI18n()) pattern.push('/i');
return pattern.join('');
},
isI18n: function () {
// As defined by ExtJS ExtJS Ext.util.Format.number
return (this.decimalSeparator != '.' && this.groupingSymbol != ',')
}
});
Ext.reg('ux.numberfield', Ext.ux.form.NumberField);