import {openByMobile, writeText} from "../util/compatibility"; import {focusByRange} from "../util/selection"; import {showMessage} from "../../dialog/message"; import {isLocalPath, pathPosix} from "../../util/pathName"; import {previewImage} from "./image"; import {needSubscribe} from "../../util/needSubscribe"; import {Constants} from "../../constants"; import {getSearch, isMobile} from "../../util/functions"; /// #if !BROWSER import {shell} from "electron"; /// #endif /// #if !MOBILE import {openAsset, openBy, updateOutline} from "../../editor/util"; import {getAllModels} from "../../layout/getAll"; import {setPanelFocus} from "../../layout/util"; /// #endif import {fetchPost} from "../../util/fetch"; import {processRender} from "../util/processCode"; import {highlightRender} from "../render/highlightRender"; import {speechRender} from "../render/speechRender"; import {avRender} from "../render/av/render"; export class Preview { public element: HTMLElement; public previewElement: HTMLElement; private mdTimeoutId: number; constructor(protyle: IProtyle) { this.element = document.createElement("div"); this.element.className = "protyle-preview fn__none"; const previewElement = document.createElement("div"); previewElement.className = "b3-typography"; if (protyle.options.classes.preview) { previewElement.classList.add(protyle.options.classes.preview); } previewElement.style.padding = protyle.wysiwyg.element.style.padding; const actions = protyle.options.preview.actions; const actionElement = document.createElement("div"); actionElement.className = "protyle-preview__action"; const actionHtml: string[] = []; for (let i = 0; i < actions.length; i++) { const action = actions[i]; if (typeof action === "object") { actionHtml.push(``); continue; } switch (action) { case "desktop": actionHtml.push(''); break; case "tablet": actionHtml.push(''); break; case "mobile": actionHtml.push(''); break; case "mp-wechat": actionHtml.push(''); break; case "zhihu": actionHtml.push(''); break; case "yuque": actionHtml.push(''); break; } } actionElement.innerHTML = actionHtml.join(""); this.element.appendChild(actionElement); this.element.appendChild(previewElement); this.element.addEventListener("click", (event) => { if (protyle.model) { setPanelFocus(protyle.model.element.parentElement.parentElement); updateOutline(getAllModels(), protyle.model.editor.protyle); } let target = event.target as HTMLElement; while (target && !target.isEqualNode(this.element)) { if (target.tagName === "A") { const linkAddress = target.getAttribute("href"); if (linkAddress.startsWith("#")) { // 导出预览模式点击块引转换后的脚注跳转不正确 https://github.com/siyuan-note/siyuan/issues/5700 previewElement.querySelector(linkAddress).scrollIntoView(); event.stopPropagation(); event.preventDefault(); break; } if (isMobile()) { openByMobile(linkAddress); event.stopPropagation(); event.preventDefault(); break; } event.stopPropagation(); event.preventDefault(); if (isLocalPath(linkAddress)) { /// #if !MOBILE if (event.metaKey || event.ctrlKey) { openBy(linkAddress, "folder"); } else if (event.shiftKey) { openBy(linkAddress, "app"); } else if (Constants.SIYUAN_ASSETS_EXTS.includes(pathPosix().extname((linkAddress.split("?page")[0])))) { openAsset(protyle.app, linkAddress.split("?page")[0], parseInt(getSearch("page", linkAddress))); } /// #endif } else { /// #if !BROWSER shell.openExternal(linkAddress).catch((e) => { showMessage(e); }); /// #else window.open(linkAddress); /// #endif } break; } else if (target.tagName === "IMG") { previewImage((event.target as HTMLImageElement).src, protyle.block.rootID); event.stopPropagation(); event.preventDefault(); break; } else if (target.tagName === "BUTTON") { const type = target.getAttribute("data-type"); const actionCustom = actions.find((w: IPreviewActionCustom) => w?.key === type) as IPreviewActionCustom; if (actionCustom) { actionCustom.click(type); } else if ((type === "mp-wechat" || type === "zhihu" || type === "yuque")) { this.copyToX(this.element.lastElementChild.cloneNode(true) as HTMLElement, protyle, type); } else if (type === "desktop") { previewElement.style.width = ""; previewElement.style.padding = protyle.wysiwyg.element.style.padding; } else if (type === "tablet") { previewElement.style.width = "1024px"; previewElement.style.padding = "8px 16px"; } else { previewElement.style.width = "360px"; previewElement.style.padding = "8px"; } this.render(protyle); actionElement.querySelectorAll("button").forEach((item) => { item.classList.remove("protyle-preview__action--current"); }); target.classList.add("protyle-preview__action--current"); } target = target.parentElement; } }); this.previewElement = previewElement; } public render(protyle: IProtyle, cb?: (outlineData: IBlockTree[]) => void) { if (this.element.style.display === "none") { return; } let loadingElement = this.element.querySelector(".fn__loading"); if (!loadingElement) { this.element.insertAdjacentHTML("beforeend", `