9
\$\begingroup\$

I use this script to block access to a one or more websites with vanilla JavaScript. I find that it helps me avoid some addictive news websites that make me depressed. (Credit to Marat Tanalin for helping me with the event handling.)

The script is aimed to be an all vanilla JavaScript imperative small script for personal usage, hence it's not modular (there isn't a HTML/CSS/JS file distribution on purpose).

To use the script please change news_website_1.com to a given news website you hate.

My personal main problem with the script is that it doesn't block websites right away or almost right away such as happens with BlockSite Google Chrome extension:
For example, the script first loads a website, then about 5 seconds pass, then it gets blocked; for some reason, listening to the sooner DOMContentLoaded event sometimes works and sometimes doesn't and a reviewed version might show an improvement in that point.

How would you revise this script?

// ==UserScript==
// @name         New Userscript
// @match        *
// ==/UserScript==

window.addEventListener('load', ()=> {
  let sitesToBlock = [
      'news_website_1.com'
  ];
  let regexToMatchTLD = /\..+/;
  let href = window.location.href;
  for (let i = 0; i < sitesToBlock.length; i++) {
      if (href.includes(sitesToBlock[i])) {
          let domain = sitesToBlock[i].replace(regexToMatchTLD, '');
          document.body.innerHTML =`
              <div style="direction: ltr; position: fixed; top: 0; z-index: 999999; display: block; width: 100%; height: 100%; background: red">
                <p style="position: relative; top: 40%; display: block; font-size: 66px; font-weight: bold; color: #fff; margin: 0 auto; text-align: center">
                  The website ${domain} successfully blocked !
                </p>
              </div>
        `;
      }
  }
}, false);
\$\endgroup\$
0

2 Answers 2

5
+100
\$\begingroup\$

The main suggestion I have is to take the values from sitesToBlock and put them in the @match metadata key instead of detecting when to update the document content. There is an extensive guide about match patterns here. With this approach there should not be any need to wait for the DOM to be loaded and check if the URL contains elements in sitesToBlock, though maybe that “news_website_1” loads slower than the one I tested with and that won’t work.

Other review points:

  • default to using const instead of let when declaring variables unless re-assignment is mandatory. This helps avoid accidental re-assignment.
  • use for...of loops when possible- e.g. for iterating through sitesToBlock and there is no need for a counter variable (e.g. i) other than accessing the current element
  • <script> tags still executed - those tags outside the body tag (e.g. in the HTML <head> element, or anywhere else) are still executed so it might make sense to remove those, otherwise the execution of a script could modify the document body after the user script has finished updating the document body, which likely would be undesirable.

Below is the script as I would update it. I know the domain might include www or another sub-domain if the site redirects to one - I modified the regex to look specifically for a final dot followed by anything that isn’t a dot and an end of string anchor (i.e. $).

// ==UserScript==
// @name         page blocker
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  block pages
// @author       Sᴀᴍ Onᴇᴌᴀ
// @match        *://*.news_website_1.com/*
// @match        *://*.news_website_2.com/*
// @grant        none
// ==/UserScript==

(() => { //IIFE arrow function
    'use strict';

    const regexToMatchTLD = /\.[^.]+$/;
    const domain = location.hostname.replace(regexToMatchTLD, '');; 
    document.body.innerHTML =`
          <div style="direction: ltr; position: fixed; top: 0; z-index: 999999; display: block; width: 100%; height: 100%; background: red">
            <p style="position: relative; top: 40%; display: block; font-size: 66px; font-weight: bold; color: #fff; margin: 0 auto; text-align: center">
              The website ${domain} successfully blocked !
            </p>
          </div>
    `;
})();
\$\endgroup\$
8
  • \$\begingroup\$ Hello Sam; thanks for the review. Please share why you used use strict, I thought in ES6+ it is usually avoided on purpose (I don't know why exactly). Thanks, \$\endgroup\$
    – user125391
    Sep 21, 2019 at 23:54
  • 3
    \$\begingroup\$ @JohnDoea I tested my code in a greasemonkey script in opera and that was from the boilerplate. the ES6 spec specifies that certain code will be run in strict mode- I believe the fifth bullet would apply: “Function code is strict mode code if the associated ... ArrowFunction is contained in strict mode code or if the code that produces the value of the function’s [[ECMAScriptCode]] internal slot begins with a Directive Prologue that contains a Use Strict Directive. \$\endgroup\$ Sep 22, 2019 at 5:30
  • 1
    \$\begingroup\$ Hi, I suggested an edit that I think make it easier to read the answer - I also noted one section that wasn't clear to me - please feel free to reject or improve the edit... \$\endgroup\$
    – user125391
    Sep 22, 2019 at 8:53
  • 2
    \$\begingroup\$ It appears the community did not accept your edit - likely because it was seen as changing the structure of my review too much. I have expanded the section about the script tags. \$\endgroup\$ Sep 23, 2019 at 16:12
  • 1
    \$\begingroup\$ I updated my answer to have more context about that end of string anchor in the regex \$\endgroup\$ Sep 24, 2019 at 18:30
2
\$\begingroup\$

You can also explicitly run the script before the document loads by adding @run-at document-start to your userscript.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.