diff --git a/functional-samples/tutorial.reading-time/README.md b/functional-samples/tutorial.reading-time/README.md index 361cf903..26547cc9 100644 --- a/functional-samples/tutorial.reading-time/README.md +++ b/functional-samples/tutorial.reading-time/README.md @@ -6,6 +6,8 @@ This sample demonstrates how to run scripts on any Chrome extension and Chrome W This sample demonstrates how developers can use content scripts which employ Document Object Models to read and change the content of a page. In this instance, the extension checks to find an article element, counts all the words inside of it, and then creates a paragraph that estimates the total reading time for that article. +As https://developer.chrome.com/ is a SPA (Single Page Application) it also includes an example of how to use `MutationObserver` to watch for changes to article content. Using `MutationObserver` can have a performance cost, so use them sparingly and only observe the most relevant changes. + ## Running this extension 1. Clone this repository. diff --git a/functional-samples/tutorial.reading-time/scripts/content.js b/functional-samples/tutorial.reading-time/scripts/content.js index 3df5db1e..cb6ec23a 100644 --- a/functional-samples/tutorial.reading-time/scripts/content.js +++ b/functional-samples/tutorial.reading-time/scripts/content.js @@ -12,10 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -const article = document.querySelector('article'); +function renderReadingTime(article) { + // If we weren't provided an article, we don't need to render anything. + if (!article) { + return; + } -// `document.querySelector` may return null if the selector doesn't match anything. -if (article) { const text = article.textContent; /** * Regular expression to find all "words" in a string. @@ -45,3 +47,25 @@ if (article) { // 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 +});