PageSourceSearch

https://www.portercable.com/core/modules/user/user.js?v=10.6.14

js portercable.com collected 2026-09-25 21:07:32 UTC 12,217 bytes, 369 lines download raw bytes

1/**
2 * @file
3 * User behaviors.
4 */
5
6(($, Drupal) => {
7  /**
8   * An object containing CSS classes used for password widget.
9   *
10   * @type {object}
11   * @prop {string} passwordParent - A CSS class for the parent element.
12   * @prop {string} passwordsMatch - A CSS class indicating password match.
13   * @prop {string} passwordsNotMatch - A CSS class indicating passwords
14   *   doesn't match.
15   * @prop {string} passwordWeak - A CSS class indicating weak password
16   *   strength.
17   * @prop {string} passwordFair - A CSS class indicating fair password
18   *   strength.
19   * @prop {string} passwordGood - A CSS class indicating good password
20   *   strength.
21   * @prop {string} passwordStrong - A CSS class indicating strong password
22   *   strength.
23   * @prop {string} widgetInitial - Initial CSS class that should be removed
24   *   on a state change.
25   * @prop {string} passwordEmpty - A CSS class indicating password has not
26   *   been filled.
27   * @prop {string} passwordFilled - A CSS class indicating password has
28   *   been filled.
29   * @prop {string} confirmEmpty - A CSS class indicating password
30   *   confirmation has not been filled.
31   * @prop {string} confirmFilled - A CSS class indicating password
32   *   confirmation has been filled.
33   */
34  Drupal.user = {
35    password: {
36      css: {
37        passwordParent: 'password-parent',
38        passwordsMatch: 'ok',
39        passwordsNotMatch: 'error',
40        passwordWeak: 'is-weak',
41        passwordFair: 'is-fair',
42        passwordGood: 'is-good',
43        passwordStrong: 'is-strong',
44        widgetInitial: '',
45        passwordEmpty: '',
46        passwordFilled: '',
47        confirmEmpty: '',
48        confirmFilled: '',
49      },
50    },
51  };
52
53  /**
54   * Attach handlers to evaluate the strength of any password fields and to
55   * check that its confirmation is correct.
56   *
57   * @type {Drupal~behavior}
58   *
59   * @prop {Drupal~behaviorAttach} attach
60   *   Attaches password strength indicator and other relevant validation to
61   *   password fields.
62   */
63  Drupal.behaviors.password = {
64    attach(context, settings) {
65      const cssClasses = Drupal.user.password.css;
66      once('password', 'input.js-password-field', context).forEach((value) => {
67        const $mainInput = $(value);
68        const $mainInputParent = $mainInput
69          .parent()
70          .addClass(cssClasses.passwordParent);
71        const $passwordWidget = $mainInput.closest(
72          '.js-form-type-password-confirm',
73        );
74        const $confirmInput = $passwordWidget.find('input.js-password-confirm');
75        const $passwordConfirmMessage = $(
76          Drupal.theme('passwordConfirmMessage', settings.password),
77        );
78
79        const $passwordMatchStatus = $passwordConfirmMessage
80          .find('[data-drupal-selector="password-match-status-text"]')
81          .first();
82
83        const $confirmInputParent = $confirmInput
84          .parent()
85          .addClass('confirm-parent')
86          .append($passwordConfirmMessage);
87
88        // List of classes to be removed from the strength bar on a state
89        // change.
90        const passwordStrengthBarClassesToRemove = [
91          cssClasses.passwordWeak || '',
92          cssClasses.passwordFair || '',
93          cssClasses.passwordGood || '',
94          cssClasses.passwordStrong || '',
95        ]
96          .join(' ')
97          .trim();
98
99        // List of classes to be removed from the text wrapper on a state
100        // change.
101        const confirmTextWrapperClassesToRemove = [
102          cssClasses.passwordsMatch || '',
103          cssClasses.passwordsNotMatch || '',
104        ]
105          .join(' ')
106          .trim();
107
108        // List of classes to be removed from the widget on a state change.
109        const widgetClassesToRemove = [
110          cssClasses.widgetInitial || '',
111          cssClasses.passwordEmpty || '',
112          cssClasses.passwordFilled || '',
113          cssClasses.confirmEmpty || '',
114          cssClasses.confirmFilled || '',
115        ]
116          .join(' ')
117          .trim();
118
119        const password = {};
120
121        // If the password strength indicator is enabled, add its markup.
122        if (settings.password.showStrengthIndicator) {
123          const $passwordStrength = $(
124            Drupal.theme('passwordStrength', settings.password),
125          );
126          password.$strengthBar = $passwordStrength
127            .find('[data-drupal-selector="password-strength-indicator"]')
128            .first();
129          password.$strengthTextWrapper = $passwordStrength
130            .find('[data-drupal-selector="password-strength-text"]')
131            .first();
132          password.$suggestions = $(
133            Drupal.theme('passwordSuggestions', settings.password, []),
134          );
135
136          password.$suggestions.hide();
137          $mainInputParent.append($passwordStrength);
138          $confirmInputParent.after(password.$suggestions);
139        }
140
141        /**
142         * Adds classes to the widget indicating if the elements are filled.
143         */
144        const addWidgetClasses = () => {
145          $passwordWidget
146            .addClass(
147              $mainInput[0].value
148                ? cssClasses.passwordFilled
149                : cssClasses.passwordEmpty,
150            )
151            .addClass(
152              $confirmInput[0].value
153                ? cssClasses.confirmFilled
154                : cssClasses.confirmEmpty,
155            );
156        };
157
158        /**
159         * Check that password and confirmation inputs match.
160         *
161         * @param {string} confirmInputVal
162         *   The value of the confirm input.
163         */
164        const passwordCheckMatch = (confirmInputVal) => {
165          const passwordsAreMatching = $mainInput[0].value === confirmInputVal;
166          const confirmClass = passwordsAreMatching
167            ? cssClasses.passwordsMatch
168            : cssClasses.passwordsNotMatch;
169          const confirmMessage = passwordsAreMatching
170            ? settings.password.confirmSuccess
171            : settings.password.confirmFailure;
172
173          // Update the success message and set the class if needed.
174          if (
175            !$passwordMatchStatus.hasClass(confirmClass) ||
176            !$passwordMatchStatus.html() === confirmMessage
177          ) {
178            if (confirmTextWrapperClassesToRemove) {
179              $passwordMatchStatus.removeClass(
180                confirmTextWrapperClassesToRemove,
181              );
182            }
183            $passwordMatchStatus.html(confirmMessage).addClass(confirmClass);
184          }
185        };
186
187        /**
188         * Checks the password strength.
189         */
190        const passwordCheck = () => {
191          if (settings.password.showStrengthIndicator) {
192            // Evaluate the password strength.
193            const result = Drupal.evaluatePasswordStrength(
194              $mainInput[0].value,
195              settings.password,
196            );
197            const $currentPasswordSuggestions = $(
198              Drupal.theme(
199                'passwordSuggestions',
200                settings.password,
201                result.messageTips,
202              ),
203            );
204
205            // Update the suggestions for how to improve the password if needed.
206            if (
207              password.$suggestions.html() !==
208              $currentPasswordSuggestions.html()
209            ) {
210              password.$suggestions.replaceWith($currentPasswordSuggestions);
211              password.$suggestions = $currentPasswordSuggestions.toggle(
212                // Only show the description box if a weakness exists in the
213                // password.
214                result.strength !== 100,
215              );
216            }
217
218            if (passwordStrengthBarClassesToRemove) {
219              password.$strengthBar.removeClass(
220                passwordStrengthBarClassesToRemove,
221              );
222            }
223            // Adjust the length of the strength indicator.
224            password.$strengthBar[0].style.width = `${result.strength}%`;
225            password.$strengthBar.addClass(result.indicatorClass);
226
227            // Update the strength indication text.
228            password.$strengthTextWrapper.html(result.indicatorText);
229          }
230
231          // Check the value in the confirm input and show results.
232          if ($confirmInput[0].value) {
233            passwordCheckMatch($confirmInput[0].value);
234            $passwordConfirmMessage[0].style.visibility = 'visible';
235          } else {
236            $passwordConfirmMessage[0].style.visibility = 'hidden';
237          }
238
239          if (widgetClassesToRemove) {
240            $passwordWidget.removeClass(widgetClassesToRemove);
241            addWidgetClasses();
242          }
243        };
244
245        if (widgetClassesToRemove) {
246          addWidgetClasses();
247        }
248
249        // Monitor input events.
250        $mainInput.on('input', passwordCheck);
251        $confirmInput.on('input', passwordCheck);
252      });
253    },
254  };
255
256  /**
257   * Evaluate the strength of a user's password.
258   *
259   * Returns the estimated strength and the relevant output message.
260   *
261   * @param {string} password
262   *   The password to evaluate.
263   * @param {object} passwordSettings
264   *   A password settings object containing the text to display and the CSS
265   *   classes for each strength level.
266   *
267   * @return {object}
268   *   An object containing strength, message, indicatorText and indicatorClass.
269   */
270  Drupal.evaluatePasswordStrength = (password, passwordSettings) => {
271    password = password.trim();
272    let indicatorText;
273    let indicatorClass;
274    let weaknesses = 0;
275    let strength = 100;
276    let msg = [];
277
278    const hasLowercase = /[a-z]/.test(password);
279    const hasUppercase = /[A-Z]/.test(password);
280    const hasNumbers = /[0-9]/.test(password);
281    const hasPunctuation = /[^a-zA-Z0-9]/.test(password);
282
283    // If there is a username edit box on the page, compare password to that,
284    // otherwise use value from the database.
285    const $usernameBox = $('input.username');
286    const username =
287      $usernameBox.length > 0
288        ? $usernameBox[0].value
289        : passwordSettings.username;
290
291    // Lose 5 points for every character less than 12, plus a 30 point penalty.
292    if (password.length < 12) {
293      msg.push(passwordSettings.tooShort);
294      strength -= (12 - password.length) * 5 + 30;
295    }
296
297    // Count weaknesses.
298    if (!hasLowercase) {
299      msg.push(passwordSettings.addLowerCase);
300      weaknesses += 1;
301    }
302    if (!hasUppercase) {
303      msg.push(passwordSettings.addUpperCase);
304      weaknesses += 1;
305    }
306    if (!hasNumbers) {
307      msg.push(passwordSettings.addNumbers);
308      weaknesses += 1;
309    }
310    if (!hasPunctuation) {
311      msg.push(passwordSettings.addPunctuation);
312      weaknesses += 1;
313    }
314
315    // Apply penalty for each weakness (balanced against length penalty).
316    switch (weaknesses) {
317      case 1:
318        strength -= 12.5;
319        break;
320
321      case 2:
322        strength -= 25;
323        break;
324
325      case 3:
326      case 4:
327        strength -= 40;
328        break;
329    }
330
331    // Check if password is the same as the username.
332    if (password !== '' && password.toLowerCase() === username.toLowerCase()) {
333      msg.push(passwordSettings.sameAsUsername);
334      // Passwords the same as username are always very weak.
335      strength = 5;
336    }
337
338    const cssClasses = Drupal.user.password.css;
339
340    // Based on the strength, work out what text should be shown by the
341    // password strength meter.
342    if (strength < 60) {
343      indicatorText = passwordSettings.weak;
344      indicatorClass = cssClasses.passwordWeak;
345    } else if (strength < 70) {
346      indicatorText = passwordSettings.fair;
347      indicatorClass = cssClasses.passwordFair;
348    } else if (strength < 80) {
349      indicatorText = passwordSettings.good;
350      indicatorClass = cssClasses.passwordGood;
351    } else if (strength <= 100) {
352      indicatorText = passwordSettings.strong;
353      indicatorClass = cssClasses.passwordStrong;
354    }
355
356    // Assemble the final message while keeping the original message array.
357    const messageTips = msg;
358    msg = `${passwordSettings.hasWeaknesses}<ul><li>${msg.join(
359      '</li><li>',
360    )}</li></ul>`;
361
362    return {
363      strength,
364      indicatorText,
365      indicatorClass,
366      messageTips,
367    };
368  };
369})(jQuery, Drupal);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.