Behind The Overlay

One click to close any overlay on any website

  1. // ==UserScript==
  2. // @name Behind The Overlay
  3. // @namespace Behind The Overlay
  4. // @description One click to close any overlay on any website
  5. // @author NicolaeNMV + daijro
  6. // @version 2.0
  7. // @include *://*
  8. // @icon https://addons.cdn.mozilla.net/user-media/addon_icons/521/521928-32.png
  9. // @grant GM_registerMenuCommand
  10. // ==/UserScript==
  11.  
  12. /**
  13. * This is a script that will remove overlay popups in the 99% of the cases.
  14. * It's doing that by detecting DOM elements.
  15. *
  16. * Originally from here: https://github.com/NicolaeNMV/BehindTheOverlay
  17. * Modified by daijro to work as a userscript
  18. **/
  19.  
  20. var debug = false;
  21.  
  22. var utils = (function () {
  23. function hideElement(element) {
  24. styleImportant(element, 'display', 'none');
  25. }
  26.  
  27. function styleImportant(element, cssProperty, cssValue) {
  28. element.style[cssProperty] = '';
  29. var cssText = element.style.cssText || '';
  30. if (cssText.length > 0 && cssText.slice(-1) != ';')
  31. cssText += ';';
  32. // Some pages are using !important on elements, so we must use it too
  33. element.style.cssText = cssText + cssProperty + ': ' + cssValue + ' !important;';
  34. }
  35.  
  36. function isVisible(element) {
  37. return element.offsetWidth > 0 && element.offsetHeight > 0;
  38. }
  39.  
  40. function getZIndex(element) {
  41. return parseInt(window.getComputedStyle(element).zIndex);
  42. }
  43.  
  44. function isAnElement(node) {
  45. return node.nodeType == 1; // nodeType 1 mean element
  46. }
  47.  
  48. function nodeListToArray(nodeList) {
  49. return Array.prototype.slice.call(nodeList);
  50. }
  51.  
  52. function forEachElement(nodeList, functionToApply) {
  53. nodeListToArray(nodeList).filter(isAnElement).forEach(function (element) {
  54. functionToApply.call(this, element);
  55. });
  56. }
  57.  
  58. function collectParrents(element, predicate) {
  59. var matchedElement = element && predicate(element) ? [element] : [];
  60. var parent = element.parentNode;
  61.  
  62. if (parent && parent != document && parent != document.body) {
  63. return matchedElement.concat(collectParrents(parent, predicate));
  64. } else {
  65. return matchedElement;
  66. }
  67. }
  68.  
  69. // Calculate the number of DOM elements inside an element
  70. function elementWeight(element, maxThreshold) {
  71. var grandTotal = 0;
  72. var nextElement = element;
  73. var nextGrandChildNodes = [];
  74.  
  75. function calculateBreathFirst(element) {
  76. var total = 0;
  77. var nextChildElements = [];
  78.  
  79. var childNodes = element.childNodes;
  80. total = childNodes.length;
  81.  
  82. forEachElement(childNodes, function (childNode) {
  83. var grandChildNodes = nodeListToArray(childNode.childNodes);
  84. total += grandChildNodes.length;
  85. nextChildElements = nextChildElements.concat(grandChildNodes.filter(isAnElement));
  86. });
  87. return [total, nextChildElements];
  88. }
  89.  
  90. while (nextElement) {
  91. var tuple_total_nextChildElements = calculateBreathFirst(nextElement);
  92. var total = tuple_total_nextChildElements[0];
  93.  
  94. grandTotal += total;
  95. nextGrandChildNodes = nextGrandChildNodes.concat(tuple_total_nextChildElements[1]);
  96.  
  97. if (grandTotal >= maxThreshold) {
  98. break;
  99. } else {
  100. nextElement = nextGrandChildNodes.pop();
  101. }
  102. }
  103.  
  104. return grandTotal;
  105. }
  106.  
  107. return {
  108. hideElement: hideElement,
  109. isVisible: isVisible,
  110. getZIndex: getZIndex,
  111. forEachElement: forEachElement,
  112. collectParrents: collectParrents,
  113. elementWeight: elementWeight,
  114. styleImportant: styleImportant
  115. }
  116. })();
  117.  
  118. var overlayRemover = function (debug, utils) {
  119. function hideElementsAtZIndexNear(nearElement, thresholdZIndex) {
  120. var parent = nearElement.parentNode;
  121. // The case when nearElement is a document
  122. if (parent === null) {
  123. return;
  124. }
  125. var children = parent.childNodes;
  126.  
  127. utils.forEachElement(children, function (child) {
  128. if (utils.getZIndex(child) >= thresholdZIndex) {
  129. utils.hideElement(child);
  130. }
  131. })
  132. }
  133.  
  134. // Check the element in the middle of the screen
  135. // Search fo elements that have zIndex attribute
  136. function methodTwoHideElementMiddle() {
  137. var overlayPopup = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);
  138.  
  139. var overlayFound = utils.collectParrents(overlayPopup, function (el) {
  140. return utils.getZIndex(el) > 0;
  141. });
  142.  
  143. if (debug)
  144. console.debug('Overlay found: ', overlayFound);
  145.  
  146. if (overlayFound.length == 0)
  147. return false;
  148.  
  149. var olderParent = overlayFound.pop();
  150.  
  151. if (debug)
  152. console.debug('Hide parrent: ', olderParent);
  153.  
  154. return olderParent;
  155. }
  156.  
  157. function disableBlur() {
  158. var someContainerMaybe = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);
  159.  
  160. var bluredParentsFound = utils.collectParrents(someContainerMaybe, function (el) {
  161. return window.getComputedStyle(el).filter.includes('blur');
  162. });
  163.  
  164. if (bluredParentsFound.length == 0)
  165. return false;
  166.  
  167. var topParent = bluredParentsFound.pop();
  168.  
  169. // Some element can act as a container, that can be blured or masking the whole content
  170. var isContainerOccupyingAboutSpaceAsBody = topParent.offsetWidth >= (document.body.offsetWidth - 100);
  171.  
  172. if (isContainerOccupyingAboutSpaceAsBody) {
  173. utils.styleImportant(topParent, 'filter', 'blur(0)');
  174.  
  175. if (debug) console.log('Blur removed!', topParent);
  176.  
  177. return true;
  178. }
  179.  
  180. return false;
  181. }
  182.  
  183. function containersOverflowAuto() {
  184. var containers = [document.documentElement, document.body];
  185.  
  186. containers.forEach(function (element) {
  187. if (window.getComputedStyle(element).overflowY == 'hidden') {
  188. utils.styleImportant(element, 'overflow', 'auto');
  189. }
  190. if (window.getComputedStyle(element).position == 'fixed') {
  191. utils.styleImportant(element, 'position', 'static');
  192. }
  193. })
  194. }
  195.  
  196. function run() {
  197. for (var i = 0; i < 10; i++) {
  198. var candidate = methodTwoHideElementMiddle();
  199. var first = i == 0;
  200. if (candidate === false) {
  201. if (first)
  202. alert('No overlay has been found on this website.');
  203. break;
  204. } else {
  205. if (!first) {
  206. // Prevent to hide the actual content
  207. var weightThreshold = 100;
  208. var candidateWeight = utils.elementWeight(candidate, weightThreshold)
  209. if (candidateWeight < weightThreshold) {
  210. if (debug)
  211. console.log('Element is too lightweight, hide it', candidate);
  212. utils.hideElement(candidate);
  213. } else {
  214. if (debug)
  215. console.log("Element is too heavy, don't hide it", candidate);
  216. }
  217. } else {
  218. utils.hideElement(candidate);
  219. containersOverflowAuto();
  220. disableBlur();
  221. }
  222. }
  223. }
  224. }
  225.  
  226. return {
  227. run: run
  228. };
  229.  
  230. };
  231.  
  232. function enableCommandMenu() {
  233. var commandMenu = true;
  234. try {
  235. if (typeof(GM_registerMenuCommand) == undefined) {
  236. return;
  237. } else {
  238. if (commandMenu == true ) {
  239. GM_registerMenuCommand('Remove overlay', function() {
  240. overlayRemoverRun();
  241. });
  242. }
  243. }
  244. }
  245. catch(err) {
  246. console.log(err);
  247. }
  248. }
  249.  
  250. overlayRemoverInstance = overlayRemover(debug, utils);
  251.  
  252. function overlayRemoverRun() {
  253. overlayRemoverInstance.run();
  254. }
  255.  
  256. function keyPress(event) {
  257. if (event.ctrlKey && event.shiftKey && event.keyCode == 88) {
  258. overlayRemoverRun();
  259. }
  260. }
  261.  
  262. enableCommandMenu();
  263. document.addEventListener('keydown', keyPress);