angular-mask
Version:
Personalized input masks for AngularJS
137 lines (106 loc) • 3.65 kB
JavaScript
'use strict';
angular.module('ui.utils.masks.global.scientific-notation', [])
.directive('uiScientificNotationMask', ['$locale', '$parse', '$log',
function($locale, $parse, $log) {
var decimalDelimiter = $locale.NUMBER_FORMATS.DECIMAL_SEP,
defaultPrecision = 2;
function significandMaskBuilder (decimals) {
var mask = '0';
if(decimals > 0) {
mask += decimalDelimiter;
for (var i = 0; i < decimals; i++) {
mask += '0';
}
}
return new StringMask(mask, {
reverse: true
});
}
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
var decimals = $parse(attrs.uiScientificNotationMask)(scope);
if(isNaN(decimals)) {
decimals = defaultPrecision;
}
var significandMask = significandMaskBuilder(decimals);
function splitNumber (value) {
var stringValue = value.toString(),
splittedNumber = stringValue.match(/(-?[0-9]*)[\.]?([0-9]*)?[Ee]?([\+-]?[0-9]*)?/);
return {
integerPartOfSignificand: splittedNumber[1],
decimalPartOfSignificand: splittedNumber[2],
exponent: splittedNumber[3] | 0
};
}
function formatter (value) {
$log.debug('[uiScientificNotationMask] Formatter called: ', value);
if (angular.isUndefined(value)) {
return value;
}
if (typeof value === 'string') {
if (value.length === 0) {
return value;
}
value = value.replace(decimalDelimiter, '.');
} else if (typeof value === 'number') {
value = value.toExponential(decimals);
}
var formattedValue, exponent;
var splittedNumber = splitNumber(value);
var integerPartOfSignificand = splittedNumber.integerPartOfSignificand | 0;
var numberToFormat = integerPartOfSignificand.toString();
if (angular.isDefined(splittedNumber.decimalPartOfSignificand)) {
numberToFormat += splittedNumber.decimalPartOfSignificand;
}
var needsNormalization =
(integerPartOfSignificand >= 1 || integerPartOfSignificand <= -1) &&
(
(angular.isDefined(splittedNumber.decimalPartOfSignificand) &&
splittedNumber.decimalPartOfSignificand.length > decimals) ||
(decimals === 0 && numberToFormat.length >= 2)
);
if (needsNormalization) {
exponent = numberToFormat.slice(decimals + 1, numberToFormat.length);
numberToFormat = numberToFormat.slice(0, decimals + 1);
}
formattedValue = significandMask.apply(numberToFormat);
if (splittedNumber.exponent !== 0) {
exponent = splittedNumber.exponent;
}
if (angular.isDefined(exponent)) {
formattedValue += 'e' + exponent;
}
return formattedValue;
}
function parser (value) {
$log.debug('[uiScientificNotationMask] Parser called: ', value);
if(angular.isUndefined(value) || value.toString().length === 0) {
return value;
}
var viewValue = formatter(value),
modelValue = parseFloat(viewValue.replace(decimalDelimiter, '.'));
if (ctrl.$viewValue !== viewValue) {
ctrl.$setViewValue(viewValue);
ctrl.$render();
}
return modelValue;
}
function validator (value) {
$log.debug('[uiScientificNotationMask] Validator called: ', value);
if(angular.isUndefined(value)) {
return value;
}
var isMaxValid = value < Number.MAX_VALUE;
ctrl.$setValidity('max', ctrl.$isEmpty(value) || isMaxValid);
return value;
}
ctrl.$formatters.push(formatter);
ctrl.$formatters.push(validator);
ctrl.$parsers.push(parser);
ctrl.$parsers.push(validator);
}
};
}
]);