web/drupal/modules/user/user.js
branchdrupal
changeset 74 0ff3ba646492
equal deleted inserted replaced
73:fcf75e232c5b 74:0ff3ba646492
       
     1 // $Id: user.js,v 1.6 2007/09/12 18:29:32 goba Exp $
       
     2 
       
     3 /**
       
     4  * Attach handlers to evaluate the strength of any password fields and to check
       
     5  * that its confirmation is correct.
       
     6  */
       
     7 Drupal.behaviors.password = function(context) {
       
     8   var translate = Drupal.settings.password;
       
     9   $("input.password-field:not(.password-processed)", context).each(function() {
       
    10     var passwordInput = $(this).addClass('password-processed');
       
    11     var parent = $(this).parent();
       
    12     // Wait this number of milliseconds before checking password.
       
    13     var monitorDelay = 700;
       
    14 
       
    15     // Add the password strength layers.
       
    16     $(this).after('<span class="password-strength"><span class="password-title">'+ translate.strengthTitle +'</span> <span class="password-result"></span></span>').parent();
       
    17     var passwordStrength = $("span.password-strength", parent);
       
    18     var passwordResult = $("span.password-result", passwordStrength);
       
    19     parent.addClass("password-parent");
       
    20 
       
    21     // Add the password confirmation layer.
       
    22     var outerItem  = $(this).parent().parent();
       
    23     $("input.password-confirm", outerItem).after('<span class="password-confirm">'+ translate["confirmTitle"] +' <span></span></span>').parent().addClass("confirm-parent");
       
    24     var confirmInput = $("input.password-confirm", outerItem);
       
    25     var confirmResult = $("span.password-confirm", outerItem);
       
    26     var confirmChild = $("span", confirmResult);
       
    27 
       
    28     // Add the description box at the end.
       
    29     $(confirmInput).parent().after('<div class="password-description"></div>');
       
    30     var passwordDescription = $("div.password-description", $(this).parent().parent()).hide();
       
    31 
       
    32     // Check the password fields.
       
    33     var passwordCheck = function () {
       
    34       // Remove timers for a delayed check if they exist.
       
    35       if (this.timer) {
       
    36         clearTimeout(this.timer);
       
    37       }
       
    38 
       
    39       // Verify that there is a password to check.
       
    40       if (!passwordInput.val()) {
       
    41         passwordStrength.css({ visibility: "hidden" });
       
    42         passwordDescription.hide();
       
    43         return;
       
    44       }
       
    45 
       
    46       // Evaluate password strength.
       
    47 
       
    48       var result = Drupal.evaluatePasswordStrength(passwordInput.val());
       
    49       passwordResult.html(result.strength == "" ? "" : translate[result.strength +"Strength"]);
       
    50 
       
    51       // Map the password strength to the relevant drupal CSS class.
       
    52       var classMap = { low: "error", medium: "warning", high: "ok" };
       
    53       var newClass = classMap[result.strength] || "";
       
    54 
       
    55       // Remove the previous styling if any exists; add the new class.
       
    56       if (this.passwordClass) {
       
    57         passwordResult.removeClass(this.passwordClass);
       
    58         passwordDescription.removeClass(this.passwordClass);
       
    59       }
       
    60       passwordDescription.html(result.message);
       
    61       passwordResult.addClass(newClass);
       
    62       if (result.strength == "high") {
       
    63         passwordDescription.hide();
       
    64       }
       
    65       else {
       
    66         passwordDescription.addClass(newClass);
       
    67       }
       
    68       this.passwordClass = newClass;
       
    69 
       
    70       // Check that password and confirmation match.
       
    71 
       
    72       // Hide the result layer if confirmation is empty, otherwise show the layer.
       
    73       confirmResult.css({ visibility: (confirmInput.val() == "" ? "hidden" : "visible") });
       
    74 
       
    75       var success = passwordInput.val() == confirmInput.val();
       
    76 
       
    77       // Remove the previous styling if any exists.
       
    78       if (this.confirmClass) {
       
    79         confirmChild.removeClass(this.confirmClass);
       
    80       }
       
    81 
       
    82       // Fill in the correct message and set the class accordingly.
       
    83       var confirmClass = success ? "ok" : "error";
       
    84       confirmChild.html(translate["confirm"+ (success ? "Success" : "Failure")]).addClass(confirmClass);
       
    85       this.confirmClass = confirmClass;
       
    86 
       
    87       // Show the indicator and tips.
       
    88       passwordStrength.css({ visibility: "visible" });
       
    89       passwordDescription.show();
       
    90     };
       
    91 
       
    92     // Do a delayed check on the password fields.
       
    93     var passwordDelayedCheck = function() {
       
    94       // Postpone the check since the user is most likely still typing.
       
    95       if (this.timer) {
       
    96         clearTimeout(this.timer);
       
    97       }
       
    98 
       
    99       // When the user clears the field, hide the tips immediately.
       
   100       if (!passwordInput.val()) {
       
   101         passwordStrength.css({ visibility: "hidden" });
       
   102         passwordDescription.hide();
       
   103         return;
       
   104       }
       
   105 
       
   106       // Schedule the actual check.
       
   107       this.timer = setTimeout(passwordCheck, monitorDelay);
       
   108     };
       
   109     // Monitor keyup and blur events.
       
   110     // Blur must be used because a mouse paste does not trigger keyup.
       
   111     passwordInput.keyup(passwordDelayedCheck).blur(passwordCheck);
       
   112     confirmInput.keyup(passwordDelayedCheck).blur(passwordCheck);
       
   113   });
       
   114 };
       
   115 
       
   116 /**
       
   117  * Evaluate the strength of a user's password.
       
   118  *
       
   119  * Returns the estimated strength and the relevant output message.
       
   120  */
       
   121 Drupal.evaluatePasswordStrength = function(value) {
       
   122   var strength = "", msg = "", translate = Drupal.settings.password;
       
   123 
       
   124   var hasLetters = value.match(/[a-zA-Z]+/);
       
   125   var hasNumbers = value.match(/[0-9]+/);
       
   126   var hasPunctuation = value.match(/[^a-zA-Z0-9]+/);
       
   127   var hasCasing = value.match(/[a-z]+.*[A-Z]+|[A-Z]+.*[a-z]+/);
       
   128 
       
   129   // Check if the password is blank.
       
   130   if (!value.length) {
       
   131     strength = "";
       
   132     msg = "";
       
   133   }
       
   134   // Check if length is less than 6 characters.
       
   135   else if (value.length < 6) {
       
   136     strength = "low";
       
   137     msg = translate.tooShort;
       
   138   }
       
   139   // Check if password is the same as the username (convert both to lowercase).
       
   140   else if (value.toLowerCase() == translate.username.toLowerCase()) {
       
   141     strength  = "low";
       
   142     msg = translate.sameAsUsername;
       
   143   }
       
   144   // Check if it contains letters, numbers, punctuation, and upper/lower case.
       
   145   else if (hasLetters && hasNumbers && hasPunctuation && hasCasing) {
       
   146     strength = "high";
       
   147   }
       
   148   // Password is not secure enough so construct the medium-strength message.
       
   149   else {
       
   150     // Extremely bad passwords still count as low.
       
   151     var count = (hasLetters ? 1 : 0) + (hasNumbers ? 1 : 0) + (hasPunctuation ? 1 : 0) + (hasCasing ? 1 : 0);
       
   152     strength = count > 1 ? "medium" : "low";
       
   153 
       
   154     msg = [];
       
   155     if (!hasLetters || !hasCasing) {
       
   156       msg.push(translate.addLetters);
       
   157     }
       
   158     if (!hasNumbers) {
       
   159       msg.push(translate.addNumbers);
       
   160     }
       
   161     if (!hasPunctuation) {
       
   162       msg.push(translate.addPunctuation);
       
   163     }
       
   164     msg = translate.needsMoreVariation +"<ul><li>"+ msg.join("</li><li>") +"</li></ul>";
       
   165   }
       
   166 
       
   167   return { strength: strength, message: msg };
       
   168 };
       
   169 
       
   170 /**
       
   171  * Set the client's system timezone as default values of form fields.
       
   172  */
       
   173 Drupal.setDefaultTimezone = function() {
       
   174   var offset = new Date().getTimezoneOffset() * -60;
       
   175   $("#edit-date-default-timezone, #edit-user-register-timezone").val(offset);
       
   176 };
       
   177 
       
   178 /**
       
   179  * On the admin/user/settings page, conditionally show all of the
       
   180  * picture-related form elements depending on the current value of the
       
   181  * "Picture support" radio buttons.
       
   182  */
       
   183 Drupal.behaviors.userSettings = function (context) {
       
   184   $('div.user-admin-picture-radios input[type=radio]:not(.userSettings-processed)', context).addClass('userSettings-processed').click(function () {
       
   185     $('div.user-admin-picture-settings', context)[['hide', 'show'][this.value]]();
       
   186   });
       
   187 };
       
   188