The following is a step by step instruction for implementing reading minutes left for a particular article, blog, or similar, just like we see on medium.com.
The JS file
- I have used this JS library.
- Place this code in a JS file named read-remaining-minutes.js and place it in the corresponding theme.
(function($) {
$.fn.readingTimeLeft = function (options) {
var s = $.extend({}, {
stepSelector: '*',
wordPerMinute: 100,
eventName: 'timechange'
}, options);
var $this = $(this)
, $window = $(window)
, $steps = $this.find(s.stepSelector);
// For each step element, store the quantity of words to come
$steps.each(function (i, el) {
var textAhead = $steps.slice(i, $steps.length).text();
$(el).data('words-left', textAhead.trim().split(/\s+/g).length);
});
// Filters elements that are in viewport
$.fn.filterVisible = function () {
var wW = $window.width(), wH = $window.height();
return this.filter(function(i, e){
var rect = e.getBoundingClientRect();
return rect.top >= 0 && rect.right <= wW &&
rect.bottom <= wH && rect.left >= 0;
});
}
function throttle (fn, limit) {
var wait = false;
return function () {
if (wait) return;
fn.call(); wait = true;
setTimeout(function () { wait = false; }, limit);
}
};
var triggerOn = 'scroll.' + s.eventName + ' resize.' + s.eventName;
// Throttle updating to 50ms
$(window).on(triggerOn, throttle(function (e) {
var wordsLeft = $steps.filterVisible().last().data('words-left');
$this.trigger(s.eventName, wordsLeft / s.wordPerMinute);
}, 50));
// Destroy function
$this.on('destroy.readingTimeLeft', function (e) {
$(window).off(triggerOn);
$steps.removeData('words-left');
});
return $this;
};
}(jQuery))
Initialization and modification in custom JS
- Next in the template.php file for your corresponding theme, you need to add the above JS file for the particular content type. You can do something like this below:
if ($vars['node']->type == 'article'') {
drupal_add_js(drupal_get_path('theme','my_theme') . '/js/read-remaining-minutes.js');
}
- After you have told Drupal to add the JS file, through the above code, your JS code will be ready for the page.
- Now you need to specify where you want to add this functionality.
- For that, I have a custom JS named “my-custom-js-code.js” file, in this same theme itself, where I usually write all my custom JS. Here I will specify my custom JS code.
// Reading time left for a blog post
// #calculable-content is the id of the content on which we want to apply the calculation for reading time
$('#calculatable-content').readingTimeLeft()
.on('timechange', function(e, minutesLeft) {
if(isNaN(minutesLeft)) {
// .time-left is the class belonging to the read remaining div
$('.time-left').hide();
}
else {
// If less than 1 min remains then display "Content Finished" else show the minutes left
var text = Math.round(minutesLeft) < 1? $('.time-left').text('Content Finished') : $('.time-left').text(Math.round(minutesLeft) + ' min left');
$('.time-left').show();
}
})
$(window).trigger('scroll');
- Here I am considering that when the scroll reaches the end, it will show “Content Finished”. I will explain the id and the class used below.
Modifying .tpl.php
- We have placed our JS codes as needed. Now we need to link it to the class in HTML so that it appears on the page.
- I have a .tpl.php file which is responsible for rendering all the HTML content for the particular page named “custom-template.tpl.php”
- In this .tpl.php file, at the place where you want this read remaining minutes block of text to appear, you have to specify the HTML for it.
<div class="time-left qtip-link" title="Time remaining to finish reading the article"></div>
<article id="calculatable-content" class="article-body"><?php print $content['body'][0]['#markup']; ?></article>
- The time-left class is the wrapper class for the block, that is the entire block of the text itself.
- The id calculatable-content is what we are using to calculate the time left, which will dynamically change while you scroll through the page.
Implementing CSS
- We need to add a decent enough css so that it appears on the page without hurting the eyes!
- You can use the following css, using this will place the block of text at the right top section of the page.
.time-left {
position: fixed;
right: 0;
top: 176px;
padding: 10px 10px 10px 40px;
background: #068bb8;
color: #fff;
font-size: 15px;
line-height: 19px;
cursor: default;
border-bottom: 0px;
z-index: 999;
&:before {
content: url('../../../../../sites/all/themes/my_theme/images/time-left-white.png');
position: absolute;
top: 12px;
left: 15px;
@media screen and (max-width: 767px) {
top: 8px;
left: 10px;
}
}
@media screen and (max-width: 767px) {
padding: 6px 6px 6px 35px;
font-size: 12px;
}
}
Final approach
Now you just need to hit the cache clear, sit back and enjoy. Observe how the time changes as you scroll through the page!