mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 12:48:11 +08:00
Break out helper functions from the frontend's managers and stores (#3920)
* Move destructor call to each manager/store constructor for safety * Break out utility functions
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import { insertAtCaret, readAtCaret } from "@graphite/utility-functions/clipboard";
|
||||
|
||||
let editorRef: Editor | undefined = undefined;
|
||||
|
||||
export function createClipboardManager(editor: Editor) {
|
||||
destroyClipboardManager();
|
||||
|
||||
editorRef = editor;
|
||||
|
||||
editor.subscriptions.subscribeFrontendMessage("TriggerClipboardWrite", (data) => {
|
||||
@@ -28,89 +31,7 @@ export function destroyClipboardManager() {
|
||||
editor.subscriptions.unsubscribeFrontendMessage("TriggerSelectionWrite");
|
||||
}
|
||||
|
||||
function readAtCaret(cut: boolean): string | undefined {
|
||||
const element = window.document.activeElement;
|
||||
|
||||
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
||||
const start = element.selectionStart;
|
||||
const end = element.selectionEnd;
|
||||
|
||||
if ((!start && start !== 0) || (!end && end !== 0) || start === end) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const value = element.value;
|
||||
const selectedText = value.slice(start, end);
|
||||
|
||||
if (cut) {
|
||||
element.value = value.slice(0, start) + value.slice(end);
|
||||
|
||||
element.selectionStart = element.selectionEnd = start;
|
||||
element.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
}
|
||||
|
||||
return selectedText;
|
||||
}
|
||||
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const selectedText = String(selection);
|
||||
if (!selectedText) return undefined;
|
||||
|
||||
if (cut) {
|
||||
const range = selection.getRangeAt(0);
|
||||
range.deleteContents();
|
||||
|
||||
range.collapse(true);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
|
||||
return selectedText;
|
||||
}
|
||||
|
||||
function insertAtCaret(text: string) {
|
||||
const element = window.document.activeElement;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
||||
const start = element.selectionStart;
|
||||
const end = element.selectionEnd;
|
||||
|
||||
if ((!start && start !== 0) || (!end && end !== 0)) return;
|
||||
|
||||
const value = element.value;
|
||||
|
||||
element.value = value.slice(0, start) + text + value.slice(end);
|
||||
|
||||
const newPos = start + text.length;
|
||||
element.selectionStart = element.selectionEnd = newPos;
|
||||
} else if (element instanceof HTMLElement && element.isContentEditable) {
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0) return;
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
range.deleteContents();
|
||||
|
||||
const textNode = window.document.createTextNode(text);
|
||||
range.insertNode(textNode);
|
||||
|
||||
range.setStartAfter(textNode);
|
||||
range.collapse(true);
|
||||
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
|
||||
element.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
}
|
||||
|
||||
// Self-accepting HMR: tear down the old instance and re-create with the new module's code
|
||||
import.meta.hot?.accept((newModule) => {
|
||||
destroyClipboardManager();
|
||||
if (editorRef) newModule?.createClipboardManager(editorRef);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user