// ==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();