Reading Time

5 minutes 46 seconds average read (1154 words)

So recently I've been building a blog for my partner and I've used Squiz Matrix to do so. I decided it would be a good idea to use my new found JavaScript skills to achieve this. When I finished it I showed it to one of the developers at Squiz and he said: "you know you can do that with Squiz Matrix Keyword Replacements and Modifiers?"

So here I'm going to detail how to achieve the Reading Time with both.

Part 1 Method

Throughout my learning of JavaScript through Wes Bos's course, I've learn that breaking the problem down into chunks makes it easier to solve, so using this I broke down the task into these blocks:

  1. Find out the Average Reading Speed, this varies on:
    1. the type of content, technical content takes longer than normal reading considerably
    2. the type of reading, skimming is way faster than reading for comprehension
    3. the readers ability, children read slower than adults, the language may not be the readers first language
    4. I've settled on 200 words per minute in this case, based on this post by the British Psychological Society.
  2. Count the words on the page and assign it to a numWords variable, I've chosen to use the <main> element for the words to count.
  3. Divide the numWords by WPM to work out the time.
  4. Round the time to 2 decimal places.
  5. Insert into the page:
    1. Time
    2. Word Count

Part 2 Using JavaScript

Average Reading Speed

Set a variable with the average reading speed of 200 WPM, this will be set as a const variable as it is not going to change.

const wordsPerMinute = 200;

Count words in the <main> element

Grab the content of the <main> element.

// grabs all the content in the &lt;main&gt; element
const content = document.querySelector('main'); 

Count the number of words in the content variable splitting it on spaces. This grabs the innerText from content, splits it into an array at each space and then outputs the length of the array, how many items are in the array.

// counts number of words in the content
const numWords = content.innerText.split(' ').length; 

Divide numWords by wordsPerMinute

Create a result variable to store the time in minutes, seconds and number of words, this is done with a let variable because later it will be updated.

// sets up a result to inject into the page
let result; 

check that the numWords is not 0 and that there are actually words on the page.

if(numWords > 0){ // checks to see that there is actuallt some content
   //code goes here to be run if numWords is greater than 0 (zero)
}

Create a let variable called time to store numWords divided by wordsPerMinute .

let time = numWords / wordsPerMinute;

Add the new variables to the result variable

Using backticks and interpolation to create the value of the result variable. In here I'm also rounding time to 2 decimal places using toFixed(2) .

result = `~${time.toFixed(2)} min read (${numWords} words)`;

Insert Result into the page

In the page I have a span element with the class reading-time .

<span class="reading-time"></span>

I am setting the innerText of that element to be the value of result variable.

document.querySelector('.reading-time').innerText = result;

Full code block

// grabs all the content in the element
const content = document.querySelector('main'); 
//counts number of words in the content
const numWords = content.innerText.split(' ').length; 
// Average reading speed.
const wordsPerMinute = 200; 
// sets up a result to inject into the page
let result; 
// checks to see that there is actually some content
if(numWords > 0){ 
  let time = numWords / wordsPerMinute;
  result = `~${time.toFixed(2)} min read (${numWords} words)`;
}
document.querySelector('.reading-time').innerText = result;

Part 3 Using Squiz Matrix Keyword Replacements and Modifiers

Count words in the <main> element

In Squiz Matrix, this is the contents of the asset, in the way I've built the blog so I can use the keyword %globals_asset_contents_raw% , this keyword shows just the contents with no Paint Layout applied, with the keyword modifier ^wordcount .

%globals_asset_contents_raw^wordcount%

Divide numWords by wordsPerMinute to get the minutes

This time I'm going to grab only the minutes and grab the seconds later. To do this I'm going to use ^divide and ^floor modifiers.

The ^divide modifier takes a number to divide by, and I'm using the WPM, so ^divide:200 .

The ^floor modifier rounds the number down to the integer, with on decimal places, hence giving us the minutes.

%globals_asset_contents_raw^wordcount^divide:200^floor%

Grab the remainder and convert to seconds

To achieve this I'm going to get the raw value of minutes as seen in the step previously without using ^floor and then ^subtract the minutes from it. This will give me a fraction of minutes, which I can then ^multiple by 60 to get the value in seconds.

Get full time

%globals_asset_contents_raw^wordcount^divide:200%

^Subtract minutes from it

Here I am subtracting the previous value using the ^subtract modifier, because I am inserting a keyword into another keyword I need to do this with curly brackets {} .

^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}
Full Keyword so far
%globals_asset_contents_raw^wordcount^divide:200%^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}

^multiply by 60 to get the seconds

Here I am ^multiply ing the value by 60 and then using the ^round keyword modifier to either round the number up or down to an integer.

^multiply:60^round

Full Keyword

%globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round%

Insert into the page

Now that I have everything I can insert it into the page, inside a <span class="reading-time"></span> element.

This will output minutesseconds word count, e.g. 2 minutes 30 seconds (500 words):

%globals_asset_contents_raw^wordcount^divide:200^floor% minutes %globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round%
 seconds read (%globals_asset_contents_raw^wordcount% words)

Conditions

I have decided to put in some conditions to check:

  1. if the minutes are greater than or equal to 1, if so show the minutes, if not only show the seconds
  2. if the number of minutes is greater than 1 add an 's' to the end of the word minute making it minutes

Number of minutes is Greater than or equal to 1

%begin_globals_asset_contents_raw^wordcount^divide:200^floor^gte:1%
  If True // show minutes and seconds
%else_globals_asset_contents%
  If False // show seconds only
%end_globals_asset_contents%

Number of seconds is Greater than 1

  minute // print the word minute
%begin_globals_asset_contents_raw^wordcount^divide:200^floor^gt:1%
  s // if there are more than 1 minute add an 's'
%end_globals_asset_contents% 

Full keywords with conditions

// Greater than or equal to 1 true
%begin_globals_asset_contents_raw^wordcount^divide:200^floor^gte:1% 
  %globals_asset_contents_raw^wordcount^divide:200^floor% minute
  // minutes greater than 1 true
  %begin_globals_asset_contents_raw^wordcount^divide:200^floor^gt:1% 
    s // print 's'
  %end_globals_asset_contents% 
  %globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round%
    seconds read // print seconds
// if less than 1 minute
%else_globals_asset_contents_raw% 
  %globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round% seconds read // print seconds
%end_globals_asset_contents_raw%
// print number of words
 (%globals_asset_contents_raw^wordcount% words)