Build Your Own Chrome Extension – Part 2

Share this article

Hello, and welcome to Part 2 of our Build your own Chrome Extension tutorial! In the previous instalment of this series we created a simple Google Chrome extension that adds a persistent word counter to your open Google Documents. Our extension detects when it’s in the context in which it should activate, and periodically runs that part of itself which helps it count the number of words in the document. While not very accurate, it was a decent and usable first version which served its original purpose well. Now let’s have a look at how we can improve it slightly. In this part of the series, we’ll update the manifest file, add a page counter, add some precision to the word counter and last but not least completely remove jQuery and replace it with vanilla JavaScript. Let’s get started!

Updating the Manifest File

As pointed out by Michael in the previous instalment’s comments section, and Mohamed Mansour in my Google+ post, Google is gradually phasing out support for manifest v1 files. The manifest files, as previously mentioned, are files that describe to Chrome what an extension does, how it does it, and whether or not it should be allowed to do something. The directives in these files often change with new versions as the web develops and Google Chrome adds new developer features, so in order to keep our extension “marketable” on the Chrome Web Store, we need to add the following line anywhere in our manifest file:
 "manifest_version" : 2, 
I added it immediately under the “version”. While we’re at it, let’s bump up the version value to 0.2. The new version of the manifest, however, has some additional requirements. We now need to list all the resources we’ll be loading “on the side” in a web_accessible_resources key. Without it, our statusbar.html won’t load and will throw the error “Denying load of chrome-extension://…/statusbar.html. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by web pages.” To avoid this, we simply add the following content to our manifest file:
 "web_accessible_resources" : ["statusbar.html"] 
That’s it! If you try reloading the extension now (as per part one), everything should go as expected and no warnings should be shown.

Adding a Page Counter

We learned last time that the “row” element in a Google document is a span with the class “kix-lineview-text-block”. Upon further inspection, we learn that the element that contains the actual page is, predictably, a div with the class “kix-page”. As such, it should be no trouble at all adding a page counter to our word counter. Change the content of the countWords() method in main.js to the following:
var pageCount = $('div.kix-page').length; 
var wordCount = 0; 
$('span.kix-lineview-text-block').each(function(i, obj){ 
  wordCount += $(obj).text().split(/s+/).length; 
}); 
$('span#GDWC_wordsTotal').text(pageCount + ' pages, ' + wordCount + ' total words'); 
timeout = setTimeout('countWords()', 5000); 
As you can see, we’ve added a new variable, pageCount. Since there’s nothing to break apart and the elements are already defined as pages, all we have to do is count them by using the length property. We then simply prepend the “page number” message to our “total words” message, and we’re set. Feel free to reload the extension and give it a go.

Adding Precision to the Word Counter

You may have noticed that our word counter uses a simple space to break apart strings and figure out word counts. Let’s make it slightly more precise by changing this line of the countWords()
function:
wordCount += $(obj).text().split(/s+/).length; 
to
words = $(obj).text().match(/S+/g); 
wordCount += words && 
words.length || 0; 
Instead of splitting, which would count inaccurately unless the document ended in a space character, we now globally match every series of non-space characters. This means every character that is not a whitespace character is being interpreted as a word, which is a little bit closer to the human definition of “word” as well. It is important to note that Google Docs loads content dynamically: that is, only on request. Thus, when you first start up a document that has some content in it already, first scroll through it all and return to the top, so that the browser receives the entire document’s data. But what if we wanted to exclude punctuation and other symbols from triggering a word count increment as well? All those “…”, commas, periods and runaway apostrophes might offset the proper count and we’d be better off without them. Let’s replace the line
words = $(obj).text().match(/S+/g); 
with
var words = $(obj).text().replace(/W+/g, ' ').match(/S+/g); 
What we did there was replace every set of one or more non-alphanumeric characters with a single space. This means “…” and “###” become a single space, just like commas, periods and other symbols, thus not counting as words. While this does add precision in removing trash characters, it removes some precision in counting strings such as dates. For example, 1998.03.05 will become 1998 03 05, thus counting as three words. This introduces some new difficulties which we might tackle in the next installment. For now, let’s leave it at this.

Removing jQuery

While this isn’t as important for Chrome Extensions as it is for websites since all the files are downloaded to the client and kept there (there is no remote downloading of jQuery every time you run the extension), removing jQuery will decrease our file size and memory footprint slightly and allow us to look at some alternative JavaScript syntax. Also, since we don’t need the backwards compatibility and cross-browser operability of jQuery due to building this extension only for Google Chrome, having its entire functionality is kind of an overkill. Since main.js is our only file that contains jQuery, let’s open it now and start with the very first command — the ajax call to our statusbar.html file. Change
 $.get(chrome.extension.getURL("statusbar.html"), {}, function(data) {$('body').append(data);}, 'html'); 
to
var xhReq = new XMLHttpRequest(); 
xhReq.onreadystatechange = function onSumResponse() { 
  if (xhReq.readyState == 4) { 
    var serverResponse = xhReq.responseText; 
    var body = document.getElementsByTagName("body")[0]; 
    var div = document.createElement('div'); 
    div.innerHTML = serverResponse; 
    body.appendChild(div); 
  } 
} 
xhReq.open("GET", chrome.extension.getURL("statusbar.html"), true); 
xhReq.send(null);
Hmm, we turned an extremely simple line of code into a mess. Or did we? This is basically what our previous code did — it merely served as a wrapper for a call identical to this one. So while this is a little bit more code, in retrospect it actually causes less code to be run because there’s no overhead of calling jQuery which in turn needs to decide which XHR wrapper to call next, etc. So what does this mess do? First, it instantiates an XMLHttpRequest, which is a JS object “used to send HTTP or HTTPS requests directly to a web server and load the server response data directly back into the script”. Essentially, it’s the thing that performs the Ajax call. We then make sure that when its readyState property changes to 4 (ready), it fetches the text of our response (our statusbar), injects it into an empty div and appends this div to the end of “body”. Finally, we start the request with open() and send(). Let’s turn our focus to checking if the document is ready for use now. Replace
$(document).ready(function(){ 
  countWords(); 
});
with
var readyStateCheckInterval = setInterval(function() { 
  if (document.readyState === "complete") { 
    countWords(); 
    clearInterval(readyStateCheckInterval); 
  } 
}, 10);
This snippet removes jQuery’s method of checking if the document is ready for manipulation, and creates an interval check that checks whether or not the document is ready every 10ms. Once it detects that it is, it calls countWords(), clears the interval and the checking stops. Now, let’s see what we can do about the pageCount variable. Replace
var pageCount = $('div.kix-page').length; 
with
var pageCount = 0; 
var divs = document.getElementsByTagName('div'), i; 
for (i in divs) { 
  if((" " + divs[i].className + " ").indexOf(" kix-page ") > -1) { pageCount++; } 
}
This fetches all the divs in a website and sees if their class property contains ours. Now let’s replace the jQuery span loop which word-counted the lines with a home-made one. Replace
$('span.kix-lineview-text-block').each(function(i, obj){ 
  var words = $(obj).text().replace(/W+/g, ' ').match(/S+/g); 
  wordCount += words && 
  words.length || 0; 
});
with
var spans = document.getElementsByTagName('span'), i; 
for (i in spans) { 
  if((" " + spans[i].className + " ").indexOf(" kix-lineview-text-block ") > -1) { 
    var words = spans[i].innerText.replace(/W+/g, ' ').match(/S+/g); 
    wordCount += words && 
    words.length || 0; 
  } 
}
Finally, we can replace
$('span#GDWC_wordsTotal').text(pageCount + ' pages, ' + wordCount + ' total words');
with
document.getElementById('GDWC_wordsTotal').innerText = pageCount + ' pages, ' + wordCount + ' total words';
… to actually display the message without jQuery. Of course, we also need to remove the loading of jQuery from the extension manifest, so change
"js": ["jq.js","main.js"],
into
"js": ["main.js"],
and feel free to delete the jq.js file.

Conclusion

In this, the second part of a three-part series on creating a Google Chrome extension, we took a look at how to modify our extension slightly in order to make it perform faster and bring it up to Google’s newest development standards. We added some precision to our word counter, implemented a page counter along side the word count, brought the manifest file up to date with some new required directives and a version declaration and we undertook the gargantuan task of converting our jQuery code to vanilla JavaScript, thus gaining on speed, memory usage and reduced file size. In the next and last instalment of this series, we’ll further upgrade the performance of our extension and add some more helpful functionality to the statusbar itself. Stay tuned!

Frequently Asked Questions (FAQs) about Building Your Own Chrome Extension

How can I install the Word Counter Plus extension on my Chrome browser?

To install the Word Counter Plus extension, you need to visit the Chrome Web Store. Search for ‘Word Counter Plus’ in the search bar. Once you find it, click on the ‘Add to Chrome’ button. A pop-up window will appear asking for confirmation. Click on ‘Add extension’ and the extension will be added to your Chrome browser. You can see it in the top right corner of your browser.

What is the purpose of the Word Counter Max for Google Docs?

The Word Counter Max for Google Docs is a tool that helps you count the number of words in your Google Docs document. It is especially useful for writers, students, and professionals who need to keep track of their word count for various reasons such as meeting word limit requirements for essays, articles, reports, and more.

How does the Word Counter extension work?

The Word Counter extension works by analyzing the text on your webpage or document. Once you’ve installed the extension, you can simply highlight the text you want to count, right-click, and select ‘Word Counter’ from the context menu. The extension will then display the number of words and characters in the selected text.

Can I use the Word Counter extension on other browsers?

The Word Counter extension is primarily designed for Google Chrome. However, there are similar extensions available for other browsers like Firefox and Safari. You can search for ‘Word Counter’ in their respective extension or add-on stores.

Is the Word Counter extension free to use?

Yes, the Word Counter extension is free to use. You can download and install it from the Chrome Web Store without any charges. However, some extensions may offer premium features for a fee.

How accurate is the Word Counter extension?

The Word Counter extension is highly accurate. It counts every word and character in the selected text, including spaces and punctuation marks. However, it may not count words or characters embedded in images or other non-text elements.

Can I use the Word Counter extension offline?

Yes, you can use the Word Counter extension offline. Once installed, it works locally on your computer and does not require an internet connection to function.

Does the Word Counter extension support other languages?

Yes, the Word Counter extension supports multiple languages. It can count words and characters in any language that uses spaces to separate words.

Can I customize the Word Counter extension?

Some Word Counter extensions allow you to customize their settings. For example, you can choose to include or exclude spaces and punctuation marks in the count. Check the settings or options of your specific extension for customization options.

Is my data safe with the Word Counter extension?

Most Word Counter extensions do not store or transmit your data. They work locally on your computer and do not send your text to any servers. However, it’s always a good idea to check the privacy policy of the specific extension you’re using.

Bruno SkvorcBruno Skvorc
View Author

Bruno is a blockchain developer and technical educator at the Web3 Foundation, the foundation that's building the next generation of the free people's internet. He runs two newsletters you should subscribe to if you're interested in Web3.0: Dot Leap covers ecosystem and tech development of Web3, and NFT Review covers the evolution of the non-fungible token (digital collectibles) ecosystem inside this emerging new web. His current passion project is RMRK.app, the most advanced NFT system in the world, which allows NFTs to own other NFTs, NFTs to react to emotion, NFTs to be governed democratically, and NFTs to be multiple things at once.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week