angular-nz-input-formats
Version:
Angular directives to validate and format NZ-specific input types
550 lines (546 loc) • 22.8 kB
JavaScript
/*!
* angular-nz-input-formats
* Angular directives to validate and format NZ-specific input types
* @version v0.5.2
* @link https://github.com/nikrolls/angular-nz-input-formats
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
(function(window, angular, undefined){///<reference path="../definitions\angularjs\angular.d.ts"/>
var NZInputFormats;
(function (NZInputFormats) {
NZInputFormats.module = angular.module('nzInputFormats', []);
})(NZInputFormats || (NZInputFormats = {}));
///<reference path="../definitions\angularjs\angular.d.ts"/>
///<reference path="angular-nz-input-formats.ts"/>
var NZInputFormats;
(function (NZInputFormats) {
var SimpleInputMask = (function () {
function SimpleInputMask(mask, maskChars) {
if (mask === void 0) { mask = null; }
if (maskChars === void 0) { maskChars = null; }
// Directive properties
this.require = 'ngModel';
this.restrict = 'A';
this.link = null;
this.directiveName = 'nzSimpleInputMask';
this.options = {
mask: null,
validateOnLoad: true
};
this.mask = null;
this.maskChars = {
'*': /./,
'A': /[A-Za-z]/,
'9': /[0-9]/
};
this.scope = null;
this.elem = null;
this.ctrl = null;
this.document = null;
this.lastLen = 0;
this.setMask(mask);
if (maskChars) {
this.maskChars = maskChars;
}
this.link = angular.bind(this, this.doLink);
}
SimpleInputMask.prototype.setMask = function (mask) {
if (mask !== this.options['mask']) {
this.mask = mask.split('');
this.options['mask'] = mask;
if (this.elem) {
this.parser(this.elem.val());
}
}
};
SimpleInputMask.Directive = function ($document, T) {
if (T === void 0) { T = SimpleInputMask; }
SimpleInputMask.Document = $document[0];
return {
require: 'ngModel',
restrict: 'A',
link: function link(scope, elem, attrs, ctrl, transclude) {
var inst = new T();
inst.document = SimpleInputMask.Document;
return inst.doLink(scope, elem, attrs, ctrl, transclude);
}
};
};
SimpleInputMask.prototype.doLink = function (scope, elem, attrs, ctrl, transclude) {
this.scope = scope;
this.elem = elem;
this.ctrl = ctrl;
attrs.$observe(this.directiveName, angular.bind(this, this.processAttributeValue));
this.processAttributeValue(attrs[this.directiveName]);
ctrl.$formatters.push(angular.bind(this, this.formatter));
ctrl.$parsers.push(angular.bind(this, this.parser));
if (angular.isObject(ctrl.$validators) && this.options['validateOnLoad']) {
ctrl.$validators[this.directiveName] = angular.bind(this, this.validator);
}
};
SimpleInputMask.prototype.processAttributeValue = function (value) {
var options = this.scope.$eval(value);
if (options) {
if (options['mask']) {
this.setMask(options['mask']);
}
this.options = angular.extend(this.options, options);
}
};
SimpleInputMask.prototype.updateMask = function (value) {
};
SimpleInputMask.prototype.formatter = function (output) {
if (output === void 0) { output = ''; }
if (!output) {
return output;
}
this.updateMask(output);
if (!this.mask) {
// Without a mask we have nothing to do
return output;
}
return this.applyMaskToString(String(output));
};
SimpleInputMask.prototype.applyMaskToString = function (str) {
var _this = this;
var formatted = '';
var rawPos = 0;
this.mask.some(function (maskChar) {
if (rawPos >= str.length) {
return true;
}
formatted += _this.isMaskCharEditable(maskChar) ? str.charAt(rawPos++) : maskChar;
});
return formatted;
};
SimpleInputMask.prototype.parser = function (input) {
if (input === void 0) { input = ''; }
if (!input) {
return this.triggerValidation(input);
}
this.updateMask(input);
if (!this.mask) {
// Without a mask we have nothing to do
return input;
}
var parsed = this.removeMaskFromString(input);
var formatted = this.formatter(parsed);
var cursorPosition = this.elem[0].selectionEnd;
var newCursorPosition = this.calculateNewCursorPosition(input, formatted, cursorPosition);
this.updateFieldWith(formatted);
this.updateCursorPositionIfElementIsActive(newCursorPosition);
return this.triggerValidation(parsed);
};
SimpleInputMask.prototype.removeMaskFromString = function (str) {
var _this = this;
var inputChars = (str || '').split('');
var parsedParts = [];
this.mask.every(function (maskChar) {
if (_this.isMaskCharEditable(maskChar)) {
inputChars = _this.discardCharactersUntilNextMatch(inputChars, maskChar);
if (inputChars && inputChars.length) {
parsedParts.push(inputChars.shift());
}
}
else if (inputChars[0] === maskChar) {
inputChars.shift();
}
return inputChars && inputChars.length > 0;
});
return parsedParts.join('');
};
SimpleInputMask.prototype.discardCharactersUntilNextMatch = function (inputChars, maskChar) {
inputChars = angular.copy(inputChars);
var maskCharPattern = this.maskChars[maskChar];
while (inputChars.length) {
if (!this.isCharacterValidInMask(inputChars[0], this.mask)) {
// If we find a character that will never match the rest of our mask, bail
// and discard the rest of the input
return null;
}
if (inputChars[0].match(maskCharPattern)) {
break;
}
inputChars.shift();
}
return inputChars;
};
SimpleInputMask.prototype.isCharacterValidInMask = function (character, mask) {
var _this = this;
return mask.some(function (maskChar) {
return _this.isMaskCharEditable(maskChar) ? character.match(_this.maskChars[maskChar]) : character === maskChar;
});
};
SimpleInputMask.prototype.isMaskCharEditable = function (maskChar) {
return this.maskChars.hasOwnProperty(maskChar);
};
SimpleInputMask.prototype.calculateNewCursorPosition = function (input, formatted, cursorPosition) {
if (input.length > this.lastLen) {
if (this.isPositionEditable(cursorPosition)) {
cursorPosition = this.revertCursorMoveIfCharacterWasInvalid(input, cursorPosition);
}
else {
cursorPosition = this.getNextEditablePosition(cursorPosition, formatted.length);
}
}
return cursorPosition;
};
SimpleInputMask.prototype.isPositionEditable = function (cursorPosition) {
var maskChar = this.mask[cursorPosition - 1];
return this.maskChars.hasOwnProperty(maskChar);
};
SimpleInputMask.prototype.revertCursorMoveIfCharacterWasInvalid = function (input, cursorPosition) {
var position = cursorPosition - 1;
var maskCharPattern = this.maskChars[this.mask[position]];
if (!input.charAt(position).match(maskCharPattern)) {
cursorPosition--;
}
return cursorPosition;
};
SimpleInputMask.prototype.getNextEditablePosition = function (cursorPosition, length) {
while (cursorPosition < length && !this.isMaskCharEditable(this.mask[cursorPosition - 1])) {
cursorPosition++;
}
return cursorPosition;
};
SimpleInputMask.prototype.updateFieldWith = function (formattedValue) {
this.lastLen = formattedValue.length;
this.elem.val(formattedValue);
this.ctrl.$viewValue = formattedValue;
this.ctrl.$commitViewValue();
};
SimpleInputMask.prototype.updateCursorPositionIfElementIsActive = function (cursorPosition) {
var elem = this.elem[0];
if (this.document.activeElement === elem) {
elem.selectionStart = elem.selectionEnd = cursorPosition;
}
};
SimpleInputMask.prototype.triggerValidation = function (currentValue) {
if (!angular.isObject(this.ctrl.$validators) || !this.options['validateOnLoad']) {
var valid = this.validator();
this.ctrl.$setValidity(this.directiveName, valid);
// Emulate Angular 1.3 model validation behaviour
return valid ? currentValue : '';
}
return currentValue;
};
SimpleInputMask.prototype.validator = function () {
var value = this.ctrl.$viewValue;
if (angular.isUndefined(value) || value === null || value === '' || value !== value) {
// No validation for an undefined model value
return true;
}
if (!this.mask) {
return true;
}
else {
return this.ctrl.$viewValue && this.ctrl.$viewValue.length === this.mask.length;
}
};
SimpleInputMask.Document = null;
return SimpleInputMask;
})();
NZInputFormats.SimpleInputMask = SimpleInputMask;
NZInputFormats.module.directive('nzSimpleInputMask', ['$document', SimpleInputMask.Directive]);
})(NZInputFormats || (NZInputFormats = {}));
///<reference path="angular-nz-input-formats.ts"/>
///<reference path="simple-input-mask.directive.ts"/>
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var NZInputFormats;
(function (NZInputFormats) {
var NZBankNumber = (function (_super) {
__extends(NZBankNumber, _super);
function NZBankNumber() {
_super.call(this);
this.shortMask = '99-9999-9999999-99';
this.longMask = '99-9999-9999999-999';
this.directiveName = 'nzBankNumber';
this.options = {
mask: null,
strict: false
};
this.banks = [
'01',
'02',
'03',
'06',
'08',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
'19',
'20',
'21',
'22',
'23',
'24',
'25',
'29',
'30',
'31',
'38'
];
this.checksumWeights = [6, 3, 7, 9, 0, 10, 5, 8, 4, 2, 1];
this.setMask(this.shortMask);
}
NZBankNumber.Directive = function ($document) {
return NZInputFormats.SimpleInputMask.Directive($document, NZBankNumber);
};
NZBankNumber.prototype.updateMask = function (value) {
if (!value) {
return;
}
value = String(value || '');
if (value.replace(/[\s-]/g, '').length <= 15) {
this.setMask(this.shortMask);
}
else {
this.setMask(this.longMask);
}
};
NZBankNumber.prototype.validator = function () {
var superVal = _super.prototype.validator.call(this);
var value = this.ctrl.$viewValue;
if (angular.isUndefined(value) || value === null || value === '' || value !== value) {
// No validation for an undefined model value
return true;
}
value = value.replace(/\D/g, '');
if (value.length < 15 || value.length > 16) {
return false;
}
if (!this.options['strict']) {
return superVal;
}
if (this.banks.indexOf(value.substr(0, 2)) === -1) {
return false;
}
return this.checksum(value);
};
NZBankNumber.prototype.checksum = function (accountNumber) {
var _this = this;
var checksumPart = accountNumber.substr(2, 11);
if (checksumPart.length !== 11) {
return false;
}
var checksum = checksumPart.split('').reduce(function (total, current, index) {
return total + (parseInt(current, 10) * _this.checksumWeights[index]);
}, 0);
return checksum % 11 === 0;
};
return NZBankNumber;
})(NZInputFormats.SimpleInputMask);
NZInputFormats.NZBankNumber = NZBankNumber;
NZInputFormats.module.directive('nzBankNumber', ['$document', NZBankNumber.Directive]);
})(NZInputFormats || (NZInputFormats = {}));
///<reference path="angular-nz-input-formats.ts"/>
///<reference path="simple-input-mask.directive.ts"/>
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var NZInputFormats;
(function (NZInputFormats) {
var NZIrdNumber = (function (_super) {
__extends(NZIrdNumber, _super);
function NZIrdNumber() {
_super.call(this);
this.shortMask = '99-999-999';
this.longMask = '999-999-999';
this.directiveName = 'nzIrdNumber';
this.setMask(this.shortMask);
}
NZIrdNumber.Directive = function ($document) {
return NZInputFormats.SimpleInputMask.Directive($document, NZIrdNumber);
};
NZIrdNumber.prototype.updateMask = function (value) {
if (!value) {
return;
}
value = String(value || '');
if (value.replace(/\D/g, '').length <= 8) {
this.setMask(this.shortMask);
}
else {
this.setMask(this.longMask);
}
};
NZIrdNumber.prototype.validator = function () {
var value = this.ctrl.$viewValue;
if (angular.isUndefined(value) || value === null || value === '' || value !== value) {
// No validation for an undefined model value
return true;
}
var input = NZIrdNumber.Extract(value);
if (!input) {
return false;
}
if (!NZIrdNumber.CheckValidRange(input)) {
return false;
}
// Remove the check digit
var base = input.substr(0, 8);
return NZIrdNumber.CalculateCheckDigit(base, input.substr(-1));
};
NZIrdNumber.Extract = function (input) {
var matches = String(input).trim().match(/(?:\d{8,9}|\d{2,3}-\d{3}-\d{3})/);
if (matches && matches.length) {
// Pad to 9 digits with a leading 0, if required
return ('0' + matches[0].replace(/-/g, '')).substr(-9);
}
else {
return null;
}
};
NZIrdNumber.CheckValidRange = function (input) {
var asNumber = Number(input);
return asNumber >= 10000000 && asNumber <= 150000000;
};
NZIrdNumber.CalculateCheckDigit = function (input, expected) {
var weighting = [3, 2, 7, 6, 5, 4, 3, 2];
var checkDigit = NZIrdNumber.CalculateCheckDigitFor(weighting, input);
if (checkDigit === 10) {
return NZIrdNumber.ReCalculateCheckDigit(input, expected);
}
else {
return checkDigit === Number(expected);
}
};
NZIrdNumber.ReCalculateCheckDigit = function (input, expected) {
var weighting = [7, 4, 3, 2, 5, 2, 7, 6];
var checkDigit = NZIrdNumber.CalculateCheckDigitFor(weighting, input);
if (checkDigit === 10) {
return false;
}
else {
return checkDigit === Number(expected);
}
};
NZIrdNumber.CalculateCheckDigitFor = function (weighting, input) {
var sum = 0;
for (var i = 0; i < weighting.length; i++) {
sum += Number(input.charAt(i)) * weighting[i];
}
var remainder = sum % 11;
if (remainder === 0) {
return 0;
}
else {
return 11 - remainder;
}
};
return NZIrdNumber;
})(NZInputFormats.SimpleInputMask);
NZInputFormats.NZIrdNumber = NZIrdNumber;
NZInputFormats.module.directive('nzIrdNumber', ['$document', NZIrdNumber.Directive]);
})(NZInputFormats || (NZInputFormats = {}));
///<reference path="angular-nz-input-formats.ts"/>
///<reference path="simple-input-mask.directive.ts"/>
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var NZInputFormats;
(function (NZInputFormats) {
var NZPhoneNumber = (function (_super) {
__extends(NZPhoneNumber, _super);
function NZPhoneNumber() {
_super.call(this);
this.defaultMask = '9999999999999';
this.mobileMask = '999 999 99999';
this.intlMobileMask = '9999 999 99999';
this.landlineMask = '99 999 9999';
this.intlLandlineMask = '999 999 9999';
this.specialMask = '9999 999 999 9999';
this.intlSpecialMask = '99999 999 999 9999';
this.directiveName = 'nzPhoneNumber';
this.minLength = 0;
this.setMask(this.defaultMask);
}
NZPhoneNumber.Directive = function ($document) {
return NZInputFormats.SimpleInputMask.Directive($document, NZPhoneNumber);
};
NZPhoneNumber.prototype.formatter = function (output) {
if (!output) {
return output;
}
var raw = NZPhoneNumber.sanitise(output);
if (angular.isDefined(this.options['intl'])) {
if (this.options['intl']) {
raw = raw.match(/^(?:64.*|6)?/)[0];
}
else {
raw = raw.match(/^(?:0.*)?/)[0];
}
}
var intl = raw.match(/^(64|6$)/);
if (intl) {
raw = '0' + raw.substr(2);
}
var type;
if (raw.match(/^0[89]0/)) {
type = 'special';
this.setMask(intl ? this.intlSpecialMask : this.specialMask);
this.minLength = intl ? 11 : 10;
}
else if (raw.substr(0, 2) === '02') {
type = 'mobile';
this.setMask(intl ? this.intlMobileMask : this.mobileMask);
this.minLength = intl ? 10 : 9;
}
else if (raw.match(/^0[345679]/)) {
type = 'landline';
this.setMask(intl ? this.intlLandlineMask : this.landlineMask);
this.minLength = intl ? 10 : 9;
}
else {
type = 'other';
this.setMask(this.defaultMask);
this.minLength = 9;
}
switch (this.options['type']) {
case 'special':
raw = raw.match(/^(?:0[89]0.*|0[89]|0)?/)[0];
break;
case 'mobile':
raw = raw.match(/^(?:02.*|0)?/)[0];
break;
case 'landline':
raw = raw.match(/^(?:0[345679].*|0)?/)[0];
break;
}
output = intl ? raw.replace(/^0/, intl[0]) : raw;
return _super.prototype.formatter.call(this, output);
};
NZPhoneNumber.prototype.validator = function () {
var value = this.ctrl.$viewValue;
if (angular.isUndefined(value) || value === null || value === '' || value !== value) {
// No validation for an undefined model value
return true;
}
value = NZPhoneNumber.sanitise(value);
return value.length === 0 || value.length >= this.minLength;
};
NZPhoneNumber.sanitise = function (input) {
return String(input).replace(/\D/g, '');
};
return NZPhoneNumber;
})(NZInputFormats.SimpleInputMask);
NZInputFormats.NZPhoneNumber = NZPhoneNumber;
NZInputFormats.module.directive('nzPhoneNumber', ['$document', NZPhoneNumber.Directive]);
})(NZInputFormats || (NZInputFormats = {}));
})(window, window.angular);