diff --git a/package.json b/package.json index ee4aceb..1bbbf09 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "scripts": { "build": "webpack --mode=production && sass src/scss/docs.scss build/docs.bundle.css && sass src/scss/frame.scss build/frame.bundle.css && sass src/scss/global.scss build/global.bundle.css && web-ext lint --source-dir=build && ts-node package.ts", "check": "prettier --check . && eslint src && stylelint '**/*.scss'", - "dev": "concurrently --names 'webpack,sass,sass,sass' --prefix-colors 'magenta,red,blue,yellow' 'webpack --watch' 'sass --watch src/scss/docs.scss build/docs.bundle.css' 'sass --watch src/scss/frame.scss build/frame.bundle.css' 'sass --watch src/scss/global.scss build/global.bundle.css'", + "dev": "concurrently --names 'webpack,sass,sass,sass' --prefix-colors 'magenta,red,blue,yellow' 'webpack --watch --mode=development' 'sass --watch src/scss/docs.scss build/docs.bundle.css' 'sass --watch src/scss/frame.scss build/frame.bundle.css' 'sass --watch src/scss/global.scss build/global.bundle.css'", "firefox": "web-ext run --source-dir build/ --keep-profile-changes", "fix:prettier": "prettier --write .", "fix:stylelint": "stylelint '**/*.scss' --fix" diff --git a/src/canvas.ts b/src/canvas.ts new file mode 100644 index 0000000..61f109e --- /dev/null +++ b/src/canvas.ts @@ -0,0 +1,27 @@ +import { Logger } from "./logger"; + +Logger.debug("Hello from ephemeral canvas script!"); + +const originalFillText = CanvasRenderingContext2D.prototype.fillText; + +CanvasRenderingContext2D.prototype.fillText = function (text, x, y, maxWidth) { + Logger.debug("fillText:", text, "at", x, y, { + fillStyle: this.fillStyle, + font: this.font, + }); + + // "this" sample: + // { + // "fillStyle": "#000000", + // "font": "14.6667px Arial" + // } + + // This is a crude conversion. Because the fillStyle could be any CSS color, + // a more robust solution should be used. + + if (this.fillStyle == "#000000") { + this.fillStyle = "#ffffff"; + } + + return originalFillText.call(this, text, x, y, maxWidth); +}; diff --git a/src/docs.ts b/src/docs.ts index 3bf2c4d..5a14ada 100644 --- a/src/docs.ts +++ b/src/docs.ts @@ -28,6 +28,7 @@ import { getElement, getElementId, getExtensionData, + insertEphemeralScript, insertStylesheet, isElementVisible, isOnHomepage, @@ -39,9 +40,9 @@ import { setStyleProperty, } from "./util"; -const browser_ns = getBrowserNamespace(); -const CURRENT_VERSION = browser_ns.runtime.getManifest().version; +const browserNamespace = getBrowserNamespace(); +const CURRENT_VERSION = browserNamespace.runtime.getManifest().version; const REPLACEMENTS_PATH = "assets/replacements/"; class DocsAfterDark { @@ -112,6 +113,19 @@ class DocsAfterDark { registerMessageListener(this.handleMessageUpdate); } + private updateCanvas() { + if (this.extensionData.mode == ExtensionMode.Dark) { + insertEphemeralScript("canvas.bundle.js"); + } else { + this.restoreCanvas(); + } + } + + private restoreCanvas() { + Logger.debug("Restoring canvas rendering functions"); + // TODO: Create and run canvas restoration script + } + private raiseButton(raise: boolean) { if (raise) { setStyleProperty("buttonPosition", buttonPosition.raised); @@ -333,8 +347,9 @@ class DocsAfterDark { } private updateExtension() { - // Always update version, regardless of extension mode - this.updateVersion(); + // Always update + this.updateVersion(); // Always show update notification + this.updateCanvas(); // Always update canvas rendering // Do not continue update if extension is off if (!this.updateMode()) { @@ -585,6 +600,7 @@ class DocsAfterDark { removeClassFromHTML(enabledClass); removeElement("stylesheet"); removeElement("button"); + this.restoreCanvas(); } } diff --git a/src/manifest.json b/src/manifest.json index 3a1b0aa..87eb84d 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -17,7 +17,7 @@ }, "web_accessible_resources": [ { - "resources": ["docs.bundle.css"], + "resources": ["docs.bundle.css", "canvas.bundle.js"], "matches": ["*://docs.google.com/*"] } ], diff --git a/src/util.ts b/src/util.ts index 41ce087..1e36470 100644 --- a/src/util.ts +++ b/src/util.ts @@ -256,6 +256,29 @@ function insertStylesheet(path: string, id: string): void { document.head.appendChild(link); } +function insertScript(path: string, id: string): void { + const elementId = getElementId(id); + + if (document.getElementById(elementId)) { + return; + } + + const script = document.createElement("script"); + script.id = elementId; + script.src = getAssetURL(path); + script.onload = () => script.remove(); + + document.head.appendChild(script); +} + +function insertEphemeralScript(path: string): void { + const script = document.createElement("script"); + script.src = getAssetURL(path); + script.onload = () => script.remove(); + + document.head.appendChild(script); +} + function getAssetURL(path: string): string { return browser_ns.runtime.getURL(path); } @@ -313,4 +336,6 @@ export { getAssetURL, isElementVisible, updateExtensionData, + insertScript, + insertEphemeralScript, }; diff --git a/webpack.config.cjs b/webpack.config.cjs index a8b059c..125ff66 100644 --- a/webpack.config.cjs +++ b/webpack.config.cjs @@ -4,63 +4,72 @@ const webpack = require("webpack"); const { execSync } = require("child_process"); const fs = require("fs"); -module.exports = (env, argv) => { - let commitHash = execSync("git rev-parse HEAD", { - encoding: "utf8", - }).trim(); +let commitHash = execSync("git rev-parse HEAD", { + encoding: "utf8", +}).trim(); - const packageJSON = JSON.parse(fs.readFileSync("package.json", "utf8")); +const packageJSON = JSON.parse(fs.readFileSync("package.json", "utf8")); - return { - mode: "production", - entry: { - docs: "./src/docs.ts", - popup: "./src/popup.ts", - }, - module: { - rules: [ +const config = { + entry: { + docs: "./src/docs.ts", + popup: "./src/popup.ts", + canvas: "./src/canvas.ts", + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: [".tsx", ".ts", ".js"], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + }, + plugins: [ + new CopyWebpackPlugin({ + patterns: [ { - test: /\.tsx?$/, - use: "ts-loader", - exclude: /node_modules/, + from: "src/popup.html", + to: "popup.html", }, - ], - }, - resolve: { - extensions: [".tsx", ".ts", ".js"], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - }, - plugins: [ - new webpack.DefinePlugin({ - // See: https://webpack.js.org/configuration/mode/ - __IS_PRODUCTION__: JSON.stringify(argv.mode === "production"), - __BUILD_DATE__: JSON.stringify(new Date().toISOString()), - __BUILD_COMMIT__: JSON.stringify(commitHash), - }), - new CopyWebpackPlugin({ - patterns: [ - { - from: "src/popup.html", - to: "popup.html", - }, - { - from: "src/manifest.json", - to: "manifest.json", - transform(content, path) { - const manifest = JSON.parse(content.toString()); - manifest.version = packageJSON.version; - return JSON.stringify(manifest, null, 2); - }, - }, - { - from: "src/assets", - to: "assets", + { + from: "src/manifest.json", + to: "manifest.json", + transform(content, path) { + const manifest = JSON.parse(content.toString()); + manifest.version = packageJSON.version; + return JSON.stringify(manifest, null, 2); }, - ], - }), - ], - }; + }, + { + from: "src/assets", + to: "assets", + }, + ], + }), + ], +}; + +module.exports = (env, argv) => { + if (argv.mode === "development") { + config.devtool = "source-map"; + } + + config.plugins.push( + new webpack.DefinePlugin({ + // See: https://webpack.js.org/configuration/mode/ + __IS_PRODUCTION__: JSON.stringify(argv.mode === "production"), + __BUILD_DATE__: JSON.stringify(new Date().toISOString()), + __BUILD_COMMIT__: JSON.stringify(commitHash), + }) + ); + + return config; };