Add an 'estimated time to read' to your blog post in Javascript

02 October 2017
|
5 min read
|
Jump to guide

While building this site, I had to come up with different ways to approach the features I might need. Since I've built this in Umbraco, there wasn't really any out-of-the-box solution for a blog system with categories, tags and featured images etc.

Sure there are some great Umbraco packages in the community but if given the choice I prefer to create the solution myself (I like to know what my code is doing).

So while building this site I thought it might be a neat idea to have a 'How long will this blog take to read' feature. While I created the solution in C# for this site, it led me to think 'what if I wanted a one size fits all solution I could run anywhere in the client?'. So that's what we'll do here today! Let's get started:

Depending on your current setup this may differ for you in many different ways. If you're already using a CMS (more than likely Wordpress) you're going to have your theme files set up in HTML and probably interspersed with some sort of server-side language that outputs your content (PHP probably). So you'll need to find the section of code that outputs your blog posts. If you're just doing this by following along you can just set up your own base HTML like the following:

<!doctype html>
<html>
   <head></head>
   <body>
      <div id="post-content"></div>
   </body>
</html>

You're basically looking for a parent div that contains all your post content. In the example above I'm using a div with the id "post-content". Similarly, in Wordpress you might find a class with the same name. It depends on the theme you are using, but if you root around you will find the right container without much trouble.

So let's populate our post with some dummy content:

<div id="post-content">
   <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu dui nunc. Phasellus ut velit lacus. Pellentesque malesuada ligula vitae nulla lacinia volutpat. Nulla a mi metus.</p>
</div>

And now to the script. Firstly, we need to get ahold of the content in our parent container. To do this we can do:

<script>
 var postContent = document.getElementById('post-content');
</script>

Or if it's a class name then:

var postContent = document.getElementsByClassName('post-content');

So now we have access to the post container, we need to get all the content. But what about all the HTML? p tags, img tags, maybe even uls and lis may all appear in our post content and we don't want to count those.

Luckily, there's a handy little method in Javascript that allows us to just get the text from the container like so:

var postContent = document.getElementsByClassName('post-content').textContent.trim(); .textContent gets us the text without any HTML tags or other fluff we might not need. .trim() will delete any white space at the beginning or the end of the string (as .textContent will include line breaks and indentations in your code).

Now we have the string in a variable we can start doing what we want to it. If we're going to count the amount of words in the string, logically we're going to need to count every time there's a space in the string and add 1 to it (as the last word won't count a space at the end).

If we're going to count the spaces in the string, we can do this with a lovely little for loop:

var postContent = document.getElementById('post-content').textContent.trim();
var wordCount = 0; //This is our counter. We can increment this by 1 everytime we find a space

 for (var i = 0; i < postContent.length; i++) { 
    //If we increment i until it reaches the length of the string we can then access each character in the string and test to see if it's a space or not 
    if (/\s/.test(postContent[i])) {
       //If the if condition returns true (meaning it is whitespace) then we add one to the word count
       wordCount++;
    }
 }
 //When the for loop gets to the end of the last word, there won't be another space to count the last word, so we can manually increment the counter by 1 to finish
 wordCount++;

If you now console out your wordCount variable it should have counted all the words in the string.

Now that we have the word count, we can start calculating how long it might take to read. http://www.readingsoft.com/ says that the average person reads about 200 words per minute. So, in theory, all we have to do is divide our word count by 200 to get the amount of minutes it would take to read the article.

So let's add that into the mix:

var postContent = document.getElementById('post-content').textContent.trim();
var wordCount = 0;
var wordsPerMinute = 200; //You can alter this if you want, but it's a good average to stick to
var timeToRead = 0; // Set up our time variable

for (var i = 0; i < postContent.length; i++) { 
   if (/\s/.test(postContent[i])) {
      wordCount++;
   }
}

wordCount++;

timeToRead = wordCount / wordsPerMinute; //Divide word count by words per minute

This is good, but still not great. We are more than likely going to get a decimal number each time we calculate this, which isn't going to look pretty. So ideally what we'd want to do is round the number up to the nearest 1. Maybe like this:

timeToRead = Math.ceil(timeToRead);

Now we've got the answer, what do we do with it? We want to display this to the user somehow. If you create yourself a div and style it up near the top of your post, you can then write your time out with the following:

<div id="word-count"></div>

<script>
   document.getElementById('word-count').innerHTML = timeToRead + " minutes to read";
</script>

And that's it! All together it looks like this:

<!doctype html>
<html>
   <head></head>
   <body>
      <div id="word-count"></div>

      <div id="post-content">
         <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque non turpis id urna imperdiet convallis. Duis maximus lorem quis ipsum finibus, egestas sodales mi dignissim.</p>
      </div>

      <script>
         var postContent = document.getElementById('post-content').textContent.trim();
         var wordCount = 0;
         var wordsPerMinute = 200;
         var timeToRead = 0;

         for (var i = 0; i < postContent.length; i++) { 
            if (/\s/.test(postContent[i])) {
               wordCount++;
            }
         }

         wordCount++;

         timeToRead = wordCount / wordsPerMinute;

         timeToRead = Math.ceil(timeToRead);

         document.getElementById('word-count').innerHTML = timeToRead + " minutes to read";
      </script>
   </body>
</html>

One last thing:

Now if want to go really pro with this, why don't we create ourselves a function that can be reused whereever we like?

function wordCount(settings) {
   var wordCount = 0;
   var timeToRead = 0;
   var wordsPerMinute = settings.wordsPerMinute;
   var postContent = document.getElementById(settings.postContainerId).textContent.trim();

   for (var i = 0; i < postContent.length; i++) { 
      if (/\s/.test(postContent[i])) {
         wordCount++;
      }
   }

   wordCount++;
   timeToRead = wordCount / wordsPerMinute;
   timeToRead = Math.ceil(timeToRead);

   return timeToRead;
 }

And its use:

var readTime = wordCount({
   wordsPerMinute: 200,
   postContainerId: "post-content"
});

document.getElementById('word-count').innerHTML = readTime + " minutes to read";