parent
136b15aa38
commit
ec1674cf11
|
|
@ -35,7 +35,7 @@
|
|||
"unist-util-visit": "^5.0.0",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"zotero-plugin-toolkit": "^4.0.8"
|
||||
"zotero-plugin-toolkit": "^4.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||
|
|
@ -13588,9 +13588,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/zotero-plugin-toolkit": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/zotero-plugin-toolkit/-/zotero-plugin-toolkit-4.0.8.tgz",
|
||||
"integrity": "sha512-uro188jzhAY+6EB2N9Kx0Vn5ITazwljJOragMi7PjrcRQrEi/R350eT+MAFrDR+pMzEOltrKtz6W7aSvMd9iqA==",
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/zotero-plugin-toolkit/-/zotero-plugin-toolkit-4.0.9.tgz",
|
||||
"integrity": "sha512-DLFB17D4hWAZRLBKHfipZke765StKBlZ1S320cQqducHaEW7dWC1tumBjB8n02DtuVGn6l9YKo4819wbyVMKcQ==",
|
||||
"dependencies": {
|
||||
"zotero-types": "^2.2.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
"unist-util-visit": "^5.0.0",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"zotero-plugin-toolkit": "^4.0.8"
|
||||
"zotero-plugin-toolkit": "^4.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
import { Plugin, PluginKey } from "prosemirror-state";
|
||||
import { md2html } from "../../utils/convert";
|
||||
|
||||
export { initPasteMarkdownPlugin };
|
||||
|
||||
declare const _currentEditorInstance: {
|
||||
_editorCore: EditorCore;
|
||||
};
|
||||
|
||||
function initPasteMarkdownPlugin() {
|
||||
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(
|
||||
(plugin) => plugin.props.handlePaste && plugin.props.handleDrop,
|
||||
);
|
||||
if (oldPastePluginIndex === -1) {
|
||||
console.error("Paste plugin not found");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
},
|
||||
},
|
||||
}),
|
||||
...oldPlugins.slice(oldPastePluginIndex + 1),
|
||||
],
|
||||
});
|
||||
core.view.updateState(newState);
|
||||
}
|
||||
|
||||
function getMarkdown(clipboardData: DataTransfer) {
|
||||
// If the clipboard contains HTML, don't handle it
|
||||
if (clipboardData.types.includes("text/html")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (clipboardData.types.includes("text/markdown")) {
|
||||
return clipboardData.getData("text/markdown");
|
||||
}
|
||||
|
||||
// For Typora
|
||||
if (clipboardData.types.includes("text/x-markdown")) {
|
||||
return clipboardData.getData("text/x-markdown");
|
||||
}
|
||||
|
||||
// Match markdown patterns
|
||||
if (clipboardData.types.includes("text/plain")) {
|
||||
const text = clipboardData.getData("text/plain");
|
||||
const markdownPatterns = [
|
||||
/^#/m, // Headers: Lines starting with #
|
||||
/^\s*[-+*]\s/m, // Unordered lists: Lines starting with -, +, or *
|
||||
/^\d+\.\s/m, // Ordered lists: Lines starting with numbers followed by a dot
|
||||
/\[.*\]\(.*\)/, // Links: [text](url)
|
||||
/`[^`]+`/, // Inline code: `code`
|
||||
/^> /m, // Blockquotes: Lines starting with >
|
||||
/```/, // Code blocks: Triple backticks
|
||||
];
|
||||
|
||||
for (const pattern of markdownPatterns) {
|
||||
if (pattern.test(text)) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { EditorState, TextSelection } from "prosemirror-state";
|
||||
import { EditorView } from "prosemirror-view";
|
||||
import { initLinkPreviewPlugin } from "./editor/linkPreview";
|
||||
import { initPasteMarkdownPlugin } from "./editor/pasteMarkdown";
|
||||
|
||||
declare const _currentEditorInstance: {
|
||||
_editorCore: EditorCore;
|
||||
|
|
@ -378,6 +379,7 @@ export const BetterNotesEditorAPI = {
|
|||
getNodeFromHTML,
|
||||
setSelection,
|
||||
initLinkPreviewPlugin,
|
||||
initPasteMarkdownPlugin,
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
|
|
|
|||
|
|
@ -452,33 +452,46 @@ function initLinkPreview(editor: Zotero.EditorInstance) {
|
|||
return;
|
||||
}
|
||||
const EditorAPI = getEditorAPI(editor);
|
||||
EditorAPI.initLinkPreviewPlugin(
|
||||
Components.utils.cloneInto(
|
||||
{
|
||||
setPreviewContent: (
|
||||
link: string,
|
||||
setContent: (content: string) => void,
|
||||
) => {
|
||||
const note = addon.api.convert.link2note(link);
|
||||
if (!note) {
|
||||
setContent(`<p style="color: red;">Invalid note link: ${link}</p>`);
|
||||
return;
|
||||
}
|
||||
addon.api.convert
|
||||
.link2html(link, {
|
||||
noteItem: note,
|
||||
dryRun: true,
|
||||
usePosition: true,
|
||||
})
|
||||
.then((content) => setContent(content));
|
||||
safeCall(() =>
|
||||
EditorAPI.initLinkPreviewPlugin(
|
||||
Components.utils.cloneInto(
|
||||
{
|
||||
setPreviewContent: (
|
||||
link: string,
|
||||
setContent: (content: string) => void,
|
||||
) => {
|
||||
const note = addon.api.convert.link2note(link);
|
||||
if (!note) {
|
||||
setContent(
|
||||
`<p style="color: red;">Invalid note link: ${link}</p>`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
addon.api.convert
|
||||
.link2html(link, {
|
||||
noteItem: note,
|
||||
dryRun: true,
|
||||
usePosition: true,
|
||||
})
|
||||
.then((content) => setContent(content));
|
||||
},
|
||||
openURL: (url: string) => {
|
||||
Zotero.getActiveZoteroPane().loadURI(url);
|
||||
},
|
||||
requireCtrl: previewType === "ctrl",
|
||||
},
|
||||
openURL: (url: string) => {
|
||||
Zotero.getActiveZoteroPane().loadURI(url);
|
||||
},
|
||||
requireCtrl: previewType === "ctrl",
|
||||
},
|
||||
editor._iframeWindow,
|
||||
{ wrapReflectors: true, cloneFunctions: true },
|
||||
editor._iframeWindow,
|
||||
{ wrapReflectors: true, cloneFunctions: true },
|
||||
),
|
||||
),
|
||||
);
|
||||
safeCall(() => EditorAPI.initPasteMarkdownPlugin());
|
||||
}
|
||||
|
||||
function safeCall(callback: () => void) {
|
||||
try {
|
||||
callback();
|
||||
} catch (e) {
|
||||
ztoolkit.log(e as Error);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue