diff --git a/package.json b/package.json index 69ac1f77..3c61969e 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.9.15", "type": "module", "private": true, - "description": "Hypertrons Chromium Extension for GitHub", + "description": "Hypertrons Chromium Extension for GitHub and other document websites", "license": "Apache", "engines": { "node": ">=16.14" diff --git a/src/pages/ContentScripts/features/fast-pr/index.tsx b/src/pages/ContentScripts/features/fast-pr/index.tsx index 50e355fb..2c661bfe 100644 --- a/src/pages/ContentScripts/features/fast-pr/index.tsx +++ b/src/pages/ContentScripts/features/fast-pr/index.tsx @@ -3,8 +3,10 @@ import { createRoot } from 'react-dom/client'; import features from '../../../../feature-manager'; import View from './view'; import i18n from '../../../../helpers/i18n'; + const featureId = features.getFeatureID(import.meta.url); const t = i18n.t; + interface MatchedUrl { filePath: string; repoName: string; @@ -14,6 +16,9 @@ interface MatchedUrl { verticalRatio: number; } +const CACHE_KEY = 'matchedUrlCache'; +const CACHE_EXPIRY = 60 * 60 * 1000; + const renderTo = ( container: HTMLElement, filePath: string, @@ -55,22 +60,47 @@ const init = async (matchedUrl: MatchedUrl | null) => { document.body.appendChild(container); } }; +const iframePostMessage = (command: string, matchedFun: string | null, url: string) => { + const iframeElement = document.getElementById('sandboxFrame') as HTMLIFrameElement; + if (iframeElement && iframeElement.contentWindow) { + iframeElement.contentWindow.postMessage({ command: command, matchedFun: matchedFun, url: url }, '*'); + } +}; +const checkCacheAndInit = (url: string) => { + const cachedData = localStorage.getItem(CACHE_KEY); + const currentTime = Date.now(); + if (cachedData) { + const { matchedFun, timestamp } = JSON.parse(cachedData); + if (currentTime - timestamp < CACHE_EXPIRY) { + iframePostMessage('useCachedData', matchedFun, url); + } else { + iframePostMessage('requestMatchedUrl', null, url); + } + return; + } + iframePostMessage('requestMatchedUrl', null, url); +}; + chrome.runtime.onMessage.addListener((message) => { if (message.type === 'urlChanged') { handleUrlChange(message.url); } }); + function handleUrlChange(url: string) { const existingContainer = document.getElementById(featureId); if (existingContainer) { existingContainer.remove(); } - const iframe = document.getElementById('sandboxFrame') as HTMLIFrameElement; - if (iframe && iframe.contentWindow) { - iframe.contentWindow.postMessage({ command: 'matchUrl', url: url }, '*'); - } + checkCacheAndInit(url); } + window.addEventListener('message', (event: MessageEvent) => { + if (event.data && event.data.matchedFun && event.data.isUpdated) { + const matchedFun = event.data.matchedFun; + const currentTime = Date.now(); + localStorage.setItem(CACHE_KEY, JSON.stringify({ matchedFun, timestamp: currentTime })); + } if (event.data && event.data.matchedUrl) { init(event.data.matchedUrl); } @@ -85,13 +115,8 @@ features.add(featureId, { iframe.style.display = 'none'; document.body.appendChild(iframe); iframe.onload = () => { - const currentUrl = window.location.href; - const iframeElement = document.getElementById('sandboxFrame') as HTMLIFrameElement; - setTimeout(() => { - if (iframeElement && iframeElement.contentWindow) { - iframeElement.contentWindow.postMessage({ command: 'matchUrl', url: currentUrl }, '*'); - } - }, 500); + const url = window.location.href; + checkCacheAndInit(url); }; }, }); diff --git a/src/pages/Sandbox/index.jsx b/src/pages/Sandbox/index.jsx index 94d891d8..ac90070e 100644 --- a/src/pages/Sandbox/index.jsx +++ b/src/pages/Sandbox/index.jsx @@ -3,35 +3,29 @@ import { FAST_PR_CONFIG_URL } from '../../constant'; import { createRoot } from 'react-dom/client'; const SandboxApp = () => { - useEffect(() => { - const fetchAndExecuteScript = () => { - fetch(FAST_PR_CONFIG_URL) - .then((response) => response.text()) - .then((scriptContent) => { - const func = new Function(scriptContent); - func(); - }); - }; - - fetchAndExecuteScript(); - - // Set a timer to run once per hour - const intervalId = setInterval( - () => { - fetchAndExecuteScript(); - }, - 60 * 60 * 1000 - ); - - return () => clearInterval(intervalId); - }, []); - useEffect(() => { const handleMessage = (event) => { - const { command, url } = event.data; - if (command === 'matchUrl') { - const matchedUrl = window.matchFastPrUrl(url); - event.source.postMessage({ matchedUrl }, event.origin); + const data = event.data; + const command = data.command; + const url = data.url; + let matchedFun = data.matchedFun; + if (command === 'requestMatchedUrl') { + fetch(FAST_PR_CONFIG_URL) + .then((response) => response.text()) + .then((scriptContent) => { + matchedFun = scriptContent; + const func = new Function(matchedFun); + func(); + const matchedUrl = window.matchFastPrUrl(url); + event.source.postMessage({ matchedUrl, matchedFun: matchedFun, isUpdated: true }, event.origin); + }); + } else { + if (matchedFun) { + const func = new Function(matchedFun); + func(); + const matchedUrl = window.matchFastPrUrl(url); + event.source.postMessage({ matchedUrl, matchedFun: matchedFun, isUpdated: false }, event.origin); + } } };