// ==UserScript== // @name Ultra Popup Blocker // @description Configurable popup blocker that blocks all popup windows by default. // @namespace https://github.com/eskander // @author Eskander // @version 3.5 // @include * // @license MIT // @homepage https://eskander.tn/ultra-popup-blocker/ // @supportURL https://github.com/Eskander/ultra-popup-blocker/issues/new // @compatible firefox Tampermonkey recommended // @compatible chrome Tampermonkey recommended // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_listValues // @grant GM_openInTab // @grant GM_registerMenuCommand // ==/UserScript== /* ---------------------------------------------------------------- */ const PERMISSION_DIALOG_ID = 'ultra_popup_blocker'; // HTML ID in the page const CONTROL_PANEL = 'https://eskander.tn/ultra-popup-blocker/settings.html'; // Reference to page's "window" through GreaseMonkey const global = unsafeWindow; global.upb_counter = 0; // Storing a reference to real "window.open" method in case we wanted it const realWindowOpen = global.open; // We need to return the fake window to not encounter JS runtime error when the popup originator // page wants to call focus() or blur(). const FakeWindow = { blur() { return false; }, focus() { return false; }, }; // Timeout before confirmation dialog closes automatically let timeleft = 15; /* ---------------------------------------------------------------- */ // Add @domain to local storage function addDomainToLocalStorage(domain) { GM_setValue(`trusted_${domain}`, true); } // Remove @domain from local storage function removeDomainFromLocalStorage(domain) { GM_deleteValue(`trusted_${domain}`); GM_deleteValue(`${domain}`); } // Return true if @domain is trusted function isDomainTrusted(domain) { return GM_getValue(`trusted_${domain}`); } // Return an Array of trusted domains function getTrustedDomains() { return GM_listValues(); } // Open permission manager in new tab function openControlPanel() { GM_openInTab(CONTROL_PANEL, false); } // Add a link to permission manager in extensions' popup menu function attachToExtensionMenu(name, callback) { GM_registerMenuCommand(name, callback); } // Permission bar; Return permission dialog, or create it if needed. function getLogDiv() { let logDiv = document.getElementById(PERMISSION_DIALOG_ID); if (!logDiv) { logDiv = document.createElement('div'); logDiv.setAttribute('id', PERMISSION_DIALOG_ID); logDiv.style.cssText = 'position: fixed;\ bottom: 0;\ left: 0;\ z-index: 99999;\ width: 100%;\ padding: 5px 5px 5px 5px;\ font: status-bar;\ background-color: black;\ color: white;\ cursor: help'; document.body.appendChild(logDiv); } return logDiv; } // Permission bar; Hide dialog function closeLogDiv(logDiv) { const currentLogDiv = logDiv; currentLogDiv.style.display = 'none'; } // Return current top domain. eg: github.com function getCurrentTopDomain() { const hostnameArray = document.location.hostname.split('.'); const topLevelDomain = hostnameArray[hostnameArray.length - 1]; const domainName = hostnameArray[hostnameArray.length - 2]; const currentDomain = `${domainName}.${topLevelDomain}`; return currentDomain; } // Return true if current domain has been trusted by the user function isCurrentDomainTrusted() { const domain = getCurrentTopDomain(); return isDomainTrusted(domain); } // Permission manager; Create a button to remove domain from permissions list function removeDomainFromPermissionList() { const div = this.parentElement; console.log(div); const domain = div.innerText.replace('\n\u00D7', ''); removeDomainFromLocalStorage(domain); div.style.display = 'none'; console.log(`[UPB] Domain removed from trust: ${domain}`); } // Permission manager; Add a new domain to permissions list function addDomainToPermissionList(domain) { const domainName = domain.replace('trusted_', ''); const li = document.createElement('li'); const t = document.createTextNode(domainName); li.appendChild(t); document.getElementById('List').appendChild(li); // Add a remove button to li const span = document.createElement('SPAN'); const txt = document.createTextNode('\u00D7'); span.className = 'close'; span.appendChild(txt); span.onclick = removeDomainFromPermissionList; li.appendChild(span); // Add domain to localStorage addDomainToLocalStorage(domainName); console.log(`[UPB] Domain added to trust: ${domainName}`); } // Permission manager; Button to add a new domain to permissions list function addNewDomainButton() { document.getElementsByClassName('addBtn')[0].addEventListener( 'click', () => { const DOMAIN = document.getElementById('Input').value; if (DOMAIN !== '') { addDomainToPermissionList(DOMAIN); } document.getElementById('Input').value = ''; }, ); } // Permission bar; Create a button with inner text @text executing onclick // @clickCallback, appended as a child of @logDiv, with style @inlineStyle. function createButton(logDiv, text, id, clickCallback, inlineStyle) { const button = document.createElement('button'); button.innerHTML = text; button.id = id; button.style.cssText = `text-decoration: none;\ color: black;\ cursor: pointer;\ margin: 0 5px;\ padding: 1px 3px;\ background-color: rgb(255, 255, 255);\ border-width: 0px;\ border-radius: 5px;\ color: black;\ ${inlineStyle}`; logDiv.appendChild(button); button.addEventListener('click', clickCallback); } // Permission bar; Create a button (child of @logDiv) which onclick trusts @domain function createTrustButton(logDiv, domain, a, b, c) { createButton( logDiv, 'Always Allow 🗸', 'upb_trust', () => { addDomainToLocalStorage(domain); realWindowOpen(a, b, c); closeLogDiv(logDiv); global.open = realWindowOpen; }, '', ); } // Permission bar; Create a button (child of @logDiv) which onclick opens @domain function createOpenPopupButton(logDiv, a, b, c) { createButton( logDiv, 'Allow ↗', 'upb_open', () => { realWindowOpen(a, b, c); closeLogDiv(logDiv); }, '', ); } // Permission bar; Create a button (child of @logDiv) which onclick hides @logDiv function createCloseButton(logDiv) { createButton( logDiv, `Deny (${timeleft})`, 'upb_close', () => { closeLogDiv(logDiv); }, ' background-color: #a00;\ color: white;', ); } // Permission bar; Create a button (child of @logDiv) which onclick opens @controlPanel function createConfigButton(logDiv) { createButton( logDiv, 'Config ⚙', 'upb_config', () => { openControlPanel(); }, ' float: right;\ margin: 0 10px 0 0;', ); } // Permission bar; Display a permission prompt when a new popup is detected function createDialogMessage(logDiv, url) { const currentLogDiv = logDiv; const domain = getCurrentTopDomain(); let msg; let popupUrl; global.upb_counter += 1; if (global.upb_counter === 1) { msg = `[UPB] Allow ${domain} to open a popup ?`; } else { msg = `[UPB] Allow ${domain} to open a popup ? (${global.upb_counter})`; } if (url[0] === '/') { popupUrl = document.domain + url; } else { popupUrl = url; } currentLogDiv.innerHTML = msg; currentLogDiv.title = popupUrl; console.log(msg); currentLogDiv.style.display = 'block'; } function createTimer(logDiv) { console.log(timeleft); if (timeleft === 15) { const Timer = setInterval(() => { document.getElementById('upb_close').innerHTML = `Deny (${timeleft})`; timeleft -= 1; if (timeleft < 0) { clearInterval(Timer); closeLogDiv(logDiv); timeleft = 15; } console.log(timeleft); }, 1000); } } // This function will be called each time a script wants to open a new window function fakeWindowOpen(a, b, c) { const domain = getCurrentTopDomain(); const popupURL = a; const logDiv = getLogDiv(); console.log(a, b, c); createDialogMessage(logDiv, popupURL); createOpenPopupButton(logDiv, a, b, c); createTrustButton(logDiv, domain, a, b, c); createCloseButton(logDiv); createConfigButton(logDiv); createTimer(logDiv); return FakeWindow; } // Override browser's "window.open" with our own implementation. function activateBlocker() { const TRUSTED = isCurrentDomainTrusted(); if (!TRUSTED) { global.open = fakeWindowOpen; console.log('[UPB] Current domain Not trusted.'); } else { console.log('[UPB] Current domain Trusted. UPB disabled.'); } } function activateControlPanel() { if (window.location.href === CONTROL_PANEL) { // Add listener to the add button addNewDomainButton(); // Show already stored elements in the list const storedTrust = getTrustedDomains(); storedTrust.forEach(addDomainToPermissionList); console.log(storedTrust); } } function activateExtensionMenu() { attachToExtensionMenu( 'Configure popup permissions', () => { openControlPanel(); }, ); } /* ---------------------------------------------------------------- */ // Add configure link to Tampermonkey's menu activateExtensionMenu(); // Initiate Control Panel logic activateControlPanel(); // Start Popup Blocker activateBlocker();