Ultra Popup Blocker

Configurable popup blocker that blocks all popup windows by default. You can easily open the blocked popup or whitelist a domain, directly from the page.

目前为 2019-08-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Ultra Popup Blocker
  3. // @description Configurable popup blocker that blocks all popup windows by default. You can easily open the blocked popup or whitelist a domain, directly from the page.
  4. // @namespace https://github.com/eskander
  5. // @author eskander
  6. // @version 2.2
  7. // @include *
  8. // @license MIT
  9. // @homepage https://github.com/eskander/ultra-popup-blocker
  10. // @supportURL https://github.com/eskander/ultra-popup-blocker/issues
  11. // @compatible firefox Tampermonkey recommended
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_deleteValue
  15. // @grant GM_listValues
  16. // @grant GM_openInTab
  17. // @grant GM_registerMenuCommand
  18. // ==/UserScript==
  19.  
  20. (function () {
  21.  
  22. // ============================== CONFIG =================================
  23. var bDisplayMessageOnPopupBlocked = true;
  24. var bDisplayOpenPopupLink = true;
  25. var bDisplayWhiteListThisDomainLink = true;
  26. var LOG_ID = "ultra_popup_blocker"; // HTML ID in the page
  27.  
  28. // ============================ FUNCTIONS ================================
  29. var global = unsafeWindow; // reference to page's "window" through GreaseMonkey
  30.  
  31. // Helper to create a button with inner text @text executing onclick @clickCallback,
  32. // appended as a child of @logDiv
  33.  
  34. var putButton = function (logDiv, text, clickCallback, inlineStyle) {
  35. var button = document.createElement("button");
  36. button.innerHTML = text;
  37. button.style.cssText = "text-decoration: none;\
  38. color: black;\
  39. cursor: pointer;\
  40. margin: 0 5px;\
  41. padding: 1px 3px;\
  42. background-color: rgb(255, 255, 255);\
  43. border-width: 0px;\
  44. border-radius: 5px;\
  45. color: black;" + inlineStyle;
  46. logDiv.appendChild(button);
  47. button.addEventListener("click", clickCallback);
  48. };
  49.  
  50.  
  51. // Helper to create a button (child of @logDiv) which onclick whitelists @domain
  52. // in internal Firefox storage.
  53.  
  54. var putWhitelistButton = function (logDiv, domain) {
  55. putButton(logDiv, "Whitelist 🗸", function () {
  56. GM_setValue("whitelisted_" + domain, true);
  57. });
  58. };
  59.  
  60. // Helper to create a text node with @text and append to @logDiv
  61.  
  62. var putText = function (logDiv, text) {
  63. var node = document.createTextNode(text);
  64. logDiv.appendChild(node);
  65. };
  66.  
  67. // Return logger div, or create it ad-hoc.
  68.  
  69. var getLogDiv = function () {
  70. var logDiv = document.getElementById(LOG_ID);
  71. if (!logDiv) {
  72. logDiv = document.createElement("div");
  73. logDiv.setAttribute("id", LOG_ID);
  74. logDiv.style.cssText = "position: fixed;\
  75. bottom: 0;\
  76. left: 0;\
  77. z-index: 99999;\
  78. width: 100%;\
  79. padding: 5px 5px 5px 5px;\
  80. font: status-bar;\
  81. background-color: black;\
  82. color: white;";
  83. document.body.appendChild(logDiv);
  84. }
  85. return logDiv;
  86. };
  87.  
  88. // Get top domain to whitelist.
  89.  
  90. var getDomainsArray = function (documentDomain) {
  91. // e.g. domain = www.google.com, topDomain = google.com
  92. var d1 = documentDomain;
  93. var domainsArr = [];
  94.  
  95. while (d1.split(".").length > 2) {
  96. d1 = d1.substring(d1.indexOf('.') + 1);
  97. }
  98.  
  99. domainsArr.push(d1);
  100. return domainsArr;
  101. };
  102.  
  103. // Checks if domain we're currently browsing has been whitelisted by the user
  104. // to display popups.
  105.  
  106. var isCurrentDomainWhiteListed = function () {
  107. var domains = getDomainsArray(document.domain);
  108. var whitelisted = domains.some(function (d) {
  109. return GM_getValue("whitelisted_" + d);
  110. }); // if any 'd' in 'domains' was whitelisted, we return true
  111. return whitelisted;
  112. };
  113.  
  114. // "window.open()" returns Window which might be then used by the originator page
  115. // to focus the popup (annoying splash popup) or blur it to retain focus in the original page
  116. // (pay-by-impressions popup, I don't need it to actually see it).
  117. // We need to return the fake window to not encounter JS runtime error when the popup originator
  118. // page wants to call focus() or blur().
  119.  
  120. var FakeWindow = {
  121. blur: function () {
  122. return false;
  123. },
  124. focus: function () {
  125. return false;
  126. }
  127. };
  128.  
  129. // Storing a reference to real "window.open" method in case we wanted
  130. // to actually open a blocked popup
  131.  
  132. var realWindowOpen = global.open;
  133.  
  134. // This function will be called each time a script wants to open a new window,
  135. // if the blocker is activated.
  136. // We handle the blocking & messaging logic here.
  137.  
  138. var fakeWindowOpen = function (url) {
  139. if (!bDisplayMessageOnPopupBlocked) {
  140. return FakeWindow;
  141. }
  142. var logDiv = getLogDiv();
  143. logMessage(logDiv, url);
  144.  
  145. if (bDisplayOpenPopupLink) {
  146. displayOpenPopupLink(logDiv, arguments);
  147. }
  148. if (bDisplayWhiteListThisDomainLink) {
  149. displayWhiteListThisDomainLink(logDiv);
  150. }
  151. displayCloseButton(logDiv);
  152.  
  153. displayConfigButton(logDiv);
  154.  
  155. return FakeWindow; // see the doc of FakeWindow
  156. };
  157.  
  158. var logMessage = function (logDiv, url) {
  159. global.upb_counter = (global.upb_counter || 0);
  160. url = (url[0] == '/') ? document.domain + url : url;
  161. if (global.upb_counter++ == 0) {
  162. var msg = ["<b>[UPB]</b> Blocked <b>1</b> popup: <u>", url, "</u>"].join("");
  163. } else {
  164. var msg = ["<b>[UPB]</b> Blocked <b>", global.upb_counter, "</b> popups, last: <u>", url, "</u>"].join("");
  165. }
  166. logDiv.innerHTML = msg;
  167. console.log(msg);
  168. logDiv.style.display = "block";
  169. };
  170.  
  171. var displayOpenPopupLink = function (logDiv, realArguments) {
  172. putButton(logDiv, "Open &#8599;", function () {
  173. realWindowOpen.apply(null, realArguments);
  174. });
  175. };
  176.  
  177. var displayWhiteListThisDomainLink = function (logDiv) {
  178. var domainsArr = getDomainsArray(document.domain);
  179. putWhitelistButton(logDiv, domainsArr[0]);
  180. };
  181.  
  182. var displayCloseButton = function (logDiv) {
  183. putButton(logDiv, "Close &#10799;", function () {
  184. logDiv.style.display = 'none';
  185. }, 'background-color: #a00;\
  186. color: white;\
  187. margin: 0 10px 0 0;\
  188. float: right');
  189. };
  190.  
  191. var displayConfigButton = function (logDiv) {
  192. putButton(logDiv, "Config &#9881;", function () {
  193. GM_openInTab("https://eskander.github.io/ultra-popup-blocker/configure.html", false);
  194. }, 'float:right');
  195. };
  196.  
  197. // Override browser's "window.open" with our own implementation.
  198.  
  199. var activateBlocker = function () {
  200. global.open = fakeWindowOpen;
  201. };
  202.  
  203. // ============================== SETTINGS PAGE =================================
  204.  
  205. // Add configure link to Tampermonkey's menu
  206.  
  207. GM_registerMenuCommand('Configure whitelist', function () {
  208. GM_openInTab("https://eskander.github.io/ultra-popup-blocker/configure.html", false);
  209. }, 'r');
  210.  
  211. // Only run whitelisting mechanism on the appropriate page
  212.  
  213. if (window.location.href === "https://eskander.github.io/ultra-popup-blocker/configure.html") {
  214.  
  215. // Add listener to the add button
  216.  
  217. document.getElementsByClassName("addBtn")[0].addEventListener("click", function () {
  218. newElement();
  219. });
  220.  
  221. // Create a "close" button and append it to each list item
  222.  
  223. var Nodelist = document.getElementsByTagName("LI");
  224. for (var i = 0; i < Nodelist.length; i++) {
  225. var span = document.createElement("SPAN");
  226. var txt = document.createTextNode("\u00D7");
  227. span.className = "close";
  228. span.appendChild(txt);
  229. span.onclick = function () {
  230. var div = this.parentElement;
  231. var domain = div.innerText.replace("\n\u00D7", "");
  232. GM_deleteValue("whitelisted_" + domain);
  233. div.style.display = "none";
  234. console.log('[UPB] Domain removed from whitelist: ' + domain);
  235. }
  236. Nodelist[i].appendChild(span);
  237. }
  238.  
  239. // Create a new list item when clicking on the "Add" button
  240.  
  241. var newElement = function () {
  242. var inputValue = document.getElementById("Input").value;
  243.  
  244. if (inputValue === '') {
  245. alert("You must write a domain or subdomain to whitelist.");
  246. } else {
  247. addElement(inputValue);
  248. }
  249.  
  250. document.getElementById("Input").value = "";
  251. }
  252.  
  253. var addElement = function (Value) {
  254. var li = document.createElement("li");
  255. var t = document.createTextNode(Value);
  256. li.appendChild(t);
  257.  
  258. document.getElementById("List").appendChild(li);
  259. GM_setValue("whitelisted_" + Value, true);
  260. console.log('[UPB] Domain added to whitelist: ' + Value);
  261.  
  262. // Add a close button to the newly created item
  263. var span = document.createElement("SPAN");
  264. var txt = document.createTextNode("\u00D7");
  265. span.className = "close";
  266. span.appendChild(txt);
  267. span.onclick = function () {
  268. var div = this.parentElement;
  269. var domain = div.innerText.replace("\n\u00D7", "");
  270. GM_deleteValue("whitelisted_" + domain);
  271. div.style.display = "none";
  272. console.log('[UPB] Domain removed from whitelist: ' + domain);
  273. }
  274. li.appendChild(span);
  275. }
  276.  
  277. // Show already stored elements in the list
  278.  
  279. var storedWhitelist = GM_listValues();
  280. storedWhitelist.forEach(populate);
  281. console.log(storedWhitelist);
  282.  
  283. function populate(value, index, array) {
  284. addElement(value.replace("whitelisted_", ""));
  285. }
  286. }
  287.  
  288. // ============================ LET'S RUN IT ================================
  289.  
  290. var disabled = isCurrentDomainWhiteListed();
  291. if (disabled) {
  292. console.log('[UPB] Current domain was found on a white list. UPB disabled.');
  293. } else {
  294. activateBlocker();
  295. }
  296. })();