// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. function renderReadingTime(article) { // If we weren't provided an article, we don't need to render anything. if (!article) { return; } const text = article.textContent; /** * Regular expression to find all "words" in a string. * * Here, a "word" is a sequence of one or more non-whitespace characters in a row. We don't use the * regular expression character class "\w" to match against "word characters" because it only * matches against the Latin alphabet. Instead, we match against any sequence of characters that * *are not* a whitespace characters. See the below link for more information. * * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions */ const wordMatchRegExp = /[^\s]+/g; const words = text.matchAll(wordMatchRegExp); // matchAll returns an iterator, convert to array to get word count const wordCount = [...words].length; const readingTime = Math.round(wordCount / 200); const badge = document.createElement('p'); // Use the same styling as the publish information in an article's header badge.classList.add('color-secondary-text', 'type--caption'); badge.textContent = `⏱️ ${readingTime} min read`; // Support for API reference docs const heading = article.querySelector('h1'); // Support for article docs with date const date = article.querySelector('time')?.parentNode; // https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement (date ?? heading).insertAdjacentElement('afterend', badge); } renderReadingTime(document.querySelector('article')); const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { // If a new article was added. for (const node of mutation.addedNodes) { if (node instanceof Element && node.tagName === 'ARTICLE') { // Render the reading time for this particular article. renderReadingTime(node); } } } }); // https://developer.chrome.com/ is a SPA (Single Page Application) so can // update the address bar and render new content without reloading. Our content // script won't be reinjected when this happens, so we need to watch for // changes to the content. observer.observe(document.querySelector('devsite-content'), { childList: true });