mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
1 Commits
2.1.8.1-be
...
2.1.8.2-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31f54db433 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.1.8.1-beta-2",
|
||||
"version": "2.1.8.2-beta-1",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -231,7 +231,7 @@ export class EmbeddedFile {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this.mtime != this.file.stat.mtime;
|
||||
return this.mtime !== this.file.stat.mtime;
|
||||
}
|
||||
|
||||
public setImage(
|
||||
@@ -817,7 +817,7 @@ export class EmbeddedFilesLoader {
|
||||
? fileCache.frontmatter[FRONTMATTER_KEYS["md-css"].name] ?? ""
|
||||
: "";
|
||||
let frontmatterCSSisAfile = false;
|
||||
if (style && style != "") {
|
||||
if (style && style !== "") {
|
||||
const f = plugin.app.metadataCache.getFirstLinkpathDest(style, file.path);
|
||||
if (f) {
|
||||
style = await plugin.app.vault.read(f);
|
||||
|
||||
@@ -38,7 +38,6 @@ import {
|
||||
} from "src/constants/constants";
|
||||
import { blobToBase64, checkAndCreateFolder, getDrawingFilename, getExcalidrawEmbeddedFilesFiletree, getListOfTemplateFiles, getNewUniqueFilepath, hasExcalidrawEmbeddedImagesTreeChanged, } from "src/utils/FileUtils";
|
||||
import {
|
||||
arrayToMap,
|
||||
//debug,
|
||||
embedFontsInSVG,
|
||||
errorlog,
|
||||
@@ -51,6 +50,7 @@ import {
|
||||
isVersionNewerThanOther,
|
||||
scaleLoadedImage,
|
||||
wrapTextAtCharLength,
|
||||
arrayToMap,
|
||||
} from "src/utils/Utils";
|
||||
import { getAttachmentsFolderAndFilePath, getLeaf, getNewOrAdjacentLeaf, isObsidianThemeDark, mergeMarkdownFiles, openLeaf } from "src/utils/ObsidianUtils";
|
||||
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI, Point } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
ERROR_IFRAME_CONVERSION_CANCELED,
|
||||
JSON_parse,
|
||||
FRONTMATTER_KEYS,
|
||||
refreshTextDimensions,
|
||||
getContainerElement,
|
||||
} from "./constants/constants";
|
||||
import { _measureText } from "./ExcalidrawAutomate";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
@@ -28,7 +30,7 @@ import {
|
||||
decompress,
|
||||
//getBakPath,
|
||||
getBinaryFileFromDataURL,
|
||||
getContainerElement,
|
||||
_getContainerElement,
|
||||
getExportTheme,
|
||||
getLinkParts,
|
||||
hasExportTheme,
|
||||
@@ -36,11 +38,13 @@ import {
|
||||
LinkParts,
|
||||
updateFrontmatterInString,
|
||||
wrapTextAtCharLength,
|
||||
arrayToMap,
|
||||
} from "./utils/Utils";
|
||||
import { cleanBlockRef, cleanSectionHeading, getAttachmentsFolderAndFilePath, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
ExcalidrawImageElement,
|
||||
ExcalidrawTextElement,
|
||||
FileId,
|
||||
} from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { BinaryFiles, DataURL, SceneData } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
@@ -48,6 +52,7 @@ import { EmbeddedFile, MimeType } from "./EmbeddedFileLoader";
|
||||
import { ConfirmationPrompt } from "./dialogs/Prompt";
|
||||
import { getMermaidImageElements, getMermaidText, shouldRenderMermaid } from "./utils/MermaidUtils";
|
||||
import { debug } from "./utils/DebugHelper";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
||||
|
||||
type SceneDataWithFiles = SceneData & { files: BinaryFiles };
|
||||
|
||||
@@ -403,7 +408,7 @@ export const getExcalidrawMarkdownHeaderSection = (data:string, keys?:[string,st
|
||||
export class ExcalidrawData {
|
||||
public textElements: Map<
|
||||
string,
|
||||
{ raw: string; parsed: string; wrapAt: number | null }
|
||||
{ raw: string; parsed: string}
|
||||
> = null;
|
||||
public elementLinks: Map<string, string> = null;
|
||||
public scene: any = null;
|
||||
@@ -604,10 +609,10 @@ export class ExcalidrawData {
|
||||
this.selectedElementIds = {};
|
||||
this.textElements = new Map<
|
||||
string,
|
||||
{ raw: string; parsed: string; wrapAt: number }
|
||||
{ raw: string; parsed: string}
|
||||
>();
|
||||
this.elementLinks = new Map<string, string>();
|
||||
if (this.file != file) {
|
||||
if (this.file !== file) {
|
||||
//this is a reload - files, equations and mermaids will take care of reloading when needed
|
||||
this.files.clear();
|
||||
this.equations.clear();
|
||||
@@ -773,7 +778,7 @@ export class ExcalidrawData {
|
||||
|
||||
//iterating through all the text elements in .md
|
||||
//Text elements always contain the raw value
|
||||
const BLOCKREF_LEN: number = " ^12345678\n\n".length;
|
||||
const BLOCKREF_LEN: number = 12; // " ^12345678\n\n".length;
|
||||
const RE_TEXT_ELEMENT_LINK = /^%%\*\*\*>>>text element-link:(\[\[[^<*\]]*]])<<<\*\*\*%%/gm;
|
||||
let res = data.matchAll(/\s\^(.{8})[\n]+/g);
|
||||
while (!(parts = res.next()).done) {
|
||||
@@ -791,9 +796,8 @@ export class ExcalidrawData {
|
||||
}
|
||||
this.elementLinks.set(id, text);
|
||||
} else {
|
||||
const wrapAt = estimateMaxLineLen(textEl.text, textEl.originalText);
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/566
|
||||
const elementLinkRes = text.matchAll(RE_TEXT_ELEMENT_LINK);
|
||||
const elementLinkRes = text.matchAll(RE_TEXT_ELEMENT_LINK);
|
||||
const elementLink = elementLinkRes.next();
|
||||
if(!elementLink.done) {
|
||||
text = text.replace(RE_TEXT_ELEMENT_LINK,"");
|
||||
@@ -808,7 +812,6 @@ export class ExcalidrawData {
|
||||
this.textElements.set(id, {
|
||||
raw: text,
|
||||
parsed: parseRes.parsed,
|
||||
wrapAt,
|
||||
});
|
||||
if (parseRes.link) {
|
||||
textEl.link = parseRes.link;
|
||||
@@ -907,7 +910,7 @@ export class ExcalidrawData {
|
||||
this.file = file;
|
||||
this.textElements = new Map<
|
||||
string,
|
||||
{ raw: string; parsed: string; wrapAt: number }
|
||||
{ raw: string; parsed: string}
|
||||
>();
|
||||
this.elementLinks = new Map<string, string>();
|
||||
this.setShowLinkBrackets();
|
||||
@@ -938,34 +941,6 @@ export class ExcalidrawData {
|
||||
await this.updateSceneTextElements(forceupdate);
|
||||
}
|
||||
|
||||
//update a single text element in the scene if the newText is different
|
||||
public updateTextElement(
|
||||
sceneTextElement: any,
|
||||
newText: string,
|
||||
newOriginalText: string,
|
||||
forceUpdate: boolean = false,
|
||||
containerType?: string,
|
||||
) {
|
||||
if (forceUpdate || newText != sceneTextElement.text) {
|
||||
const measure = _measureText(
|
||||
newText,
|
||||
sceneTextElement.fontSize,
|
||||
sceneTextElement.fontFamily,
|
||||
sceneTextElement.lineHeight??getDefaultLineHeight(sceneTextElement.fontFamily),
|
||||
);
|
||||
sceneTextElement.text = newText;
|
||||
sceneTextElement.originalText = newOriginalText;
|
||||
|
||||
if (!sceneTextElement.containerId || containerType==="arrow") {
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/376
|
||||
//I leave the setting of text width to excalidraw, when text is in a container
|
||||
//because text width is fixed to the container width
|
||||
sceneTextElement.width = measure.w;
|
||||
}
|
||||
sceneTextElement.height = measure.h;
|
||||
sceneTextElement.baseline = measure.baseline;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the TextElements in the Excalidraw scene based on textElements MAP in ExcalidrawData
|
||||
@@ -976,24 +951,25 @@ export class ExcalidrawData {
|
||||
private async updateSceneTextElements(forceupdate: boolean = false) {
|
||||
//update text in scene based on textElements Map
|
||||
//first get scene text elements
|
||||
const texts = this.scene.elements?.filter((el: any) => el.type === "text");
|
||||
const elementsMap = arrayToMap(this.scene.elements);
|
||||
const texts = this.scene.elements?.filter((el: any) => el.type === "text") as Mutable<ExcalidrawTextElement>[];
|
||||
for (const te of texts) {
|
||||
const container = getContainerElement(te,this.scene);
|
||||
const container = getContainerElement(te, elementsMap);
|
||||
const originalText =
|
||||
(await this.getText(te.id)) ?? te.originalText ?? te.text;
|
||||
const wrapAt = this.textElements.get(te.id)?.wrapAt;
|
||||
const {text, x, y, width, height} = refreshTextDimensions(
|
||||
te,
|
||||
container,
|
||||
elementsMap,
|
||||
originalText,
|
||||
)
|
||||
try { //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1062
|
||||
this.updateTextElement(
|
||||
te,
|
||||
wrapAt ? wrapText(
|
||||
originalText,
|
||||
getFontString({fontSize: te.fontSize, fontFamily: te.fontFamily}),
|
||||
getBoundTextMaxWidth(container as any)
|
||||
) : originalText,
|
||||
originalText,
|
||||
forceupdate,
|
||||
container?.type,
|
||||
); //(await this.getText(te.id))??te.text serves the case when the whole #Text Elements section is deleted by accident
|
||||
te.originalText = originalText;
|
||||
te.text = text;
|
||||
te.x = x;
|
||||
te.y = y;
|
||||
te.width = width;
|
||||
te.height = height;
|
||||
} catch(e) {
|
||||
debug(`ExcalidrawData.updateSceneTextElements, textElement: ${te?.id}`, te, this.updateSceneTextElements);
|
||||
}
|
||||
@@ -1012,7 +988,6 @@ export class ExcalidrawData {
|
||||
this.textElements.set(id, {
|
||||
raw: text.raw,
|
||||
parsed: (await this.parse(text.raw)).parsed,
|
||||
wrapAt: text.wrapAt,
|
||||
});
|
||||
}
|
||||
//console.log("parsed",this.textElements.get(id).parsed);
|
||||
@@ -1089,21 +1064,18 @@ export class ExcalidrawData {
|
||||
this.textElements.set(id, {
|
||||
raw: text.raw,
|
||||
parsed: text.parsed,
|
||||
wrapAt: text.wrapAt,
|
||||
});
|
||||
this.textElements.delete(te.id); //delete the old ID from the Map
|
||||
}
|
||||
if (!this.textElements.has(id)) {
|
||||
const raw = te.rawText && te.rawText !== "" ? te.rawText : te.text; //this is for compatibility with drawings created before the rawText change on ExcalidrawTextElement
|
||||
const wrapAt = estimateMaxLineLen(te.text, te.originalText);
|
||||
this.textElements.set(id, { raw, parsed: null, wrapAt });
|
||||
this.parseasync(id, raw, wrapAt);
|
||||
this.textElements.set(id, { raw, parsed: null});
|
||||
this.parseasync(id, raw);
|
||||
}
|
||||
} else if (!this.textElements.has(te.id)) {
|
||||
const raw = te.rawText && te.rawText !== "" ? te.rawText : te.text; //this is for compatibility with drawings created before the rawText change on ExcalidrawTextElement
|
||||
const wrapAt = estimateMaxLineLen(te.text, te.originalText);
|
||||
this.textElements.set(id, { raw, parsed: null, wrapAt });
|
||||
this.parseasync(id, raw, wrapAt);
|
||||
this.textElements.set(id, { raw, parsed: null});
|
||||
this.parseasync(id, raw);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1151,22 +1123,19 @@ export class ExcalidrawData {
|
||||
? el[0].rawText
|
||||
: (el[0].originalText ?? el[0].text);
|
||||
if (text !== (el[0].originalText ?? el[0].text)) {
|
||||
const wrapAt = estimateMaxLineLen(el[0].text, el[0].originalText);
|
||||
this.textElements.set(key, {
|
||||
raw,
|
||||
parsed: (await this.parse(raw)).parsed,
|
||||
wrapAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async parseasync(key: string, raw: string, wrapAt: number) {
|
||||
private async parseasync(key: string, raw: string) {
|
||||
this.textElements.set(key, {
|
||||
raw,
|
||||
parsed: (await this.parse(raw)).parsed,
|
||||
wrapAt,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1633,12 +1602,12 @@ export class ExcalidrawData {
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
public getParsedText(id: string): [parseResultWrapped: string, parseResultOriginal: string, link: string] {
|
||||
public getParsedText(id: string): string {
|
||||
const t = this.textElements.get(id);
|
||||
if (!t) {
|
||||
return [null, null, null];
|
||||
return null;
|
||||
}
|
||||
return [wrap(t.parsed, t.wrapAt), t.parsed, null];
|
||||
return t.parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1655,24 +1624,23 @@ export class ExcalidrawData {
|
||||
* @param rawText
|
||||
* @param rawOriginalText
|
||||
* @param updateSceneCallback
|
||||
* @returns [parseResultWrapped: string, parseResultOriginal: string, link: string]
|
||||
* @returns [parseResultOriginal: string, link: string]
|
||||
*/
|
||||
public setTextElement(
|
||||
elementID: string,
|
||||
rawText: string,
|
||||
rawOriginalText: string,
|
||||
updateSceneCallback: Function,
|
||||
): [parseResultWrapped: string, parseResultOriginal: string, link: string] {
|
||||
const maxLineLen = estimateMaxLineLen(rawText, rawOriginalText);
|
||||
|
||||
): [parseResultOriginal: string, link: string] {
|
||||
//const maxLineLen = estimateMaxLineLen(rawText, rawOriginalText);
|
||||
const [parseResult, link] = this.quickParse(rawOriginalText); //will return the parsed result if raw text does not include transclusion
|
||||
if (parseResult) {
|
||||
//No transclusion
|
||||
this.textElements.set(elementID, {
|
||||
raw: rawOriginalText,
|
||||
parsed: parseResult,
|
||||
wrapAt: maxLineLen,
|
||||
});
|
||||
return [wrap(parseResult, maxLineLen), parseResult, link];
|
||||
return [parseResult, link];
|
||||
}
|
||||
//transclusion needs to be resolved asynchornously
|
||||
this.parse(rawOriginalText).then((parseRes) => {
|
||||
@@ -1680,35 +1648,28 @@ export class ExcalidrawData {
|
||||
this.textElements.set(elementID, {
|
||||
raw: rawOriginalText,
|
||||
parsed: parsedText,
|
||||
wrapAt: maxLineLen,
|
||||
});
|
||||
if (parsedText) {
|
||||
updateSceneCallback(wrap(parsedText, maxLineLen), parsedText);
|
||||
updateSceneCallback(parsedText);
|
||||
}
|
||||
});
|
||||
return [null, null, null];
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
public async addTextElement(
|
||||
elementID: string,
|
||||
rawText: string,
|
||||
rawOriginalText: string,
|
||||
): Promise<[string, string, string]> {
|
||||
let wrapAt: number = estimateMaxLineLen(rawText, rawOriginalText);
|
||||
if (this.textElements.has(elementID)) {
|
||||
wrapAt = this.textElements.get(elementID).wrapAt;
|
||||
}
|
||||
): Promise<{parseResult: string, link:string}> {
|
||||
const parseResult = await this.parse(rawOriginalText);
|
||||
this.textElements.set(elementID, {
|
||||
raw: rawOriginalText,
|
||||
parsed: parseResult.parsed,
|
||||
wrapAt,
|
||||
});
|
||||
return [
|
||||
wrap(parseResult.parsed, wrapAt),
|
||||
parseResult.parsed,
|
||||
parseResult.link,
|
||||
];
|
||||
return {
|
||||
parseResult: parseResult.parsed,
|
||||
link: parseResult.link,
|
||||
};
|
||||
}
|
||||
|
||||
public deleteTextElement(id: string) {
|
||||
@@ -1722,7 +1683,8 @@ export class ExcalidrawData {
|
||||
: this.plugin.settings.defaultMode;
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["default-mode"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["default-mode"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["default-mode"].name] !== "undefined")
|
||||
) {
|
||||
mode = fileCache.frontmatter[FRONTMATTER_KEYS["default-mode"].name];
|
||||
}
|
||||
@@ -1742,7 +1704,8 @@ export class ExcalidrawData {
|
||||
let opacity = this.plugin.settings.linkOpacity;
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["linkbutton-opacity"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["linkbutton-opacity"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["linkbutton-opacity"].name] !== "undefined")
|
||||
) {
|
||||
opacity = fileCache.frontmatter[FRONTMATTER_KEYS["linkbutton-opacity"].name];
|
||||
}
|
||||
@@ -1753,7 +1716,8 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["onload-script"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["onload-script"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["onload-script"].name] !== "undefined")
|
||||
) {
|
||||
return fileCache.frontmatter[FRONTMATTER_KEYS["onload-script"].name];
|
||||
}
|
||||
@@ -1765,13 +1729,13 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-prefix"].name] != null
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["link-prefix"].name] !== "undefined")
|
||||
) {
|
||||
this.linkPrefix = fileCache.frontmatter[FRONTMATTER_KEYS["link-prefix"].name];
|
||||
this.linkPrefix = fileCache.frontmatter[FRONTMATTER_KEYS["link-prefix"].name]??"";
|
||||
} else {
|
||||
this.linkPrefix = this.plugin.settings.linkPrefix;
|
||||
}
|
||||
return linkPrefix != this.linkPrefix;
|
||||
return linkPrefix !== this.linkPrefix;
|
||||
}
|
||||
|
||||
private setUrlPrefix(): boolean {
|
||||
@@ -1779,20 +1743,21 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["url-prefix"].name] != null
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["url-prefix"].name] !== "undefined")
|
||||
) {
|
||||
this.urlPrefix = fileCache.frontmatter[FRONTMATTER_KEYS["url-prefix"].name];
|
||||
this.urlPrefix = fileCache.frontmatter[FRONTMATTER_KEYS["url-prefix"].name]??"";
|
||||
} else {
|
||||
this.urlPrefix = this.plugin.settings.urlPrefix;
|
||||
}
|
||||
return urlPrefix != this.urlPrefix;
|
||||
return urlPrefix !== this.urlPrefix;
|
||||
}
|
||||
|
||||
private setAutoexportPreferences() {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["autoexport"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["autoexport"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["autoexport"].name] !== "undefined")
|
||||
) {
|
||||
switch ((fileCache.frontmatter[FRONTMATTER_KEYS["autoexport"].name]).toLowerCase()) {
|
||||
case "none": this.autoexportPreference = AutoexportPreference.none; break;
|
||||
@@ -1811,7 +1776,8 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["iframe-theme"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["iframe-theme"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["iframe-theme"].name] !== "undefined")
|
||||
) {
|
||||
this.embeddableTheme = fileCache.frontmatter[FRONTMATTER_KEYS["iframe-theme"].name].toLowerCase();
|
||||
if (!EMBEDDABLE_THEME_FRONTMATTER_VALUES.includes(this.embeddableTheme)) {
|
||||
@@ -1820,7 +1786,7 @@ export class ExcalidrawData {
|
||||
} else {
|
||||
this.embeddableTheme = this.plugin.settings.iframeMatchExcalidrawTheme ? "auto" : "default";
|
||||
}
|
||||
return embeddableTheme != this.embeddableTheme;
|
||||
return embeddableTheme !== this.embeddableTheme;
|
||||
}
|
||||
|
||||
private setShowLinkBrackets(): boolean {
|
||||
@@ -1828,14 +1794,15 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] !== "undefined")
|
||||
) {
|
||||
this.showLinkBrackets =
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] != false;
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] !== false;
|
||||
} else {
|
||||
this.showLinkBrackets = this.plugin.settings.showLinkBrackets;
|
||||
}
|
||||
return showLinkBrackets != this.showLinkBrackets;
|
||||
return showLinkBrackets !== this.showLinkBrackets;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2068,7 +2035,7 @@ export const getTransclusion = async (
|
||||
{ isCancelled: () => false },
|
||||
file,
|
||||
)
|
||||
).blocks.filter((block: any) => block.node.type != "comment");
|
||||
).blocks.filter((block: any) => block.node.type !== "comment");
|
||||
if (!blocks) {
|
||||
return { contents: linkParts.original.trim(), lineNum: 0 };
|
||||
}
|
||||
|
||||
20
src/ExcalidrawLib.d.ts
vendored
20
src/ExcalidrawLib.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import { RestoredDataState } from "@zsviczian/excalidraw/types/excalidraw/data/restore";
|
||||
import { ImportedDataState } from "@zsviczian/excalidraw/types/excalidraw/data/types";
|
||||
import { BoundingBox } from "@zsviczian/excalidraw/types/excalidraw/element/bounds";
|
||||
import { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawTextElement, FontFamilyValues, FontString, NonDeleted, NonDeletedExcalidrawElement, Theme } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawTextContainer, ExcalidrawTextElement, FontFamilyValues, FontString, NonDeleted, NonDeletedExcalidrawElement, Theme } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { AppState, BinaryFiles, ExportOpts, Point, Zoom } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
||||
|
||||
@@ -87,6 +87,24 @@ declare namespace ExcalidrawLib {
|
||||
elements: ExcalidrawElement[] | readonly NonDeleted<ExcalidrawElement>[],
|
||||
): BoundingBox;
|
||||
|
||||
function getContainerElement(
|
||||
element: ExcalidrawTextElement | null,
|
||||
elementsMap: ElementsMap,
|
||||
): ExcalidrawTextContainer | null;
|
||||
|
||||
function refreshTextDimensions(
|
||||
textElement: ExcalidrawTextElement,
|
||||
container: ExcalidrawTextContainer | null,
|
||||
elementsMap: ElementsMap,
|
||||
text: string,
|
||||
): {
|
||||
text: string,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
};
|
||||
|
||||
function getMaximumGroups(
|
||||
elements: ExcalidrawElement[],
|
||||
elementsMap: ElementsMap,
|
||||
|
||||
@@ -51,6 +51,8 @@ import {
|
||||
fileid,
|
||||
sceneCoordsToViewportCoords,
|
||||
MD_EX_SECTIONS,
|
||||
refreshTextDimensions,
|
||||
getContainerElement,
|
||||
} from "./constants/constants";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
import {
|
||||
@@ -99,7 +101,8 @@ import {
|
||||
fragWithHTML,
|
||||
isMaskFile,
|
||||
shouldEmbedScene,
|
||||
getContainerElement,
|
||||
_getContainerElement,
|
||||
arrayToMap,
|
||||
} from "./utils/Utils";
|
||||
import { cleanBlockRef, cleanSectionHeading, getLeaf, getParentOfClass, obsidianPDFQuoteWithRef, openLeaf } from "./utils/ObsidianUtils";
|
||||
import { splitFolderAndFilename } from "./utils/FileUtils";
|
||||
@@ -965,7 +968,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (!linkText || partsArray.length === 0) {
|
||||
//the container link takes precedence over the text link
|
||||
if(selectedTextElement?.containerId) {
|
||||
const container = getContainerElement(selectedTextElement, {elements: this.excalidrawAPI.getSceneElements()});
|
||||
const container = _getContainerElement(selectedTextElement, {elements: this.excalidrawAPI.getSceneElements()});
|
||||
if(container) {
|
||||
linkText = container.link;
|
||||
}
|
||||
@@ -1393,7 +1396,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return;
|
||||
}
|
||||
const { offsetLeft, offsetTop } = target;
|
||||
if (offsetLeft !== self.offsetLeft || offsetTop != self.offsetTop) {
|
||||
if (offsetLeft !== self.offsetLeft || offsetTop !== self.offsetTop) {
|
||||
if (self.excalidrawAPI) {
|
||||
self.refreshCanvasOffset();
|
||||
}
|
||||
@@ -2796,26 +2799,32 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (!api) {
|
||||
return false;
|
||||
}
|
||||
const elementsMap = arrayToMap(api.getSceneElements());
|
||||
const textElements = newElements.filter((el) => el.type == "text");
|
||||
for (let i = 0; i < textElements.length; i++) {
|
||||
const [parseResultWrapped, parseResult, link] =
|
||||
const textElement = textElements[i] as Mutable<ExcalidrawTextElement>;
|
||||
const {parseResult, link} =
|
||||
await this.excalidrawData.addTextElement(
|
||||
textElements[i].id,
|
||||
textElement.id,
|
||||
//@ts-ignore
|
||||
textElements[i].text,
|
||||
textElement.text,
|
||||
//@ts-ignore
|
||||
textElements[i].rawText, //TODO: implement originalText support in ExcalidrawAutomate
|
||||
textElement.rawText, //TODO: implement originalText support in ExcalidrawAutomate
|
||||
);
|
||||
if (link) {
|
||||
//@ts-ignore
|
||||
textElements[i].link = link;
|
||||
textElement.link = link;
|
||||
}
|
||||
if (this.textMode == TextMode.parsed) {
|
||||
this.excalidrawData.updateTextElement(
|
||||
textElements[i],
|
||||
parseResultWrapped,
|
||||
parseResult,
|
||||
const {text, x, y, width, height} = refreshTextDimensions(
|
||||
textElement,null,elementsMap,parseResult
|
||||
);
|
||||
textElement.text = text;
|
||||
textElement.originalText = parseResult;
|
||||
textElement.x = x;
|
||||
textElement.y = y;
|
||||
textElement.width = width;
|
||||
textElement.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3857,6 +3866,8 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return true;
|
||||
}
|
||||
|
||||
//returns the raw text of the element which is the original text without parsing
|
||||
//in compatibility mode, returns the original text, and for backward compatibility the text if originalText is not available
|
||||
private onBeforeTextEdit (textElement: ExcalidrawTextElement) {
|
||||
clearTimeout(this.isEditingTextResetTimer);
|
||||
this.isEditingTextResetTimer = null;
|
||||
@@ -3871,15 +3882,16 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return raw;
|
||||
}
|
||||
|
||||
|
||||
private onBeforeTextSubmit (
|
||||
textElement: ExcalidrawTextElement,
|
||||
text: string,
|
||||
originalText: string,
|
||||
nextText: string,
|
||||
nextOriginalText: string,
|
||||
isDeleted: boolean,
|
||||
): [string, string, string] {
|
||||
): {updatedNextOriginalText: string, nextLink: string} {
|
||||
const api = this.excalidrawAPI;
|
||||
if (!api) {
|
||||
return [null, null, null];
|
||||
return {updatedNextOriginalText: null, nextLink: null};
|
||||
}
|
||||
|
||||
// 1. Set the isEditingText flag to true to prevent autoresize on mobile
|
||||
@@ -3898,7 +3910,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (isDeleted) {
|
||||
this.excalidrawData.deleteTextElement(textElement.id);
|
||||
this.setDirty(7);
|
||||
return [null, null, null];
|
||||
return {updatedNextOriginalText: null, nextLink: null};
|
||||
}
|
||||
|
||||
// 3. Check if the user accidently pasted Excalidraw data from the clipboard
|
||||
@@ -3906,7 +3918,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
// textElements cache and update the text element in the scene with a warning.
|
||||
const FORBIDDEN_TEXT = `{"type":"excalidraw/clipboard","elements":[{"`;
|
||||
const WARNING = t("WARNING_PASTING_ELEMENT_AS_TEXT");
|
||||
if(text.startsWith(FORBIDDEN_TEXT)) {
|
||||
if(nextOriginalText.startsWith(FORBIDDEN_TEXT)) {
|
||||
setTimeout(()=>{
|
||||
const elements = this.excalidrawAPI.getSceneElements();
|
||||
const el = elements.filter((el:ExcalidrawElement)=>el.id === textElement.id);
|
||||
@@ -3914,23 +3926,23 @@ export default class ExcalidrawView extends TextFileView {
|
||||
const clone = cloneElement(el[0]);
|
||||
clone.rawText = WARNING;
|
||||
elements[elements.indexOf(el[0])] = clone;
|
||||
this.excalidrawData.setTextElement(clone.id,WARNING,WARNING,()=>{});
|
||||
this.excalidrawData.setTextElement(clone.id,WARNING,()=>{});
|
||||
this.updateScene({elements});
|
||||
api.history.clear();
|
||||
}
|
||||
});
|
||||
return [WARNING,WARNING,null];
|
||||
return {updatedNextOriginalText:WARNING, nextLink:null};
|
||||
}
|
||||
|
||||
const containerId = textElement.containerId;
|
||||
|
||||
const REG_TRANSCLUSION = /^!\[\[([^|\]]*)?.*?]]$|^!\[[^\]]*?]\((.*?)\)$/g;
|
||||
// 4. Check if the text matches the transclusion pattern and if so,
|
||||
// check if the link in the transclusion can be resolved to a file in the vault
|
||||
// if the link can be resolved, check if the file is a markdown file but not an
|
||||
// Excalidraw file. If so, create a timeout to remove the text element from the
|
||||
// scene and invoke the UniversalInsertFileModal with the file.
|
||||
const match = originalText.trim().matchAll(REG_TRANSCLUSION).next(); //reset the iterator
|
||||
// check if the link in the transclusion can be resolved to a file in the vault.
|
||||
// If the link is an image or a PDF file, replace the text element with the image or the PDF.
|
||||
// If the link is an embedded markdown file, then display a message, but otherwise transclude the text step 5.
|
||||
// 1 2
|
||||
const REG_TRANSCLUSION = /^!\[\[([^|\]]*)?.*?]]$|^!\[[^\]]*?]\((.*?)\)$/g;
|
||||
const match = nextOriginalText.trim().matchAll(REG_TRANSCLUSION).next(); //reset the iterator
|
||||
if(match?.value?.[0]) {
|
||||
const link = match.value[1] ?? match.value[2];
|
||||
const file = this.app.metadataCache.getFirstLinkpathDest(link, this.file.path);
|
||||
@@ -3958,7 +3970,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.setDirty(9);
|
||||
}
|
||||
});
|
||||
return [null, null, null];
|
||||
return {updatedNextOriginalText: null, nextLink: null};
|
||||
} else {
|
||||
new Notice(t("USE_INSERT_FILE_MODAL"),5000);
|
||||
}
|
||||
@@ -3968,8 +3980,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
// 5. Check if the user made changes to the text, or
|
||||
// the text is missing from ExcalidrawData textElements cache (recently copy/pasted)
|
||||
if (
|
||||
text !== textElement.text ||
|
||||
originalText !== textElement.originalText ||
|
||||
nextOriginalText !== textElement.originalText ||
|
||||
!this.excalidrawData.getRawText(textElement.id)
|
||||
) {
|
||||
//the user made changes to the text or the text is missing from Excalidraw Data (recently copy/pasted)
|
||||
@@ -3978,24 +3989,25 @@ export default class ExcalidrawView extends TextFileView {
|
||||
|
||||
// setTextElement will invoke this callback function in case quick parse was not possible, the parsed text contains transclusions
|
||||
// in this case I need to update the scene asynchronously when parsing is complete
|
||||
const callback = async (wrappedParsedText:string, parsedText:string) => {
|
||||
const callback = async (parsedText:string) => {
|
||||
//this callback function will only be invoked if quick parse fails, i.e. there is a transclusion in the raw text
|
||||
if(this.textMode === TextMode.raw) return;
|
||||
|
||||
const elements = this.excalidrawAPI.getSceneElements();
|
||||
const elementsMap = arrayToMap(elements);
|
||||
const el = elements.filter((el:ExcalidrawElement)=>el.id === textElement.id);
|
||||
if(el.length === 1) {
|
||||
const container = getContainerElement(el[0],elementsMap);
|
||||
const clone = cloneElement(el[0]);
|
||||
const containerType = el[0].containerId
|
||||
? api.getSceneElements().filter((e:ExcalidrawElement)=>e.id===el[0].containerId)?.[0]?.type
|
||||
: undefined;
|
||||
this.excalidrawData.updateTextElement(
|
||||
clone,
|
||||
wrappedParsedText,
|
||||
parsedText,
|
||||
true,
|
||||
containerType
|
||||
);
|
||||
const {text, x, y, width, height} = refreshTextDimensions(el[0], container, elementsMap, parsedText);
|
||||
|
||||
clone.x = x;
|
||||
clone.y = y;
|
||||
clone.width = width;
|
||||
clone.height = height;
|
||||
clone.originalText = parsedText;
|
||||
clone.text = text;
|
||||
|
||||
elements[elements.indexOf(el[0])] = clone;
|
||||
this.updateScene({elements});
|
||||
if(clone.containerId) this.updateContainerSize(clone.containerId);
|
||||
@@ -4004,11 +4016,10 @@ export default class ExcalidrawView extends TextFileView {
|
||||
api.history.clear();
|
||||
};
|
||||
|
||||
const [parseResultWrapped, parseResultOriginal, link] =
|
||||
const [parseResultOriginal, link] =
|
||||
this.excalidrawData.setTextElement(
|
||||
textElement.id,
|
||||
text,
|
||||
originalText,
|
||||
nextOriginalText,
|
||||
callback,
|
||||
);
|
||||
|
||||
@@ -4017,34 +4028,35 @@ export default class ExcalidrawView extends TextFileView {
|
||||
// because the parsed text will have a different size than the raw text had
|
||||
// - depending on the textMode, return the text with markdown markup or the parsed text
|
||||
// if quick parse was not successful return [null, null, null] to indicate that the no changes were made to the text element
|
||||
if (parseResultWrapped) {
|
||||
if (parseResultOriginal) {
|
||||
//there were no transclusions in the raw text, quick parse was successful
|
||||
if (containerId) {
|
||||
this.updateContainerSize(containerId, true);
|
||||
}
|
||||
if (this.textMode === TextMode.raw) {
|
||||
return [text, originalText, link];
|
||||
return {updatedNextOriginalText: nextOriginalText, nextLink: link};
|
||||
} //text is displayed in raw, no need to clear the history, undo will not create problems
|
||||
if (text === parseResultWrapped) {
|
||||
if (nextOriginalText === parseResultOriginal) {
|
||||
if (link) {
|
||||
//don't forget the case: link-prefix:"" && link-brackets:true
|
||||
return [parseResultWrapped, parseResultOriginal, link];
|
||||
return {updatedNextOriginalText: parseResultOriginal, nextLink: link};
|
||||
}
|
||||
return [null, null, null];
|
||||
return {updatedNextOriginalText: null, nextLink: null};
|
||||
} //There were no links to parse, raw text and parsed text are equivalent
|
||||
api.history.clear();
|
||||
return [parseResultWrapped, parseResultOriginal, link];
|
||||
return {updatedNextOriginalText: parseResultOriginal, nextLink:link};
|
||||
}
|
||||
return [null, null, null];
|
||||
return {updatedNextOriginalText: null, nextLink: null};
|
||||
}
|
||||
// even if the text did not change, container sizes might need to be updated
|
||||
if (containerId) {
|
||||
this.updateContainerSize(containerId, true);
|
||||
}
|
||||
if (this.textMode === TextMode.parsed) {
|
||||
return this.excalidrawData.getParsedText(textElement.id);
|
||||
const parseResultOriginal = this.excalidrawData.getParsedText(textElement.id);
|
||||
return {updatedNextOriginalText: parseResultOriginal, nextLink: textElement.link};
|
||||
}
|
||||
return [null, null, null];
|
||||
return {updatedNextOriginalText: null, nextLink: null};
|
||||
}
|
||||
|
||||
private async onLinkOpen(element: ExcalidrawElement, e: any): Promise<void> {
|
||||
@@ -4290,14 +4302,13 @@ export default class ExcalidrawView extends TextFileView {
|
||||
const selectedTextElements = this.getViewSelectedElements().filter(el=>el.type === "text");
|
||||
if(selectedTextElements.length===1) {
|
||||
const selectedTextElement = selectedTextElements[0] as ExcalidrawTextElement;
|
||||
this.excalidrawData.getParsedText(selectedTextElement.id);
|
||||
const containerElement = (this.getViewElements() as ExcalidrawElement[]).find(el=>el.id === selectedTextElement.containerId);
|
||||
|
||||
//if the text element in the container no longer has a link associated with it...
|
||||
if(
|
||||
containerElement &&
|
||||
selectedTextElement.link &&
|
||||
this.excalidrawData.getParsedText(selectedTextElement.id)[1] === selectedTextElement.rawText
|
||||
this.excalidrawData.getParsedText(selectedTextElement.id) === selectedTextElement.rawText
|
||||
) {
|
||||
contextMenuActions.push([
|
||||
renderContextMenuAction(
|
||||
@@ -4866,10 +4877,10 @@ export default class ExcalidrawView extends TextFileView {
|
||||
onBeforeTextEdit: (textElement: ExcalidrawTextElement) => this.onBeforeTextEdit(textElement),
|
||||
onBeforeTextSubmit: (
|
||||
textElement: ExcalidrawTextElement,
|
||||
text: string,
|
||||
originalText: string,
|
||||
nextText: string,
|
||||
nextOriginalText: string,
|
||||
isDeleted: boolean,
|
||||
): [string, string, string] => this.onBeforeTextSubmit(textElement, text, originalText, isDeleted),
|
||||
): {updatedNextOriginalText: string, nextLink: string} => this.onBeforeTextSubmit(textElement, nextText, nextOriginalText, isDeleted),
|
||||
onLinkOpen: (element: ExcalidrawElement, e: any) => this.onLinkOpen(element, e),
|
||||
onLinkHover: (element: NonDeletedExcalidrawElement, event: React.PointerEvent<HTMLCanvasElement>) => this.onLinkHover(element, event),
|
||||
onContextMenu,
|
||||
|
||||
@@ -808,10 +808,10 @@ const legacyExcalidrawPopoverObserverFn: MutationCallback = async (m) => {
|
||||
if (!plugin.hover.linkText) {
|
||||
return;
|
||||
}
|
||||
if (m.length != 1) {
|
||||
if (m.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (m[0].addedNodes.length != 1) {
|
||||
if (m[0].addedNodes.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
|
||||
@@ -93,6 +93,8 @@ export const {
|
||||
mutateElement,
|
||||
restore,
|
||||
mermaidToExcalidraw,
|
||||
getContainerElement,
|
||||
refreshTextDimensions,
|
||||
} = excalidrawLib;
|
||||
|
||||
export function JSON_parse(x: string): any {
|
||||
|
||||
@@ -713,7 +713,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
*/
|
||||
private experimentalFileTypeDisplay() {
|
||||
const insertFiletype = (el: HTMLElement) => {
|
||||
if (el.childElementCount != 1) {
|
||||
if (el.childElementCount !== 1) {
|
||||
return;
|
||||
}
|
||||
const filename = el.getAttribute("data-path");
|
||||
@@ -1055,7 +1055,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if (checking) {
|
||||
return (
|
||||
Boolean(this.app.workspace.getActiveViewOfType(MarkdownView)) &&
|
||||
this.lastActiveExcalidrawFilePath != null
|
||||
this.lastActiveExcalidrawFilePath !== null
|
||||
);
|
||||
}
|
||||
const file = this.app.vault.getAbstractFileByPath(
|
||||
|
||||
@@ -21,9 +21,10 @@ import {
|
||||
EXCALIDRAW_PLUGIN,
|
||||
getCommonBoundingBox,
|
||||
DEVICE,
|
||||
getContainerElement,
|
||||
} from "../constants/constants";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { ExcalidrawElement, ExcalidrawTextElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { ExportSettings } from "../ExcalidrawView";
|
||||
import { getDataURLFromURL, getIMGFilename, getMimeType, getURLImageExtension } from "./FileUtils";
|
||||
import { generateEmbeddableLink } from "./CustomEmbeddableUtils";
|
||||
@@ -293,7 +294,7 @@ export const getSVG = async (
|
||||
appState: {
|
||||
exportBackground: exportSettings.withBackground,
|
||||
exportWithDarkMode: exportSettings.withTheme
|
||||
? scene.appState?.theme != "light"
|
||||
? scene.appState?.theme !== "light"
|
||||
: false,
|
||||
...scene.appState,
|
||||
},
|
||||
@@ -345,7 +346,7 @@ export const getPNG = async (
|
||||
appState: {
|
||||
exportBackground: exportSettings.withBackground,
|
||||
exportWithDarkMode: exportSettings.withTheme
|
||||
? scene.appState?.theme != "light"
|
||||
? scene.appState?.theme !== "light"
|
||||
: false,
|
||||
...scene.appState,
|
||||
},
|
||||
@@ -392,13 +393,13 @@ export const embedFontsInSVG = (
|
||||
): SVGSVGElement => {
|
||||
//replace font references with base64 fonts)
|
||||
const includesVirgil = !localOnly &&
|
||||
svg.querySelector("text[font-family^='Virgil']") != null;
|
||||
svg.querySelector("text[font-family^='Virgil']") !== null;
|
||||
const includesCascadia = !localOnly &&
|
||||
svg.querySelector("text[font-family^='Cascadia']") != null;
|
||||
svg.querySelector("text[font-family^='Cascadia']") !== null;
|
||||
const includesAssistant = !localOnly &&
|
||||
svg.querySelector("text[font-family^='Assistant']") != null;
|
||||
svg.querySelector("text[font-family^='Assistant']") !== null;
|
||||
const includesLocalFont =
|
||||
svg.querySelector("text[font-family^='LocalFont']") != null;
|
||||
svg.querySelector("text[font-family^='LocalFont']") !== null;
|
||||
const defs = svg.querySelector("defs");
|
||||
if (defs && (includesCascadia || includesVirgil || includesLocalFont || includesAssistant)) {
|
||||
let style = defs.querySelector("style");
|
||||
@@ -467,7 +468,7 @@ export const scaleLoadedImage = (
|
||||
}
|
||||
if(f.shouldScale) {
|
||||
const elementAspectRatio = w_old / h_old;
|
||||
if (imageAspectRatio != elementAspectRatio) {
|
||||
if (imageAspectRatio !== elementAspectRatio) {
|
||||
dirty = true;
|
||||
const h_new = Math.sqrt((w_old * h_old * h_image) / w_image);
|
||||
const w_new = Math.sqrt((w_old * h_old * w_image) / h_image);
|
||||
@@ -558,7 +559,8 @@ export const isMaskFile = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name] !== "undefined")
|
||||
) {
|
||||
return Boolean(fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name]);
|
||||
}
|
||||
@@ -574,7 +576,8 @@ export const hasExportTheme = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] !== "undefined")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -591,7 +594,8 @@ export const getExportTheme = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] !== "undefined")
|
||||
) {
|
||||
return fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name]
|
||||
? "dark"
|
||||
@@ -609,7 +613,8 @@ export const shouldEmbedScene = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-embed-scene"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-embed-scene"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-embed-scene"].name] !== "undefined")
|
||||
) {
|
||||
return fileCache.frontmatter[FRONTMATTER_KEYS["export-embed-scene"].name];
|
||||
}
|
||||
@@ -625,7 +630,8 @@ export const hasExportBackground = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] !== "undefined")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -641,7 +647,8 @@ export const getWithBackground = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] !== "undefined")
|
||||
) {
|
||||
return !fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name];
|
||||
}
|
||||
@@ -657,7 +664,10 @@ export const getExportPadding = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if(!fileCache?.frontmatter) return plugin.settings.exportPaddingSVG;
|
||||
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name] != null) {
|
||||
if (
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name] !== "undefined")
|
||||
) {
|
||||
const val = parseInt(
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name],
|
||||
);
|
||||
@@ -667,7 +677,10 @@ export const getExportPadding = (
|
||||
}
|
||||
|
||||
//deprecated. Retained for backward compatibility
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name] != null) {
|
||||
if (
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name] !== "undefined")
|
||||
) {
|
||||
const val = parseInt(
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name],
|
||||
);
|
||||
@@ -685,7 +698,8 @@ export const getPNGScale = (plugin: ExcalidrawPlugin, file: TFile): number => {
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name] !== null &&
|
||||
(typeof fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name] !== "undefined")
|
||||
) {
|
||||
const val = parseFloat(
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name],
|
||||
@@ -764,21 +778,38 @@ export const awaitNextAnimationFrame = async () => new Promise(requestAnimationF
|
||||
//export const debug = function(){};
|
||||
|
||||
|
||||
export const getContainerElement = (
|
||||
export const _getContainerElement = (
|
||||
element:
|
||||
| (ExcalidrawElement & { containerId: ExcalidrawElement["id"] | null })
|
||||
| null,
|
||||
scene: any,
|
||||
) => {
|
||||
if (!element) {
|
||||
if (!element || !scene?.elements || element.type !== "text") {
|
||||
return null;
|
||||
}
|
||||
if (element.containerId) {
|
||||
return scene.elements.find((el:ExcalidrawElement)=>el.id === element.containerId) ?? null;
|
||||
return getContainerElement(element as ExcalidrawTextElement, arrayToMap(scene.elements))
|
||||
//return scene.elements.find((el:ExcalidrawElement)=>el.id === element.containerId) ?? null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms array of objects containing `id` attribute,
|
||||
* or array of ids (strings), into a Map, keyd by `id`.
|
||||
*/
|
||||
export const arrayToMap = <T extends { id: string } | string>(
|
||||
items: readonly T[] | Map<string, T>,
|
||||
) => {
|
||||
if (items instanceof Map) {
|
||||
return items;
|
||||
}
|
||||
return items.reduce((acc: Map<string, T>, element) => {
|
||||
acc.set(typeof element === "string" ? element : element.id, element);
|
||||
return acc;
|
||||
}, new Map());
|
||||
};
|
||||
|
||||
export const updateFrontmatterInString = (data:string, keyValuePairs?: [string,string][]):string => {
|
||||
if(!data || !keyValuePairs) return data;
|
||||
for(const kvp of keyValuePairs) {
|
||||
@@ -863,20 +894,4 @@ export const addIframe = (containerEl: HTMLElement, link:string, startAt?: numbe
|
||||
sandbox: "allow-forms allow-presentation allow-same-origin allow-scripts allow-modals",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms array of objects containing `id` attribute,
|
||||
* or array of ids (strings), into a Map, keyd by `id`.
|
||||
*/
|
||||
export const arrayToMap = <T extends { id: string } | string>(
|
||||
items: readonly T[] | Map<string, T>,
|
||||
) => {
|
||||
if (items instanceof Map) {
|
||||
return items;
|
||||
}
|
||||
return items.reduce((acc: Map<string, T>, element) => {
|
||||
acc.set(typeof element === "string" ? element : element.id, element);
|
||||
return acc;
|
||||
}, new Map());
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user