username-1.0.x-dev/js/username.js
js/username.js
/**
* @file
* Extends the Drupal user form functionality.
*/
(function ($, Drupal, drupalSettings, once) {
"use strict";
/**
* Attaches the username behavior to user forms.
*
* @type {Drupal~behavior}
*/
Drupal.behaviors.username = {
attach(context, settings) {
const options = drupalSettings.username.options;
const isAdmin = drupalSettings.username.isAdmin;
if (once('username-init', '.username-init').length) {
if (drupalSettings.username.masks) {
const masks = drupalSettings.username.masks;
Drupal.usernameMask(masks);
}
if (options.autocomplete && !isAdmin) {
Drupal.usernameClearSaved();
}
if (options.emailmask) {
if ($('#edit-mail').length) {
let email = document.getElementById('edit-mail');
Drupal.usernameEmailMask(email);
}
}
if (options.capslock) {
Drupal.capsLockWarning();
}
if (options.showhide) {
Drupal.passwordShowHide();
}
if (options.generate && $('form.user-form').length) {
Drupal.securePasswordGenerator();
}
}
},
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.usernameMask = function (masks) {
let username = document.getElementById('edit-name');
let specialChars = '';
specialChars = masks.period ? specialChars + '.' : specialChars;
specialChars = masks.hyphen ? specialChars + '-' : specialChars;
specialChars = masks.apostrophe ? specialChars + '\'' : specialChars;
specialChars = masks.underscore ? specialChars + '_' : specialChars;
specialChars = masks.sign ? specialChars + '@' : specialChars;
let maskOptions = {
allow : specialChars, // Allow extra characters
disallow : '~!#$%^&*()[]{}', // Disallow extra characters
allowSpace : !!masks.space, // Allow the space character
allowNewline : false, // Allow the newline character \n ascii 10
allowNumeric : !!masks.numeric, // Allow digits 0-9
allowOtherCharSets : false, // eg é, Á, Arabic, Chinese etc
maxLength : masks.maxlength // eg Max Length
};
if (masks.lowercase && !masks.uppercase) {
/*username.addEventListener('input', function (e) {
e.target.value = e.target.value.toLowerCase();
});*/
Drupal.usernameToLowerCase(username);
}
if (!masks.lowercase && masks.uppercase) {
/*username.addEventListener('input', function (e) {
e.target.value = e.target.value.toUpperCase();
});*/
Drupal.usernameToUpperCase(username);
}
if (!masks.lowercase && !masks.uppercase) {
maskOptions.allowLatin = false;
maskOptions.allowUpper = false;
maskOptions.allowLower = false;
}
console.log(maskOptions);
$(username).alphanum(maskOptions);
}
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.usernameClearSaved = function () {
// User form inputs.
let inputs = [
'edit-name',
'edit-mail',
'edit-pass',
'edit-pass-pass1',
'edit-pass-pass2',
];
// loop through each input to clear saved value.
let inputElement = '';
inputs.forEach(function(input) {
if (inputElement = document.getElementById(input)) {
$(inputElement).attr('autocomplete', 'off').val('');
}
});
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.usernameToLowerCase = function (input) {
// loop through each input and add an input event listener.
if (input) {
input.addEventListener('input', function (e) {
e.target.value = e.target.value.toLowerCase();
});
}
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.usernameToUpperCase = function (input) {
// loop through each input and add an input event listener.
if (input) {
input.addEventListener('input', function (e) {
e.target.value = e.target.value.toUpperCase();
});
}
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.usernameEmailMask = function (email) {
Drupal.usernameToLowerCase(email);
/*let maskOptions = {
allow : '@.', // Allow extra characters
disallow : '~!#$%^&*()[]{}', // Disallow extra characters
allowSpace : false, // Allow the space character
allowNewline : false, // Allow the newline character \n ascii 10
allowNumeric : true, // Allow digits 0-9
allowOtherCharSets : false, // eg é, Á, Arabic, Chinese etc
maxLength : 60 // eg Max Length
};
$(email).alphanum(maskOptions);*/
var filter = /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
email.addEventListener('keydown', function (e) {
if (e.key && e.key === " ") {
e.preventDefault();
return false;
}
if (email.value) {
if (e.key && e.key === "@") {
if (email.value.includes('@')) {
e.preventDefault();
return false;
}
}
}
else {
if (e.key && (e.key === "@" || e.key === ".")) {
email.value = '';
e.preventDefault();
return false;
}
}
if (filter.test(email.value)) {
if ($(email).hasClass('invalid-email')) {
$(email).removeClass('invalid-email')
}
if (!$(email).hasClass('valid-email')) {
$(email).addClass('valid-email');
}
}
else {
if ($(email).hasClass('valid-email')) {
$(email).removeClass('valid-email')
}
if (!$(email).hasClass('invalid-email')) {
$(email).addClass('invalid-email');
}
}
});
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.capsLockWarning = function () {
const capslockOn = Drupal.t('ON');
const capslockOff = Drupal.t('OFF');
const $passwordCapsLockWarning = Drupal.passwordCapsLockWarning();
const $passwordInputParent = $('input[type="password"]')
.closest('.form-item')
.append($passwordCapsLockWarning);
console.log($('input[type="password"]')
.closest('.form-item'));
const $passwordCapsLockStatus = $passwordInputParent
.find('[data-drupal-selector="password-capslock-status-text"]')
.first();
// Run this function, when user press any key inside password field.
document.querySelector('input[type="password"]').addEventListener('keydown', function(e) {
// Check the state of getModifierState.
if (e.getModifierState && e.getModifierState("CapsLock")) {
// Caps Lock is on, update output text and color
$passwordCapsLockStatus.removeClass('capslock-off');
$passwordCapsLockStatus.addClass('capslock-on');
$passwordCapsLockStatus.text(capslockOn);
$passwordCapsLockStatus.css('color', '#ff3c41');
$passwordCapsLockStatus.parent().fadeIn();
}
else {
// Caps Lock is off, update output text and color
$passwordCapsLockStatus.removeClass('capslock-on');
$passwordCapsLockStatus.addClass('capslock-off');
$passwordCapsLockStatus.text(capslockOff);
$passwordCapsLockStatus.css('color', '#47cf73');
$passwordCapsLockStatus.parent().fadeOut();
}
});
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.passwordShowHide = function (username) {
if (once('edit-pass', '#edit-pass').length) {
const usernameField = document.getElementById('edit-name') || document.getElementById('edit-mail');
if (usernameField) {
const usernameWidth = usernameField.getBoundingClientRect().width;
const usernameHeight = usernameField.getBoundingClientRect().height;
$('.password-input').css('max-width', usernameWidth);
$('.password-input').css('height', usernameHeight);
}
const toggleShow = '<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" viewBox="0 0 48 48"><path d="M24 31.5Q27.55 31.5 30.025 29.025Q32.5 26.55 32.5 23Q32.5 19.45 30.025 16.975Q27.55 14.5 24 14.5Q20.45 14.5 17.975 16.975Q15.5 19.45 15.5 23Q15.5 26.55 17.975 29.025Q20.45 31.5 24 31.5ZM24 28.6Q21.65 28.6 20.025 26.975Q18.4 25.35 18.4 23Q18.4 20.65 20.025 19.025Q21.65 17.4 24 17.4Q26.35 17.4 27.975 19.025Q29.6 20.65 29.6 23Q29.6 25.35 27.975 26.975Q26.35 28.6 24 28.6ZM24 38Q16.7 38 10.8 33.85Q4.9 29.7 2 23Q4.9 16.3 10.8 12.15Q16.7 8 24 8Q31.3 8 37.2 12.15Q43.1 16.3 46 23Q43.1 29.7 37.2 33.85Q31.3 38 24 38ZM24 23Q24 23 24 23Q24 23 24 23Q24 23 24 23Q24 23 24 23Q24 23 24 23Q24 23 24 23Q24 23 24 23Q24 23 24 23ZM24 35Q30.05 35 35.125 31.725Q40.2 28.45 42.85 23Q40.2 17.55 35.125 14.275Q30.05 11 24 11Q17.95 11 12.875 14.275Q7.8 17.55 5.1 23Q7.8 28.45 12.875 31.725Q17.95 35 24 35Z" /></svg>';
const toggleHide = '<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" viewBox="0 0 48 48"><path d="M31.45 27.05 29.25 24.85Q30.55 21.3 27.9 18.95Q25.25 16.6 22.15 17.75L19.95 15.55Q20.8 15 21.85 14.75Q22.9 14.5 24 14.5Q27.55 14.5 30.025 16.975Q32.5 19.45 32.5 23Q32.5 24.1 32.225 25.175Q31.95 26.25 31.45 27.05ZM37.9 33.5 35.9 31.5Q38.35 29.7 40.175 27.475Q42 25.25 42.85 23Q40.35 17.45 35.35 14.225Q30.35 11 24.5 11Q22.4 11 20.2 11.4Q18 11.8 16.75 12.35L14.45 10Q16.2 9.2 18.925 8.6Q21.65 8 24.25 8Q31.4 8 37.325 12.075Q43.25 16.15 46 23Q44.7 26.2 42.65 28.85Q40.6 31.5 37.9 33.5ZM40.8 44.8 32.4 36.55Q30.65 37.25 28.45 37.625Q26.25 38 24 38Q16.7 38 10.75 33.925Q4.8 29.85 2 23Q3 20.4 4.775 17.925Q6.55 15.45 9.1 13.2L2.8 6.9L4.9 4.75L42.75 42.6ZM11.15 15.3Q9.3 16.65 7.575 18.85Q5.85 21.05 5.1 23Q7.65 28.55 12.775 31.775Q17.9 35 24.4 35Q26.05 35 27.65 34.8Q29.25 34.6 30.05 34.2L26.85 31Q26.3 31.25 25.5 31.375Q24.7 31.5 24 31.5Q20.5 31.5 18 29.05Q15.5 26.6 15.5 23Q15.5 22.25 15.625 21.5Q15.75 20.75 16 20.15ZM26.4 22.4Q26.4 22.4 26.4 22.4Q26.4 22.4 26.4 22.4Q26.4 22.4 26.4 22.4Q26.4 22.4 26.4 22.4Q26.4 22.4 26.4 22.4Q26.4 22.4 26.4 22.4ZM20.6 25.3Q20.6 25.3 20.6 25.3Q20.6 25.3 20.6 25.3Q20.6 25.3 20.6 25.3Q20.6 25.3 20.6 25.3Q20.6 25.3 20.6 25.3Q20.6 25.3 20.6 25.3Z" /></svg>';
let passwordField = document.getElementById('edit-pass');
let passwordConfirm = document.getElementById('edit-pass-pass2');
if (passwordField.tagName === "DIV") {
const $passwordStrength = $('.password-strength');
if ($passwordStrength.length) {
//$passwordStrength.parent().after($passwordStrength);
}
const $passwordConfirm = $('.password-confirm-message');
if ($passwordConfirm.length) {
//$passwordConfirm.parent().after($passwordConfirm);
}
passwordField = document.getElementById('edit-pass-pass1');
}
if (typeof passwordField.type === "undefined" || passwordField.type === null) {
return;
}
$('input[type="password"]').wrap('<div class="password-input"></div>');
const $passwordToggleWrapper = Drupal.passwordShowHideToggle();
const $passwordInputParent = $('input[type="password"]')
.parent()
.append($passwordToggleWrapper);
const $passwordShowHideToggle = $passwordInputParent
.find('[data-drupal-selector="password-input-toggle"]');
$passwordShowHideToggle.html(toggleHide);
const showButton = document.querySelector("span.password-input-toggle");
$passwordShowHideToggle.on('click', function (event) {
if (passwordField.type === "password") {
passwordField.type = "text";
if (passwordConfirm) {
passwordConfirm.type = "text";
}
$passwordShowHideToggle.html(toggleShow);
}
else {
passwordField.type = "password";
if (passwordConfirm) {
passwordConfirm.type = "password";
}
$passwordShowHideToggle.html(toggleHide);
}
});
}
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.securePasswordGenerator = function () {
//if (once('edit-pass', '#edit-pass').length) {
const $passwordGenerateWrapper = Drupal.passwordGenerator();
const $passwordGenerateParent = $('#edit-pass')
.append($passwordGenerateWrapper);
const $passwordGenerateButton = $passwordGenerateParent
.find('[data-drupal-selector="password-update-button"]');
const $passwordClipboardButton = $passwordGenerateParent
.find('[data-drupal-selector="password-copy-button"]');
const $passwordClipboardStatus = $passwordGenerateParent
.find('[data-drupal-selector="password-clipboard-status"]');
const $passwordGenerateInput = $('#edit-pass-gen');
if ($passwordGenerateInput.length) {
$passwordGenerateButton.on('click', function (event) {
setTimeout(function () {
$('.animate__replay').trigger('click');
let securePassword = Drupal.generatePassword();
$passwordGenerateInput.val(securePassword);
}, 12);
event.preventDefault();
}).trigger('click');
$passwordClipboardButton.on('click', async function (event) {
// Navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText($passwordGenerateInput.text());
$passwordClipboardStatus.fadeIn('fast').delay(999).fadeOut('fast');
} catch (error) {
console.error('Failed to copy: ', error);
}
} else {
// Use the 'out of viewport hidden text area' trick.
const textArea = document.createElement("textarea");
textArea.value = $passwordGenerateInput.val();
// Move textarea out of the viewport, so it's not visible.
textArea.style.position = "absolute";
textArea.style.left = "-999999px";
document.body.prepend(textArea);
textArea.select();
try {
document.execCommand('copy');
$passwordClipboardStatus.fadeIn('fast').delay(999).fadeOut('fast');
} catch (error) {
console.error(error);
} finally {
textArea.remove();
}
}
event.preventDefault();
});
$passwordGenerateInput.on('focus', function (event) {
$passwordGenerateInput.select();
event.preventDefault();
});
}
//}
};
/**
* Provides detect caps lock is on and warning message.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.generatePassword = function () {
const string = 'abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#%&*-_+=^?';
let password = '';
let i = 0;
while (password.length < 12) {
// Returns a random integer from 0 to string.length
let num = Math.floor(Math.random() * string.length);
let char = string[num];
password += char;
let similar = password.replace(/(0|o|i|l|L|O|1|I)/g, '');
if (password.length !== similar.length) {
password = similar;
}
}
if (drupalSettings.password.showStrengthIndicator) {
// Evaluate the password strength.
let result = Drupal.evaluatePasswordStrength(
password,
drupalSettings.password,
);
if (result.strength !== 100) {
password = Drupal.generatePassword();
}
}
return password;
};
/**
* Constructs a password confirm message element.
*
* @param {object} passwordSettings
* An object containing password related settings and translated text to
* display.
* @param {string} passwordSettings.confirmTitle
* The translated confirm description that labels the actual confirm text.
*
* @return {string}
* Markup for the password confirm message.
*/
Drupal.passwordCapsLockWarning = () => {
const capslockTitle = Drupal.t('Caps Lock is');
const capslockWarningWrapper =
'<span data-drupal-selector="password-capslock-status-text"></span>';
return `<div aria-live="polite" aria-atomic="true" class="password-capslock-warning" data-drupal-selector="password-capslock-warning" style="display: none">${capslockTitle} ${capslockWarningWrapper}</div>`;
};
/**
* Constructs a password confirm message element.
*
* @param {object} passwordSettings
* An object containing password related settings and translated text to
* display.
* @param {string} passwordSettings.confirmTitle
* The translated confirm description that labels the actual confirm text.
*
* @return {string}
* Markup for the password confirm message.
*/
Drupal.passwordShowHideToggle = () => {
return `<span class="password-input-toggle" data-drupal-selector="password-input-toggle"></span>`;
};
/**
* Constructs a password confirm message element.
*
* @param {object} passwordSettings
* An object containing password related settings and translated text to
* display.
* @param {string} passwordSettings.confirmTitle
* The translated confirm description that labels the actual confirm text.
*
* @return {string}
* Markup for the password confirm message.
*/
Drupal.passwordGenerator = () => {
const passwordCopiedStatus = Drupal.t('Copied!');
const passwordGenerateLabel =
'<label for="edit-pass-gen" class="form-item__label">Generate secure password</label>';
const passwordGenerateInput =
'<input id="edit-pass-gen" name="pass-gen" type="text" class="password-generate js-password-generate form-text form-element form-element--type-password form-element--api-password" />';
const passwordGenerateButton =
'<a class="password-update-button btn update" data-drupal-selector="password-update-button"><svg t="1567045466457" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1598" width="40" height="40"><path d="M320.067666 286.437731c53.150524-53.15564 126.532835-86.077447 207.455889-86.077447 89.598644 0 172.483376 40.805358 227.39501 108.063181l-101.596909 101.603049 251.597225 0L904.918881 158.424172l-90.333378 90.361007C743.985562 166.207439 639.765919 116.493178 527.524578 116.493178c-104.055914 0-198.409862 42.322921-266.757506 110.670565-49.444109 49.455365-84.98865 112.251573-100.999298 182.862771l86.263689 0C260.052804 362.352725 285.750069 320.744072 320.067666 286.437731L320.067666 286.437731z" p-id="1599"></path><path d="M734.974327 701.344393c-53.151547 53.15564-126.533858 86.083587-207.450772 86.083587-89.599667 0-172.488493-40.810474-227.402173-108.069321l101.603049-101.596909L150.122089 577.76175 150.122089 829.358975l90.333378-90.333378c70.601988 82.555228 174.820608 132.270513 287.067065 132.270513 104.055914 0 198.402699-42.306548 266.750343-110.650099 49.360198-49.397037 84.866876-112.477724 100.920504-182.883237L808.689213 577.762773C794.560424 624.99654 768.983909 667.338904 734.974327 701.344393L734.974327 701.344393z" p-id="1600"></path></svg></a>';
const passwordCopyClipboardButton =
'<a class="password-copy-button btn copy" data-drupal-selector="password-copy-button"><svg t="1567050168595" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2397" width="40" height="40"><path d="M731.68184 676.057473 731.68184 183.323259c0-30.233582-24.512277-54.745858-54.747905-54.745858L184.216093 128.577401c-30.233582 0-54.746882 24.512277-54.746882 54.745858l0 492.734214c0 30.207999 24.5133 54.746882 54.746882 54.746882l492.717841 0C707.16854 730.804355 731.68184 706.265472 731.68184 676.057473zM622.1891 676.057473 238.962975 676.057473c-30.233582 0-54.746882-24.538883-54.746882-54.745858L184.216093 238.07014c0-30.233582 24.5133-54.746882 54.746882-54.746882l383.226125 0c30.233582 0 54.744835 24.512277 54.744835 54.746882l0 383.242498C676.933935 651.51859 652.421658 676.057473 622.1891 676.057473zM841.17458 292.817022l-54.745858 0 0 54.746882c30.232558 0 54.745858 24.5133 54.745858 54.759161l0 383.228171c0 30.206976-24.5133 54.745858-54.745858 54.745858L403.201573 840.297095c-30.233582 0-54.746882-24.538883-54.746882-54.745858l-54.746882 0 0 54.745858c0 30.207999 24.5133 54.747905 54.746882 54.747905l492.719888 0c30.234605 0 54.747905-24.539906 54.747905-54.747905L895.922485 347.563904C895.922485 317.329299 871.408161 292.817022 841.17458 292.817022z" p-id="2398"></path></svg></a>';
return `<div class="js-form-item form-item js-form-type-generate-password form-item-pass-gen js-form-item-pass-gen" data-drupal-selector="password-generate"> ${passwordGenerateLabel} <div class="password-generate-wrapper" data-drupal-selector="password-generate-wrapper"> ${passwordGenerateInput} ${passwordGenerateButton} ${passwordCopyClipboardButton} <span class="password-clipboard-status" data-drupal-selector="password-clipboard-status" style="display: none"> ${passwordCopiedStatus} </span></div></div>`;
};
})(jQuery, Drupal, drupalSettings, once);
