mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 22:50:13 +01:00
Merge 07e0eb26d2 into 7217c66636
This commit is contained in:
commit
8ca6d2c8dd
8 changed files with 476 additions and 220 deletions
|
|
@ -1,21 +1,21 @@
|
|||
import {hideMessage, showMessage} from "../../dialog/message";
|
||||
import {Constants} from "../../constants";
|
||||
import { hideMessage, showMessage } from "../../dialog/message";
|
||||
import { Constants } from "../../constants";
|
||||
/// #if !BROWSER
|
||||
import {ipcRenderer} from "electron";
|
||||
import { ipcRenderer } from "electron";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import {afterExport} from "./util";
|
||||
import { afterExport } from "./util";
|
||||
/// #endif
|
||||
import {confirmDialog} from "../../dialog/confirmDialog";
|
||||
import {getThemeMode, setInlineStyle} from "../../util/assets";
|
||||
import {fetchPost, fetchSyncPost} from "../../util/fetch";
|
||||
import {Dialog} from "../../dialog";
|
||||
import {replaceLocalPath} from "../../editor/rename";
|
||||
import {getScreenWidth, isInAndroid, isInHarmony, isInIOS, setStorageVal} from "../util/compatibility";
|
||||
import {getFrontend} from "../../util/functions";
|
||||
import { confirmDialog } from "../../dialog/confirmDialog";
|
||||
import { getThemeMode, setInlineStyle } from "../../util/assets";
|
||||
import { fetchPost, fetchSyncPost } from "../../util/fetch";
|
||||
import { Dialog } from "../../dialog";
|
||||
import { replaceLocalPath } from "../../editor/rename";
|
||||
import { getScreenWidth, isInAndroid, isInHarmony, isInIOS, setStorageVal } from "../util/compatibility";
|
||||
import { getFrontend } from "../../util/functions";
|
||||
|
||||
const getPluginStyle = async () => {
|
||||
const response = await fetchSyncPost("/api/petal/loadPetals", {frontend: getFrontend()});
|
||||
const response = await fetchSyncPost("/api/petal/loadPetals", { frontend: getFrontend() });
|
||||
let css = "";
|
||||
// 为加快启动速度,不进行 await
|
||||
response.data.forEach((item: IPluginData) => {
|
||||
|
|
@ -103,7 +103,7 @@ export const saveExport = (option: IExportOptions) => {
|
|||
btnsElement[1].addEventListener("click", () => {
|
||||
const removeAssets = (wordDialog.element.querySelector("#removeAssets") as HTMLInputElement).checked;
|
||||
const mergeSubdocs = (wordDialog.element.querySelector("#mergeSubdocs") as HTMLInputElement).checked;
|
||||
window.siyuan.storage[Constants.LOCAL_EXPORTWORD] = {removeAssets, mergeSubdocs};
|
||||
window.siyuan.storage[Constants.LOCAL_EXPORTWORD] = { removeAssets, mergeSubdocs };
|
||||
setStorageVal(Constants.LOCAL_EXPORTWORD, window.siyuan.storage[Constants.LOCAL_EXPORTWORD]);
|
||||
getExportPath(option, removeAssets, mergeSubdocs);
|
||||
wordDialog.destroy();
|
||||
|
|
@ -476,7 +476,7 @@ ${getIconScript(servePath)}
|
|||
Protyle.flowchartRender(wysElement, "${servePath}stage/protyle");
|
||||
Protyle.graphvizRender(wysElement, "${servePath}stage/protyle");
|
||||
Protyle.chartRender(wysElement, "${servePath}stage/protyle");
|
||||
Protyle.mindmapRender(wysElement, "${servePath}stage/protyle");
|
||||
Protyle.mindmapRender(wysElement, "${servePath}stage/protyle", {zoom: false, pan: false});
|
||||
Protyle.abcRender(wysElement, "${servePath}stage/protyle");
|
||||
Protyle.htmlRender(wysElement);
|
||||
Protyle.plantumlRender(wysElement, "${servePath}stage/protyle");
|
||||
|
|
@ -637,7 +637,7 @@ ${getIconScript(servePath)}
|
|||
</script>
|
||||
${getSnippetJS()}
|
||||
</body></html>`;
|
||||
fetchPost("/api/export/exportTempContent", {content: html}, (response) => {
|
||||
fetchPost("/api/export/exportTempContent", { content: html }, (response) => {
|
||||
ipcRenderer.send(Constants.SIYUAN_EXPORT_NEWWINDOW, response.data.url);
|
||||
});
|
||||
};
|
||||
|
|
@ -722,7 +722,7 @@ export const onExport = async (data: IWebSocketData, filePath: string, servePath
|
|||
js: `document.body.style.minWidth = "${screenWidth}px";`,
|
||||
css: `@page { size: A4; margin: 10mm 0 10mm 0; background-color: var(--b3-theme-background); }
|
||||
.protyle-wysiwyg {padding: 0; margin: 0;}`
|
||||
} : {js: "", css: ""};
|
||||
} : { js: "", css: "" };
|
||||
const html = `<!DOCTYPE html>
|
||||
<html lang="${window.siyuan.config.appearance.lang}" data-theme-mode="${isInMobile ? "light" : getThemeMode()}" data-light-theme="${window.siyuan.config.appearance.themeLight}" data-dark-theme="${window.siyuan.config.appearance.themeDark}">
|
||||
<head>
|
||||
|
|
@ -775,7 +775,7 @@ ${getIconScript(servePath)}
|
|||
Protyle.flowchartRender(previewElement, "stage/protyle");
|
||||
Protyle.graphvizRender(previewElement, "stage/protyle");
|
||||
Protyle.chartRender(previewElement, "stage/protyle");
|
||||
Protyle.mindmapRender(previewElement, "stage/protyle");
|
||||
Protyle.mindmapRender(previewElement, "stage/protyle", {zoom: false, pan: false});
|
||||
Protyle.abcRender(previewElement, "stage/protyle");
|
||||
Protyle.htmlRender(previewElement);
|
||||
Protyle.plantumlRender(previewElement, "stage/protyle");
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import {addScript} from "../util/addScript";
|
||||
import {Constants} from "../../constants";
|
||||
import {hasClosestByClassName} from "../util/hasClosest";
|
||||
import {genIconHTML} from "./util";
|
||||
import { addScript } from "../util/addScript";
|
||||
import { Constants } from "../../constants";
|
||||
import { hasClosestByClassName } from "../util/hasClosest";
|
||||
import { genIconHTML } from "./util";
|
||||
|
||||
export const mindmapRender = (element: Element, cdn = Constants.PROTYLE_CDN) => {
|
||||
export const mindmapRender = (element: Element, cdn = Constants.PROTYLE_CDN, markmapOptions: { zoom?: boolean; pan?: boolean } = {}) => {
|
||||
let mindmapElements: Element[] = [];
|
||||
if (element.getAttribute("data-subtype") === "mindmap") {
|
||||
// 编辑器内代码块编辑渲染
|
||||
|
|
@ -14,78 +14,158 @@ export const mindmapRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
|
|||
if (mindmapElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
addScript(`${cdn}/js/echarts/echarts.min.js?v=0.0.0`, "protyleEchartsScript").then(() => {
|
||||
const wysiswgElement = hasClosestByClassName(element, "protyle-wysiwyg", true);
|
||||
let width: number = undefined;
|
||||
if (wysiswgElement && wysiswgElement.clientWidth > 0 && mindmapElements[0].firstElementChild.clientWidth === 0 && wysiswgElement.firstElementChild) {
|
||||
width = wysiswgElement.firstElementChild.clientWidth;
|
||||
}
|
||||
mindmapElements.forEach((e: HTMLDivElement) => {
|
||||
if (e.getAttribute("data-render") === "true") {
|
||||
return;
|
||||
// load d3 first, then markmap-lib, then markmap-view (in order)
|
||||
addScript(`${cdn}/js/d3/d3.min.js?v6.7.0`, "protyleD3Script")
|
||||
.then(() => addScript(`${cdn}/js/markmap/markmap-lib.min.js?v0.14.4`, "protyleMarkmapLibScript"))
|
||||
.then(() => addScript(`${cdn}/js/markmap/markmap-view.min.js?v0.14.4`, "protyleMarkmapScript"))
|
||||
.then(() => {
|
||||
const wysiswgElement = hasClosestByClassName(element, "protyle-wysiwyg", true);
|
||||
let width: number = undefined;
|
||||
if (wysiswgElement && wysiswgElement.clientWidth > 0 && mindmapElements[0].firstElementChild.clientWidth === 0 && wysiswgElement.firstElementChild) {
|
||||
width = wysiswgElement.firstElementChild.clientWidth;
|
||||
}
|
||||
if (!e.firstElementChild.classList.contains("protyle-icons")) {
|
||||
e.insertAdjacentHTML("afterbegin", genIconHTML(wysiswgElement));
|
||||
}
|
||||
const renderElement = e.firstElementChild.nextElementSibling as HTMLElement;
|
||||
if (!e.getAttribute("data-content")) {
|
||||
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span>`;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!renderElement.lastElementChild || renderElement.childElementCount === 1) {
|
||||
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span><div style="height:${e.style.height || "420px"}" contenteditable="false"></div>`;
|
||||
} else {
|
||||
renderElement.lastElementChild.classList.remove("ft__error");
|
||||
mindmapElements.forEach((e: HTMLDivElement) => {
|
||||
if (e.getAttribute("data-render") === "true") {
|
||||
return;
|
||||
}
|
||||
window.echarts.init(renderElement.lastElementChild, window.siyuan.config.appearance.mode === 1 ? "dark" : undefined, {
|
||||
width,
|
||||
}).setOption({
|
||||
series: [
|
||||
{
|
||||
data: [JSON.parse(Lute.EChartsMindmapStr(Lute.UnEscapeHTMLStr(e.getAttribute("data-content"))))],
|
||||
initialTreeDepth: -1,
|
||||
itemStyle: {
|
||||
borderWidth: 0,
|
||||
color: "#4285f4",
|
||||
},
|
||||
label: {
|
||||
backgroundColor: "#f6f8fa",
|
||||
borderColor: "#d1d5da",
|
||||
borderRadius: 6,
|
||||
borderWidth: 0.5,
|
||||
color: "#586069",
|
||||
lineHeight: 20,
|
||||
offset: [-5, 0],
|
||||
padding: [0, 5],
|
||||
position: "insideRight",
|
||||
},
|
||||
lineStyle: {
|
||||
color: "#d1d5da",
|
||||
width: 1,
|
||||
},
|
||||
roam: true,
|
||||
symbol: (value: number, params: { data?: { children?: string } }) => {
|
||||
if (params?.data?.children) {
|
||||
return "circle";
|
||||
} else {
|
||||
return "path://";
|
||||
if (!e.firstElementChild.classList.contains("protyle-icons")) {
|
||||
// Add home icon for mindmap (reset view), edit and more
|
||||
e.insertAdjacentHTML("afterbegin", genIconHTML(wysiswgElement, ["home", "edit", "more"]));
|
||||
}
|
||||
const renderElement = e.firstElementChild.nextElementSibling as HTMLElement;
|
||||
if (!e.getAttribute("data-content")) {
|
||||
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span>`;
|
||||
return;
|
||||
}
|
||||
let transformer: any = null;
|
||||
try {
|
||||
// create or reuse container for markmap
|
||||
if (!renderElement.lastElementChild || renderElement.childElementCount === 1) {
|
||||
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span><div style="height:${e.style.height || "420px"}" contenteditable="false"></div>`;
|
||||
} else {
|
||||
renderElement.lastElementChild.classList.remove("ft__error");
|
||||
}
|
||||
|
||||
// Convert stored content to markdown using Lute (prefer existing instance), then transform/render with markmap
|
||||
const raw = Lute.UnEscapeHTMLStr(e.getAttribute("data-content"));
|
||||
let md: string = raw;
|
||||
// prefer protyle's lute instance if available
|
||||
if ((window as any).protyle && (window as any).protyle.lute && typeof (window as any).protyle.lute.BlockDOM2Md === "function") {
|
||||
md = (window as any).protyle.lute.BlockDOM2Md(raw);
|
||||
} else if (typeof Lute === "function" && typeof Lute.New === "function") {
|
||||
try {
|
||||
const luteInst = Lute.New();
|
||||
if (luteInst && typeof luteInst.BlockDOM2Md === "function") {
|
||||
md = luteInst.BlockDOM2Md(raw);
|
||||
} else if (luteInst && typeof luteInst.BlockDOM2HTML === "function") {
|
||||
md = luteInst.BlockDOM2HTML(raw);
|
||||
}
|
||||
} catch (e) {
|
||||
// fallback to raw
|
||||
md = raw;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to obtain markmap entry from loaded bundles (single unified reference)
|
||||
const mm: any = (window as any).markmap || (window as any).Markmap || null;
|
||||
|
||||
// Prefer the Transformer API when available (transform -> getUsedAssets -> load assets -> create)
|
||||
let rootData: any = null;
|
||||
if (mm) {
|
||||
if (typeof mm.Transformer === "function") {
|
||||
transformer = new mm.Transformer();
|
||||
// transform markdown -> { root, features }
|
||||
const tx = transformer.transform(md) || {};
|
||||
rootData = tx.root || null;
|
||||
|
||||
// select asset getter: prefer getUsedAssets then getAssets
|
||||
const assetsGetter = typeof transformer.getUsedAssets === "function" ? "getUsedAssets" : (typeof transformer.getAssets === "function" ? "getAssets" : null);
|
||||
if (assetsGetter) {
|
||||
const assets = (transformer as any)[assetsGetter](tx.features || {});
|
||||
const styles = assets && assets.styles;
|
||||
const scripts = assets && assets.scripts;
|
||||
|
||||
const loadCSS = typeof mm.loadCSS === "function" ? mm.loadCSS : null;
|
||||
const loadJS = typeof mm.loadJS === "function" ? mm.loadJS : null;
|
||||
if (styles && loadCSS) {
|
||||
try { loadCSS(styles); } catch (err) { /* ignore */ }
|
||||
}
|
||||
},
|
||||
type: "tree",
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
triggerOn: "mousemove",
|
||||
},
|
||||
backgroundColor: "transparent",
|
||||
});
|
||||
} catch (error) {
|
||||
window.echarts.dispose(renderElement.lastElementChild);
|
||||
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span><div class="ft__error" style="height:${e.style.height || "420px"}" contenteditable="false">Mindmap render error: <br>${error}</div>`;
|
||||
}
|
||||
e.setAttribute("data-render", "true");
|
||||
if (scripts && loadJS) {
|
||||
try { loadJS(scripts, { getMarkmap: () => (window as any).markmap || mm }); } catch (err) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// fallback: try older transform functions (may return root-like object)
|
||||
const transformFn = mm.transform || (window as any).markmap && (window as any).markmap.transform;
|
||||
if (typeof transformFn === "function") {
|
||||
try {
|
||||
const tx = transformFn(md) || {};
|
||||
rootData = tx.root || tx || null;
|
||||
} catch (err) {
|
||||
rootData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// container for svg
|
||||
const container = renderElement.lastElementChild as HTMLElement;
|
||||
// clear existing content and append an svg for markmap
|
||||
container.innerHTML = "";
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
// use width if calculated earlier
|
||||
if (typeof width === "number" && width > 0) {
|
||||
svg.setAttribute("width", String(width));
|
||||
} else {
|
||||
svg.setAttribute("width", "100%");
|
||||
}
|
||||
svg.setAttribute("height", "100%");
|
||||
container.appendChild(svg);
|
||||
|
||||
// prefer Markmap.create if available
|
||||
const MarkmapCtor = (mm && (mm.Markmap || mm.default || mm)) || (window as any).Markmap;
|
||||
// default options, allow overriding via markmapOptions (e.g. in export we can pass zoom/pan false)
|
||||
const options = Object.assign({
|
||||
duration: 0, // 🔥 禁用动画,设为0
|
||||
}, markmapOptions || {});
|
||||
// create and store markmap + transformer on the element so callers can update instead of re-creating
|
||||
if (MarkmapCtor && typeof MarkmapCtor.create === "function") {
|
||||
if (rootData) {
|
||||
const markmapInstance = MarkmapCtor.create(svg, options, rootData);
|
||||
const mmEntry: any = (e as any).__markmap || {};
|
||||
mmEntry.transformer = transformer || mmEntry.transformer || null;
|
||||
mmEntry.markmap = markmapInstance;
|
||||
mmEntry.options = options;
|
||||
(e as any).__markmap = mmEntry;
|
||||
}
|
||||
} else {
|
||||
throw new Error("Markmap not available");
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
renderElement.innerHTML = `<span style="position: absolute;left:0;top:0;width: 1px;">${Constants.ZWSP}</span><div class="ft__error" style="height:${e.style.height || "420px"}" contenteditable="false">Mindmap render error: <br>${error}</div>`;
|
||||
}
|
||||
e.setAttribute("data-render", "true");
|
||||
// expose a small helper to update content (callable by toolbar)
|
||||
try {
|
||||
const mmEntry: any = (e as any).__markmap;
|
||||
if (mmEntry && mmEntry.transformer && mmEntry.markmap) {
|
||||
(e as any).__markmap.updateContent = (newMarkdown: string) => {
|
||||
try {
|
||||
const tx2 = mmEntry.transformer.transform(newMarkdown) || {};
|
||||
const root2 = tx2.root || null;
|
||||
if (mmEntry.markmap && typeof mmEntry.markmap.setData === "function") {
|
||||
mmEntry.markmap.setData(root2, mmEntry.options);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore update errors
|
||||
console.error("markmap updateContent error", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {isInEmbedBlock} from "../util/hasClosest";
|
||||
import {Constants} from "../../constants";
|
||||
import { isInEmbedBlock } from "../util/hasClosest";
|
||||
import { Constants } from "../../constants";
|
||||
|
||||
export const genIconHTML = (element?: false | HTMLElement, actions = ["edit", "more"]) => {
|
||||
let enable = true;
|
||||
|
|
@ -11,18 +11,51 @@ export const genIconHTML = (element?: false | HTMLElement, actions = ["edit", "m
|
|||
return '<div class="protyle-icons"></div>';
|
||||
}
|
||||
}
|
||||
if (actions.length === 3) {
|
||||
return `<div class="protyle-icons">
|
||||
<span aria-label="${window.siyuan.languages.refresh}" data-position="4north" class="ariaLabel protyle-icon protyle-icon--first protyle-action__reload"><svg><use xlink:href="#iconRefresh"></use></svg></span>
|
||||
<span aria-label="${window.siyuan.languages.edit}" data-position="4north" class="ariaLabel protyle-icon protyle-action__edit${enable ? "" : " fn__none"}"><svg><use xlink:href="#iconEdit"></use></svg></span>
|
||||
<span aria-label="${window.siyuan.languages.more}" data-position="4north" class="ariaLabel protyle-icon protyle-action__menu protyle-icon--last"><svg><use xlink:href="#iconMore"></use></svg></span>
|
||||
</div>`;
|
||||
} else {
|
||||
return `<div class="protyle-icons">
|
||||
<span aria-label="${window.siyuan.languages.edit}" data-position="4north" class="ariaLabel protyle-icon protyle-icon--first protyle-action__edit${enable ? "" : " fn__none"}"><svg><use xlink:href="#iconEdit"></use></svg></span>
|
||||
<span aria-label="${window.siyuan.languages.more}" data-position="4north" class="ariaLabel protyle-icon protyle-action__menu protyle-icon--last${enable ? "" : " protyle-icon--first"}"><svg><use xlink:href="#iconMore"></use></svg></span>
|
||||
</div>`;
|
||||
const mapActionToHTML = (action: string, isFirst: boolean, isLast: boolean) => {
|
||||
const classList = ["ariaLabel", "protyle-icon"];
|
||||
if (isFirst) classList.push("protyle-icon--first");
|
||||
if (isLast) classList.push("protyle-icon--last");
|
||||
let aria = "";
|
||||
let className = "";
|
||||
let icon = "";
|
||||
switch (action) {
|
||||
case "reload":
|
||||
case "refresh":
|
||||
aria = window.siyuan.languages.refresh;
|
||||
className = "protyle-action__reload";
|
||||
icon = "iconRefresh";
|
||||
break;
|
||||
case "home":
|
||||
case "fit":
|
||||
aria = window.siyuan.languages.reset;
|
||||
className = "protyle-action__home";
|
||||
icon = "iconHistory";
|
||||
break;
|
||||
case "edit":
|
||||
aria = window.siyuan.languages.edit;
|
||||
className = "protyle-action__edit";
|
||||
icon = "iconEdit";
|
||||
break;
|
||||
case "more":
|
||||
default:
|
||||
aria = window.siyuan.languages.more;
|
||||
className = "protyle-action__menu";
|
||||
icon = "iconMore";
|
||||
break;
|
||||
}
|
||||
// Only the edit button honors read-only enable
|
||||
const hidden = (action === "edit" && !enable) ? " fn__none" : "";
|
||||
return `<span aria-label="${aria}" data-position="4north" class="${classList.join(" ")} ${className}${hidden}"><svg><use xlink:href="#${icon}"></use></svg></span>`;
|
||||
};
|
||||
const res: string[] = [];
|
||||
for (let i = 0; i < actions.length; i++) {
|
||||
const isFirst = i === 0;
|
||||
const isLast = i === actions.length - 1;
|
||||
res.push(mapActionToHTML(actions[i], isFirst, isLast));
|
||||
}
|
||||
return `<div class="protyle-icons">
|
||||
${res.join("\n ")}
|
||||
</div>`;
|
||||
};
|
||||
|
||||
export const genRenderFrame = (renderElement: Element) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Divider} from "./Divider";
|
||||
import {Font, hasSameTextStyle, setFontStyle} from "./Font";
|
||||
import {ToolbarItem} from "./ToolbarItem";
|
||||
import { Divider } from "./Divider";
|
||||
import { Font, hasSameTextStyle, setFontStyle } from "./Font";
|
||||
import { ToolbarItem } from "./ToolbarItem";
|
||||
import {
|
||||
fixTableRange,
|
||||
focusBlock,
|
||||
|
|
@ -12,40 +12,40 @@ import {
|
|||
setFirstNodeRange,
|
||||
setLastNodeRange
|
||||
} from "../util/selection";
|
||||
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../util/hasClosest";
|
||||
import {Link} from "./Link";
|
||||
import {setPosition} from "../../util/setPosition";
|
||||
import {transaction, updateTransaction} from "../wysiwyg/transaction";
|
||||
import {Constants} from "../../constants";
|
||||
import {copyPlainText, openByMobile, readClipboard, setStorageVal} from "../util/compatibility";
|
||||
import {upDownHint} from "../../util/upDownHint";
|
||||
import {highlightRender} from "../render/highlightRender";
|
||||
import {getContenteditableElement, hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock";
|
||||
import {processRender} from "../util/processCode";
|
||||
import {BlockRef} from "./BlockRef";
|
||||
import {hintRenderTemplate, hintRenderWidget} from "../hint/extend";
|
||||
import {blockRender} from "../render/blockRender";
|
||||
import { hasClosestBlock, hasClosestByAttribute, hasClosestByClassName } from "../util/hasClosest";
|
||||
import { Link } from "./Link";
|
||||
import { setPosition } from "../../util/setPosition";
|
||||
import { transaction, updateTransaction } from "../wysiwyg/transaction";
|
||||
import { Constants } from "../../constants";
|
||||
import { copyPlainText, openByMobile, readClipboard, setStorageVal } from "../util/compatibility";
|
||||
import { upDownHint } from "../../util/upDownHint";
|
||||
import { highlightRender } from "../render/highlightRender";
|
||||
import { getContenteditableElement, hasNextSibling, hasPreviousSibling } from "../wysiwyg/getBlock";
|
||||
import { processRender } from "../util/processCode";
|
||||
import { BlockRef } from "./BlockRef";
|
||||
import { hintRenderTemplate, hintRenderWidget } from "../hint/extend";
|
||||
import { blockRender } from "../render/blockRender";
|
||||
/// #if !BROWSER
|
||||
import {openBy} from "../../editor/util";
|
||||
import { openBy } from "../../editor/util";
|
||||
/// #endif
|
||||
import {fetchPost} from "../../util/fetch";
|
||||
import {isArrayEqual, isMobile} from "../../util/functions";
|
||||
import { fetchPost } from "../../util/fetch";
|
||||
import { isArrayEqual, isMobile } from "../../util/functions";
|
||||
import * as dayjs from "dayjs";
|
||||
import {insertEmptyBlock} from "../../block/util";
|
||||
import {matchHotKey} from "../util/hotKey";
|
||||
import {hideElements} from "../ui/hideElements";
|
||||
import {electronUndo} from "../undo";
|
||||
import {previewTemplate, toolbarKeyToMenu} from "./util";
|
||||
import {hideMessage, showMessage} from "../../dialog/message";
|
||||
import {InlineMath} from "./InlineMath";
|
||||
import {InlineMemo} from "./InlineMemo";
|
||||
import {mathRender} from "../render/mathRender";
|
||||
import {linkMenu} from "../../menus/protyle";
|
||||
import {addScript} from "../util/addScript";
|
||||
import {confirmDialog} from "../../dialog/confirmDialog";
|
||||
import {paste, pasteAsPlainText, pasteEscaped} from "../util/paste";
|
||||
import {escapeHtml} from "../../util/escape";
|
||||
import {resizeSide} from "../../history/resizeSide";
|
||||
import { insertEmptyBlock } from "../../block/util";
|
||||
import { matchHotKey } from "../util/hotKey";
|
||||
import { hideElements } from "../ui/hideElements";
|
||||
import { electronUndo } from "../undo";
|
||||
import { previewTemplate, toolbarKeyToMenu } from "./util";
|
||||
import { hideMessage, showMessage } from "../../dialog/message";
|
||||
import { InlineMath } from "./InlineMath";
|
||||
import { InlineMemo } from "./InlineMemo";
|
||||
import { mathRender } from "../render/mathRender";
|
||||
import { linkMenu } from "../../menus/protyle";
|
||||
import { addScript } from "../util/addScript";
|
||||
import { confirmDialog } from "../../dialog/confirmDialog";
|
||||
import { paste, pasteAsPlainText, pasteEscaped } from "../util/paste";
|
||||
import { escapeHtml } from "../../util/escape";
|
||||
import { resizeSide } from "../../history/resizeSide";
|
||||
|
||||
export class Toolbar {
|
||||
public element: HTMLElement;
|
||||
|
|
@ -309,12 +309,12 @@ export class Toolbar {
|
|||
const startPreviousSibling = hasPreviousSibling(this.range.startContainer);
|
||||
const endNextSibling = hasNextSibling(this.range.endContainer);
|
||||
if ((
|
||||
this.range.startOffset !== 0 ||
|
||||
// https://github.com/siyuan-note/siyuan/issues/14869
|
||||
(this.range.startOffset === 0 && startPreviousSibling &&
|
||||
(startPreviousSibling.nodeType === 3 || (startPreviousSibling as HTMLElement).tagName === "BR") &&
|
||||
this.range.startContainer.previousSibling.parentElement === this.range.startContainer.parentElement)
|
||||
) && (
|
||||
this.range.startOffset !== 0 ||
|
||||
// https://github.com/siyuan-note/siyuan/issues/14869
|
||||
(this.range.startOffset === 0 && startPreviousSibling &&
|
||||
(startPreviousSibling.nodeType === 3 || (startPreviousSibling as HTMLElement).tagName === "BR") &&
|
||||
this.range.startContainer.previousSibling.parentElement === this.range.startContainer.parentElement)
|
||||
) && (
|
||||
this.range.endOffset !== this.range.endContainer.textContent.length ||
|
||||
// https://github.com/siyuan-note/siyuan/issues/14869#issuecomment-2911553387
|
||||
(
|
||||
|
|
@ -987,6 +987,17 @@ export class Toolbar {
|
|||
break;
|
||||
case "refresh":
|
||||
btnElement.classList.toggle("block__icon--active");
|
||||
// If this is a mindmap, call markmap instance fit() to reset view
|
||||
if (renderElement.getAttribute("data-subtype") === "mindmap") {
|
||||
const mmEntry: any = (renderElement as any).__markmap || (nodeElement as any).__markmap || null;
|
||||
if (mmEntry && mmEntry.markmap && typeof mmEntry.markmap.fit === "function") {
|
||||
try {
|
||||
mmEntry.markmap.fit();
|
||||
} catch (e) {
|
||||
console.error("markmap fit error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "before":
|
||||
insertEmptyBlock(protyle, "beforebegin", id);
|
||||
|
|
@ -1017,6 +1028,55 @@ export class Toolbar {
|
|||
});
|
||||
return;
|
||||
}
|
||||
// mindmap: try to export SVG directly using the rendered SVG
|
||||
if (renderElement.getAttribute("data-subtype") === "mindmap") {
|
||||
try {
|
||||
// find rendered svg inside the renderElement
|
||||
const svgElement = renderElement.querySelector("svg.markmap") as SVGSVGElement;
|
||||
if (!svgElement) {
|
||||
throw new Error("SVG not found");
|
||||
}
|
||||
const clonedSvg = svgElement.cloneNode(true) as SVGSVGElement;
|
||||
const bbox = svgElement.getBBox();
|
||||
clonedSvg.setAttribute("viewBox", `${bbox.x - 20} ${bbox.y - 20} ${bbox.width + 40} ${bbox.height + 40}`);
|
||||
clonedSvg.setAttribute("width", String(bbox.width + 40));
|
||||
clonedSvg.setAttribute("height", String(bbox.height + 40));
|
||||
clonedSvg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
||||
clonedSvg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||
|
||||
// inline styles
|
||||
const styles = Array.from(document.styleSheets)
|
||||
.filter(sheet => {
|
||||
try {
|
||||
return sheet.cssRules;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.reduce((acc, sheet) => {
|
||||
return acc + Array.from((sheet as CSSStyleSheet).cssRules).map(rule => rule.cssText).join("\n");
|
||||
}, "");
|
||||
|
||||
const styleElement = document.createElementNS("http://www.w3.org/2000/svg", "style");
|
||||
styleElement.textContent = styles;
|
||||
clonedSvg.insertBefore(styleElement, clonedSvg.firstChild);
|
||||
|
||||
const serializer = new XMLSerializer();
|
||||
const svgString = serializer.serializeToString(clonedSvg);
|
||||
const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
|
||||
const formData = new FormData();
|
||||
formData.append("file", blob);
|
||||
formData.append("type", "image/svg+xml");
|
||||
fetchPost("/api/export/exportAsFile", formData, (response) => {
|
||||
openByMobile(response.data.file);
|
||||
hideMessage(msgId);
|
||||
});
|
||||
return;
|
||||
} catch (err) {
|
||||
console.error("mindmap export error", err);
|
||||
// fall through to html-to-image fallback
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
addScript("/stage/protyle/js/html-to-image.min.js?v=1.11.13", "protyleHtml2image").then(() => {
|
||||
(renderElement as HTMLHtmlElement).style.display = "inline-block";
|
||||
|
|
@ -1067,11 +1127,32 @@ export class Toolbar {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
renderElement.setAttribute("data-content", Lute.EscapeHTMLStr(textElement.value));
|
||||
renderElement.removeAttribute("data-render");
|
||||
// mindmap: try incremental update via stored markmap instance
|
||||
const isMindmap = renderElement.getAttribute("data-subtype") === "mindmap";
|
||||
const mmEntry: any = (renderElement as any).__markmap || (nodeElement as any).__markmap || null;
|
||||
if (isMindmap && mmEntry && mmEntry.transformer && mmEntry.markmap && this.subElement.querySelector('[data-type="refresh"]').classList.contains("block__icon--active")) {
|
||||
try {
|
||||
// update markmap in-place
|
||||
const txu = mmEntry.transformer.transform(textElement.value) || {};
|
||||
const rootu = txu.root || null;
|
||||
mmEntry.markmap.setData(rootu, mmEntry.options);
|
||||
renderElement.setAttribute("data-content", Lute.EscapeHTMLStr(textElement.value));
|
||||
} catch (err) {
|
||||
// fallback to re-render
|
||||
renderElement.setAttribute("data-content", Lute.EscapeHTMLStr(textElement.value));
|
||||
renderElement.removeAttribute("data-render");
|
||||
}
|
||||
} else {
|
||||
renderElement.setAttribute("data-content", Lute.EscapeHTMLStr(textElement.value));
|
||||
renderElement.removeAttribute("data-render");
|
||||
}
|
||||
}
|
||||
if (!types.includes("NodeBlockQueryEmbed") || !types.includes("NodeHTMLBlock") || !isInlineMemo) {
|
||||
processRender(renderElement);
|
||||
// If mindmap was updated via markmap.setData above, no need to run full processRender.
|
||||
const didIncrementalUpdate = renderElement.getAttribute("data-subtype") === "mindmap" && ((renderElement as any).__markmap && (renderElement as any).__markmap.markmap) && this.subElement.querySelector('[data-type="refresh"]').classList.contains("block__icon--active");
|
||||
if (!didIncrementalUpdate) {
|
||||
if (!types.includes("NodeBlockQueryEmbed") || !types.includes("NodeHTMLBlock") || !isInlineMemo) {
|
||||
processRender(renderElement);
|
||||
}
|
||||
}
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
|
@ -1158,11 +1239,30 @@ export class Toolbar {
|
|||
} else {
|
||||
renderElement.setAttribute("data-content", Lute.EscapeHTMLStr(textElement.value));
|
||||
renderElement.removeAttribute("data-render");
|
||||
if (types.includes("NodeBlockQueryEmbed")) {
|
||||
blockRender(protyle, renderElement);
|
||||
(renderElement as HTMLElement).style.height = "";
|
||||
// If this is a mindmap and we have a stored markmap instance, prefer incremental update
|
||||
const isMindmap = renderElement.getAttribute("data-subtype") === "mindmap";
|
||||
const mmEntry: any = (renderElement as any).__markmap || (nodeElement as any).__markmap || null;
|
||||
if (isMindmap && mmEntry && mmEntry.transformer && mmEntry.markmap) {
|
||||
try {
|
||||
const txu = mmEntry.transformer.transform(textElement.value) || {};
|
||||
const rootu = txu.root || null;
|
||||
mmEntry.markmap.setData(rootu, mmEntry.options);
|
||||
} catch (err) {
|
||||
// fallback to full render
|
||||
if (types.includes("NodeBlockQueryEmbed")) {
|
||||
blockRender(protyle, renderElement);
|
||||
(renderElement as HTMLElement).style.height = "";
|
||||
} else {
|
||||
processRender(renderElement);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processRender(renderElement);
|
||||
if (types.includes("NodeBlockQueryEmbed")) {
|
||||
blockRender(protyle, renderElement);
|
||||
(renderElement as HTMLElement).style.height = "";
|
||||
} else {
|
||||
processRender(renderElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1248,7 +1348,7 @@ export class Toolbar {
|
|||
let html = `<div data-id="clearLanguage" class="b3-list-item">${window.siyuan.languages.clear}</div>`;
|
||||
let hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort();
|
||||
|
||||
const eventDetail = {languages: hljsLanguages, type: "init", listElement};
|
||||
const eventDetail = { languages: hljsLanguages, type: "init", listElement };
|
||||
if (protyle.app && protyle.app.plugins) {
|
||||
protyle.app.plugins.forEach((plugin: any) => {
|
||||
plugin.eventBus.emit("code-language-update", eventDetail);
|
||||
|
|
@ -1322,7 +1422,7 @@ export class Toolbar {
|
|||
}
|
||||
}
|
||||
|
||||
const eventDetail = {languages: value ? matchLanguages : hljsLanguages, type: "match", value, listElement};
|
||||
const eventDetail = { languages: value ? matchLanguages : hljsLanguages, type: "match", value, listElement };
|
||||
if (protyle.app && protyle.app.plugins) {
|
||||
protyle.app.plugins.forEach((plugin: any) => {
|
||||
plugin.eventBus.emit("code-language-update", eventDetail);
|
||||
|
|
@ -1489,7 +1589,7 @@ export class Toolbar {
|
|||
/// #endif
|
||||
if (iconElement && iconElement.getAttribute("data-type") === "remove") {
|
||||
confirmDialog(window.siyuan.languages.remove, window.siyuan.languages.confirmDelete + "?", () => {
|
||||
fetchPost("/api/search/removeTemplate", {path: iconElement.parentElement.getAttribute("data-value")}, () => {
|
||||
fetchPost("/api/search/removeTemplate", { path: iconElement.parentElement.getAttribute("data-value") }, () => {
|
||||
if (iconElement.parentElement.parentElement.childElementCount === 1) {
|
||||
iconElement.parentElement.parentElement.innerHTML = `<li class="b3-list--empty">${window.siyuan.languages.emptyContent}</li>`;
|
||||
previewTemplate("", previewElement, protyle.block.parentID);
|
||||
|
|
@ -1513,13 +1613,13 @@ export class Toolbar {
|
|||
}
|
||||
const previousElement = hasClosestByAttribute(target, "data-type", "previous");
|
||||
if (previousElement) {
|
||||
inputElement.dispatchEvent(new KeyboardEvent("keydown", {key: "ArrowUp"}));
|
||||
inputElement.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowUp" }));
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
const nextElement = hasClosestByAttribute(target, "data-type", "next");
|
||||
if (nextElement) {
|
||||
inputElement.dispatchEvent(new KeyboardEvent("keydown", {key: "ArrowDown"}));
|
||||
inputElement.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown" }));
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
|
@ -1691,7 +1791,7 @@ ${item.name}
|
|||
} else {
|
||||
try {
|
||||
const text = await readClipboard();
|
||||
paste(protyle, Object.assign(text, {target: nodeElement as HTMLElement}));
|
||||
paste(protyle, Object.assign(text, { target: nodeElement as HTMLElement }));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {enableLuteMarkdownSyntax, getTextStar, paste, restoreLuteMarkdownSyntax} from "../util/paste";
|
||||
import { enableLuteMarkdownSyntax, getTextStar, paste, restoreLuteMarkdownSyntax } from "../util/paste";
|
||||
import {
|
||||
hasClosestBlock,
|
||||
hasClosestByAttribute,
|
||||
|
|
@ -18,9 +18,9 @@ import {
|
|||
setInsertWbrHTML,
|
||||
setLastNodeRange,
|
||||
} from "../util/selection";
|
||||
import {Constants} from "../../constants";
|
||||
import {isMobile} from "../../util/functions";
|
||||
import {previewDocImage} from "../preview/image";
|
||||
import { Constants } from "../../constants";
|
||||
import { isMobile } from "../../util/functions";
|
||||
import { previewDocImage } from "../preview/image";
|
||||
import {
|
||||
contentMenu,
|
||||
enterBack,
|
||||
|
|
@ -34,8 +34,8 @@ import {
|
|||
zoomOut
|
||||
} from "../../menus/protyle";
|
||||
import * as dayjs from "dayjs";
|
||||
import {dropEvent} from "../util/editorCommonEvent";
|
||||
import {input} from "./input";
|
||||
import { dropEvent } from "../util/editorCommonEvent";
|
||||
import { input } from "./input";
|
||||
import {
|
||||
getContenteditableElement,
|
||||
getNextBlock,
|
||||
|
|
@ -45,43 +45,43 @@ import {
|
|||
isEndOfBlock,
|
||||
isNotEditBlock
|
||||
} from "./getBlock";
|
||||
import {transaction, updateTransaction} from "./transaction";
|
||||
import {hideElements} from "../ui/hideElements";
|
||||
import { transaction, updateTransaction } from "./transaction";
|
||||
import { hideElements } from "../ui/hideElements";
|
||||
/// #if !BROWSER
|
||||
import {ipcRenderer} from "electron";
|
||||
import { ipcRenderer } from "electron";
|
||||
/// #endif
|
||||
import {getEnableHTML, removeEmbed} from "./removeEmbed";
|
||||
import {keydown} from "./keydown";
|
||||
import {openMobileFileById} from "../../mobile/editor";
|
||||
import {removeBlock} from "./remove";
|
||||
import {highlightRender} from "../render/highlightRender";
|
||||
import {openAttr} from "../../menus/commonMenuItem";
|
||||
import {blockRender} from "../render/blockRender";
|
||||
import { getEnableHTML, removeEmbed } from "./removeEmbed";
|
||||
import { keydown } from "./keydown";
|
||||
import { openMobileFileById } from "../../mobile/editor";
|
||||
import { removeBlock } from "./remove";
|
||||
import { highlightRender } from "../render/highlightRender";
|
||||
import { openAttr } from "../../menus/commonMenuItem";
|
||||
import { blockRender } from "../render/blockRender";
|
||||
/// #if !MOBILE
|
||||
import {getAllModels} from "../../layout/getAll";
|
||||
import {pushBack} from "../../util/backForward";
|
||||
import {openFileById} from "../../editor/util";
|
||||
import {openGlobalSearch} from "../../search/util";
|
||||
import { getAllModels } from "../../layout/getAll";
|
||||
import { pushBack } from "../../util/backForward";
|
||||
import { openFileById } from "../../editor/util";
|
||||
import { openGlobalSearch } from "../../search/util";
|
||||
/// #else
|
||||
import {popSearch} from "../../mobile/menu/search";
|
||||
import { popSearch } from "../../mobile/menu/search";
|
||||
/// #endif
|
||||
import {BlockPanel} from "../../block/Panel";
|
||||
import {copyPlainText, isInIOS, isMac, isOnlyMeta, readClipboard, encodeBase64} from "../util/compatibility";
|
||||
import {MenuItem} from "../../menus/Menu";
|
||||
import {fetchPost, fetchSyncPost} from "../../util/fetch";
|
||||
import {onGet} from "../util/onGet";
|
||||
import {clearTableCell, isIncludeCell, setTableAlign} from "../util/table";
|
||||
import {countBlockWord, countSelectWord} from "../../layout/status";
|
||||
import {showMessage} from "../../dialog/message";
|
||||
import {getBacklinkHeadingMore, loadBreadcrumb} from "./renderBacklink";
|
||||
import {removeSearchMark} from "../toolbar/util";
|
||||
import {activeBlur} from "../../mobile/util/keyboardToolbar";
|
||||
import {commonClick} from "./commonClick";
|
||||
import {avClick, avContextmenu, updateAVName} from "../render/av/action";
|
||||
import {selectRow, stickyRow} from "../render/av/row";
|
||||
import {showColMenu} from "../render/av/col";
|
||||
import {openViewMenu} from "../render/av/view";
|
||||
import {checkFold} from "../../util/noRelyPCFunction";
|
||||
import { BlockPanel } from "../../block/Panel";
|
||||
import { copyPlainText, isInIOS, isMac, isOnlyMeta, readClipboard, encodeBase64 } from "../util/compatibility";
|
||||
import { MenuItem } from "../../menus/Menu";
|
||||
import { fetchPost, fetchSyncPost } from "../../util/fetch";
|
||||
import { onGet } from "../util/onGet";
|
||||
import { clearTableCell, isIncludeCell, setTableAlign } from "../util/table";
|
||||
import { countBlockWord, countSelectWord } from "../../layout/status";
|
||||
import { showMessage } from "../../dialog/message";
|
||||
import { getBacklinkHeadingMore, loadBreadcrumb } from "./renderBacklink";
|
||||
import { removeSearchMark } from "../toolbar/util";
|
||||
import { activeBlur } from "../../mobile/util/keyboardToolbar";
|
||||
import { commonClick } from "./commonClick";
|
||||
import { avClick, avContextmenu, updateAVName } from "../render/av/action";
|
||||
import { selectRow, stickyRow } from "../render/av/row";
|
||||
import { showColMenu } from "../render/av/col";
|
||||
import { openViewMenu } from "../render/av/view";
|
||||
import { checkFold } from "../../util/noRelyPCFunction";
|
||||
import {
|
||||
addDragFill,
|
||||
dragFillCellsValue,
|
||||
|
|
@ -91,6 +91,16 @@ import {
|
|||
getTypeByCellElement,
|
||||
updateCellsValue
|
||||
} from "../render/av/cell";
|
||||
import { openEmojiPanel, unicode2Emoji } from "../../emoji";
|
||||
import { openLink } from "../../editor/openLink";
|
||||
import { mathRender } from "../render/mathRender";
|
||||
import { editAssetItem } from "../render/av/asset";
|
||||
import { img3115 } from "../../boot/compatibleVersion";
|
||||
import { globalClickHideMenu } from "../../boot/globalEvent/click";
|
||||
import { hideTooltip } from "../../dialog/tooltip";
|
||||
import { openGalleryItemMenu } from "../render/av/gallery/util";
|
||||
import { clearSelect } from "../util/clearSelect";
|
||||
import { chartRender } from "../render/chartRender";
|
||||
import {openEmojiPanel, unicode2Emoji} from "../../emoji";
|
||||
import {openLink} from "../../editor/openLink";
|
||||
import {mathRender} from "../render/mathRender";
|
||||
|
|
@ -1554,11 +1564,11 @@ export class WYSIWYG {
|
|||
const scrollTop = tableBlockElement.querySelector("table").scrollTop;
|
||||
tableBlockElement.querySelectorAll("th, td").forEach((item: HTMLTableCellElement) => {
|
||||
if (!item.classList.contains("fn__none") && isIncludeCell({
|
||||
tableSelectElement,
|
||||
scrollLeft,
|
||||
scrollTop,
|
||||
item,
|
||||
}) &&
|
||||
tableSelectElement,
|
||||
scrollLeft,
|
||||
scrollTop,
|
||||
item,
|
||||
}) &&
|
||||
(selectCellElements.length === 0 || (selectCellElements.length > 0 && item.offsetTop === selectCellElements[0].offsetTop))) {
|
||||
selectCellElements.push(item);
|
||||
}
|
||||
|
|
@ -1604,11 +1614,11 @@ export class WYSIWYG {
|
|||
const scrollTop = tableBlockElement.querySelector("table").scrollTop;
|
||||
tableBlockElement.querySelectorAll("th, td").forEach((item: HTMLTableCellElement) => {
|
||||
if (!item.classList.contains("fn__none") && isIncludeCell({
|
||||
tableSelectElement,
|
||||
scrollLeft,
|
||||
scrollTop,
|
||||
item,
|
||||
}) &&
|
||||
tableSelectElement,
|
||||
scrollLeft,
|
||||
scrollTop,
|
||||
item,
|
||||
}) &&
|
||||
(selectCellElements.length === 0 || (selectCellElements.length > 0 && item.offsetTop === selectCellElements[0].offsetTop))) {
|
||||
selectCellElements.push(item);
|
||||
}
|
||||
|
|
@ -1700,7 +1710,7 @@ export class WYSIWYG {
|
|||
} else if (tableBlockElement) {
|
||||
try {
|
||||
const text = await readClipboard();
|
||||
paste(protyle, Object.assign(text, {target: tableBlockElement as HTMLElement}));
|
||||
paste(protyle, Object.assign(text, { target: tableBlockElement as HTMLElement }));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
|
@ -1708,7 +1718,7 @@ export class WYSIWYG {
|
|||
}
|
||||
}).element);
|
||||
}
|
||||
window.siyuan.menus.menu.popup({x: mouseUpEvent.clientX - 8, y: mouseUpEvent.clientY - 16});
|
||||
window.siyuan.menus.menu.popup({ x: mouseUpEvent.clientX - 8, y: mouseUpEvent.clientY - 16 });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2104,7 +2114,7 @@ export class WYSIWYG {
|
|||
// 多选块
|
||||
hideElements(["util"], protyle);
|
||||
protyle.gutter.renderMenu(protyle, selectElements[0]);
|
||||
window.siyuan.menus.menu.popup({x, y});
|
||||
window.siyuan.menus.menu.popup({ x, y });
|
||||
return;
|
||||
}
|
||||
const target = event.detail.target || event.target as HTMLElement;
|
||||
|
|
@ -2117,7 +2127,7 @@ export class WYSIWYG {
|
|||
/// #if MOBILE
|
||||
window.siyuan.menus.menu.fullscreen();
|
||||
/// #else
|
||||
window.siyuan.menus.menu.popup({x, y});
|
||||
window.siyuan.menus.menu.popup({ x, y });
|
||||
/// #endif
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2191,7 +2201,7 @@ export class WYSIWYG {
|
|||
const avTabHeaderElement = hasClosestByClassName(target, "item");
|
||||
if (nodeElement.classList.contains("av") && avTabHeaderElement) {
|
||||
if (avTabHeaderElement.classList.contains("item--focus")) {
|
||||
openViewMenu({protyle, blockElement: nodeElement, element: avTabHeaderElement});
|
||||
openViewMenu({ protyle, blockElement: nodeElement, element: avTabHeaderElement });
|
||||
} else {
|
||||
transaction(protyle, [{
|
||||
action: "setAttrViewBlockView",
|
||||
|
|
@ -2275,7 +2285,7 @@ export class WYSIWYG {
|
|||
) {
|
||||
if ((!isMobile() || protyle.toolbar?.element.classList.contains("fn__none")) && !nodeElement.classList.contains("av")) {
|
||||
contentMenu(protyle, nodeElement);
|
||||
window.siyuan.menus.menu.popup({x, y: y + 13, h: 26});
|
||||
window.siyuan.menus.menu.popup({ x, y: y + 13, h: 26 });
|
||||
protyle.toolbar?.element.classList.add("fn__none");
|
||||
if (nodeElement.classList.contains("table")) {
|
||||
nodeElement.querySelector(".table__select").removeAttribute("style");
|
||||
|
|
@ -2289,7 +2299,7 @@ export class WYSIWYG {
|
|||
/// #if MOBILE
|
||||
window.siyuan.menus.menu.fullscreen();
|
||||
/// #else
|
||||
window.siyuan.menus.menu.popup({x, y});
|
||||
window.siyuan.menus.menu.popup({ x, y });
|
||||
/// #endif
|
||||
protyle.toolbar?.element.classList.add("fn__none");
|
||||
}
|
||||
|
|
@ -2360,7 +2370,7 @@ export class WYSIWYG {
|
|||
window.siyuan.menus.menu.remove();
|
||||
}
|
||||
}
|
||||
}, {passive: true});
|
||||
}, { passive: true });
|
||||
|
||||
this.element.addEventListener("paste", (event: ClipboardEvent & { target: HTMLElement }) => {
|
||||
// https://github.com/siyuan-note/siyuan/issues/11241
|
||||
|
|
@ -2696,7 +2706,7 @@ export class WYSIWYG {
|
|||
zoomIn,
|
||||
scrollPosition: "start"
|
||||
});
|
||||
window.dispatchEvent(new KeyboardEvent("keydown", {key: "Escape"}));
|
||||
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
|
||||
} else if (event.altKey) {
|
||||
openFileById({
|
||||
app: protyle.app,
|
||||
|
|
@ -2809,7 +2819,7 @@ export class WYSIWYG {
|
|||
const tagElement = hasClosestByAttribute(event.target, "data-type", "tag");
|
||||
if (tagElement && !event.altKey && !event.shiftKey && range.toString() === "") {
|
||||
/// #if !MOBILE
|
||||
openGlobalSearch(protyle.app, `#${tagElement.textContent}#`, !ctrlIsPressed, {method: 0});
|
||||
openGlobalSearch(protyle.app, `#${tagElement.textContent}#`, !ctrlIsPressed, { method: 0 });
|
||||
hideElements(["dialog"]);
|
||||
/// #else
|
||||
popSearch(protyle.app, {
|
||||
|
|
@ -2863,7 +2873,7 @@ export class WYSIWYG {
|
|||
app: protyle.app,
|
||||
targetElement: embedItemElement,
|
||||
isBacklink: false,
|
||||
refDefs: [{refID: embedId}]
|
||||
refDefs: [{ refID: embedId }]
|
||||
}));
|
||||
}
|
||||
/// #endif
|
||||
|
|
@ -2927,6 +2937,24 @@ export class WYSIWYG {
|
|||
return;
|
||||
}
|
||||
|
||||
const fitElement = hasClosestByClassName(event.target, "protyle-action__home");
|
||||
if (fitElement) {
|
||||
const blockElement = hasClosestBlock(fitElement);
|
||||
if (blockElement && blockElement.getAttribute("data-subtype") === "mindmap") {
|
||||
try {
|
||||
const mmEntry: any = (blockElement as any).__markmap || null;
|
||||
if (mmEntry && mmEntry.markmap && typeof mmEntry.markmap.fit === "function") {
|
||||
mmEntry.markmap.fit();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("markmap fit error", e);
|
||||
}
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const languageElement = hasClosestByClassName(event.target, "protyle-action__language");
|
||||
if (languageElement && !protyle.disabled && !ctrlIsPressed) {
|
||||
protyle.toolbar.showCodeLanguage(protyle, [languageElement]);
|
||||
|
|
@ -2986,7 +3014,7 @@ export class WYSIWYG {
|
|||
} else if (event.shiftKey && !protyle.disabled) {
|
||||
openAttr(actionElement.parentElement, "bookmark", protyle);
|
||||
} else if (ctrlIsPressed) {
|
||||
zoomOut({protyle, id: actionId});
|
||||
zoomOut({ protyle, id: actionId });
|
||||
} else {
|
||||
if (actionElement.classList.contains("protyle-action--task")) {
|
||||
if (!protyle.disabled) {
|
||||
|
|
@ -3005,7 +3033,7 @@ export class WYSIWYG {
|
|||
if (protyle.block.showAll && protyle.block.id === actionId) {
|
||||
enterBack(protyle, actionId);
|
||||
} else {
|
||||
zoomOut({protyle, id: actionId});
|
||||
zoomOut({ protyle, id: actionId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
app/stage/protyle/js/d3/d3.min.js
vendored
Normal file
2
app/stage/protyle/js/d3/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
app/stage/protyle/js/markmap/markmap-lib.min.js
vendored
Normal file
6
app/stage/protyle/js/markmap/markmap-lib.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
app/stage/protyle/js/markmap/markmap-view.min.js
vendored
Normal file
7
app/stage/protyle/js/markmap/markmap-view.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue