How I Built a Chrome Extension to Automate Clapping a Medium Article

Bashir
5 min readDec 29, 2020

--

Reading Medium articles is my main way of staying up to date with the current trends in Software Engineering. To show my appreciation for the authors, I usually clap an article 50 times (the maximum number of claps allowed by Medium). To clap an article 50 times you can either click on the clap button 50 times or click and hold the clap button until the clap count goes up to 50. This makes clapping an article 50 times a bit tedious so I decided to look into automating the process. I created a Chrome extension that allows me to clap an article once and the extension will do the remaining claps until the maximum clap of 50.

Chrome Extensions

Chrome extensions are lightweight programs that can be installed and run in the Chrome Browsers to add additional functionality to a website. There are many extensions out there that serve a variety of purposes, and to my surprise, they are very easy to design and implement. In fact, they are built using the same fundamental tools used to build a website: HTML, CSS, and JavaScript. Below is a walkthrough of how I built the Medium Clap.

The Medium Clap Extension

The first very important file that comes with every extension is the manifest.json. This file provides very important information about the extension such as the scope of where it can operate, permissions, and the file dependencies. For our Medium Clap extension, this is the content of the manifest.json file:

{
"manifest_version": 2,
"name": "Medium Clap",
"description": "This extension will allow you to give 50 claps to
any medium article with only one clap from your end",
"version": "1.0",
"icons": {
"16": "clap16.png",
"48": "clap48.png",
"128": "clap128.png"
},
"browser_action": { "default_popup": "popup.html" },
"content_scripts": [
{
"matches": ["*://*.medium.com/*"],
"js": ["content.js"]
}
],
"permissions": [ "activeTab" ]
}

From the manifest file above, we have the name, description, and version of our extension. We also have an entry for icons, where we are required to have three logos with the specified sizes required by the Chrome Store (16x16, 48x48, and 128x128 pixels). When choosing your logos make sure not to pick one that is fully black as this will not display well in browsers using dark mode. We also have an entry “browser_action” where you add the interface for the user to interact with our extension. For illustration purposes, we have added the default popup. If a user clicks on our extension icon, then a window will pop up and the HTML content for this window will be written in popup.html. If you want to give the user the option to customize the extension, then the files handling the user selection and interface will be listed in our “browser_action.”

In “content_scripts” we list the files that interact with the website the user is currently on. In our case, we don’t want to access any website, we only want our scripts to run when the user visits medium.com. So we specify our extension to only run when the URL matches the given pattern: “*://*.medium.com/*”.

In our manifest.json file, we listed under content_scripts the content.js file. This is the file where the main logic of our extension will go.

The Clapping Logic

I want to simulate a user clicking the clap button 50 times so to do that I have to carry out the following steps:

  1. Select the Medium clap button from the page
  2. Add an event listener to the clap button
  3. If a button is clicked once, then run a loop to click it 49 times (for a total of 50 times).

To select the clap button, we can do so using the following code:

let clapSVG = document.querySelector('[aria-label="clap"]')

the above code selects the SVG, but if we want to select the button itself we can simply append “.parentElement” to the above code as follow:

let clapButton = document.querySelector('[aria-label="clap"]').parentElement 

then for the second and third point, we can add an event listener to clapButton and click for 49 times as follow:

clapButton.addEventListener('click', ()=> {
for(let i =1; i < 50; i++){
clapButton.click()
}
}

The above code will certainly clap the article 50 times as expected, but it will not have the cool clap animation. I tried a few different ways but all seem to get rid of the clapping animations and I don’t have the best CSS skills to add my own animation so I decided to simulate a user clicking the clap button with the help of a timer (setInterval).

Simulate Mouse Click

To simulate a user clicking a particular element on a page, I used the following function :

function triggerMouseEvent (elem, eventType) { 
if(counter >= 100) clearInterval(timer)
var clickEvent = document.createEvent ('MouseEvents');
clickEvent.initEvent (eventType, true, true);
elem.dispatchEvent (clickEvent);
counter++; // a variable initialized to zero in the event listener
}

The function takes an element as well as an event type. For example, we can pass in the clap element we selected earlier and the event type “mousedown” and this function will simulate a mouse press down over the clap element. You can read more about dispatching events here if you are interested.

I then created a timer to call the triggerMouseEvent every 200ms until the counter is greater than 100 (corresponding to 50 clicks). The triggerMouseEvent function gets called twice, to simulate mouse down and mouse up events, hence the reason our counter must go to 100 and not 50.

timer = setInterval(() => {                                     
triggerMouseEvent(svg, 'mousedown')
triggerMouseEvent(svg, 'mouseup')
}, 200)

After adding the clapping logic to our content.js file, it was not working to my surprise. The reason for that is the content.js file runs within the scope of our extension and not the medium article the user is reading. We will have to ‘inject’ our script into the page if the user is on a medium website and this can be done in multiple ways but I chose to inject the script content into the header using the following code:

(document.head||document.documentElement).appendChild(myScript);

For the sake of completeness, this is the entire code for the manifest.js file.

//add event listener to the page 
var actualCode = '(' + function(){
document.addEventListener('click', (e) => {
try {
if(e.target.childNodes[0].getAttribute('aria-label')){
let svg = e.target.childNodes[0]
let counter = 1;
let timer;
//change style of clap svg to green
svg.style.fill="green"
svg.style.stroke="green"

function triggerMouseEvent (node, eventType) {
if(counter > 100) clearInterval(timer)
var clickEvent = document.createEvent ('MouseEvents');
clickEvent.initEvent (eventType, true, true);
node.dispatchEvent (clickEvent);
counter++;
}



timer = setInterval(() => {
triggerMouseEvent(svg, 'mousedown')
triggerMouseEvent(svg, 'mouseup')
}, 200)

}
} catch (error) {
//no need to console an error
}

})
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();

Look at the source code and please feel free to make a pull request to add additional functionality. Also, feel free to fork and make it your own 😀. I hope you enjoyed this blog!

--

--