DEV Community

Cover image for Creating the TurboReader browser extension
Chris Bongers
Chris Bongers

Posted on • Originally published at daily-dev-tips.com

Creating the TurboReader browser extension

So far, we have had a good mix of different elements. This article will show you how I made the turboReader browser extension.

For those unfamiliar with turbo reading, it's a concept where you modify words to be partially bold to increase reading speed. This concept is called Bionic reading.

Read more about Bionic reading.

In this article, I won't be using the API of bionic but instead opt for my scripted version of the output.

The result will be this fantastic extension that can work on any webpage.

Creating the TurboReader browser extension

Setting up the project

Let's first start by setting up the project. Our extension will power with the click of the options button.
So we will only need our manifest and background worker.

We'll start by creating a new folder and navigating to it.

mkdir turboReader && cd turboReader
Enter fullscreen mode Exit fullscreen mode

Once inside, open the project and start by adding the manifest.json file.

{
  "manifest_version": 3,
  "version": "1.0",
  "name": "TurboReader",
  "description": "Become a faster reader with TurboReader",
  "action": {},
  "icons": {
    "48": "icons/icon-48.png"
  },
  "background": {
    "service_worker": "background.js"
  },
  "permissions": [ "activeTab", "scripting"]
}
Enter fullscreen mode Exit fullscreen mode

As you can see, we use manifest version 3.
Then we also define an empty action object, which is needed to attach handlers to the action icon.
And we set our background worker to a file called background.js.
Lastly, we'll need permissions to inject scripting on the active tab.

Let's go ahead and create the background.js file.
First, we'll need to add the action that fires on clicking the options button.

chrome.action.onClicked.addListener(async () => {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    function: turboMode,
  });
});
Enter fullscreen mode Exit fullscreen mode

Here, we fetch the active tab and inject a function called turboMode.

Now go ahead and create the turboMode function.

const turboMode = () => {
  // Our function
};
Enter fullscreen mode Exit fullscreen mode

Creating the turbo reading mode function

To achieve this function, we first need to retrieve all paragraphs on the page.

const paragraphs = document.getElementsByTagName('p');
Enter fullscreen mode Exit fullscreen mode

Then we want to ensure we are not yet in turbo reading mode. We'll do this by checking if a specific class is added to the body.

const isTurboMode = document.body.classList.contains('trms');
Enter fullscreen mode Exit fullscreen mode

Then we can loop over each paragraph and do something with each one.

for (const paragraph of paragraphs) {
  if (isTurboMode) {
    // Turbo mode is one
  } else {
    // Turbo mode is off
  }
}
Enter fullscreen mode Exit fullscreen mode

If turbo mode is on, we should return the paragraphs to their original form.
We'll do that by replacing the innerText with its non-html version.

paragraph.innerText = paragraph.innerText;
Enter fullscreen mode Exit fullscreen mode

Note: side effect could cause existing bold/italic markup to be removed. πŸ˜…

If we are not in turbo mode, we should take the text for each paragraph and split it by word.
Then we'll map each word and eventually return them with a space in between.

paragraph.innerHTML = paragraph.innerText
  .split(' ')
  .map((word) => {
    // Each word
  })
  .join(' ');
Enter fullscreen mode Exit fullscreen mode

Now comes the fun part. We must evaluate which part of the word we want to show in bold.

My thoughts here are that we can roughly make half the word bold.
To achieve that, we first need to determine the length of the word.

const length = word.replace(/[^a-zA-Z0-9]+$/, '').length;
Enter fullscreen mode Exit fullscreen mode

We can then get the length of the part we'll make bold. If the word is one letter, it should always become bold. Else we floor half of the length.

const boldLength = length === 1 ? 1 : Math.floor(length / 2);
Enter fullscreen mode Exit fullscreen mode

And then we return the word, but with the first half being bold.

return `<strong>${word.substring(0, boldLength)}</strong>${word.substring(
  boldLength
)}`;
Enter fullscreen mode Exit fullscreen mode

The last part outside of the loop is to add a body class determining if we are in turbo mode or not.

isTurboMode
  ? document.body.classList.remove('trms')
  : document.body.classList.add('trms');
Enter fullscreen mode Exit fullscreen mode

And that's it. Our full function will now look like this:

const turboMode = () => {
  const paragraphs = document.getElementsByTagName('p');
  const isTurboMode = document.body.classList.contains('trms');
  for (const paragraph of paragraphs) {
    if (isTurboMode) {
      paragraph.innerText = paragraph.innerText;
    } else {
      paragraph.innerHTML = paragraph.innerText
        .split(' ')
        .map((word) => {
          const length = word.replace(/[^a-zA-Z0-9]+$/, '').length;
          const boldLength = length === 1 ? 1 : Math.floor(length / 2);
          return `<strong>${word.substring(
            0,
            boldLength
          )}</strong>${word.substring(boldLength)}`;
        })
        .join(' ');
    }
  }

  isTurboMode
    ? document.body.classList.remove('trms')
    : document.body.classList.add('trms');
};
Enter fullscreen mode Exit fullscreen mode

You can also find the completed code in this GitHub repo.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Top comments (1)

Collapse
 
bionicscript profile image
bionicscript

I know a tools that convert plain text to bionic text: bionicscript.com/