parent
a808742523
commit
5bb5ef1d9a
|
|
@ -39,6 +39,11 @@
|
||||||
native="true"
|
native="true"
|
||||||
preference="__prefsPrefix__.workspace.outline.keepLinks"
|
preference="__prefsPrefix__.workspace.outline.keepLinks"
|
||||||
/>
|
/>
|
||||||
|
<checkbox
|
||||||
|
data-l10n-id="editor-noteLinkPreview"
|
||||||
|
native="true"
|
||||||
|
preference="__prefsPrefix__.editor.noteLinkPreview"
|
||||||
|
/>
|
||||||
</groupbox>
|
</groupbox>
|
||||||
<groupbox>
|
<groupbox>
|
||||||
<label><html:h2 data-l10n-id="sync-title"></html:h2></label>
|
<label><html:h2 data-l10n-id="sync-title"></html:h2></label>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ editor-title = Note Editor
|
||||||
editor-expandLevel-label = Outline expand to heading level
|
editor-expandLevel-label = Outline expand to heading level
|
||||||
editor-keepLinks =
|
editor-keepLinks =
|
||||||
.label = Show note links in outline
|
.label = Show note links in outline
|
||||||
|
editor-noteLinkPreview =
|
||||||
|
.label = Show note link preview on hover
|
||||||
|
|
||||||
sync-title = Sync
|
sync-title = Sync
|
||||||
sync-period-label = Auto-sync period (seconds)
|
sync-period-label = Auto-sync period (seconds)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ editor-title = Note Editor
|
||||||
editor-expandLevel-label = Espansione dello schema al livello delle intestazioni
|
editor-expandLevel-label = Espansione dello schema al livello delle intestazioni
|
||||||
editor-keepLinks =
|
editor-keepLinks =
|
||||||
.label = Mostra i collegamenti delle note nello schema
|
.label = Mostra i collegamenti delle note nello schema
|
||||||
|
editor-noteLinkPreview =
|
||||||
|
.label = Show note link preview on hover
|
||||||
|
|
||||||
sync-title = Sincronizzazione
|
sync-title = Sincronizzazione
|
||||||
sync-period-label = Intervallo della sincronizzazione automatica (secondi)
|
sync-period-label = Intervallo della sincronizzazione automatica (secondi)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ editor-title = Note Editor
|
||||||
editor-expandLevel-label = Outline расширить до уровня заголовка
|
editor-expandLevel-label = Outline расширить до уровня заголовка
|
||||||
editor-keepLinks =
|
editor-keepLinks =
|
||||||
.label = Сохранить ссылки
|
.label = Сохранить ссылки
|
||||||
|
editor-noteLinkPreview =
|
||||||
|
.label = Show note link preview on hover
|
||||||
|
|
||||||
sync-title = Синк
|
sync-title = Синк
|
||||||
sync-period-label = Авто-синк период (сек)
|
sync-period-label = Авто-синк период (сек)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ editor-title = Note Editor
|
||||||
editor-expandLevel-label = Anahat başlık seviyesine genişletildi
|
editor-expandLevel-label = Anahat başlık seviyesine genişletildi
|
||||||
editor-keepLinks =
|
editor-keepLinks =
|
||||||
.label = Not linklerini anahatta göster
|
.label = Not linklerini anahatta göster
|
||||||
|
editor-noteLinkPreview =
|
||||||
|
.label = Show note link preview on hover
|
||||||
|
|
||||||
sync-title = Senkronize Et
|
sync-title = Senkronize Et
|
||||||
sync-period-label = Oto-Senkronize aralığı (saniye)
|
sync-period-label = Oto-Senkronize aralığı (saniye)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ editor-title = 笔记编辑器
|
||||||
editor-expandLevel-label = 大纲展开至标题层级
|
editor-expandLevel-label = 大纲展开至标题层级
|
||||||
editor-keepLinks =
|
editor-keepLinks =
|
||||||
.label = 在大纲中显示笔记链接
|
.label = 在大纲中显示笔记链接
|
||||||
|
editor-noteLinkPreview =
|
||||||
|
.label = 鼠标悬停时显示笔记链接预览
|
||||||
|
|
||||||
sync-title = 同步
|
sync-title = 同步
|
||||||
sync-period-label = 自动同步周期 (秒)
|
sync-period-label = 自动同步周期 (秒)
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,10 @@ pref("__prefsPrefix__.exportPDF", false);
|
||||||
pref("__prefsPrefix__.exportFreeMind", false);
|
pref("__prefsPrefix__.exportFreeMind", false);
|
||||||
pref("__prefsPrefix__.exportNote", false);
|
pref("__prefsPrefix__.exportNote", false);
|
||||||
|
|
||||||
pref("__prefsPrefix__.OCREngine", "bing");
|
|
||||||
pref("__prefsPrefix__.OCRMathpix.Appid", "");
|
|
||||||
pref("__prefsPrefix__.OCRMathpix.Appkey", "");
|
|
||||||
pref("__prefsPrefix__.OCRXunfei.APPID", "");
|
|
||||||
pref("__prefsPrefix__.OCRMathpix.APISecret", "");
|
|
||||||
pref("__prefsPrefix__.OCRMathpix.APIKey", "");
|
|
||||||
|
|
||||||
pref("__prefsPrefix__.workspace.outline.expandLevel", 2);
|
pref("__prefsPrefix__.workspace.outline.expandLevel", 2);
|
||||||
pref("__prefsPrefix__.workspace.outline.keepLinks", true);
|
pref("__prefsPrefix__.workspace.outline.keepLinks", true);
|
||||||
|
|
||||||
|
pref("__prefsPrefix__.editor.noteLinkPreview", true);
|
||||||
|
|
||||||
pref("__prefsPrefix__.openNote.takeover", true);
|
pref("__prefsPrefix__.openNote.takeover", true);
|
||||||
pref("__prefsPrefix__.openNote.defaultAsWindow", false);
|
pref("__prefsPrefix__.openNote.defaultAsWindow", false);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
|
||||||
|
import { Popup } from "./popup";
|
||||||
|
|
||||||
|
export { initLinkPreviewPlugin };
|
||||||
|
|
||||||
|
declare const _currentEditorInstance: {
|
||||||
|
_editorCore: EditorCore;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface LinkPreviewOptions {
|
||||||
|
setPreviewContent: (
|
||||||
|
link: string,
|
||||||
|
setContent: (content: string) => void,
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
openURL: (url: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinkPreviewState {
|
||||||
|
state: EditorState;
|
||||||
|
|
||||||
|
options: LinkPreviewOptions;
|
||||||
|
|
||||||
|
popup: Popup | null = null;
|
||||||
|
|
||||||
|
node: HTMLElement | null = null;
|
||||||
|
|
||||||
|
currentLink: string | null = null;
|
||||||
|
|
||||||
|
hasHover = false;
|
||||||
|
|
||||||
|
constructor(state: EditorState, options: LinkPreviewOptions) {
|
||||||
|
this.state = state;
|
||||||
|
this.options = options;
|
||||||
|
this.update(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(state: EditorState, prevState?: EditorState) {
|
||||||
|
this.state = state;
|
||||||
|
|
||||||
|
if (
|
||||||
|
prevState &&
|
||||||
|
prevState.doc.eq(state.doc) &&
|
||||||
|
prevState.selection.eq(state.selection)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Handle selection change
|
||||||
|
setTimeout(() => {
|
||||||
|
this.popup?.layoutPopup(this);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.popup?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseMove = async (event: MouseEvent) => {
|
||||||
|
const { target } = event;
|
||||||
|
|
||||||
|
let isValid = false;
|
||||||
|
if (target instanceof HTMLElement) {
|
||||||
|
const href = target.closest("a")?.getAttribute("href");
|
||||||
|
if (href?.startsWith("zotero://note/")) {
|
||||||
|
isValid = true;
|
||||||
|
if (this.currentLink !== href) {
|
||||||
|
this.node = target;
|
||||||
|
this.currentLink = href;
|
||||||
|
this.hasHover = true;
|
||||||
|
this.tryOpenPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValid && this.currentLink) {
|
||||||
|
this.hasHover = false;
|
||||||
|
this.currentLink = null;
|
||||||
|
this.tryClosePopup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tryOpenPopup() {
|
||||||
|
const href = this.currentLink!;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.currentLink === href) {
|
||||||
|
this._openPopup();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
_openPopup() {
|
||||||
|
console.log("Enter Link Preview", this.currentLink, this.options);
|
||||||
|
document.querySelectorAll(".link-preview").forEach((el) => el.remove());
|
||||||
|
this.popup = new Popup(document, "link-preview", [
|
||||||
|
document.createRange().createContextualFragment(`
|
||||||
|
<style>
|
||||||
|
.link-preview > .popup {
|
||||||
|
max-width: 360px;
|
||||||
|
max-height: 360px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.link-preview > .popup > * {
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
.link-preview .primary-editor img:not(.ProseMirror-separator) {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>`),
|
||||||
|
]);
|
||||||
|
this.popup.popup.classList.add("primary-editor");
|
||||||
|
this.popup.container.style.display = "none";
|
||||||
|
|
||||||
|
this.popup.layoutPopup(this);
|
||||||
|
|
||||||
|
this.options.setPreviewContent(this.currentLink!, (content: string) => {
|
||||||
|
this.popup?.popup.append(
|
||||||
|
document.createRange().createContextualFragment(content),
|
||||||
|
);
|
||||||
|
this.popup!.container.style.removeProperty("display");
|
||||||
|
this.popup?.layoutPopup(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.popup.container.addEventListener("mouseleave", () => {
|
||||||
|
this.currentLink = null;
|
||||||
|
this.tryClosePopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.popup.container.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
if (target.localName === "a") {
|
||||||
|
const href = target.getAttribute("href");
|
||||||
|
if (href) {
|
||||||
|
this.options.openURL(href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._closePopup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tryClosePopup() {
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("Close Link Preview", this.currentLink, this.popup?.hasHover);
|
||||||
|
if (this.hasHover || this.popup?.hasHover) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._closePopup();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
_closePopup() {
|
||||||
|
this.node = null;
|
||||||
|
document.querySelectorAll(".link-preview").forEach((el) => el.remove());
|
||||||
|
this.popup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initLinkPreviewPlugin(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);
|
||||||
|
},
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
wheel: (view, event) => {
|
||||||
|
const pluginState = key.getState(view.state) as LinkPreviewState;
|
||||||
|
pluginState.popup?.layoutPopup(pluginState);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
core.view.updateState(newState);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
export { Popup };
|
||||||
|
|
||||||
|
class Popup {
|
||||||
|
_popup: HTMLDivElement;
|
||||||
|
|
||||||
|
hasHover = false;
|
||||||
|
|
||||||
|
get container() {
|
||||||
|
return this._popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
get popup() {
|
||||||
|
return this._popup.querySelector(".popup") as HTMLDivElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
doc: Document,
|
||||||
|
className?: string,
|
||||||
|
children: (HTMLElement | DocumentFragment)[] = [],
|
||||||
|
) {
|
||||||
|
this._popup = doc.createElement("div");
|
||||||
|
this._popup.className = `popup-container ${className}`;
|
||||||
|
this._popup.innerHTML = `
|
||||||
|
<div class="popup popup-top">
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
this.popup.append(...children);
|
||||||
|
doc.querySelector(".relative-container")?.appendChild(this._popup);
|
||||||
|
|
||||||
|
this._popup.addEventListener("mouseenter", () => {
|
||||||
|
this.hasHover = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._popup.addEventListener("mouseleave", () => {
|
||||||
|
this.hasHover = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutPopup(pluginState: any) {
|
||||||
|
const rect = pluginState.rect || pluginState.node?.getBoundingClientRect();
|
||||||
|
if (!rect) return;
|
||||||
|
|
||||||
|
const padding = 10;
|
||||||
|
|
||||||
|
const editor = document.querySelector(".editor-core") as HTMLElement;
|
||||||
|
|
||||||
|
const popupParent = this.container.parentElement!;
|
||||||
|
|
||||||
|
const parentScrollTop = popupParent.scrollTop;
|
||||||
|
const parentTop = popupParent.getBoundingClientRect().top;
|
||||||
|
const popupHeight = this.popup.offsetHeight;
|
||||||
|
const maxWidth = this.container.offsetWidth;
|
||||||
|
const topSpace = rect.top - popupHeight - padding;
|
||||||
|
|
||||||
|
let top;
|
||||||
|
|
||||||
|
if (topSpace < 0) {
|
||||||
|
// Bottom
|
||||||
|
const otherPopupHeight = Array.from(
|
||||||
|
popupParent.querySelectorAll(
|
||||||
|
".popup-container:not(.link-preview) > .popup.popup-bottom",
|
||||||
|
),
|
||||||
|
).reduce((acc, el) => acc + (el as HTMLElement).offsetHeight, 0);
|
||||||
|
top =
|
||||||
|
parentScrollTop +
|
||||||
|
(rect.bottom - parentTop) +
|
||||||
|
otherPopupHeight +
|
||||||
|
padding;
|
||||||
|
this.popup.classList.remove("popup-top");
|
||||||
|
this.popup.classList.add("popup-bottom");
|
||||||
|
} else {
|
||||||
|
// Top
|
||||||
|
const otherPopupHeight = Array.from(
|
||||||
|
popupParent.querySelectorAll(
|
||||||
|
".popup-container:not(.link-preview) > .popup.popup-top",
|
||||||
|
),
|
||||||
|
).reduce((acc, el) => acc + (el as HTMLElement).offsetHeight, 0);
|
||||||
|
top =
|
||||||
|
parentScrollTop +
|
||||||
|
(rect.top - parentTop) -
|
||||||
|
popupHeight -
|
||||||
|
otherPopupHeight -
|
||||||
|
padding;
|
||||||
|
this.popup.classList.remove("popup-bottom");
|
||||||
|
this.popup.classList.add("popup-top");
|
||||||
|
}
|
||||||
|
|
||||||
|
const width = this.popup.offsetWidth;
|
||||||
|
let left = rect.left + (rect.right - rect.left) / 2 - width / 2 + 1;
|
||||||
|
|
||||||
|
if (left + width >= maxWidth) {
|
||||||
|
left = maxWidth - width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left < 2) {
|
||||||
|
left = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.popup.style.top = Math.round(top) + "px";
|
||||||
|
this.popup.style.left = Math.round(left) + "px";
|
||||||
|
|
||||||
|
// Make sure the popup height is not larger than the editor height
|
||||||
|
// if (editor) {
|
||||||
|
// const editorRect = editor.getBoundingClientRect();
|
||||||
|
// const popupRect = this.popup.getBoundingClientRect();
|
||||||
|
// if (popupRect.bottom > editorRect.bottom + padding) {
|
||||||
|
// this.popup.style.maxHeight =
|
||||||
|
// editorRect.bottom - popupRect.top - padding + "px";
|
||||||
|
// } else {
|
||||||
|
// this.popup.style.maxHeight = "";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
this._popup.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
} from "prosemirror-model";
|
} from "prosemirror-model";
|
||||||
import { EditorState, TextSelection } from "prosemirror-state";
|
import { EditorState, TextSelection } from "prosemirror-state";
|
||||||
import { EditorView } from "prosemirror-view";
|
import { EditorView } from "prosemirror-view";
|
||||||
|
import { initLinkPreviewPlugin } from "./editor/linkPreview";
|
||||||
|
|
||||||
declare const _currentEditorInstance: {
|
declare const _currentEditorInstance: {
|
||||||
_editorCore: EditorCore;
|
_editorCore: EditorCore;
|
||||||
|
|
@ -376,6 +377,7 @@ export const BetterNotesEditorAPI = {
|
||||||
getSliceFromHTML,
|
getSliceFromHTML,
|
||||||
getNodeFromHTML,
|
getNodeFromHTML,
|
||||||
setSelection,
|
setSelection,
|
||||||
|
initLinkPreviewPlugin,
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { initEditorImagePreviewer } from "./image";
|
import { initEditorImagePreviewer } from "./image";
|
||||||
import { injectEditorCSS, injectEditorScripts } from "./inject";
|
import { injectEditorCSS, injectEditorScripts } from "./inject";
|
||||||
|
import { initEditorLinkPreview } from "./linkPreview";
|
||||||
import { initEditorMenu } from "./menu";
|
import { initEditorMenu } from "./menu";
|
||||||
import { initEditorPopup } from "./popup";
|
import { initEditorPopup } from "./popup";
|
||||||
import { initEditorToolbar } from "./toolbar";
|
import { initEditorToolbar } from "./toolbar";
|
||||||
|
|
@ -36,4 +37,5 @@ async function onEditorInstanceCreated(editor: Zotero.EditorInstance) {
|
||||||
await initEditorToolbar(editor);
|
await initEditorToolbar(editor);
|
||||||
initEditorPopup(editor);
|
initEditorPopup(editor);
|
||||||
initEditorMenu(editor);
|
initEditorMenu(editor);
|
||||||
|
initEditorLinkPreview(editor);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { initLinkPreview } from "../../utils/editor";
|
||||||
|
|
||||||
|
export function initEditorLinkPreview(editor: Zotero.EditorInstance) {
|
||||||
|
initLinkPreview(editor);
|
||||||
|
}
|
||||||
|
|
@ -186,7 +186,11 @@ function link2params(link: string) {
|
||||||
|
|
||||||
async function link2html(
|
async function link2html(
|
||||||
link: string,
|
link: string,
|
||||||
options: { noteItem?: Zotero.Item; dryRun?: boolean } = {},
|
options: {
|
||||||
|
noteItem?: Zotero.Item;
|
||||||
|
dryRun?: boolean;
|
||||||
|
usePosition?: boolean;
|
||||||
|
} = {},
|
||||||
) {
|
) {
|
||||||
ztoolkit.log("link2html", link, options);
|
ztoolkit.log("link2html", link, options);
|
||||||
const linkParams = getNoteLinkParams(link);
|
const linkParams = getNoteLinkParams(link);
|
||||||
|
|
@ -196,8 +200,22 @@ async function link2html(
|
||||||
const refIds = getLinkedNotesRecursively(link);
|
const refIds = getLinkedNotesRecursively(link);
|
||||||
const refNotes = options.noteItem ? Zotero.Items.get(refIds) : [];
|
const refNotes = options.noteItem ? Zotero.Items.get(refIds) : [];
|
||||||
ztoolkit.log(refIds);
|
ztoolkit.log(refIds);
|
||||||
const html =
|
let html;
|
||||||
addon.api.sync.getNoteStatus(linkParams.noteItem.id)?.content || "";
|
if (options.usePosition) {
|
||||||
|
const item = linkParams.noteItem;
|
||||||
|
let lineIndex = linkParams.lineIndex;
|
||||||
|
|
||||||
|
if (typeof linkParams.sectionName === "string") {
|
||||||
|
const sectionTree = addon.api.note.getNoteTreeFlattened(item);
|
||||||
|
const sectionNode = sectionTree.find(
|
||||||
|
(node) => node.model.name.trim() === linkParams.sectionName!.trim(),
|
||||||
|
);
|
||||||
|
lineIndex = sectionNode?.model.lineIndex;
|
||||||
|
}
|
||||||
|
html = addon.api.note.getLinesInNote(item).slice(lineIndex).join("\n");
|
||||||
|
} else {
|
||||||
|
html = addon.api.sync.getNoteStatus(linkParams.noteItem.id)?.content || "";
|
||||||
|
}
|
||||||
if (options.dryRun) {
|
if (options.dryRun) {
|
||||||
return await renderNoteHTML(html, refNotes);
|
return await renderNoteHTML(html, refNotes);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import TreeModel = require("tree-model");
|
import TreeModel = require("tree-model");
|
||||||
import { TextSelection } from "prosemirror-state";
|
import { TextSelection } from "prosemirror-state";
|
||||||
import { getNoteTreeFlattened } from "./note";
|
import { getNoteTreeFlattened } from "./note";
|
||||||
|
import { getPref } from "./prefs";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
insert,
|
insert,
|
||||||
|
|
@ -24,6 +25,7 @@ export {
|
||||||
getTextBetween,
|
getTextBetween,
|
||||||
getTextBetweenLines,
|
getTextBetweenLines,
|
||||||
isImageAtCursor,
|
isImageAtCursor,
|
||||||
|
initLinkPreview,
|
||||||
};
|
};
|
||||||
|
|
||||||
function insert(
|
function insert(
|
||||||
|
|
@ -433,3 +435,38 @@ function getTextBetweenLines(
|
||||||
const to = getPositionAtLine(editor, toIndex, "end");
|
const to = getPositionAtLine(editor, toIndex, "end");
|
||||||
return core.view.state.doc.textBetween(from, to);
|
return core.view.state.doc.textBetween(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initLinkPreview(editor: Zotero.EditorInstance) {
|
||||||
|
if (!getPref("editor.noteLinkPreview")) {
|
||||||
|
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));
|
||||||
|
},
|
||||||
|
openURL: (url: string) => {
|
||||||
|
Zotero.getActiveZoteroPane().loadURI(url);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
editor._iframeWindow,
|
||||||
|
{ wrapReflectors: true, cloneFunctions: true },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ async function renderNoteHTML(
|
||||||
if (await attachment.fileExists()) {
|
if (await attachment.fileExists()) {
|
||||||
const imageNodes = Array.from(
|
const imageNodes = Array.from(
|
||||||
doc.querySelectorAll(`img[data-attachment-key="${attachment.key}"]`),
|
doc.querySelectorAll(`img[data-attachment-key="${attachment.key}"]`),
|
||||||
);
|
) as HTMLImageElement[];
|
||||||
if (imageNodes.length) {
|
if (imageNodes.length) {
|
||||||
try {
|
try {
|
||||||
const b64 = await getItemDataURL(attachment);
|
const b64 = await getItemDataURL(attachment);
|
||||||
|
|
@ -244,6 +244,12 @@ async function renderNoteHTML(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (node.hasAttribute("width")) {
|
||||||
|
node.style.width = `${node.getAttribute("width")}px`;
|
||||||
|
}
|
||||||
|
if (node.hasAttribute("height")) {
|
||||||
|
node.style.width = `${node.getAttribute("height")}px`;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ztoolkit.log(e);
|
ztoolkit.log(e);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue