6♠ – Make a Chrome extension

There is a dirty little secret in programming and it is called stackoverflow.com. What (non-programming) people don’t realize is that for a lot of things you don’t actually have to know to code or to know a specific programming language to actually make something in it. What helps is knowing some basic programming principles and programming logic and with that, you can just go to stackoverflow, find the solution for your problem and adjust it to fit your needs. More about that in the boring stuff.

The good thing about making stuff is that you can always go back to them and improve them. This is actually the second variation of this extension. I made the first one during quarantine because I was tired of seeing the name of the Serbian president everywhere on social media but it wasn’t working that well so I never even told my friends about it. It did remove his name but not on dynamically loaded content which is the most common case on social media so I’ve put it aside to improve it some other time and this project seemed like a great opportunity to revisit it.

Unfortunately, I forgot about the review process for Chrome extensions so when this post goes live, the new and improved version of the extension probably still won’t be live. But it will come soon HERE.

Boring stuff

I really don’t like Javascript. It’s a very personal and subjective opinion but I think it’s an ugly language and it’s my least favorite language to code in. That being said, when you’re working with stuff on the web, sometimes you just can’t avoid it. But, that is where stackoverflow comes to the rescue.

The first version was really easy because there are detailed tutorials on how to make chrome extensions for swapping words. But those solutions never worked on dynamically loaded content so I did what you do in those situations – I googled it. This is the solution I started from and then I adjusted it to do what I needed it to do. You don’t have to know how to write the code, but you need to at least understand it so you can adapt it to your needs and you need to know how to search for the things you don’t know. The consequences are that the code you get this way will almost never be as good or as efficient as it would be if you knew what you were doing, but if you’re making something for personal use, it mostly doesn’t even matter.

The Serbian language came with it’s own difficulties. First, there is a lot of grammatical cases (padeži) and variations that words can have. And second, in Serbia we use two alphabets, Latin and Cyrillic. And f that wasn’t enough, we sometimes use the Latin alphabet with and sometimes without diacritics. So all that adds up to 47 different variations just for one name. I haven’t tested this but I can bet that this extension is not efficient at all.

I could go through code line by line and explain everything but almost nobody would care about that. But if someone is interested, please write to me and I’ll explain whatever you want to know. For everyone else, here’s code.

var nameVariations = [
  "Aleksandar Vučić", "Aleksandra Vučića", "Aleksandrom Vučićem", "Aleksandru Vučiću", "Vučiću", "Vučićevom", "Vučićevu", "Vučića", "Vučićem", "Vučićeva", "Vučićevoj", "Vučićevi", "Vučićeve", "Vučićev", "Vučić",
  "Aleksandar Vucic", "Aleksandra Vucica", "Aleksandrom Vučicem", "Aleksandru Vucicu", "Vucicu", "Vucicevom", "Vucicevu", "Vucica", "Vucicem", "Vuciceva", "Vucicevoj", "Vucicevi", "Vuciceve", "Vucicev", "Vucic",
  "Александар Вучић", "Александра Вучића", "Александром Вучићем", "Александру Вучићу", "Вучићу", "Вучићевом", "Вучићеву", "Вучића", "Вучићем", "Вучићева", "Вучићевој", "Вучићеви", "Вучићеве", "Вучићев", "Вучић", "Predsednik Srbije Aleksandar", "Председник Србије Александар"
]

var reNameVariations = new RegExp(nameVariations.join("|"), "gi");

var observer = new MutationObserver(onMutation);
observer.observe(document, {
  childList: true,
  subtree: true,
});

function onMutation(mutations) {
  for (var i = 0, len = mutations.length; i < len; i++) {
    var added = mutations[i].addedNodes;
    for (var j = 0, node; (node = added[j]); j++) {
        if (reNameVariations.test(node.textContent)) {
          replaceText(node);
        }
    }
  }
}

function replaceText(el) {
  const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
  for (let node; (node = walker.nextNode());) {
    const text = node.nodeValue;
    const newText = text.replace(reNameVariations, ''); //this is where you can change what to replace the name to
    //random example: const newText = text.replace(reNameVariations, 'Zvoncica');
    if (text !== newText) {
      node.nodeValue = newText;
    }
  }
}

var walker = document.createTreeWalker(
  document.body,
  NodeFilter.SHOW_TEXT, {
    acceptNode: function(node) {
      return NodeFilter.FILTER_ACCEPT;
    }
  },
  false
);

while (walker.nextNode()) {
  walker.currentNode.data = walker.currentNode.data.replace(reNameVariations, '');//If you want to replace the text, you need to change it here too
  //random example: walker.currentNode.data = walker.currentNode.data.replace(reNameVariations, 'Zvoncica');
}

To publish an extension in Chrome extension store, you don’t need much. You need your script, icons and manifest file. It’s not fresh in my memory but I remember that making a developer account for the store was a bit tricky. Other than that, it’s all pretty easy. In the future I’ll see if I can make this extension work for Opera and Firefox, but until then, it’s exclusive for Chrome.

{
  "name": "Delete Vučić",
  "version": "2.0",
  "description": "Deletes Vučić's name wherever he is mentioned'",
  "manifest_version": 2,

  "icons": { "16": "icon16.png",
           "48": "icon48.png",
          "128": "icon128.png" },

  "content_scripts":
  [
    {
      "matches": ["<all_urls>"],
      "all_frames": true,
      "js": ["content_script.js"],
      "run_at": "document_end"
    }
  ]
}

Fun fact, you can also change anything to anything with this code, you don’t have to use it only to delete a certain word. Here’s a random example of that:

Share:

Leave a Comment

Your email address will not be published. Required fields are marked *