(function() { 'use strict'; angular.module('ngMask', []); })();(function() { 'use strict'; angular.module('ngMask') .directive('mask', ['$log', '$timeout', 'MaskService', function($log, $timeout, MaskService) { return { restrict: 'A', require: 'ngModel', compile: function($element, $attrs) {  if (!$attrs.mask || !$attrs.ngModel) { $log.info('Mask and ng-model attributes are required!'); return; } var maskService = MaskService.create(); var timeout; var promise; function setSelectionRange(selectionStart){ if (typeof selectionStart !== 'number') { return; } // using $timeout: // it should run after the DOM has been manipulated by Angular // and after the browser renders (which may cause flicker in some cases) $timeout.cancel(timeout); timeout = $timeout(function(){ var selectionEnd = selectionStart + 1; var input = $element[0]; if (input.setSelectionRange) { input.focus(); input.setSelectionRange(selectionStart, selectionEnd); } else if (input.createTextRange) { var range = input.createTextRange(); range.collapse(true); range.moveEnd('character', selectionEnd); range.moveStart('character', selectionStart); range.select(); } }); } return { pre: function($scope, $element, $attrs, controller) { promise = maskService.generateRegex({ mask: $attrs.mask, // repeat mask expression n times repeat: ($attrs.repeat || $attrs.maskRepeat), // clean model value - without divisors clean: (($attrs.clean || $attrs.maskClean) === 'true'), // limit length based on mask length limit: (($attrs.limit || $attrs.maskLimit || 'true') === 'true'), // how to act with a wrong value restrict: ($attrs.restrict || $attrs.maskRestrict || 'select'), //select, reject, accept // set validity mask validate: (($attrs.validate || $attrs.maskValidate || 'true') === 'true'), // default model value model: $attrs.ngModel, // default input value value: $attrs.ngValue }); }, post: function($scope, $element, $attrs, controller) { promise.then(function() { // get initial options var timeout; var options = maskService.getOptions(); function parseViewValue(value) { var untouchedValue = value; // set default value equal 0 value = value || ''; // get view value object var viewValue = maskService.getViewValue(value); // get mask without question marks var maskWithoutOptionals = options['maskWithoutOptionals'] || ''; // get view values capped // used on view var viewValueWithDivisors = viewValue.withDivisors(true); // used on model var viewValueWithoutDivisors = viewValue.withoutDivisors(true); try { // get current regex var regex = maskService.getRegex(viewValueWithDivisors.length - 1); var fullRegex = maskService.getRegex(maskWithoutOptionals.length - 1); // current position is valid var validCurrentPosition = regex.test(viewValueWithDivisors) || fullRegex.test(viewValueWithDivisors); // difference means for select option var diffValueAndViewValueLengthIsOne = (value.length - viewValueWithDivisors.length) === 1; var diffMaskAndViewValueIsGreaterThanZero = (maskWithoutOptionals.length - viewValueWithDivisors.length) > 0; if (options.restrict !== 'accept') { if (options.restrict === 'select' && (!validCurrentPosition || diffValueAndViewValueLengthIsOne)) { var lastCharInputed = value[(value.length-1)]; var lastCharGenerated = viewValueWithDivisors[(viewValueWithDivisors.length-1)]; if ((lastCharInputed !== lastCharGenerated) && diffMaskAndViewValueIsGreaterThanZero) { viewValueWithDivisors = viewValueWithDivisors + lastCharInputed; } var wrongPosition = maskService.getFirstWrongPosition(viewValueWithDivisors); if (angular.isDefined(wrongPosition)) { setSelectionRange(wrongPosition); } } else if (options.restrict === 'reject' && !validCurrentPosition) { viewValue = maskService.removeWrongPositions(viewValueWithDivisors); viewValueWithDivisors = viewValue.withDivisors(true); viewValueWithoutDivisors = viewValue.withoutDivisors(true); // setSelectionRange(viewValueWithDivisors.length); } } if (!options.limit) { viewValueWithDivisors = viewValue.withDivisors(false); viewValueWithoutDivisors = viewValue.withoutDivisors(false); } // Set validity if (options.validate && controller.$dirty) { if (fullRegex.test(viewValueWithDivisors) || controller.$isEmpty(untouchedValue)) { controller.$setValidity('mask', true); } else { controller.$setValidity('mask', false); } } // Update view and model values if(value !== viewValueWithDivisors){ controller.$setViewValue(angular.copy(viewValueWithDivisors), 'input'); controller.$render(); } } catch (e) { $log.error('[mask - parseViewValue]'); throw e; } // Update model, can be different of view value if (options.clean) { return viewValueWithoutDivisors; } else { return viewValueWithDivisors; } } controller.$parsers.push(parseViewValue); $element.on('click input paste keyup', function() { timeout = $timeout(function() { // Manual debounce to prevent multiple execution $timeout.cancel(timeout); parseViewValue($element.val()); $scope.$apply(); }, 100); }); // Register the watch to observe remote loading or promised data // Deregister calling returned function var watcher = $scope.$watch($attrs.ngModel, function (newValue, oldValue) { if (angular.isDefined(newValue)) { parseViewValue(newValue); watcher(); } }); // $evalAsync from a directive // it should run after the DOM has been manipulated by Angular // but before the browser renders if(options.value) { $scope.$evalAsync(function($scope) { controller.$setViewValue(angular.copy(options.value), 'input'); controller.$render(); }); } }); } } } } }]); })(); (function() { 'use strict'; angular.module('ngMask') .factory('MaskService', ['$q', 'OptionalService', 'UtilService', function($q, OptionalService, UtilService) { function create() { var options; var maskWithoutOptionals; var maskWithoutOptionalsLength = 0; var maskWithoutOptionalsAndDivisorsLength = 0; var optionalIndexes = []; var optionalDivisors = {}; var optionalDivisorsCombinations = []; var divisors = []; var divisorElements = {}; var regex = []; var patterns = { '9': /[0-9]/, '8': /[0-8]/, '7': /[0-7]/, '6': /[0-6]/, '5': /[0-5]/, '4': /[0-4]/, '3': /[0-3]/, '2': /[0-2]/, '1': /[0-1]/, '0': /[0]/, '*': /./, 'w': /\w/, 'W': /\W/, 'd': /\d/, 'D': /\D/, 's': /\s/, 'S': /\S/, 'b': /\b/, 'A': /[A-Z]/, 'a': /[a-z]/, 'Z': /[A-ZÇÀÁÂÃÈÉÊẼÌÍÎĨÒÓÔÕÙÚÛŨ]/, 'z': /[a-zçáàãâéèêẽíìĩîóòôõúùũüû]/, '@': /[a-zA-Z]/, '#': /[a-zA-ZçáàãâéèêẽíìĩîóòôõúùũüûÇÀÁÂÃÈÉÊẼÌÍÎĨÒÓÔÕÙÚÛŨ]/, '%': /[0-9a-zA-ZçáàãâéèêẽíìĩîóòôõúùũüûÇÀÁÂÃÈÉÊẼÌÍÎĨÒÓÔÕÙÚÛŨ]/ }; // REGEX function generateIntermetiateElementRegex(i, forceOptional) { var charRegex; try { var element = maskWithoutOptionals[i]; var elementRegex = patterns[element]; var hasOptional = isOptional(i); if (elementRegex) { charRegex = '(' + elementRegex.source + ')'; } else { // is a divisor if (!isDivisor(i)) { divisors.push(i); divisorElements[i] = element; } charRegex = '(' + '\\' + element + ')'; } } catch (e) { throw e; } if (hasOptional || forceOptional) { charRegex += '?'; } return new RegExp(charRegex); } function generateIntermetiateRegex(i, forceOptional) { var elementRegex var elementOptionalRegex; try { var intermetiateElementRegex = generateIntermetiateElementRegex(i, forceOptional); elementRegex = intermetiateElementRegex; var hasOptional = isOptional(i); var currentRegex = intermetiateElementRegex.source; if (hasOptional && ((i+1) < maskWithoutOptionalsLength)) { var intermetiateRegex = generateIntermetiateRegex((i+1), true).elementOptionalRegex(); currentRegex += intermetiateRegex.source; } elementOptionalRegex = new RegExp(currentRegex); } catch (e) { throw e; } return { elementRegex: function() { return elementRegex; }, elementOptionalRegex: function() { // from element regex, gets the flow of regex until first not optional return elementOptionalRegex; } }; } function generateRegex(opts) { var deferred = $q.defer(); options = opts; try { var mask = opts['mask']; var repeat = opts['repeat']; if (!mask) return; if (repeat) { mask = Array((parseInt(repeat)+1)).join(mask); } optionalIndexes = OptionalService.getOptionals(mask).fromMaskWithoutOptionals(); options['maskWithoutOptionals'] = maskWithoutOptionals = OptionalService.removeOptionals(mask); maskWithoutOptionalsLength = maskWithoutOptionals.length; var cumulativeRegex; for (var i=0; i= divisor) { break; } if (optionalDivisors[divisor]) { optionalDivisors[divisor] = optionalDivisors[divisor].concat(divisor-j); } else { optionalDivisors[divisor] = [(divisor-j)]; } // get the original divisor for alternative divisor divisorElements[(divisor-j)] = divisorElements[divisor]; } } } function removeDivisors(value) { value = value.toString(); try { if (divisors.length > 0 && value) { var keys = Object.keys(divisorElements); var elments = []; for (var i = keys.length - 1; i >= 0; i--) { var divisor = divisorElements[keys[i]]; if (divisor) { elments.push(divisor); } } elments = UtilService.uniqueArray(elments); // remove if it is not pattern var regex = new RegExp(('[' + '\\' + elments.join('\\') + ']'), 'g'); return value.replace(regex, ''); } else { return value; } } catch (e) { throw e; } } function insertDivisors(array, combination) { function insert(array, output) { var out = output; for (var i=0; i 0) { var lazyArguments = []; var optionalDivisorsKeys = Object.keys(optionalDivisors); // get all optional divisors as array of arrays [[], [], []...] for (var i=0; i= 0; i--) { var outputClone = angular.copy(output); outputClone = insertDivisors(outputClone, optionalDivisorsCombinations[i]); // try validation var viewValueWithDivisors = outputClone.join(''); var regex = getRegex(maskWithoutOptionals.length - 1); if (regex.test(viewValueWithDivisors)) { defaultDivisors = false; output = outputClone; break; } } } if (defaultDivisors) { output = insertDivisors(output, divisors); } return output.join(''); } // MASK function getOptions() { return options; } function getViewValue(value) { try { var outputWithoutDivisors = removeDivisors(value); var output = tryDivisorConfiguration(outputWithoutDivisors); return { withDivisors: function(capped) { if (capped) { return output.substr(0, maskWithoutOptionalsLength); } else { return output; } }, withoutDivisors: function(capped) { if (capped) { return outputWithoutDivisors.substr(0, maskWithoutOptionalsAndDivisorsLength); } else { return outputWithoutDivisors; } } }; } catch (e) { throw e; } } // SELECTOR function getWrongPositions(viewValueWithDivisors, onlyFirst) { var pos = []; if (!viewValueWithDivisors) { return 0; } for (var i=0; i -1; } catch (e) { throw e; } return output; } function uniqueArray(array) { var u = {}; var a = []; for (var i = 0, l = array.length; i < l; ++i) { if(u.hasOwnProperty(array[i])) { continue; } a.push(array[i]); u[array[i]] = 1; } return a; } return { lazyProduct: lazyProduct, inArray: inArray, uniqueArray: uniqueArray } }]); })();