From 5694635db6a4721814319e3019925aa135e429c3 Mon Sep 17 00:00:00 2001 From: Balaji R Date: Sat, 23 May 2026 19:07:54 +0530 Subject: [PATCH 1/2] fix(ClearURLs#509): add disable on current site control --- _locales/en/messages.json | 34 ++++++++- clearurls.js | 4 + core_js/historyListener.js | 2 +- core_js/popup.js | 87 +++++++++++++++++++++- core_js/storage.js | 7 ++ core_js/tools.js | 145 +++++++++++++++++++++++++++++++++++++ html/popup.html | 13 ++++ 7 files changed, 287 insertions(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 37393d55..eae52c86 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -123,6 +123,38 @@ "message": "Open the log", "description": "This string is used as title for the log button on the popup page." }, + "popup_html_site_head": { + "message": "Site", + "description": "This string is used as title for the current site section on the popup page." + }, + "popup_html_site_disable": { + "message": "Disable on this site", + "description": "This string is used as label for disabling ClearURLs on the current site." + }, + "popup_html_site_disable_title": { + "message": "Disable ClearURLs on the current site", + "description": "This string is used as title for the current-site disable button." + }, + "popup_html_site_enable": { + "message": "Enable on this site", + "description": "This string is used as label for enabling ClearURLs on the current site." + }, + "popup_html_site_enable_title": { + "message": "Enable ClearURLs again on the current site", + "description": "This string is used as title for the current-site enable button." + }, + "popup_html_site_enabled": { + "message": "ClearURLs is active on $1", + "description": "This string is used to show that ClearURLs is active on the current site." + }, + "popup_html_site_disabled": { + "message": "ClearURLs is disabled on $1", + "description": "This string is used to show that ClearURLs is disabled on the current site." + }, + "popup_html_site_unavailable": { + "message": "This page does not have a normal site hostname.", + "description": "This string is used when the current tab does not expose a normal site hostname." + }, "popup_html_report_button": { "message": "Report current URL", "description": "Note: Currently not used." @@ -375,4 +407,4 @@ "message": " ", "description": "not needed, only to prevent exceptions" } -} \ No newline at end of file +} diff --git a/clearurls.js b/clearurls.js index 66a4aeeb..b6e69b3a 100644 --- a/clearurls.js +++ b/clearurls.js @@ -606,6 +606,10 @@ function start() { * @return {Array} redirectUrl or none */ function clearUrl(request) { + if (isURLDisabled(getRequestContextURL(request))) { + return {}; + } + const URLbeforeReplaceCount = countFields(request.url); //Add Fields form Request to global url counter diff --git a/core_js/historyListener.js b/core_js/historyListener.js index ec54174e..c0b3f0c5 100644 --- a/core_js/historyListener.js +++ b/core_js/historyListener.js @@ -37,7 +37,7 @@ function historyListenerStart() { * which is associated with the new history entry created by replaceState() */ function historyCleaner(details) { - if(storage.globalStatus) { + if(storage.globalStatus && !isURLDisabled(details.url)) { const urlBefore = details.url; const urlAfter = pureCleaning(details.url); diff --git a/core_js/popup.js b/core_js/popup.js index 343ce375..adfdca85 100644 --- a/core_js/popup.js +++ b/core_js/popup.js @@ -31,6 +31,10 @@ var hashStatus; var loggingStatus; var statisticsStatus; var currentURL; +var disabledDomains = []; +var currentHostname = ""; +var siteSwitchButton = document.getElementById('siteSwitchButton'); +var siteStatus = document.getElementById('siteStatus'); /** * Initialize the UI. @@ -44,6 +48,7 @@ function init() setSwitchButton("statistics", "statisticsStatus"); setHashStatus(); changeStatistics(); + updateSiteSection(); } /** @@ -180,6 +185,78 @@ function resetGlobalCounter(){ changeStatistics(); } +function updateSiteSection() { + if (!siteSwitchButton || !siteStatus) { + return; + } + + const siteDisabled = disabledDomains.includes(currentHostname); + + if (!currentHostname) { + siteStatus.textContent = translate('popup_html_site_unavailable'); + siteSwitchButton.disabled = true; + siteSwitchButton.textContent = translate('popup_html_site_disable'); + siteSwitchButton.removeAttribute('title'); + return; + } + + siteSwitchButton.disabled = false; + + if (siteDisabled) { + siteStatus.textContent = translate('popup_html_site_disabled', currentHostname); + siteSwitchButton.textContent = translate('popup_html_site_enable'); + siteSwitchButton.setAttribute('title', translate('popup_html_site_enable_title')); + } else { + siteStatus.textContent = translate('popup_html_site_enabled', currentHostname); + siteSwitchButton.textContent = translate('popup_html_site_disable'); + siteSwitchButton.setAttribute('title', translate('popup_html_site_disable_title')); + } +} + +function toggleCurrentSite() { + if (!currentHostname) { + return; + } + + const siteDisabled = disabledDomains.includes(currentHostname); + + browser.runtime.sendMessage({ + function: "setDisabledDomain", + params: [currentHostname, !siteDisabled] + }).then(() => { + if (siteDisabled) { + disabledDomains = disabledDomains.filter((domain) => domain !== currentHostname); + } else { + disabledDomains.push(currentHostname); + disabledDomains.sort(); + } + + updateSiteSection(); + + return browser.runtime.sendMessage({ + function: "saveOnExit", + params: [] + }); + }).catch(handleError); +} + +function loadCurrentTab() { + return browser.tabs.query({ + active: true, + currentWindow: true + }).then((tabs) => { + const activeTab = tabs[0]; + + currentURL = activeTab && activeTab.url ? activeTab.url : ""; + + try { + currentHostname = currentURL ? new URL(currentURL).hostname.toLowerCase() : ""; + } catch (error) { + currentHostname = ""; + } + }); +} + (function() { loadData("cleanedCounter") .then(() => loadData("totalCounter")) @@ -188,7 +265,8 @@ function resetGlobalCounter(){ .then(() => loadData("hashStatus")) .then(() => loadData("loggingStatus")) .then(() => loadData("statisticsStatus")) - .then(() => loadData("getCurrentURL", "currentURL")) + .then(() => loadData("disabledDomains")) + .then(() => loadCurrentTab()) .then(() => { init(); document.getElementById('reset_counter_btn').onclick = resetGlobalCounter; @@ -196,6 +274,7 @@ function resetGlobalCounter(){ changeSwitchButton("tabcounter", "badgedStatus"); changeSwitchButton("logging", "loggingStatus"); changeSwitchButton("statistics", "statisticsStatus"); + siteSwitchButton.onclick = toggleCurrentSite; document.getElementById('loggingPage').href = browser.runtime.getURL('./html/log.html'); document.getElementById('settings').href = browser.runtime.getURL('./html/settings.html'); document.getElementById('cleaning_tools').href = browser.runtime.getURL('./html/cleaningTool.html'); @@ -209,6 +288,7 @@ function resetGlobalCounter(){ function setText() { injectText('loggingPage','popup_html_log_head'); + injectText('siteHead', 'popup_html_site_head'); injectText('reset_counter_btn','popup_html_statistics_reset_button'); injectText('rules_status_head','popup_html_rules_status_head'); injectText('statistics_percentage','popup_html_statistics_percentage'); @@ -221,6 +301,7 @@ function setText() injectText('configs_head','popup_html_configs_head'); injectText('configs_switch_statistics','configs_switch_statistics'); document.getElementById('donate').title = translate('donate_button'); + updateSiteSection(); } /** @@ -271,9 +352,9 @@ async function loadData(name, varName=name) { * * @param {string} string Name of the attribute used for localization */ -function translate(string) +function translate(string, ...placeholders) { - return browser.i18n.getMessage(string); + return browser.i18n.getMessage(string, placeholders); } function handleError(error) { diff --git a/core_js/storage.js b/core_js/storage.js index ee552c6c..7ae75437 100644 --- a/core_js/storage.js +++ b/core_js/storage.js @@ -116,6 +116,9 @@ function genesis() { //Set correct icon on startup changeIcon(); + // Cache active and open tab URLs for per-site controls and filtering + initializeTabURLs(); + // Start the context_menu contextMenuStart(); @@ -163,6 +166,9 @@ function setData(key, value) { case "types": storage[key] = value.split(','); break; + case "disabledDomains": + storage[key] = Array.isArray(value) ? value : value.split(',').filter(Boolean); + break; case "logLimit": storage[key] = Math.max(0, Number(value)); break; @@ -224,6 +230,7 @@ function initSettings() { storage.domainBlocking = true; storage.pingBlocking = true; storage.eTagFiltering = false; + storage.disabledDomains = []; storage.watchDogErrorCount = 0; if (getBrowser() === "Firefox") { diff --git a/core_js/tools.js b/core_js/tools.js index 8e204818..a277766e 100644 --- a/core_js/tools.js +++ b/core_js/tools.js @@ -23,6 +23,8 @@ // Needed by the sha256 method const enc = new TextEncoder(); +let currentURL = ""; +let tabURLs = {}; // Max amount of log entries to prevent performance issues const logThreshold = 5000; @@ -222,6 +224,126 @@ function getCurrentURL() { return currentURL; } +function normalizeHostname(hostname) { + return (hostname || "").trim().toLowerCase(); +} + +function extractHostnameFromURL(url) { + try { + return normalizeHostname(new URL(url).hostname); + } catch (error) { + return ""; + } +} + +function getDisabledDomains() { + return storage.disabledDomains || []; +} + +function setDisabledDomain(hostname, disabled = true) { + const normalizedHostname = normalizeHostname(hostname); + + if (!normalizedHostname) { + return false; + } + + const domains = new Set(getDisabledDomains()); + + if (disabled) { + domains.add(normalizedHostname); + } else { + domains.delete(normalizedHostname); + } + + storage.disabledDomains = Array.from(domains).sort(); + + return true; +} + +function isDomainDisabled(hostname) { + const normalizedHostname = normalizeHostname(hostname); + + if (!normalizedHostname) { + return false; + } + + return getDisabledDomains().includes(normalizedHostname); +} + +function isURLDisabled(url) { + return isDomainDisabled(extractHostnameFromURL(url)); +} + +function setTabURL(tabId, url) { + if (typeof tabId !== "number" || tabId < 0 || !url) { + return; + } + + tabURLs[tabId] = url; +} + +function getTabURL(tabId) { + if (typeof tabId !== "number" || tabId < 0) { + return ""; + } + + return tabURLs[tabId] || ""; +} + +function removeTabURL(tabId) { + delete tabURLs[tabId]; +} + +function refreshCurrentURL() { + browser.tabs.query({ + active: true, + currentWindow: true + }).then((tabs) => { + if (tabs.length > 0) { + currentURL = tabs[0].url || ""; + setTabURL(tabs[0].id, currentURL); + } else { + currentURL = ""; + } + }).catch(handleError); +} + +function getRequestContextURL(request) { + if (request.type === "main_frame") { + return request.url; + } + + const tabURL = getTabURL(request.tabId); + + if (tabURL) { + return tabURL; + } + + if (request.documentUrl) { + return request.documentUrl; + } + + if (request.originUrl) { + return request.originUrl; + } + + if (request.initiator) { + return request.initiator; + } + + return ""; +} + +function initializeTabURLs() { + browser.tabs.query({}).then((tabs) => { + tabs.forEach((tab) => { + setTabURL(tab.id, tab.url); + }); + }).catch(handleError); + + refreshCurrentURL(); +} + /** * Check for browser. */ @@ -233,6 +355,29 @@ function getBrowser() { } } +browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + if (changeInfo.url) { + setTabURL(tabId, changeInfo.url); + } else if (tab && tab.url) { + setTabURL(tabId, tab.url); + } + + if (tab && tab.active) { + currentURL = tab.url || changeInfo.url || currentURL; + } +}); + +browser.tabs.onActivated.addListener((activeInfo) => { + browser.tabs.get(activeInfo.tabId).then((tab) => { + currentURL = tab.url || ""; + setTabURL(tab.id, currentURL); + }).catch(handleError); +}); + +browser.tabs.onRemoved.addListener((tabId) => { + removeTabURL(tabId); +}); + /** * Decodes an URL, also one that is encoded multiple times. * diff --git a/html/popup.html b/html/popup.html index 5f10bf08..49ac2d02 100644 --- a/html/popup.html +++ b/html/popup.html @@ -90,6 +90,19 @@
+
+
+
+

+
+ +
+
+
+
+
+
From b176f417e89c6505321d5469a72ebd443ca8b0c4 Mon Sep 17 00:00:00 2001 From: Balaji R Date: Sat, 23 May 2026 19:18:37 +0530 Subject: [PATCH 2/2] fix: sort alphabetically --- core_js/popup.js | 2 +- core_js/tools.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core_js/popup.js b/core_js/popup.js index adfdca85..2f5f6552 100644 --- a/core_js/popup.js +++ b/core_js/popup.js @@ -228,7 +228,7 @@ function toggleCurrentSite() { disabledDomains = disabledDomains.filter((domain) => domain !== currentHostname); } else { disabledDomains.push(currentHostname); - disabledDomains.sort(); + disabledDomains.sort((left, right) => left.localeCompare(right)); } updateSiteSection(); diff --git a/core_js/tools.js b/core_js/tools.js index a277766e..aa713559 100644 --- a/core_js/tools.js +++ b/core_js/tools.js @@ -255,7 +255,7 @@ function setDisabledDomain(hostname, disabled = true) { domains.delete(normalizedHostname); } - storage.disabledDomains = Array.from(domains).sort(); + storage.disabledDomains = Array.from(domains).sort((left, right) => left.localeCompare(right)); return true; }