Skip to content

Commit

Permalink
Fix issue #450 Add the valuesToStrings option to allow displaying a…
Browse files Browse the repository at this point in the history
… pre-defined string when the `rawValue` equal a specific value

Signed-off-by: Alexandre Bonneau <alexandre.bonneau@linuxfr.eu>
  • Loading branch information
AlexandreBonneau committed Aug 11, 2017
1 parent 75272a6 commit dca06f0
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 45 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

### 4.1.0-beta.1
+ Fix issue #475 Migrate to eslint 4
+ Fix issue #450 Add the `valuesToStrings` option to allow displaying a pre-defined string when the `rawValue` equal a specific value

### 4.0.3
+ Fix issue #474 `AutoNumeric.format()` and `AutoNumeric.unformat()` do not accept named options
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -334,6 +334,7 @@ Multiple options allow you to customize precisely how a form input will format y
| `symbolWhenUnfocused` | Symbol placed as a suffix when unfocused. This is used in combination with the `divisorWhenUnfocused` option. | `null` |
| `unformatOnHover` | Defines if the element value should be unformatted when the user hover his mouse over it while holding the `Alt` key | `true` |
| `unformatOnSubmit` | Removes formatting on submit event | `false` |
| `valuesToStrings` | Provide a way for automatically replacing the formatted value with a pre-defined string, when the raw value is equal to a specific value.<br>For instance when using `{ 0: '-' }`, the hyphen `'-'` is displayed when the `rawValue` is equal to `0`. Multiple 'replacements' can be defined. | `null` |
| `wheelStep` | Used in conjonction with the `modifyValueOnWheel` option, this allow to either define a *fixed* step (ie. `1000`), or a *progressive* one | `'progressive'` |

#### Predefined options
Expand Down
160 changes: 115 additions & 45 deletions src/AutoNumeric.js
Expand Up @@ -2,7 +2,7 @@
* AutoNumeric.js
*
* @version 4.1.0-beta.1
* @date 2017-08-11 UTC 04:12
* @date 2017-08-11 UTC 21:45
*
* @authors Bob Knothe, Alexandre Bonneau
* @contributors Sokolov Yura and others, cf. AUTHORS
Expand Down Expand Up @@ -801,6 +801,11 @@ class AutoNumeric {

return this;
},
valuesToStrings : valuesToStrings => {
this.update({ valuesToStrings });

return this;
},
wheelStep : wheelStep => {
this.settings.wheelStep = wheelStep; //FIXME test this

Expand Down Expand Up @@ -1549,7 +1554,7 @@ class AutoNumeric {
* @example anElement.northAmerican().set('$12,345.67') // Set an already formatted value (this does not _exactly_ respect the currency symbol/negative placements, but only remove all non-numbers characters, according to the ones given in the settings)
* @example anElement.set(null) // Set the rawValue and element value to `null`
*
* @param {number|string|null} newValue The value must be a number, a numeric string or `null` (if `emptyInputBehavior` is set to `'null'`)
* @param {number|string|null} newValue The value must be a Number, a numeric string or `null` (if `emptyInputBehavior` is set to `'null'`)
* @param {object} options A settings object that will override the current settings. Note: the update is done only if the `newValue` is defined.
* @param {boolean} saveChangeToHistory If set to `true`, then the change is recorded in the history table
* @returns {AutoNumeric}
Expand Down Expand Up @@ -1598,6 +1603,16 @@ class AutoNumeric {

if (value !== '') {
const [minTest, maxTest] = this.constructor._checkIfInRangeWithOverrideOption(value, this.settings);

// Modify the formatted value if the rawValue is found in the `valuesToStrings` option
if (minTest && maxTest && this.settings.valuesToStrings && this._checkValuesToStrings(value)) {
// Set the raw value normally, and the formatted value with the corresponding string
this._setElementAndRawValue(this.settings.valuesToStrings[value], value, saveChangeToHistory);
this._saveValueToPersistentStorage();

return this;
}

// This test is needed by the `showPositiveSign` option
const isZero = AutoNumericHelper.isZeroOrHasNoValue(value);
if (isZero) {
Expand Down Expand Up @@ -1818,6 +1833,17 @@ class AutoNumeric {
return rawValueForTheElementValue;
}

/**
* Check if the given value has a corresponding key in the `valuesToStrings` option object.
*
* @param {number|string} value
* @returns {boolean} Returns `true` if such a key is found.
* @private
*/
_checkValuesToStrings(value) {
return AutoNumericHelper.isInArray(String(value), this.valuesToStringsKeys);
}

/**
* Return `true` if the user is currently modifying the element value manually.
*
Expand Down Expand Up @@ -3431,6 +3457,11 @@ class AutoNumeric {
AutoNumericHelper.throwError(`The remove formatting on submit option 'unformatOnSubmit' is invalid ; it should be either 'false' or 'true', [${options.unformatOnSubmit}] given.`);
}

if (!AutoNumericHelper.isNull(options.valuesToStrings) &&
!(AutoNumericHelper.isObject(options.valuesToStrings))) {
AutoNumericHelper.throwError(`The option 'valuesToStrings' is invalid ; it should be an object, ideally with 'key -> value' entries, [${options.valuesToStrings}] given.`);
}

if (!AutoNumericHelper.isNull(options.outputFormat) && !AutoNumericHelper.isInArray(options.outputFormat, [
AutoNumeric.options.outputFormat.string,
AutoNumeric.options.outputFormat.number,
Expand Down Expand Up @@ -5721,62 +5752,84 @@ To solve that, you'd need to either set \`decimalPlacesRawValue\` to \`null\`, o

// Use the rawValue, multiplied by `rawValueDivisor` if defined
const rawValueToFormat = this._getRawValueToFormat(this.rawValue);

let value;
const isRawValueNull = AutoNumericHelper.isNull(rawValueToFormat);
if (isRawValueNull || rawValueToFormat === '') {
value = rawValueToFormat;
} else {
value = String(rawValueToFormat);
}
const [minTest, maxTest] = this.constructor._checkIfInRangeWithOverrideOption(rawValueToFormat, this.settings);

// Directly set the formatted value if the `rawValue` is found in `valuesToStrings`
let elementValueIsAlreadySet = false;
if (rawValueToFormat !== '' && !isRawValueNull) {
const [minTest, maxTest] = this.constructor._checkIfInRangeWithOverrideOption(rawValueToFormat, this.settings);
if (minTest && maxTest && !this.constructor._isElementValueEmptyOrOnlyTheNegativeSign(rawValueToFormat, this.settings)) {
value = this._modifyNegativeSignAndDecimalCharacterForRawValue(value);
if (!minTest) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.minRangeExceeded, this.domElement);
}

if (this.settings.divisorWhenUnfocused && !AutoNumericHelper.isNull(value)) {
value = value / this.settings.divisorWhenUnfocused;
value = value.toString();
}
if (!maxTest) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.maxRangeExceeded, this.domElement);
}

value = this.constructor._roundFormattedValueShownOnBlur(value, this.settings);
value = this.constructor._modifyNegativeSignAndDecimalCharacterForFormattedValue(value, this.settings);
} else {
if (!minTest) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.minRangeExceeded, this.domElement);
}
if (!maxTest) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.maxRangeExceeded, this.domElement);
}
if (this.settings.valuesToStrings && this._checkValuesToStrings(rawValueToFormat)) {
// Set the formatted value with the corresponding string
this._setElementValue(this.settings.valuesToStrings[rawValueToFormat]);
elementValueIsAlreadySet = true;
}
} else if (rawValueToFormat === '' && this.settings.emptyInputBehavior === AutoNumeric.options.emptyInputBehavior.zero) {
this._setRawValue('0');
value = this.constructor._roundValue('0', this.settings, 0);
}

// Only generate the formatted value if no `valuesToStrings` have been found
if (!elementValueIsAlreadySet) {
let value;
if (isRawValueNull || rawValueToFormat === '') {
value = rawValueToFormat;
} else {
value = String(rawValueToFormat);
}

if (rawValueToFormat !== '' && !isRawValueNull) {
if (minTest && maxTest && !this.constructor._isElementValueEmptyOrOnlyTheNegativeSign(rawValueToFormat, this.settings)) {
value = this._modifyNegativeSignAndDecimalCharacterForRawValue(value);

let groupedValue = this.constructor._orderValueCurrencySymbolAndSuffixText(value, this.settings, false);
if (!(this.constructor._isElementValueEmptyOrOnlyTheNegativeSign(value, this.settings) ||
(isRawValueNull && this.settings.emptyInputBehavior === AutoNumeric.options.emptyInputBehavior.null))) {
groupedValue = this.constructor._addGroupSeparators(value, this.settings, false, rawValueToFormat);
}
if (this.settings.divisorWhenUnfocused && !AutoNumericHelper.isNull(value)) {
value = value / this.settings.divisorWhenUnfocused;
value = value.toString();
}

// Testing for `allowDecimalPadding.never` or `allowDecimalPadding.floats` is needed to make sure we do not keep a trailing decimalCharacter (like '500.') in the element, since the raw value would still be a correctly formatted integer ('500')
if (groupedValue !== rawValueToFormat ||
rawValueToFormat === '' || // This make sure we get rid on any currency symbol or suffix that might have been added on focus
this.settings.allowDecimalPadding === AutoNumeric.options.allowDecimalPadding.never ||
this.settings.allowDecimalPadding === AutoNumeric.options.allowDecimalPadding.floats) {
if (this.settings.symbolWhenUnfocused && rawValueToFormat !== '' && rawValueToFormat !== null) {
groupedValue = `${groupedValue}${this.settings.symbolWhenUnfocused}`;
value = this.constructor._roundFormattedValueShownOnBlur(value, this.settings);
value = this.constructor._modifyNegativeSignAndDecimalCharacterForFormattedValue(value, this.settings);
} else {
if (!minTest) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.minRangeExceeded, this.domElement);
}

if (!maxTest) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.maxRangeExceeded, this.domElement);
}
}
} else if (rawValueToFormat === '' && this.settings.emptyInputBehavior === AutoNumeric.options.emptyInputBehavior.zero) {
this._setRawValue('0');
value = this.constructor._roundValue('0', this.settings, 0);
}

this._setElementValue(groupedValue);
}

if (groupedValue !== this.valueOnFocus) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.native.change, this.domElement);
delete this.valueOnFocus;
let groupedValue = this.constructor._orderValueCurrencySymbolAndSuffixText(value, this.settings, false);
if (!(this.constructor._isElementValueEmptyOrOnlyTheNegativeSign(value, this.settings) ||
(isRawValueNull && this.settings.emptyInputBehavior === AutoNumeric.options.emptyInputBehavior.null))) {
groupedValue = this.constructor._addGroupSeparators(value, this.settings, false, rawValueToFormat);
}

// Testing for `allowDecimalPadding.never` or `allowDecimalPadding.floats` is needed to make sure we do not keep a trailing decimalCharacter (like '500.') in the element, since the raw value would still be a correctly formatted integer ('500')
if (groupedValue !== rawValueToFormat ||
rawValueToFormat === '' || // This make sure we get rid on any currency symbol or suffix that might have been added on focus
this.settings.allowDecimalPadding === AutoNumeric.options.allowDecimalPadding.never ||
this.settings.allowDecimalPadding === AutoNumeric.options.allowDecimalPadding.floats) {
if (this.settings.symbolWhenUnfocused && rawValueToFormat !== '' && rawValueToFormat !== null) {
groupedValue = `${groupedValue}${this.settings.symbolWhenUnfocused}`;
}

this._setElementValue(groupedValue);
}

if (groupedValue !== this.valueOnFocus) {
AutoNumericHelper.triggerEvent(AutoNumeric.events.native.change, this.domElement);
delete this.valueOnFocus;
}
}

this._onBlur(e);
Expand Down Expand Up @@ -6731,6 +6784,7 @@ To solve that, you'd need to either set \`decimalPlacesRawValue\` to \`null\`, o

/**
* Analyze and save the minimumValue and maximumValue integer size for later uses
* @private
*/
_calculateVMinAndVMaxIntegerSizes() {
let [maximumValueIntegerPart] = this.settings.maximumValue.toString().split('.');
Expand All @@ -6741,8 +6795,22 @@ To solve that, you'd need to either set \`decimalPlacesRawValue\` to \`null\`, o
this.settings.mIntPos = Math.max(maximumValueIntegerPart.length, 1);
this.settings.mIntNeg = Math.max(minimumValueIntegerPart.length, 1);
}

/**
* Calculate once what are the `valuesToStrings` option keys.
* @private
*/
_calculateValuesToStringsKeys() {
if (this.settings.valuesToStrings) {
this.valuesToStringsKeys = Object.keys(this.settings.valuesToStrings);
} else {
this.valuesToStringsKeys = [];
}
}

/**
* Sets the alternative decimal separator key.
* @private
*/
_setAlternativeDecimalSeparatorCharacter() {
if (AutoNumericHelper.isNull(this.settings.decimalCharacterAlternative) && Number(this.settings.decimalPlaces) > 0) {
Expand Down Expand Up @@ -6891,6 +6959,7 @@ To solve that, you'd need to either set \`decimalPlacesRawValue\` to \`null\`, o
symbolWhenUnfocused : true,
unformatOnHover : true,
unformatOnSubmit : true,
valuesToStrings : true,
wheelStep : true,

// Additional information that are added to the `settings` object :
Expand Down Expand Up @@ -7020,6 +7089,7 @@ To solve that, you'd need to either set \`decimalPlacesRawValue\` to \`null\`, o
this.regex = {}; // Create the object that will store the regular expressions
this.constructor._cachesUsualRegularExpressions(this.settings, this.regex);
this._setBrackets();
this._calculateValuesToStringsKeys();

// Validate the settings. Both tests throws if necessary.
if (AutoNumericHelper.isEmptyObj(this.settings)) {
Expand Down
1 change: 1 addition & 0 deletions src/AutoNumericDefaultSettings.js
Expand Up @@ -87,6 +87,7 @@ Object.defineProperty(AutoNumeric, 'defaultSettings', {
symbolWhenUnfocused : AutoNumeric.options.symbolWhenUnfocused.none,
unformatOnHover : AutoNumeric.options.unformatOnHover.unformat,
unformatOnSubmit : AutoNumeric.options.unformatOnSubmit.keepCurrentValue,
valuesToStrings : AutoNumeric.options.valuesToStrings.none,
wheelStep : AutoNumeric.options.wheelStep.progressive,
};
},
Expand Down
14 changes: 14 additions & 0 deletions src/AutoNumericOptions.js
Expand Up @@ -716,6 +716,20 @@ Object.defineProperty(AutoNumeric, 'options', {
keepCurrentValue: false,
},

/* Provide a way for automatically replacing the formatted value with a pre-defined string, when the raw value is equal to a specific value
* Here you can specify as many 'conversion' as possible.
*/
valuesToStrings: {
none : null,
zeroDash : {
0: '-',
},
oneAroundZero: {
'-1': 'Min',
1 : 'Max',
},
},

/* That option is linked to the `modifyValueOnWheel` one and will only be used if the latter is set to `true`.
* This option will modify the wheel behavior and can be used in two ways, either by setting :
* - a 'fixed' step value (a positive float or integer number `1000`), or
Expand Down
21 changes: 21 additions & 0 deletions test/e2e/index.html
Expand Up @@ -737,6 +737,14 @@ <h5 id="tag_h5">12345.67</h5>
<p id="result_452">Testing the raw value</p>
</div>
</div>

<div class="testSuite">
<div class="test">
<p class="description">Issue #450</p>
<input id="issue_450" type="text" placeholder="#450" value="">
<input id="issue_450_limits" type="text" placeholder="#450" value="">
</div>
</div>
</div>
<script>
//-------------- Classic input
Expand Down Expand Up @@ -1600,6 +1608,19 @@ <h5 id="tag_h5">12345.67</h5>
input452.addEventListener('drop', () => {
result452.textContent = anElement452.getNumber();
}, false);

//-------------- Issue #450
new AutoNumeric('#issue_450', 42, { valuesToStrings: AutoNumeric.options.valuesToStrings.zeroDash });
new AutoNumeric('#issue_450_limits', 222, {
valuesToStrings: {
0 : 'zero',
100: 'Min',
200: 'Ok',
400: 'Max',
},
minimumValue : 100,
maximumValue : 400,
});
</script>
</body>
</html>

0 comments on commit dca06f0

Please sign in to comment.