mirror of
https://github.com/Nystik-gh/ignis.git
synced 2026-06-17 04:35:53 +00:00
clipboard fixes
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -2,6 +2,17 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.7.2] - Orm (2026-03-29)
|
||||
|
||||
### Added
|
||||
|
||||
- utils shim
|
||||
|
||||
### Fixed
|
||||
|
||||
- right sidebar toggle with css overrides
|
||||
- clipboard functionality
|
||||
|
||||
## [0.7.1] - Orm (2026-03-29)
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ignis",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.2",
|
||||
"private": true,
|
||||
"description": "An Electron shim and server bridge for running Obsidian in a browser.",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "ignis-bridge",
|
||||
"name": "Ignis Bridge",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.2",
|
||||
"minAppVersion": "1.12.4",
|
||||
"description": "Additional Ignis specific functionality and ignis plugin management.",
|
||||
"author": "Nystik",
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { ipcRenderer } from "./ipc-renderer.js";
|
||||
import { webFrame } from "./web-frame.js";
|
||||
import { remoteShim } from "./remote/index.js";
|
||||
import { nativeImageShim } from "./remote/native-image.js";
|
||||
import { clipboardShim } from "./remote/clipboard.js";
|
||||
|
||||
export const electronShim = {
|
||||
ipcRenderer,
|
||||
webFrame,
|
||||
remote: remoteShim,
|
||||
nativeImage: nativeImageShim,
|
||||
clipboard: clipboardShim,
|
||||
|
||||
safeStorage: {
|
||||
isEncryptionAvailable() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// stub
|
||||
export const clipboardShim = {
|
||||
readText() {
|
||||
return "";
|
||||
@@ -15,7 +14,16 @@ export const clipboardShim = {
|
||||
},
|
||||
|
||||
writeHTML(html) {
|
||||
console.log("[shim:clipboard] writeHTML (stub)");
|
||||
navigator.clipboard
|
||||
.write([
|
||||
new ClipboardItem({
|
||||
"text/html": new Blob([html], { type: "text/html" }),
|
||||
"text/plain": new Blob([html], { type: "text/plain" }),
|
||||
}),
|
||||
])
|
||||
.catch((e) => {
|
||||
console.warn("[shim:clipboard] writeHTML failed:", e);
|
||||
});
|
||||
},
|
||||
|
||||
readImage() {
|
||||
@@ -23,7 +31,23 @@ export const clipboardShim = {
|
||||
},
|
||||
|
||||
writeImage(image) {
|
||||
console.log("[shim:clipboard] writeImage (stub)");
|
||||
if (!image || image.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pngData = image.toPNG();
|
||||
|
||||
if (!pngData || pngData.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
has(format) {
|
||||
|
||||
@@ -1,20 +1,83 @@
|
||||
function createImage(buffer, mimeType) {
|
||||
return {
|
||||
_buffer: buffer,
|
||||
_mimeType: mimeType || "image/png",
|
||||
|
||||
isEmpty() {
|
||||
return !buffer || buffer.length === 0;
|
||||
},
|
||||
|
||||
getSize() {
|
||||
return { width: 0, height: 0 };
|
||||
},
|
||||
|
||||
toPNG() {
|
||||
return buffer || new Uint8Array(0);
|
||||
},
|
||||
|
||||
toJPEG(quality) {
|
||||
return buffer || new Uint8Array(0);
|
||||
},
|
||||
|
||||
toDataURL() {
|
||||
if (!buffer || buffer.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const bytes =
|
||||
buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
||||
let binary = "";
|
||||
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
|
||||
return `data:${this._mimeType};base64,${btoa(binary)}`;
|
||||
},
|
||||
|
||||
toBitmap() {
|
||||
return buffer || new Uint8Array(0);
|
||||
},
|
||||
|
||||
getBitmap() {
|
||||
return buffer || new Uint8Array(0);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const nativeImageShim = {
|
||||
createFromBuffer(buffer) {
|
||||
return {
|
||||
isEmpty: () => !buffer || buffer.length === 0,
|
||||
getSize: () => ({ width: 0, height: 0 }),
|
||||
toPNG: () => buffer || new Uint8Array(0),
|
||||
toJPEG: (quality) => buffer || new Uint8Array(0),
|
||||
toDataURL: () => "",
|
||||
};
|
||||
createFromBuffer(buffer, options) {
|
||||
return createImage(buffer, options?.mimeType);
|
||||
},
|
||||
|
||||
createFromPath(filePath) {
|
||||
// TODO: could fetch from server and create image
|
||||
return nativeImageShim.createFromBuffer(new Uint8Array(0));
|
||||
return createImage(new Uint8Array(0));
|
||||
},
|
||||
|
||||
createEmpty() {
|
||||
return nativeImageShim.createFromBuffer(new Uint8Array(0));
|
||||
return createImage(new Uint8Array(0));
|
||||
},
|
||||
|
||||
createFromDataURL(dataURL) {
|
||||
if (!dataURL || !dataURL.startsWith("data:")) {
|
||||
return createImage(new Uint8Array(0));
|
||||
}
|
||||
|
||||
const parts = dataURL.split(",");
|
||||
const mimeMatch = parts[0].match(/data:([^;]+)/);
|
||||
const mimeType = mimeMatch ? mimeMatch[1] : "image/png";
|
||||
|
||||
try {
|
||||
const binary = atob(parts[1]);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
|
||||
for (let i = 0; i < binary.length; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
|
||||
return createImage(bytes, mimeType);
|
||||
} catch {
|
||||
return createImage(new Uint8Array(0));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -196,10 +196,58 @@ const currentWebContents = {
|
||||
document.execCommand("copy");
|
||||
},
|
||||
paste() {
|
||||
document.execCommand("paste");
|
||||
navigator.clipboard
|
||||
.read()
|
||||
.then(async (items) => {
|
||||
const dt = new DataTransfer();
|
||||
let hasFiles = false;
|
||||
|
||||
for (const item of items) {
|
||||
for (const type of item.types) {
|
||||
const blob = await item.getType(type);
|
||||
|
||||
if (type.startsWith("text/")) {
|
||||
const text = await blob.text();
|
||||
dt.items.add(text, type);
|
||||
} else {
|
||||
const ext = type.split("/")[1] || "bin";
|
||||
dt.items.add(
|
||||
new File([blob], `pasted-image.${ext}`, { type }),
|
||||
);
|
||||
hasFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pasteEvent = new ClipboardEvent("paste", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clipboardData: dt,
|
||||
});
|
||||
|
||||
const target = document.activeElement || document.body;
|
||||
target.dispatchEvent(pasteEvent);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.warn("[shim:webContents] paste failed:", e);
|
||||
});
|
||||
},
|
||||
pasteAndMatchStyle() {
|
||||
document.execCommand("paste");
|
||||
navigator.clipboard
|
||||
.read()
|
||||
.then(async (items) => {
|
||||
for (const item of items) {
|
||||
if (item.types.includes("text/plain")) {
|
||||
const blob = await item.getType("text/plain");
|
||||
const text = await blob.text();
|
||||
document.execCommand("insertText", false, text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.warn("[shim:webContents] pasteAndMatchStyle failed:", e);
|
||||
});
|
||||
},
|
||||
replaceMisspelling(word) {},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user