mirror of
https://github.com/GoogleChrome/chrome-extensions-samples.git
synced 2026-03-27 13:29:34 +07:00
In the move to new infrastructure for https://developer.chrome.com/, the site became an SPA which can soft navigate outside of browser navigations. Therefore, we need to update the sample to watch for changes to content after the content script is injected.
72 lines
2.8 KiB
JavaScript
72 lines
2.8 KiB
JavaScript
// 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
|
|
});
|