var CFSLogin = { options: { emailField: "#email", passwordField: "#password", gotoURL: "", gravDefault: "mm", allowRegistration: false, seed: "", magic: { set: false } }, data: { cachedAccounts: [], selectedAccount: null, urlAfterPasswordChange: "/", autoCountdownInterval: null }, passwordStengthResults: { 0: "OK", 1: "Error, not logged in.", 2: "Error, no connection", 3: "Error, no user", 10: "Not matched current", 11: "Choose a password you haven't used for this site before.", 12: "Choose a password you haven't used for this site before.", 13: "Use at least 1 uppercase letter.", 14: "Use at least 1 lowercase letter.", 15: "Use at least 1 number.", 16: "Use a symbol (!£$%^&*()-@#.).", 17: "Use at least 8 characters.", 18: "This password may have been compromised." }, init: function () { var self = this; $(self.options.emailField).keyup(function (event) { if (event.keyCode == 13) { self.testEmail(); } }); $(self.options.passwordField).keyup(function (event) { if (event.keyCode == 13) { self.login(); } }); $("#validate-ga-code").keyup(function (event) { if (event.keyCode == 13) { self.validate2FACode(); } }); var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1); if (c.indexOf("_cfs_px_accsn=") == 0) { var accs = c.substring(14, c.length); accs = accs.replace(/[^a-zA-Z0-9~|@•. ']-/g, ""); if (accs != "") { var savedAccounts = accs.split("||"); for (var x = 0; x < savedAccounts.length; x++) { var px = savedAccounts[x].split("~"); self.data.cachedAccounts.push({ account: px[0], type: px[1], email: px[2] }); } } } } self.displayHistory(); self.setupAutoCountDown(); if (self.options.magic.set === true) { $(".a-section").hide(); $(".magic-section").show(); $('body.login-page').addClass('magic-loading'); self.data.selectedAccount = { account: self.options.magic.code, type: "magic" }; // delay the login by 1s if using a magic link, to make sure that it is visible before the 2FA screen (otherwise it looks like a bug) setTimeout(() => self.login(), 1000); } // new login page input handling for removing error state on keypress if ($('.login-page.-auto').length > 0) { const inputs = $('input'); inputs.off('keydown.invalidMessage') inputs.on('keydown.invalidMessage', function () { $(this).removeClass('invalid'); const field = $(this).closest('.md-field-holder'); field.find('#strengthometer').removeClass('fail'); field.find('.invalid-message').text(''); }) } // enable new 6 box inputs this.splitInputHandling(); }, setupAutoCountDown: function () { var self = this; clearInterval(self.data.autoCountdownInterval); this.data.autoCountdownInterval = setInterval(function () { $(".auto-countdown").each(function () { var c = parseInt($(this).html().replace("seconds", "").replace("second", "").replace("in", "")) - 1; $(this).html("in " + c + (c == 1 ? " second" : " seconds")); if (c <= 0) { self.unlockField($(this).attr("data-field")); $(this).html("").removeClass("auto-countdown"); } }); }, 1000); }, passwordCodeRequest: function () { $(".a-section").hide(); $(".password-lost-section").show(); $(".reset-code-email").html(this.data.selectedAccount.email); $(".invalid").removeClass("invalid"); }, processPasswordCodeRequest: function () { var self = this; var email = self.data.selectedAccount.type == "id" ? self.data.selectedAccount.id : self.data.selectedAccount.account; var acc = this.data.selectedAccount.type + "|:" + email; self.showLoader(); Durell.CFS.Website.SecureLogin.SendPasswordResetCode(acc, function (rsp) { if (rsp.Success) { self.passwordCodeSent(); } else { self.showFeedback(rsp.ErrorDescription, true,false); self.hideLoader(); } }); }, passwordCodeSent: function () { var self = this; $(".a-section").hide(); $(".password-email-sent-section").show(); $("#validate-code").focus(); self.hideLoader(); }, validatePasswordCode: function () { var self = this; self.showLoader(); var code = ''; // new way if ($("#validate-code").is('.split-input-holder')) { $(`#validate-code > input`).each(function () { providedCode += $(this).val(); }) } // old way else code = $("#validate-code").val(); if (code == "") { self.showInvalidMessage($("#validate-code"), "Enter a code."); } else if (code.length != 6) { self.showInvalidMessage($("#validate-code"), "Wrong number of digits. Try again."); if ($("#validate-code").is('.split-input-holder')) $('#validate-code > input').val(''); } else { var email = self.data.selectedAccount.type == "id" ? self.data.selectedAccount.id : self.data.selectedAccount.account; var acc = this.data.selectedAccount.type + "|:" + email; Durell.CFS.Website.SecureLogin.ValidateVerificationCode(acc, code, function (rsp) { if (rsp.Success) { self.hideLoader(); // All good, go ahead and log the user in and ask them to choose a new password before going any further ... $(self.options.passwordField).val(code); self.login(); } else { self.showInvalidMessage($("#validate-code"), rsp.ErrorDescription, true); if (rsp.AdditionalInfo == "LockPassword") { self.lockField("#validate-code"); } } }); } }, preValidatePasswordStrengthOnboarding: function (passwordField) { var self = this; var pw = $(passwordField).val(); var level = 1; var showLevel = function (rspLevel, level) { $(".strength-ometer").removeClass("level-1").removeClass("level-2").removeClass("level-3").removeClass("level-4").addClass("level-" + level); if (level < 4) { $("#onboard-pass1").addClass("invalid"); //.focus(); $("#onboarding-change-pass footer a.main").addClass("disabled"); if (rspLevel != "") { $("#onboarding-change-pass footer p.invalid-message").html(self.passwordStengthResults[rspLevel]).show(); } } else { $(passwordField).removeClass("invalid"); $("#onboarding-change-pass footer a.main").removeClass("disabled"); $("#onboarding-change-pass footer p.invalid-message").hide(); } } if (pw == "" || pw.length <= 5) { showLevel("17", 1); } else { Durell.CFS.Website.SecureLogin.PreValidatePasswordStrength("", pw, function (rsp) { if (rsp.Success) { if (rsp.ResponseText == "0") level = 4; else if (parseInt(rsp.ResponseText) < 13) level = 2; else if (parseInt(rsp.ResponseText) <= 17) level = 3; showLevel(rsp.ResponseText, level); } }); } }, preValidatePasswordStrength: function (passwordField) { var self = this; var pw = $(passwordField).val(); Durell.CFS.Website.SecureLogin.PreValidatePasswordStrength($(self.options.passwordField).val(), pw, function (rsp) { if (rsp.Success) { if (self.passwordStengthResults[rsp.ResponseText] != "OK") { if ($('#strengthometer').is('.2026')) { $("#strengthometer").html("Weak

" + self.passwordStengthResults[rsp.ResponseText] + '

').addClass("fail"); } else $("#strengthometer").html("Weak
" + self.passwordStengthResults[rsp.ResponseText] + "
").addClass("fail"); $(passwordField).addClass("invalid"); //.focus(); $(".password-reset-section a.standard-button-style").addClass("disabled"); } else { $("#strengthometer").html("OK").removeClass("fail"); $(passwordField).removeClass("invalid"); $(".password-reset-section a.standard-button-style").removeClass("disabled"); } } }); }, updatePasswordAndLogin: function () { var self = this; var newPassword1 = $("#new-password"), newPasswordRepeat = $("#new-password-repeat"); if (onboarding) { newPassword1 = $("#onboard-pass1"); newPasswordRepeat = $("#onboard-pass2"); } if (newPassword1.hasClass("invalid")) return; if (newPassword1.val() != newPasswordRepeat.val()) { self.showInvalidMessage(newPasswordRepeat, "Passwords do not match."); newPasswordRepeat.focus(); return; } else { $(".password-reset-section a.standard-button-style").addClass("disabled"); newPassword1.attr("disabled", "disabled").addClass("disabled"); newPasswordRepeat.attr("disabled", "disabled").addClass("disabled").removeClass("invalid"); $("p.invalid-message").hide(); self.showLoader(); self.data.selectedAccount.changedPassword = newPassword1.val(); self.login(); } }, displayHistory: function (isReturn) { var self = this; if (self.data.cachedAccounts.length > 0) { $("#email-have-history").show(); $(".a-section").hide(); $(".history-section .accs").html(""); var idx = 0; $(self.data.cachedAccounts).each(function () { $(".history-section .accs").append("

" + this.account + "

"); idx++; }); $(".history-section").show(); } else { $("#email-have-history").hide(); if (isReturn === true) self.cancelPassword(); $(".a-section").hide(); $(".email-section").show(); } }, selectHistory: function (index) { var self = this; self.cancelPassword(); $(this.options.emailField).val(self.data.cachedAccounts[index].account); self.testEmail(); //self.data.selectedAccount = self.data.cachedAccounts[index]; //self.promptPassword(); }, removeHistory: function (index) { var self = this; self.data.cachedAccounts.splice(index, 1); self.displayHistory(); self.storeCacheInCookie(); }, allowPasswordEntry: function () { //AttemptsBlocked var self = this; Durell.CFS.Website.SecureLogin.AttemptsBlocked(function (rsp) { if (!rsp.Success) { self.showInvalidMessage($(self.options.passwordField), rsp.ErrorDescription, true); self.lockField(self.options.passwordField); } }); }, lockField: function (fld) { $(fld).attr("disabled", "disabled").addClass("disabled"); $(".standard-button-style.main").addClass("disabled"); this.setupAutoCountDown(); }, unlockField: function (fld) { $(fld).removeAttr("disabled").removeClass("disabled").removeClass("invalid").focus(); $(".standard-button-style.main").removeClass("disabled"); $("p.invalid-message").hide(); }, testEmail: function (em) { var self = this; self.showLoader(); var email = em ? em : $(this.options.emailField).val(); if (email == "") { self.showInvalidMessage($(self.options.emailField), "Enter an email or username."); } else { try { Durell.CFS.Website.SecureLogin.TestEmail(email, function (rsp) { if (!rsp.Success) { if (rsp.Message == null || rsp.Message == "") { self.showInvalidMessage($(self.options.emailField), "Invalid login details."); } else { if (rsp.StatusIndicator == "MultiAccount") { self.promptAccount(); self.data.selectedAccount = { account: email, type: "", email: "" }; } else { self.showInvalidMessage($(self.options.emailField), rsp.Message); } } } else { self.data.selectedAccount = { account: email, type: rsp.LoginType, email: rsp.AccountEmail }; self.promptPassword(); self.hideLoader(); } }, function (error) { console.error("Got error during login", error); if (error._statusCode == 403) { self.showInvalidMessage($(self.options.emailField), "Access to this login form has been restricted as you have made too many failed login attempts. Please try again later.

ID:" + CFSLogin.options.seed); } else { self.showInvalidMessage($(self.options.emailField), "Something went wrong, please try again."); } }); } catch (ex) { console.error("Got ex during login", ex); } } }, promptPasswordChange: function () { $("#new-password, #new-password-repeat").attr("disabled", false).removeClass("disabled").removeClass("invalid").val(""); $(".a-section").hide(); $(".password-reset-section").show(); this.hideLoader(); }, prompt2FA: function () { // make sure we disable the fancy magic loading state $('body.login-page.magic-loading').removeClass('magic-loading'); $('#validate-ga-code').val(""); $(".a-section").hide(); $(".two-factor-entry-ga").show(); this.hideLoader(); }, prompt2FASetup: function (imgUrl, setupCode, invalidAttempt) { // make sure we disable the fancy magic loading state $('body.login-page.magic-loading').removeClass('magic-loading'); var self = this; if (onboarding) { $("#onboarding-verify-email").hide(); $("#onboarding-setup-2fa").show(); console.warn("Need to setup onboarding 2FA code...", imgUrl, setupCode, invalidAttempt) } else { $("#img-2fa").attr("src", imgUrl); var setupCodeHTML = ""; for (var x = 0; x < setupCode.length; x++) { setupCodeHTML += setupCode[x] + ((x + 1) % 4 == 0 ? " " : ""); } $("#code-2fa").html(setupCodeHTML); $(".a-section").hide(); $(".two-factor-setup").show(); } if (invalidAttempt) { self.showInvalidMessage($("#validate-lp-setup-code"), "Invalid code. Try again.", true); } self.hideLoader(); }, validate2FACode: function (setup) { var self = this; var providedCode = ''; const inputId = "#" + setup === true ? "validate-lp-setup-code" : "validate-ga-code" // using new inputs if ($(inputId).is('.split-input-holder')) { $(`${inputId} > input`).each(function () { providedCode += $(this).val(); }) } // old way else providedCode = $("#" + (setup === true ? "validate-lp-setup-code" : "validate-ga-code")).val(); self.data.selectedAccount.secondFactor = providedCode; self.login(); }, promptAccount: function () { $('#validate-user-code').val(""); $(".a-section").hide(); $(".email-section-multi-account").show(); this.hideLoader(); }, promptPassword: function (fromAccount) { var self = this; if (fromAccount === true) { if ($('#validate-user-code').val() == "") { self.showInvalidMessage($("#validate-user-code"), "Enter a valid number."); return; } self.data.selectedAccount.type = "id"; self.data.selectedAccount.id = $('#validate-user-code').val(); self.data.selectedAccount.email = " the email address associated with your account."; } $("p.email").html("" + self.data.selectedAccount.account + ""); $("img.gravatar.main").attr("src", "//gravatar.com/avatar/" + hex_md5(self.data.selectedAccount.account) + "?default=" + self.options.gravDefault + "&s=100"); $(".a-section").hide(); $(".password-section").show(); $(self.options.passwordField).val("").focus(); $(".invalid").removeClass("invalid"); self.allowPasswordEntry(); $(".password-section .help").css("display", (self.data.selectedAccount.email == null || self.data.selectedAccount.email == "" ? "none" : "block")); }, cancelPassword: function () { $(this.options.emailField).val(""); $(this.options.passwordField).val(""); $(".a-section").hide(); $(".email-section").show(); $("img.gravatar.main").attr("src", "//gravatar.com/avatar/53444f91e698c0c7caa2dbc3bdbf93fc?default=mm&s=100"); $(this.options.emailField).focus(); //$("a, input").show(); }, onboardingPasswordSet: false, login: function () { var self = this; var f = $(self.options.passwordField); self.showLoader(); var email = self.data.selectedAccount.type == "id" ? self.data.selectedAccount.id : self.data.selectedAccount.account, password = f.val(); var verify = ""; if (email == "") email = $(self.options.emailField).val(); console.debug("Login with type ", self.data.selectedAccount.type); switch (self.data.selectedAccount.type) { case "google": email = self.data.selectedAccount.email; password = self.data.selectedAccount.name; verify = self.data.selectedAccount.googleVerify + "|" + self.data.selectedAccount.googleToken; break; case "magic": email = self.options.magic.code; password = self.options.magic.code; self.data.selectedAccount.passwordPreChange = self.options.magic.code; break; } if (!self.data.selectedAccount.changedPassword) self.data.selectedAccount.changedPassword = ""; if (self.data.selectedAccount.changedPassword != "") { if (self.data.selectedAccount.passwordPreChange != "") { password = self.data.selectedAccount.passwordPreChange; } } if (password == "" && self.data.selectedAccount.type != "magic") { self.showInvalidMessage(f, "Enter a password"); } else { var onboardingPassChange = function () { setTimeout(function () { $(".onboarding-setup aside ol.steppers").removeClass("activeStep-1").removeClass("activeStep-2").removeClass("activeStep-3").removeClass("activeStep-4").removeClass("activeStep-5").addClass("activeStep-3"); $("#onboarding-verify-email, #onboarding-setup-2fa, #onboarding-magic-failed").hide(); $("#onboarding-change-pass").show(); // make sure we disable the fancy magic loading state $('body.login-page.magic-loading').removeClass('magic-loading'); self.onboardingPasswordSet = true; }, 2000); } if (!self.data.selectedAccount.secondFactor) self.data.selectedAccount.secondFactor = ""; Durell.CFS.Website.SecureLogin.AttemptLoginNew(self.data.selectedAccount.type + "|:" + email, password, verify, self.options.gotoURL, "00/00/0000", self.data.selectedAccount.secondFactor, self.data.selectedAccount.changedPassword, function (response) { if (!response.Success) { if (response.StatusIndicator == null) response.StatusIndicator = ""; if (response.StatusIndicator == "Request2Factor") { self.prompt2FA(); } else if (response.StatusIndicator == "Failed2Factor") { self.prompt2FA(); self.showInvalidMessage($("#validate-ga-code"), "Invalid code. Try again.", true); if ($("#validate-ga-code").is('.split-input-holder')) $('#validate-code > input').val(''); } else if (response.StatusIndicator == "Request2FASetup") { if (onboarding) { if (self.onboardingPasswordSet === true) { location.href = "/Portal/Login.aspx?magic=" + self.options.magic.code; } else { onboardingPassChange(); } } else { var prts = response.Message.split("||"); self.prompt2FASetup(prts[0], prts[1], prts[2] == "True"); } } else if (response.StatusIndicator == "PassChangeOnboarding" && $(".onboarding-setup").length > 0) { onboardingPassChange(); } else if (response.StatusIndicator == "PassChangeInitial" || response.StatusIndicator == "PassChangeOnboarding") { $("#change-password-reason").html("Please choose your own password to continue, include numbers, symbols and a mix of letters for extra security."); self.data.selectedAccount.passwordPreChange = password; self.promptPasswordChange(); } else if (response.StatusIndicator == "PassChangeInsecure") { $("#change-password-reason").html("Your password is not secure enough and must be changed."); self.data.selectedAccount.passwordPreChange = password; self.promptPasswordChange(); } else if (response.StatusIndicator == "PassChangeExpired") { $("#change-password-reason").html("Your password has expired and must be changed."); self.data.selectedAccount.passwordPreChange = password; self.promptPasswordChange(); } else if (response.StatusIndicator == "PassChangeInsecureChange") { $("#change-password-reason").html("Sorry you can't use that password, please enter a new one."); self.data.selectedAccount.passwordPreChange = password; self.promptPasswordChange(); } else if (self.data.selectedAccount.type == "magic") { if (onboarding) { $("#onboarding-verify-email, #onboarding-setup-2fa, #onboarding-change-pass").hide(); $("#onboarding-magic-failed").show().find("p").html(response.Message); if (response.StatusIndicator == "MagicCanResend") { $("#onboard-link-email").val(response.AccountEmail + ""); $("#onboarding-magic-failed footer").show(); } } else { // login 2026 specific if ($(".magic-loader").length > 0) { $('.a-section').hide(); $('.email-section').show(); $('body.magic-loading').removeClass('magic-loading'); self.showInvalidMessage($("#email"), response.Message, true); } else { $(".magic-section").addClass("magic-failed"); $(".magic-section > p").html(response.Message); } $(".load-bar").hide(); } } else { self.showInvalidMessage(f, response.Message, true); if (response.StatusIndicator == "LockPassword") { self.lockField(self.options.passwordField); } if (!document.getElementById("toast")) { $("body").append("
 
"); } $("#toast").html(response.Message).fadeIn().addClass("error"); setTimeout(function () { $("#toast").fadeOut(); }, 10000); if (googleAuth === "True") { gapi.auth2.getAuthInstance().signOut(); } //durell.cfs.showFeedback(response.ErrorDescription, true, false); } } else { if (self.data.selectedAccount.type != "google" && self.data.selectedAccount.type != "magic" && $('#remember-email').attr("checked")) { /* Make sure we haven't already remembered the email */ var alreadyStored = false; $(self.data.cachedAccounts).each(function () { if (this.account == self.data.selectedAccount.account) { alreadyStored = true; } }); if (!alreadyStored) { /* Add the clicked item to the top of the history array */ self.data.cachedAccounts.splice(0, 0, self.data.selectedAccount); } self.storeCacheInCookie(); } if (response.Message.indexOf("=") > -1 && (response.Message + "").split("=")[0] == "/ChangePassword.aspx?URL") { console.info("Prompt initial password change for verification code usage."); self.hideLoader(); $(".a-section").hide(); $(".password-reset-section").show(); // make sure we disable the fancy magic loading state $('body.login-page.magic-loading').removeClass('magic-loading'); } else { location.href = response.Message; } } }, function (error) { if (error._statusCode == 403) { self.showInvalidMessage(f, "Access to this login form has been restricted as you have made too many failed login attempts. Please try again later.

ID:" + CFSLogin.options.seed); } else { self.showInvalidMessage(f, "Something went wrong, please try again."); } }); } }, storeCacheInCookie: function () { var self = this; /* Limit the number of items in the history to 5 */ if (self.data.cachedAccounts.length > 5) self.data.cachedAccounts.length = 5; var accs = ""; $(self.data.cachedAccounts).each(function () { accs += this.account + "~" + this.type + "~" + this.email + "||"; }); if (accs != "") accs = accs.substr(0, accs.length - 2); var exdate = new Date(); exdate.setDate(exdate.getDate() + 7); document.cookie = "_cfs_px_accsn=" + accs + "; expires=" + exdate.toUTCString(); }, showInvalidMessage: function (field, message, noDelay) { mdDialogCloseBox(); console.warn(message); field.addClass("invalid"); if (field.parent().find(".invalid-message").length > 0) { $(".invalid-message", field.parent()).html(message).show(); } else { field.parent().append("

" + message + "

"); } field.next().show(); this.hideLoader(noDelay === true ? 0 : 300); }, showLoader: function () { $(".standard-button-style:not(.disabled)").addClass("loading").addClass("disabled"); $(".login-box .load-bar").show(); }, hideLoader: function (delay) { if (!delay || delay == 0) { $(".standard-button-style.disabled.loading").removeClass("loading").removeClass("disabled"); $(".login-box .load-bar").fadeOut(); } else { setTimeout(function () { $(".standard-button-style.disabled.loading").removeClass("loading").removeClass("disabled"); $(".login-box .load-bar").fadeOut(); }, delay) } }, // enable custom input handling for the new 6-box 2FA screen splitInputHandling: function () { var fields = $('.split-input-holder'); // doing this as a loop to avoid having to have the query to find the relevant input group on each keypress fields.each(function () { var inputs = $(this).find('> input'); const submitOnComplete = () => { var allInputsFilled = true; $(inputs).each(function () { if ($(this).val() === '') return allInputsFilled = false; }) if (allInputsFilled === true) CFSLogin.validate2FACode(); } // this is async because we are reading from the clipboard which needs to be async according to the mozilla docs inputs.off('keydown.login'); inputs.on('keydown.login', function (e) { // add keys to this array to keep their default behaviour if (['Tab', 'Escape'].includes(e.key) || (e.key === 'v' && e.ctrlKey)) return; // prevent default so that we can just do our own thing e.preventDefault(); // handle moving to the next input when number is entered if (/^[0-9]+$/.test(e.key)) { $(this).val(e.key); // auto submit form when last input is filled if ($(this).is(inputs.last())) $(this).blur(); else $(this).next().focus(); submitOnComplete(); } // not 100% sure on the UX of this but we shall see if (e.key === 'Backspace') { $(this).val(''); if (!$(this).is(inputs.first())) $(this).prev().focus(); } if (e.key === 'ArrowLeft') $(this).prev().focus(); if (e.key === 'ArrowRight') $(this).next().focus(); // submit when enter is pressed if (e.key === 'Enter') { CFSLogin.validate2FACode(); } }) inputs.off('paste.login'); inputs.on('paste.login', async function (e) { try { var clipboard = await navigator.clipboard.readText(); } catch (err) { console.warn("Can't paste from clipboard: " + err); inputs.blur(); return; } // get only the correct amount of numeric characters from the clipboard string var code = clipboard.replace(/\D/g, "").slice(0, inputs.length); var startIndex = $(this).index(); inputs.each(function (i) { var thisIndex = i + startIndex; if (thisIndex > inputs.length) return; inputs.eq(thisIndex).val(code[i]); }) inputs.blur(); submitOnComplete(); }) inputs.off('focus.login'); inputs.on('focus.login', function (e) { // make sure that the first empty field is always the first one selected, to function similar to a regular input field if ($(this).val() === '' && $(this).prev().val() === '' && $(this).index() !== 0) { $(this).prev().focus(); } else $(this).select(); }) }) }, showPassword: function (f) { var input = f.closest('.md-input-holder').find('> input').first(); if (input.length === 0) return; var type = input.attr('type'); if (type === 'password') { input.attr('type', 'text'); f.addClass('mdi-eye-off'); f.removeClass('mdi-eye'); } else { input.attr('type', 'password'); f.addClass('mdi-eye'); f.removeClass('mdi-eye-off'); } }, showFeedback: function (message, isError, noHide, buttons = [], duration = null, isMD3 = false) { let toast = document.getElementById("toast") if (!toast) { $("body").append("
 
"); toast = document.getElementById("toast") } let html = message if (Array.isArray(buttons) && buttons.length > 0) { html += "" buttons.forEach((button) => { html += `${button.text}` }) html += "" } $("#toast").removeClass("error").removeClass('clickable').removeClass('md3').html(html).fadeIn(); const lastTimeoutId = toast.getAttribute('data-toast-timeout-id') if (lastTimeoutId) clearTimeout(lastTimeoutId) var durationSecs = duration || 3; if (isError === "soft") { $("#toast").addClass("soft-error"); durationSecs = 10; } if (isError === true) { $("#toast").addClass("error"); durationSecs = 10; } if (Array.isArray(buttons) && buttons.length > 0) $("#toast").addClass("clickable"); if (noHide !== true) { const timeoutId = setTimeout("CFSLogin.hideToast()", durationSecs * 1000); toast.setAttribute('data-toast-timeout-id', timeoutId) } if (isMD3) $("#toast").addClass("md3"); }, hideToast: function () { $("#toast").fadeOut(); const toast = document.getElementById('toast') if (toast) toast.setAttribute('data-toast-timeout-id', '') } };