webmaster@1: // $Id: user.js,v 1.6 2007/09/12 18:29:32 goba Exp $ webmaster@1: webmaster@1: /** webmaster@1: * Attach handlers to evaluate the strength of any password fields and to check webmaster@1: * that its confirmation is correct. webmaster@1: */ webmaster@1: Drupal.behaviors.password = function(context) { webmaster@1: var translate = Drupal.settings.password; webmaster@1: $("input.password-field:not(.password-processed)", context).each(function() { webmaster@1: var passwordInput = $(this).addClass('password-processed'); webmaster@1: var parent = $(this).parent(); webmaster@1: // Wait this number of milliseconds before checking password. webmaster@1: var monitorDelay = 700; webmaster@1: webmaster@1: // Add the password strength layers. webmaster@1: $(this).after(''+ translate.strengthTitle +' ').parent(); webmaster@1: var passwordStrength = $("span.password-strength", parent); webmaster@1: var passwordResult = $("span.password-result", passwordStrength); webmaster@1: parent.addClass("password-parent"); webmaster@1: webmaster@1: // Add the password confirmation layer. webmaster@1: var outerItem = $(this).parent().parent(); webmaster@1: $("input.password-confirm", outerItem).after(''+ translate["confirmTitle"] +' ').parent().addClass("confirm-parent"); webmaster@1: var confirmInput = $("input.password-confirm", outerItem); webmaster@1: var confirmResult = $("span.password-confirm", outerItem); webmaster@1: var confirmChild = $("span", confirmResult); webmaster@1: webmaster@1: // Add the description box at the end. webmaster@1: $(confirmInput).parent().after('
'); webmaster@1: var passwordDescription = $("div.password-description", $(this).parent().parent()).hide(); webmaster@1: webmaster@1: // Check the password fields. webmaster@1: var passwordCheck = function () { webmaster@1: // Remove timers for a delayed check if they exist. webmaster@1: if (this.timer) { webmaster@1: clearTimeout(this.timer); webmaster@1: } webmaster@1: webmaster@1: // Verify that there is a password to check. webmaster@1: if (!passwordInput.val()) { webmaster@1: passwordStrength.css({ visibility: "hidden" }); webmaster@1: passwordDescription.hide(); webmaster@1: return; webmaster@1: } webmaster@1: webmaster@1: // Evaluate password strength. webmaster@1: webmaster@1: var result = Drupal.evaluatePasswordStrength(passwordInput.val()); webmaster@1: passwordResult.html(result.strength == "" ? "" : translate[result.strength +"Strength"]); webmaster@1: webmaster@1: // Map the password strength to the relevant drupal CSS class. webmaster@1: var classMap = { low: "error", medium: "warning", high: "ok" }; webmaster@1: var newClass = classMap[result.strength] || ""; webmaster@1: webmaster@1: // Remove the previous styling if any exists; add the new class. webmaster@1: if (this.passwordClass) { webmaster@1: passwordResult.removeClass(this.passwordClass); webmaster@1: passwordDescription.removeClass(this.passwordClass); webmaster@1: } webmaster@1: passwordDescription.html(result.message); webmaster@1: passwordResult.addClass(newClass); webmaster@1: if (result.strength == "high") { webmaster@1: passwordDescription.hide(); webmaster@1: } webmaster@1: else { webmaster@1: passwordDescription.addClass(newClass); webmaster@1: } webmaster@1: this.passwordClass = newClass; webmaster@1: webmaster@1: // Check that password and confirmation match. webmaster@1: webmaster@1: // Hide the result layer if confirmation is empty, otherwise show the layer. webmaster@1: confirmResult.css({ visibility: (confirmInput.val() == "" ? "hidden" : "visible") }); webmaster@1: webmaster@1: var success = passwordInput.val() == confirmInput.val(); webmaster@1: webmaster@1: // Remove the previous styling if any exists. webmaster@1: if (this.confirmClass) { webmaster@1: confirmChild.removeClass(this.confirmClass); webmaster@1: } webmaster@1: webmaster@1: // Fill in the correct message and set the class accordingly. webmaster@1: var confirmClass = success ? "ok" : "error"; webmaster@1: confirmChild.html(translate["confirm"+ (success ? "Success" : "Failure")]).addClass(confirmClass); webmaster@1: this.confirmClass = confirmClass; webmaster@1: webmaster@1: // Show the indicator and tips. webmaster@1: passwordStrength.css({ visibility: "visible" }); webmaster@1: passwordDescription.show(); webmaster@1: }; webmaster@1: webmaster@1: // Do a delayed check on the password fields. webmaster@1: var passwordDelayedCheck = function() { webmaster@1: // Postpone the check since the user is most likely still typing. webmaster@1: if (this.timer) { webmaster@1: clearTimeout(this.timer); webmaster@1: } webmaster@1: webmaster@1: // When the user clears the field, hide the tips immediately. webmaster@1: if (!passwordInput.val()) { webmaster@1: passwordStrength.css({ visibility: "hidden" }); webmaster@1: passwordDescription.hide(); webmaster@1: return; webmaster@1: } webmaster@1: webmaster@1: // Schedule the actual check. webmaster@1: this.timer = setTimeout(passwordCheck, monitorDelay); webmaster@1: }; webmaster@1: // Monitor keyup and blur events. webmaster@1: // Blur must be used because a mouse paste does not trigger keyup. webmaster@1: passwordInput.keyup(passwordDelayedCheck).blur(passwordCheck); webmaster@1: confirmInput.keyup(passwordDelayedCheck).blur(passwordCheck); webmaster@1: }); webmaster@1: }; webmaster@1: webmaster@1: /** webmaster@1: * Evaluate the strength of a user's password. webmaster@1: * webmaster@1: * Returns the estimated strength and the relevant output message. webmaster@1: */ webmaster@1: Drupal.evaluatePasswordStrength = function(value) { webmaster@1: var strength = "", msg = "", translate = Drupal.settings.password; webmaster@1: webmaster@1: var hasLetters = value.match(/[a-zA-Z]+/); webmaster@1: var hasNumbers = value.match(/[0-9]+/); webmaster@1: var hasPunctuation = value.match(/[^a-zA-Z0-9]+/); webmaster@1: var hasCasing = value.match(/[a-z]+.*[A-Z]+|[A-Z]+.*[a-z]+/); webmaster@1: webmaster@1: // Check if the password is blank. webmaster@1: if (!value.length) { webmaster@1: strength = ""; webmaster@1: msg = ""; webmaster@1: } webmaster@1: // Check if length is less than 6 characters. webmaster@1: else if (value.length < 6) { webmaster@1: strength = "low"; webmaster@1: msg = translate.tooShort; webmaster@1: } webmaster@1: // Check if password is the same as the username (convert both to lowercase). webmaster@1: else if (value.toLowerCase() == translate.username.toLowerCase()) { webmaster@1: strength = "low"; webmaster@1: msg = translate.sameAsUsername; webmaster@1: } webmaster@1: // Check if it contains letters, numbers, punctuation, and upper/lower case. webmaster@1: else if (hasLetters && hasNumbers && hasPunctuation && hasCasing) { webmaster@1: strength = "high"; webmaster@1: } webmaster@1: // Password is not secure enough so construct the medium-strength message. webmaster@1: else { webmaster@1: // Extremely bad passwords still count as low. webmaster@1: var count = (hasLetters ? 1 : 0) + (hasNumbers ? 1 : 0) + (hasPunctuation ? 1 : 0) + (hasCasing ? 1 : 0); webmaster@1: strength = count > 1 ? "medium" : "low"; webmaster@1: webmaster@1: msg = []; webmaster@1: if (!hasLetters || !hasCasing) { webmaster@1: msg.push(translate.addLetters); webmaster@1: } webmaster@1: if (!hasNumbers) { webmaster@1: msg.push(translate.addNumbers); webmaster@1: } webmaster@1: if (!hasPunctuation) { webmaster@1: msg.push(translate.addPunctuation); webmaster@1: } webmaster@1: msg = translate.needsMoreVariation +"