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