(function () { const userLanguage = navigator.language.substr(0, 2); const submitBtn = $("#check-access"); const allowAccessBtn = $("#allowAccess"); const requestAccessBtn = $("#requestAccess"); const requestAccessExtension = $("#requestAccess-extension"); submitBtn.attr('disabled', true); let isPageScanEnabled; let isUncategorized; let psApiTimeInterval; let pageScanRequestComplete = false; let tooltipInstance; const translationKeys = { en: { "Allow access": "Allow access", "Request access": "Request access", "allowed": "allowed", "blocked": "blocked", "keyword" : "keyword", "Access allowed": "Access allowed", "mins": "mins", "Request sent": "Request sent", "Checking...": "Checking...", "Check access": "Check access", "Checking access": "Checking access", "Please wait": "Please wait", "This website may be blocked for browser extension users.": "This website may be blocked for browser extension users.", "This website may be blocked for SmartPAC and browser extension users.": "This website may be blocked for SmartPAC and browser extension users.", "This website may be blocked for SmartPAC users.": "This website may be blocked for SmartPAC users.", "Users will be allowed to access the site for only": "Users will be allowed to access the site for only", "Your request for access was accepted": "Your request for access was accepted", "It may take some time to process your request. Check back later.": "It may take some time to process your request. Check back later." }, es: { "Allow access": "Permitir el acceso", "Request access": "Solicitar acceso", "allowed": "Permitido", "blocked": "Bloqueado", "keyword" : "Palabra clave", "Access allowed": "Acceso permitido", "mins": "minutos", "Request sent": "Solicitud enviada", "Checking...": "Verificando...", "Check access": "Verificar acceso", "Checking access": "Verificando acceso", "Please wait": "Por favor espere", "This website may be blocked for browser extension users.": "Este sitio web puede estar bloqueado para los usuarios de extensiones de navegador.", "This website may be blocked for SmartPAC and browser extension users.": "Este sitio web puede estar bloqueado para los usuarios de SmartPAC y de extensiones de navegador.", "This website may be blocked for SmartPAC users.": "Este sitio web puede estar bloqueado para los usuarios de SmartPAC.", "Users will be allowed to access the site for only": "Los usuarios podrán acceder al sitio solo por", "Your request for access was accepted": "Su solicitud de acceso fue aceptada", "It may take some time to process your request. Check back later.": "Puede tomar algún tiempo procesar su solicitud. Vuelva a verificar más tarde." }, fr: { "Allow access": "Autoriser l'accès", "Request access": "Demander l'accès", "allowed": "Autorisé", "blocked": "Bloqué", "keyword" : "Mot-clé", "Access allowed": "Accès autorisé", "mins": "minutes", "Request sent": "Demande envoyée", "Checking...": "Vérification...", "Check access": "Vérifier l'accès", "Checking access": "Vérification de l'accès", "Please wait": "Veuillez patienter", "This website may be blocked for browser extension users.": "Ce site web peut être bloqué pour les utilisateurs d'extensions de navigateur.", "This website may be blocked for SmartPAC and browser extension users.": "Ce site web peut être bloqué pour les utilisateurs de SmartPAC et d'extensions de navigateur.", "This website may be blocked for SmartPAC users.": "Ce site peut être bloqué pour les utilisateurs de SmartPAC.", "Users will be allowed to access the site for only": "Les utilisateurs pourront accéder au site uniquement pendant", "Your request for access was accepted": "Votre demande d'accès a été acceptée", "It may take some time to process your request. Check back later.": "Il peut falloir un certain temps pour traiter votre demande. Revenez plus tard." } }; const allCategories = [ {caption: 'Drugs', id: 'Drugs'}, {caption: 'Educational', id: 'Educational'}, {caption: 'Gambling', id: 'Gambling'}, {caption: 'Games', id: 'Games'}, {caption: 'Health', id: 'Health'}, {caption: 'Hate', id: 'Idealogies'}, {caption: 'Chat/Messaging', id: 'Messaging'}, {caption: 'Network misuse', id: 'Network Misuse'}, {caption: 'Social networking', id: 'Networking'}, {caption: 'Other adult content', id: 'Other Adult'}, {caption: 'Other search engines', id: 'Other Search'}, {caption: 'Pornography', id: 'Pornography'}, {caption: 'Social media', id: 'Social Media'}, {caption: 'Streaming Media', id: 'Streaming Media'}, {caption: 'Web mail', id: 'Web Mail'} ]; let usingKeyboard = false; // Store event handler references for cleanup const handleKeydown = (e) => { usingKeyboard = true; }; const handleMousedown = () => { usingKeyboard = false; }; const handleFocusin = (e) => { if (usingKeyboard && e.target.tagName === 'INPUT') { e.target.classList.add('keyboard-focused'); } }; const handleFocusout = (e) => { if (e.target.tagName === 'INPUT') { e.target.classList.remove('keyboard-focused'); } }; // Add event listeners with named functions document.addEventListener('keydown', handleKeydown); document.addEventListener('mousedown', handleMousedown); document.addEventListener('focusin', handleFocusin); document.addEventListener('focusout', handleFocusout); function validateFields() { $("#lookup-error").text(''); $("#lookup-domain-error").text(''); const domain = $("#domain").val(); const userEmail = $("#email").val(); const domainREGEX = new RegExp(/^(((http|https|ftp):\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,63}(:[0-9]{1,5})?(\/[^\s]*)?(\?[^\s]*)?(#[^\s]*)?)$/); const emailREGEX = new RegExp(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/); if (domain && domain !== "" && userEmail && userEmail !== "") { if (domainREGEX.test(domain) && emailREGEX.test(userEmail)) { submitBtn.attr('disabled', false); } else { submitBtn.attr('disabled', true); } } return; } $("#accessForm input").keyup(function () { validateFields(); pageReset(); }); submitBtn.click(function (event) { checkAccess(); event.preventDefault(); }); allowAccessBtn.click(function (event) { allowAccess(); event.preventDefault(); }); requestAccessExtension.click(function (event) { const checkingText = getTranslationKeys("Checking..."); setButtonLoading(requestAccessExtension, checkingText); $("#pageScan-spinner").removeClass("hide"); requestAccessPageScan(); event.preventDefault(); }); requestAccessBtn.click(function (event) { if(isPageScanEnabled && isUncategorized){ const checkingText = getTranslationKeys("Checking..."); setButtonLoading(requestAccessBtn, checkingText); $("#pageScan-spinner").removeClass("hide"); requestAccessPageScan(); } else { requestAccess(); } event.preventDefault(); }); /** * Cleanup function to remove all event listeners * Call this when the page is unloaded or when you need to clean up */ function cleanupEventListeners() { // Remove native DOM event listeners document.removeEventListener('keydown', handleKeydown); document.removeEventListener('mousedown', handleMousedown); document.removeEventListener('focusin', handleFocusin); document.removeEventListener('focusout', handleFocusout); } window.addEventListener('beforeunload', cleanupEventListeners); function pageReset() { $("#lookup-results").addClass("hide"); $("#isSchoolIP").addClass("hide"); $("#result-note").addClass("hide"); $("#allow-access").addClass("hide"); $("#request-access").addClass("hide"); $("#result-note").addClass("hide"); $("#request-access-note").addClass("hide"); $("#ttl-note").addClass("hide"); $('#blocked-on-ext-note').addClass('hide'); $('#blocked-on-ext-uncategorised').addClass('hide'); $("#blocked-on-ext-uncategorised").parent().addClass("hide"); $("#cg-enabled").addClass("hide"); $("#cg-enabled").parent().addClass("hide"); $("#pageScan-check-later").addClass("hide"); $("#pageScan-success").addClass("hide"); allowAccessBtn.attr('disabled', false); requestAccessBtn.attr('disabled', false); requestAccessExtension.attr('disabled', false); allowAccessBtn.text(getTranslationKeys("Allow access")); requestAccessBtn.text(getTranslationKeys("Request access")); requestAccessExtension.text(getTranslationKeys("Request access")); } function getBlockedMessage(blockedOnExtOnly, blockedOnSpacOnly) { if (blockedOnExtOnly && blockedOnSpacOnly) { return "This website may be blocked for SmartPAC and browser extension users."; } else if (blockedOnExtOnly) { return "This website may be blocked for browser extension users."; } else if (blockedOnSpacOnly) { return "This website may be blocked for SmartPAC users."; } else { return "This website may be blocked for browser extension users."; } } function updateStatus(status, isKeyword = false) { $("#status").removeClass('allowed blocked'); $("#status-mark").removeClass('ss-check ss-ban'); $("#status-content").removeClass('red green'); if (status == 'allowed') { $("#status").addClass('allowed'); $("#status-mark").addClass('ss-check'); $("#status-content").addClass('green'); } else { $("#status").addClass('blocked'); $("#status-mark").addClass('ss-ban'); $("#status-content").addClass('red'); } displaytext = getTranslationKeys(status); if(isKeyword) { displaytext = displaytext + " (" + getTranslationKeys('keyword')+ ")"; } const displayText = getTranslationKeys(displaytext); $("#status-content").text(displayText); return displayText; } function updateCategory(categories, blockedOnExtOnly, blockedOnSpacOnly) { let categoryText = "-"; if(tooltipInstance) { tooltipInstance.destroy(); } if((blockedOnExtOnly || blockedOnSpacOnly) && !isUncategorized && !isPageScanEnabled) { const blockedMessage = getBlockedMessage(blockedOnExtOnly, blockedOnSpacOnly); $('#extn-blocked-message').text(getTranslationKeys(blockedMessage)); $('#blocked-on-ext-note').removeClass('hide'); $("#blocked-on-ext-note").parent().removeClass("hide"); } $("#category-info").text(""); if (categories && categories.length) { if (categories.length == 1 && categories[0]?.toUpperCase() == 'CANNOT_CATEGORIZE') { $("#category-info").text("-"); categoryText = "Uncategorized"; } else { let categoryInfo = []; for (let i = 0; i < categories.length; i++) { categoryInfo.push(getCategoryDisplayName(categories[i])); } const category = categoryInfo.toString(); categoryText = category; if(category === 'Popular sites') { const tooltipText = 'These domains are typically frequented for general information purposes.They do not function as CDN sites and may be proxied as needed.Example of Popular sites: cnn.com, msn.com'; $("#category-info").html(`${categoryInfo.toString()} `); tooltipInstance = window.createTooltip(document.getElementById('infoIcon'), tooltipText); } else { $("#category-info").text(category); } } } else { $("#category-info").text("-"); categoryText = "Uncategorized"; } return categoryText; } function announceToScreenReader(message, isUrgent = false) { // Announce message to screen readers using the dedicated live region // This element is always in the DOM (not hidden), so screen readers will monitor it const announcementEl = document.getElementById('results-announcement'); if (announcementEl) { // Update aria-live based on urgency announcementEl.setAttribute('aria-live', isUrgent ? 'assertive' : 'polite'); // Clear first to ensure announcement triggers on next change announcementEl.textContent = ''; // Set new content after a brief delay to ensure screen readers detect the change setTimeout(function() { announcementEl.textContent = message; }, 100); } } function announceResults(statusText, categoryText) { // Announce results to screen readers const announcement = "Lookup Results. Status: " + statusText + ". Category: " + categoryText + "."; announceToScreenReader(announcement, false); } /** * Announce error message to screen readers * @param {string} errorMessage - The error message to announce * @param {boolean} isUrgent - Whether the error is urgent (default: true) */ function announceError(errorMessage, isUrgent = true) { announceToScreenReader("Error: " + errorMessage, isUrgent); } /** * Set button to loading state * @param {jQuery} $button - jQuery button element * @param {string} loadingText - Text to show while loading * @returns {string} Original button text for restoration */ function setButtonLoading($button, loadingText) { const originalText = $button.text(); $button.attr('disabled', true); $button.attr('aria-busy', 'true'); $button.text(loadingText); $button.attr('aria-label', loadingText); return originalText; } /** * Restore button from loading state * @param {jQuery} $button - jQuery button element * @param {string} originalText - Original button text to restore * @param {boolean} keepDisabled - Whether to keep button disabled (default: false) */ function restoreButton($button, originalText, keepDisabled = false) { $button.attr('disabled', keepDisabled); $button.attr('aria-busy', 'false'); $button.text(originalText); $button.attr('aria-label', originalText); } /** * Restore PageScan button states (both requestAccessExtension and requestAccessBtn) * @param {string} buttonText - Text to set on buttons (default: "Request access") * @param {boolean} keepRequestAccessBtnDisabled - Whether to keep requestAccessBtn disabled (default: false) */ function restorePageScanButtons(buttonText = null, keepRequestAccessBtnDisabled = false) { const text = buttonText || getTranslationKeys("Request access"); // Restore requestAccessExtension button requestAccessExtension.attr('disabled', false); requestAccessExtension.attr('aria-busy', 'false'); requestAccessExtension.text(text); requestAccessExtension.attr('aria-label', text); // Restore requestAccessBtn button requestAccessBtn.attr('disabled', keepRequestAccessBtnDisabled); requestAccessBtn.attr('aria-busy', 'false'); requestAccessBtn.text(text); requestAccessBtn.attr('aria-label', text); } // To map category name with ID function getCategoryDisplayName(categoryId) { const categoryInfo = allCategories.filter(category => category.id === categoryId); return categoryInfo && categoryInfo.length ? categoryInfo[0].caption : categoryId; } function updateCGAccess(customGroupApplied) { $("#cg-enabled").addClass("hide"); if (customGroupApplied) { $("#cg-enabled").removeClass("hide"); $("#cg-enabled").parent().removeClass("hide"); } else $("#cg-enabled").addClass("hide"); } function updateRequestAcess(lookupAccess) { $("#isSchoolIP").addClass("hide"); $("#result-note").addClass("hide"); // Request Access button based on API Response $("#allow-access").addClass("hide"); $("#request-access").addClass("hide"); $("#result-note").addClass("hide"); $("#request-access-note").addClass("hide"); if (lookupAccess && (lookupAccess.customGroupApplied || !lookupAccess.isSchoolIP)) $("#result-note").removeClass("hide"); if (lookupAccess && !lookupAccess.isSchoolIP) { //If IP not from school $("#isSchoolIP").removeClass("hide"); return; } if (lookupAccess && lookupAccess.status == "blocked" && lookupAccess.canAllowAccess) $("#allow-access").removeClass("hide"); else if (lookupAccess && lookupAccess.status == "blocked" && !lookupAccess.canAllowAccess) { $("#request-access").removeClass("hide"); $("#result-note").removeClass("hide"); if(!lookupAccess.isPageScanEnabled && !lookupAccess.isUncategorized) { $("#request-access-note").removeClass("hide"); } }//uncategorised and allowed but blocked on extension and pagescan is enabled else if (lookupAccess.status == "allowed" && lookupAccess.isUncategorized && (lookupAccess.blockedOnExtOnly || lookupAccess.blockedOnSpacOnly)) { const blockedMessage = getBlockedMessage(lookupAccess.blockedOnExtOnly, lookupAccess.blockedOnSpacOnly); $('#extn-blocked-message').text(getTranslationKeys(blockedMessage)); $('#blocked-on-ext-note').removeClass('hide'); $("#blocked-on-ext-note").parent().removeClass("hide"); if(lookupAccess.isPageScanEnabled) { $('#extn-blocked-message-ps').text(getTranslationKeys(blockedMessage)); $('#blocked-on-ext-uncategorised').removeClass('hide'); $("#blocked-on-ext-uncategorised").parent().removeClass("hide"); $('#blocked-on-ext-note').addClass('hide'); $("#blocked-on-ext-note").parent().addClass("hide"); } } } function getTranslationKeys(key) { const convertedKey = translationKeys[userLanguage][key]; return convertedKey ? convertedKey : key; } function checkAccess() { // Announce that request is being processed const domain = $("#domain").val(); const email = $("#email").val(); const checkingMsg = getTranslationKeys("Checking access") + " " + getTranslationKeys("Please wait") + "."; announceToScreenReader(checkingMsg, false); // Set button to loading state const checkingText = getTranslationKeys("Checking..."); const originalButtonText = setButtonLoading(submitBtn, checkingText); $.ajax({ url: "/lookup-tool/status", type: "get", data: { domain: encodeURIComponent(domain), email: email }, success: function (response) { //Do Something if (response && response.type == "success") { // Remove hide class FIRST to make the live region visible $("#lookup-results").removeClass("hide"); restoreButton(submitBtn, originalButtonText, true); isPageScanEnabled = response.isPageScanEnabled; isUncategorized = response.isUncategorized; // Update status and category, get text for announcement const statusText = updateStatus(response.status, response.isKeyword); const categoryText = updateCategory(response.categories, response.blockedOnExtOnly, response.blockedOnSpacOnly); // Announce results after DOM updates setTimeout(function() { announceResults(statusText, categoryText); }, 100); updateCGAccess(response.customGroupApplied); updateRequestAcess(response); // need to success call } else if (response && response.type == "error") { restoreButton(submitBtn, originalButtonText); if (response.errorCode == 'INVALID_DOMAIN') { $("#lookup-domain-error").text(response.errorMessage); $("#domain").focus(); } else { $("#lookup-error").text(response.errorMessage); $("#email").focus(); } } }, error: function (error) { //Do Something to handle error console.log("Error occured", error); restoreButton(submitBtn, originalButtonText); const errorMsg = "An error occurred while checking access. Please try again."; announceError(errorMsg); $("#lookup-error").text(errorMsg); submitBtn.focus(); } }); } function allowAccess() { // Announce that access is being allowed const allowingMsg = getTranslationKeys("Allow access") + ". " + getTranslationKeys("Please wait") + "."; announceToScreenReader(allowingMsg, false); const checkingText = getTranslationKeys("Checking..."); const originalButtonText = setButtonLoading(allowAccessBtn, checkingText); $.ajax({ url: "/lookup-tool/allowAccess", type: "post", data: { domain: $("#domain").val(), email: $("#email").val() }, success: function (response) { //Do Something $("#ttl-note").addClass("hide"); console.log("Allow Access response came", response); if (response && response.type == "success") { const accessAllowedText = getTranslationKeys("Access allowed"); restoreButton(allowAccessBtn, accessAllowedText, true); let announcement = accessAllowedText; if (response.accessTime != false) { $("#ttl-note").removeClass("hide"); $("#ttl").text(response.accessTime + " " + getTranslationKeys("mins")); announcement += ". " + getTranslationKeys("Users will be allowed to access the site for only") + " " + response.accessTime + " " + getTranslationKeys("mins") + "."; } else { $("#ttl-note").addClass("hide"); } announceToScreenReader(announcement, false); } else if (response && response.type == "error") { restoreButton(allowAccessBtn, originalButtonText); const errorMsg = response.errorMessage || "An error occurred while allowing access. Please try again."; announceError(errorMsg); } }, error: function (error) { //Do Something to handle error console.log("Allow Access Error occured", error); restoreButton(allowAccessBtn, originalButtonText); const errorMsg = "An error occurred while allowing access. Please try again."; announceError(errorMsg); } }); } function requestAccess() { // Announce that request is being sent const requestingMsg = getTranslationKeys("Request access") + ". " + getTranslationKeys("Please wait") + "."; announceToScreenReader(requestingMsg, false); const checkingText = getTranslationKeys("Checking..."); const originalButtonText = setButtonLoading(requestAccessBtn, checkingText); $.ajax({ url: "/lookup-tool/requestAccess", type: "post", data: { domain: $("#domain").val(), email: $("#email").val() }, success: function (response) { //Do Something console.log("Request Access response came", response); if (response && response.type == "success") { const requestSentText = getTranslationKeys("Request sent"); restoreButton(requestAccessBtn, requestSentText, true); announceToScreenReader(requestSentText, false); } else if (response && response.type == "error") { restoreButton(requestAccessBtn, originalButtonText); const errorMsg = response.errorMessage || "An error occurred while requesting access. Please try again."; announceError(errorMsg); } }, error: function (error) { //Do Something to handle error console.log("Request Access Error occured", error); restoreButton(requestAccessBtn, originalButtonText); const errorMsg = "An error occurred while requesting access. Please try again."; announceError(errorMsg); } }); } function requestAccessPageScan(){ // Announce that PageScan request is being initiated const requestingMsg = getTranslationKeys("Request access") + ". " + "Processing PageScan analysis, " + getTranslationKeys("Please wait") + "."; announceToScreenReader(requestingMsg, false); pageScanRequestComplete = false; let params={}; params['domain']= $("#domain").val(); params['requester'] = $("#email").val(); $.get( "/app/api/sendps",params) .done(function( data ) { }) .fail(function (err) { const errorMsg = "An error occurred while initiating PageScan request. Please try again."; announceError(errorMsg); }); //We will call checkAccessPageScan 6 times with interval for 5 seconds each pagescanInterval = setIntervalX(checkAccessPageScan, 5000, 6); } function checkAccessPageScan() { $.ajax({ url: "/lookup-tool/status", type: "get", data: { domain: $("#domain").val(), email: $("#email").val() }, success: function (response) { //Category is successfully changed by pagescan if (response && response.type == "success" && !response.isUncategorized) { isPageScanEnabled = response.isPageScanEnabled; isUncategorized = response.isUncategorized; clearInterval(psApiTimeInterval); const statusText = updateStatus(response.status, response.isKeyword); const categoryText = updateCategory(response.categories, response.blockedOnExtOnly, response.blockedOnSpacOnly); updateRequestAcess(response); $("#pageScan-spinner").addClass("hide"); if(response.status == "allowed") { $("#pageScan-success").removeClass("hide"); const requestSentText = getTranslationKeys("Request sent"); restorePageScanButtons(requestSentText, true); const successMsg = getTranslationKeys("Your request for access was accepted") + ". " + "Status: " + statusText + ". Category: " + categoryText + "."; announceToScreenReader(successMsg, false); } else { restorePageScanButtons(); const updateMsg = "PageScan analysis complete. Status: " + statusText + ". Category: " + categoryText + "."; announceToScreenReader(updateMsg, false); } $('#blocked-on-ext-uncategorised').addClass('hide'); $("#blocked-on-ext-uncategorised").parent().addClass("hide"); return; } //category is still not changed after 6 api calls - show check later message if(pageScanRequestComplete){ $("#pageScan-spinner").addClass("hide"); $("#pageScan-check-later").removeClass("hide"); $('#blocked-on-ext-uncategorised').addClass('hide'); $("#blocked-on-ext-uncategorised").parent().addClass("hide"); restorePageScanButtons(); const laterMsg = getTranslationKeys("It may take some time to process your request. Check back later."); announceToScreenReader(laterMsg, false); return; } if (response && response.type == "error") { if (response.errorCode == 'INVALID_DOMAIN') { $("#lookup-domain-error").text(response.errorMessage); } else { $("#lookup-error").text(response.errorMessage); } } }, error: function (error) { console.log("Error occured", error); restorePageScanButtons(); const errorMsg = "An error occurred while checking PageScan status. Please try again."; announceError(errorMsg); } }); } function setIntervalX(callback, delay, repetitions) { let x = 0; psApiTimeInterval = setInterval(function () { callback(); if (++x === repetitions) { clearInterval(psApiTimeInterval); pageScanRequestComplete = true; } }, delay); } })();