fix: note editor plugin reconfigure

fix: #1190
fix: #1189
This commit is contained in:
windingwind 2024-11-11 10:32:04 +01:00
parent 4defc19ba3
commit caa18fc5e2
5 changed files with 145 additions and 113 deletions

View File

@ -1,7 +1,7 @@
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
import { Popup } from "./popup";
export { initLinkPreviewPlugin };
export { initLinkPreviewPlugin, LinkPreviewOptions };
declare const _currentEditorInstance: {
_editorCore: EditorCore;
@ -191,43 +191,57 @@ class LinkPreviewState {
}
}
function initLinkPreviewPlugin(options: LinkPreviewOptions) {
function initLinkPreviewPlugin(
plugins: readonly Plugin[],
options: LinkPreviewOptions,
) {
const core = _currentEditorInstance._editorCore;
console.log("Init BN Link Preview Plugin");
const key = new PluginKey("linkPreviewPlugin");
const newState = core.view.state.reconfigure({
plugins: [
...core.view.state.plugins,
new Plugin({
key,
state: {
init(config, state) {
return new LinkPreviewState(state, options);
return [
...plugins,
new Plugin({
key,
state: {
init(config, state) {
return new LinkPreviewState(state, options);
},
apply: (tr, pluginState, oldState, newState) => {
pluginState.update(newState, oldState);
return pluginState;
},
},
props: {
handleDOMEvents: {
mousemove: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.update(view.state);
pluginState.handleMouseMove(event);
},
apply: (tr, pluginState, oldState, newState) => {
pluginState.update(newState, oldState);
return pluginState;
keydown: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.handleKeydown(event);
},
wheel: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.popup?.layoutPopup(pluginState);
},
},
props: {
handleDOMEvents: {
mousemove: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.update(view.state);
pluginState.handleMouseMove(event);
},
keydown: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.handleKeydown(event);
},
wheel: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.popup?.layoutPopup(pluginState);
},
},
view: (editorView) => {
return {
update(view, prevState) {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.update(view.state, prevState);
},
},
}),
],
});
core.view.updateState(newState);
destroy() {
const pluginState = key.getState(
editorView.state,
) as LinkPreviewState;
pluginState.destroy();
},
};
},
}),
];
}

View File

@ -7,91 +7,92 @@ declare const _currentEditorInstance: {
_editorCore: EditorCore;
};
function initPasteMarkdownPlugin() {
function initPasteMarkdownPlugin(plugins: readonly Plugin[]) {
const core = _currentEditorInstance._editorCore;
console.log("Init BN Paste Markdown Plugin");
const key = new PluginKey("pasteDropPlugin");
const oldPlugins = core.view.state.plugins;
const oldPastePluginIndex = oldPlugins.findIndex(
const oldPastePluginIndex = plugins.findIndex(
(plugin) => plugin.props.handlePaste && plugin.props.handleDrop,
);
if (oldPastePluginIndex === -1) {
console.error("Paste plugin not found");
return;
return plugins;
}
const oldPastePlugin = oldPlugins[oldPastePluginIndex];
const newState = core.view.state.reconfigure({
plugins: [
...oldPlugins.slice(0, oldPastePluginIndex),
new Plugin({
key,
props: {
handlePaste: (view, event, slice) => {
if (!event.clipboardData) {
return false;
}
const markdown = getMarkdown(event.clipboardData);
const oldPastePlugin = plugins[oldPastePluginIndex];
return [
...plugins.slice(0, oldPastePluginIndex),
new Plugin({
key,
props: {
handlePaste: (view, event, slice) => {
if (!event.clipboardData) {
return false;
}
const markdown = getMarkdown(event.clipboardData);
if (!markdown) {
// Try the old paste plugin
return oldPastePlugin.props.handlePaste?.apply(oldPastePlugin, [
view,
event,
slice,
]);
}
if (!markdown) {
// Try the old paste plugin
return oldPastePlugin.props.handlePaste?.apply(oldPastePlugin, [
view,
event,
slice,
]);
}
md2html(markdown).then((html: string) => {
const slice = window.BetterNotesEditorAPI.getSliceFromHTML(
view.state,
html,
);
const tr = view.state.tr.replaceSelection(slice);
view.dispatch(tr);
});
return true;
},
handleDrop: (view, event, slice, moved) => {
if (!event.dataTransfer) {
return false;
}
const markdown = getMarkdown(event.dataTransfer);
if (!markdown) {
// Try the old drop plugin first
return oldPastePlugin.props.handleDrop?.apply(oldPastePlugin, [
view,
event,
slice,
moved,
]);
}
md2html(markdown).then((html: string) => {
const slice = window.BetterNotesEditorAPI.getSliceFromHTML(
view.state,
html,
);
const pos = view.posAtCoords({
left: event.clientX,
top: event.clientY,
});
if (!pos) {
return;
}
// Insert the slice to the current position
const tr = view.state.tr.insert(pos.pos, slice);
view.dispatch(tr);
});
return true;
},
md2html(markdown).then((html: string) => {
const slice = window.BetterNotesEditorAPI.getSliceFromHTML(
view.state,
html,
);
const tr = view.state.tr.replaceSelection(slice);
view.dispatch(tr);
});
return true;
},
}),
...oldPlugins.slice(oldPastePluginIndex + 1),
],
});
core.view.updateState(newState);
handleDrop: (view, event, slice, moved) => {
if (!event.dataTransfer) {
return false;
}
const markdown = getMarkdown(event.dataTransfer);
if (!markdown) {
// Try the old drop plugin first
return oldPastePlugin.props.handleDrop?.apply(oldPastePlugin, [
view,
event,
slice,
moved,
]);
}
md2html(markdown).then((html: string) => {
const slice = window.BetterNotesEditorAPI.getSliceFromHTML(
view.state,
html,
);
const pos = view.posAtCoords({
left: event.clientX,
top: event.clientY,
});
if (!pos) {
return;
}
// Insert the slice to the current position
const tr = view.state.tr.insert(pos.pos, slice);
view.dispatch(tr);
});
return true;
},
},
view: (editorView) => {
return {
destroy() {},
};
},
}),
...plugins.slice(oldPastePluginIndex + 1),
];
}
function getMarkdown(clipboardData: DataTransfer) {

View File

@ -0,0 +1,20 @@
import { initLinkPreviewPlugin, LinkPreviewOptions } from "./linkPreview";
import { initPasteMarkdownPlugin } from "./pasteMarkdown";
export { initPlugins };
declare const _currentEditorInstance: {
_editorCore: EditorCore;
};
function initPlugins(options: LinkPreviewOptions) {
const core = _currentEditorInstance._editorCore;
let plugins = core.view.state.plugins;
plugins = initLinkPreviewPlugin(plugins, options);
plugins = initPasteMarkdownPlugin(plugins);
// Collect all plugins and reconfigure the state only once
const newState = core.view.state.reconfigure({
plugins,
});
core.view.updateState(newState);
}

View File

@ -11,8 +11,7 @@ import {
} from "prosemirror-model";
import { EditorState, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { initLinkPreviewPlugin } from "./editor/linkPreview";
import { initPasteMarkdownPlugin } from "./editor/pasteMarkdown";
import { initPlugins } from "./editor/plugins";
declare const _currentEditorInstance: {
_editorCore: EditorCore;
@ -378,8 +377,7 @@ export const BetterNotesEditorAPI = {
getSliceFromHTML,
getNodeFromHTML,
setSelection,
initLinkPreviewPlugin,
initPasteMarkdownPlugin,
initPlugins,
};
// @ts-ignore

View File

@ -453,7 +453,7 @@ function initLinkPreview(editor: Zotero.EditorInstance) {
}
const EditorAPI = getEditorAPI(editor);
safeCall(() =>
EditorAPI.initLinkPreviewPlugin(
EditorAPI.initPlugins(
Components.utils.cloneInto(
{
setPreviewContent: (
@ -485,7 +485,6 @@ function initLinkPreview(editor: Zotero.EditorInstance) {
),
),
);
safeCall(() => EditorAPI.initPasteMarkdownPlugin());
}
function safeCall(callback: () => void) {