diff --git a/packages/shim/src/electron/remote/clipboard.js b/packages/shim/src/electron/remote/clipboard.js index d19aab9..28713ce 100644 --- a/packages/shim/src/electron/remote/clipboard.js +++ b/packages/shim/src/electron/remote/clipboard.js @@ -1,10 +1,18 @@ +import { getClipboard } from "./native-clipboard.js"; + export const clipboardShim = { readText() { return ""; }, writeText(text) { - navigator.clipboard.writeText(text).catch((e) => { + const clip = getClipboard(); + + if (!clip) { + return; + } + + clip.writeText(text).catch((e) => { console.warn("[shim:clipboard] writeText failed:", e); }); }, @@ -14,7 +22,13 @@ export const clipboardShim = { }, writeHTML(html) { - navigator.clipboard + const clip = getClipboard(); + + if (!clip) { + return; + } + + clip .write([ new ClipboardItem({ "text/html": new Blob([html], { type: "text/html" }), @@ -35,6 +49,12 @@ export const clipboardShim = { return; } + const clip = getClipboard(); + + if (!clip) { + return; + } + const pngData = image.toPNG(); if (!pngData || pngData.length === 0) { @@ -43,11 +63,9 @@ export const clipboardShim = { const blob = new Blob([pngData], { type: "image/png" }); - navigator.clipboard - .write([new ClipboardItem({ "image/png": blob })]) - .catch((e) => { - console.warn("[shim:clipboard] writeImage failed:", e); - }); + clip.write([new ClipboardItem({ "image/png": blob })]).catch((e) => { + console.warn("[shim:clipboard] writeImage failed:", e); + }); }, has(format) { @@ -59,6 +77,12 @@ export const clipboardShim = { }, clear() { - navigator.clipboard.writeText("").catch(() => {}); + const clip = getClipboard(); + + if (!clip) { + return; + } + + clip.writeText("").catch(() => {}); }, }; diff --git a/packages/shim/src/electron/remote/native-clipboard.js b/packages/shim/src/electron/remote/native-clipboard.js new file mode 100644 index 0000000..086936c --- /dev/null +++ b/packages/shim/src/electron/remote/native-clipboard.js @@ -0,0 +1,22 @@ +// Obsidian points navigator.clipboard.writeText at electron.clipboard, which already points at this shim. +// To avoid recursion, use the untouched native prototype methods. +const proto = typeof Clipboard !== "undefined" ? Clipboard.prototype : null; + +// Returns a native-backed clipboard facade, or null in insecure (non-localhost http) contexts. +export function getClipboard() { + const clip = + typeof navigator !== "undefined" ? navigator.clipboard : undefined; + + if (!proto || !clip) { + console.warn( + "[shim:clipboard] clipboard API unavailable (insecure context?)", + ); + return null; + } + + return { + writeText: (text) => proto.writeText.call(clip, text), + write: (items) => proto.write.call(clip, items), + read: () => proto.read.call(clip), + }; +} diff --git a/packages/shim/src/electron/remote/window.js b/packages/shim/src/electron/remote/window.js index 1312d4d..7d62e37 100644 --- a/packages/shim/src/electron/remote/window.js +++ b/packages/shim/src/electron/remote/window.js @@ -1,3 +1,5 @@ +import { getClipboard } from "./native-clipboard.js"; + const currentWindowState = { title: "Obsidian", isMaximized: false, @@ -196,7 +198,13 @@ const currentWebContents = { document.execCommand("copy"); }, paste() { - navigator.clipboard + const clip = getClipboard(); + + if (!clip) { + return; + } + + clip .read() .then(async (items) => { const dt = new DataTransfer(); @@ -233,7 +241,13 @@ const currentWebContents = { }); }, pasteAndMatchStyle() { - navigator.clipboard + const clip = getClipboard(); + + if (!clip) { + return; + } + + clip .read() .then(async (items) => { for (const item of items) {