angular.module('MyApp') .directive('passwordStrength', function() { return { restrict: 'A', require: 'ngModel', link: function(scope, element, attrs, ngModel) { var indicator = element.children(); var dots = Array.prototype.slice.call(indicator.children()); var weakest = dots.slice(-1)[0]; var weak = dots.slice(-2); var strong = dots.slice(-3); var strongest = dots.slice(-4); element.after(indicator); element.bind('keyup', function() { var matches = { positive: {}, negative: {} }, counts = { positive: {}, negative: {} }, tmp, strength = 0, letters = 'abcdefghijklmnopqrstuvwxyz', numbers = '01234567890', symbols = '\\!@#$%&/()=?¿', strValue; angular.forEach(dots, function(el) { el.style.backgroundColor = '#ebeef1'; }); if (ngModel.$viewValue) { // Increase strength level matches.positive.lower = ngModel.$viewValue.match(/[a-z]/g); matches.positive.upper = ngModel.$viewValue.match(/[A-Z]/g); matches.positive.numbers = ngModel.$viewValue.match(/\d/g); matches.positive.symbols = ngModel.$viewValue.match(/[$-/:-?{-~!^_`\[\]]/g); matches.positive.middleNumber = ngModel.$viewValue.slice(1, -1).match(/\d/g); matches.positive.middleSymbol = ngModel.$viewValue.slice(1, -1).match(/[$-/:-?{-~!^_`\[\]]/g); counts.positive.lower = matches.positive.lower ? matches.positive.lower.length : 0; counts.positive.upper = matches.positive.upper ? matches.positive.upper.length : 0; counts.positive.numbers = matches.positive.numbers ? matches.positive.numbers.length : 0; counts.positive.symbols = matches.positive.symbols ? matches.positive.symbols.length : 0; counts.positive.numChars = ngModel.$viewValue.length; tmp += (counts.positive.numChars >= 8) ? 1 : 0; counts.positive.requirements = (tmp >= 3) ? tmp : 0; counts.positive.middleNumber = matches.positive.middleNumber ? matches.positive.middleNumber.length : 0; counts.positive.middleSymbol = matches.positive.middleSymbol ? matches.positive.middleSymbol.length : 0; // Decrease strength level matches.negative.consecLower = ngModel.$viewValue.match(/(?=([a-z]{2}))/g); matches.negative.consecUpper = ngModel.$viewValue.match(/(?=([A-Z]{2}))/g); matches.negative.consecNumbers = ngModel.$viewValue.match(/(?=(\d{2}))/g); matches.negative.onlyNumbers = ngModel.$viewValue.match(/^[0-9]*$/g); matches.negative.onlyLetters = ngModel.$viewValue.match(/^([a-z]|[A-Z])*$/g); counts.negative.consecLower = matches.negative.consecLower ? matches.negative.consecLower.length : 0; counts.negative.consecUpper = matches.negative.consecUpper ? matches.negative.consecUpper.length : 0; counts.negative.consecNumbers = matches.negative.consecNumbers ? matches.negative.consecNumbers.length : 0; // Calculations strength += counts.positive.numChars * 4; if (counts.positive.upper) { strength += (counts.positive.numChars - counts.positive.upper) * 2; } if (counts.positive.lower) { strength += (counts.positive.numChars - counts.positive.lower) * 2; } if (counts.positive.upper || counts.positive.lower) { strength += counts.positive.numbers * 4; } strength += counts.positive.symbols * 6; strength += (counts.positive.middleSymbol + counts.positive.middleNumber) * 2; strength += counts.positive.requirements * 2; strength -= counts.negative.consecLower * 2; strength -= counts.negative.consecUpper * 2; strength -= counts.negative.consecNumbers * 2; if (matches.negative.onlyNumbers) { strength -= counts.positive.numChars; } if (matches.negative.onlyLetters) { strength -= counts.positive.numChars; } strength = Math.max(0, Math.min(100, Math.round(strength))); if (strength > 85) { angular.forEach(strongest, function(el) { el.style.backgroundColor = '#008cdd'; }); } else if (strength > 65) { angular.forEach(strong, function(el) { el.style.backgroundColor = '#6ead09'; }); } else if (strength > 30) { angular.forEach(weak, function(el) { el.style.backgroundColor = '#e09115'; }); } else { weakest.style.backgroundColor = '#e01414'; } } }); }, template: '' }; });