Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 17 additions & 60 deletions assets/js/checkout.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global Vue, moment, _, wu_checkout, pwsL10n, wu_checkout_form, wu_create_cookie, wu_listen_to_cookie_change */
/* global Vue, moment, _, wu_checkout, wu_checkout_form, wu_create_cookie, wu_listen_to_cookie_change */
(function ($, hooks, _) {

/*
Expand Down Expand Up @@ -748,73 +748,33 @@
});

},
check_pass_strength() {
init_password_strength() {

const pass1_el = '#field-password';
const that = this;
const pass1_el = jQuery('#field-password');

if (!jQuery('#pass-strength-result').length) {
if (!pass1_el.length) {

return;

} // end if;

jQuery('#pass-strength-result')
.attr('class', 'wu-py-2 wu-px-4 wu-bg-gray-100 wu-block wu-text-sm wu-border-solid wu-border wu-border-gray-200');

const pass1 = jQuery(pass1_el).val();
// Use the shared WU_PasswordStrength utility
if (typeof window.WU_PasswordStrength !== 'undefined') {

if (!pass1) {
this.password_strength_checker = new window.WU_PasswordStrength({
pass1: pass1_el,
result: jQuery('#pass-strength-result'),
minStrength: 3,
onValidityChange: function(isValid) {

jQuery('#pass-strength-result').addClass('empty').html('Enter Password');
that.valid_password = isValid;

return;
}
});

} // end if;

this.valid_password = false;

const disallowed_list = typeof wp.passwordStrength.userInputDisallowedList === 'undefined'
? wp.passwordStrength.userInputBlacklist()
: wp.passwordStrength.userInputDisallowedList();

const strength = wp.passwordStrength.meter(pass1, disallowed_list, pass1);

switch (strength) {

case -1:
jQuery('#pass-strength-result').addClass('wu-bg-red-200 wu-border-red-300').html(pwsL10n.unknown);

break;

case 2:
jQuery('#pass-strength-result').addClass('wu-bg-red-200 wu-border-red-300').html(pwsL10n.bad);

break;

case 3:
jQuery('#pass-strength-result').addClass('wu-bg-green-200 wu-border-green-300').html(pwsL10n.good);

this.valid_password = true;

break;

case 4:
jQuery('#pass-strength-result').addClass('wu-bg-green-200 wu-border-green-300').html(pwsL10n.strong);

this.valid_password = true;

break;

case 5:
jQuery('#pass-strength-result').addClass('wu-bg-yellow-200 wu-border-yellow-300').html(pwsL10n.mismatch);

break;

default:
jQuery('#pass-strength-result').addClass('wu-bg-yellow-200 wu-border-yellow-300').html(pwsL10n.short);

} // end switch;

},
check_user_exists_debounced: _.debounce(function(field_type, value) {

Expand Down Expand Up @@ -1162,11 +1122,8 @@

hooks.doAction('wu_on_change_gateway', this.gateway, this.gateway);

jQuery('#field-password').on('input pwupdate', function () {

that.check_pass_strength();

});
// Initialize password strength checker using the shared utility
this.init_password_strength();

wu_initialize_tooltip();

Expand Down
45 changes: 45 additions & 0 deletions assets/js/wu-password-reset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* global jQuery, WU_PasswordStrength */
/**
* Password strength meter for the password reset form.
*
* Uses the shared WU_PasswordStrength utility to check password strength
* and enforces minimum strength requirements.
*
* @since 2.3.0
*/
(function($) {
'use strict';

var passwordStrength;

/**
* Initialize the password strength meter.
*/
$(document).ready(function() {
var $pass1 = $('#field-pass1');
var $pass2 = $('#field-pass2');
var $submit = $('#wp-submit');
var $form = $pass1.closest('form');

if (!$pass1.length || typeof WU_PasswordStrength === 'undefined') {
return;
}

// Initialize the password strength checker using the shared utility
passwordStrength = new WU_PasswordStrength({
pass1: $pass1,
pass2: $pass2,
submit: $submit,
minStrength: 3 // Require at least medium strength
});

// Prevent form submission if password is too weak
$form.on('submit', function(e) {
if (!passwordStrength.isValid()) {
e.preventDefault();
return false;
}
});
});

})(jQuery);
241 changes: 241 additions & 0 deletions assets/js/wu-password-strength.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/* global jQuery, wp, pwsL10n */
/**
* Shared password strength utility for WP Ultimo.
*
* This module provides reusable password strength checking functionality
* that can be used across different forms (checkout, password reset, etc.)
*
* @since 2.3.0
*/
(function($) {
'use strict';

/**
* Password strength checker utility.
*
* @param {Object} options Configuration options
* @param {jQuery} options.pass1 First password field element
* @param {jQuery} options.pass2 Second password field element (optional)
* @param {jQuery} options.result Strength result display element
* @param {jQuery} options.submit Submit button element (optional)
* @param {number} options.minStrength Minimum required strength level (default: 3)
* @param {Function} options.onValidityChange Callback when password validity changes
*/
window.WU_PasswordStrength = function(options) {
this.options = $.extend({
pass1: null,
pass2: null,
result: null,
submit: null,
minStrength: 3,
onValidityChange: null
}, options);

this.isPasswordValid = false;

this.init();
};

WU_PasswordStrength.prototype = {
/**
* Initialize the password strength checker.
*/
init: function() {
var self = this;

if (!this.options.pass1 || !this.options.pass1.length) {
return;
}

// Create or find strength meter element
if (!this.options.result || !this.options.result.length) {
this.options.result = $('#pass-strength-result');

if (!this.options.result.length) {
this.options.result = $('<div id="pass-strength-result" class="wu-py-2 wu-px-4 wu-bg-gray-100 wu-block wu-text-sm wu-border-solid wu-border wu-border-gray-200 wu-mt-2"></div>');
this.options.pass1.after(this.options.result);
}
}

// Set initial message
this.options.result.html(this.getStrengthLabel('empty'));

// Bind events
this.options.pass1.on('keyup input', function() {
self.checkStrength();
});

if (this.options.pass2 && this.options.pass2.length) {
this.options.pass2.on('keyup input', function() {
self.checkStrength();
});
}

// Disable submit initially if provided
if (this.options.submit && this.options.submit.length) {
this.options.submit.prop('disabled', true);
}

// Initial check
this.checkStrength();
},

/**
* Check password strength and update the UI.
*/
checkStrength: function() {
var pass1 = this.options.pass1.val();
var pass2 = this.options.pass2 ? this.options.pass2.val() : '';

// Reset classes
this.options.result.attr('class', 'wu-py-2 wu-px-4 wu-block wu-text-sm wu-border-solid wu-border wu-mt-2');

if (!pass1) {
this.options.result.addClass('wu-bg-gray-100 wu-border-gray-200').html(this.getStrengthLabel('empty'));
this.setValid(false);
return;
}

// Get disallowed list from WordPress
var disallowedList = this.getDisallowedList();

var strength = wp.passwordStrength.meter(pass1, disallowedList, pass2);

this.updateUI(strength);
this.updateValidity(strength);
},

/**
* Get the disallowed list for password checking.
*
* @return {Array} The disallowed list
*/
getDisallowedList: function() {
if (typeof wp === 'undefined' || typeof wp.passwordStrength === 'undefined') {
return [];
}

// Support both old and new WordPress naming
return typeof wp.passwordStrength.userInputDisallowedList === 'undefined'
? wp.passwordStrength.userInputBlacklist()
: wp.passwordStrength.userInputDisallowedList();
},

/**
* Get the appropriate label for a given strength level.
*
* @param {string|number} strength The strength level
* @return {string} The label text
*/
getStrengthLabel: function(strength) {
// Use WordPress's built-in localized strings
if (typeof pwsL10n === 'undefined') {
// Fallback labels if pwsL10n is not available
var fallbackLabels = {
'empty': 'Enter a password',
'-1': 'Unknown',
'0': 'Very weak',
'1': 'Very weak',
'2': 'Weak',
'3': 'Medium',
'4': 'Strong',
'5': 'Mismatch'
};
return fallbackLabels[strength] || fallbackLabels['0'];
}

switch (strength) {
case 'empty':
return pwsL10n.empty || 'Strength indicator';
case -1:
return pwsL10n.unknown || 'Unknown';
case 0:
case 1:
return pwsL10n.short || 'Very weak';
case 2:
return pwsL10n.bad || 'Weak';
case 3:
return pwsL10n.good || 'Medium';
case 4:
return pwsL10n.strong || 'Strong';
case 5:
return pwsL10n.mismatch || 'Mismatch';
default:
return pwsL10n.short || 'Very weak';
}
},

/**
* Update the UI based on password strength.
*
* @param {number} strength The password strength level
*/
updateUI: function(strength) {
switch (strength) {
case -1:
case 0:
case 1:
this.options.result.addClass('wu-bg-red-200 wu-border-red-300').html(this.getStrengthLabel(strength));
break;
case 2:
this.options.result.addClass('wu-bg-red-200 wu-border-red-300').html(this.getStrengthLabel(2));
break;
case 3:
this.options.result.addClass('wu-bg-yellow-200 wu-border-yellow-300').html(this.getStrengthLabel(3));
break;
case 4:
this.options.result.addClass('wu-bg-green-200 wu-border-green-300').html(this.getStrengthLabel(4));
break;
case 5:
this.options.result.addClass('wu-bg-red-200 wu-border-red-300').html(this.getStrengthLabel(5));
break;
default:
this.options.result.addClass('wu-bg-red-200 wu-border-red-300').html(this.getStrengthLabel(0));
}
},

/**
* Update password validity based on strength.
*
* @param {number} strength The password strength level
*/
updateValidity: function(strength) {
var isValid = false;

if (strength >= this.options.minStrength && strength !== 5) {
isValid = true;
}

this.setValid(isValid);
},

/**
* Set password validity and update submit button.
*
* @param {boolean} isValid Whether the password is valid
*/
setValid: function(isValid) {
var wasValid = this.isPasswordValid;
this.isPasswordValid = isValid;

if (this.options.submit && this.options.submit.length) {
this.options.submit.prop('disabled', !isValid);
}

// Trigger callback if validity changed
if (wasValid !== isValid && typeof this.options.onValidityChange === 'function') {
this.options.onValidityChange(isValid);
}
},

/**
* Get the current password validity.
*
* @return {boolean} Whether the password is valid
*/
isValid: function() {
return this.isPasswordValid;
}
};

})(jQuery);
Loading
Loading