mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
2.0.19
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.0.18",
|
||||
"version": "2.0.19",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zsviczian/excalidraw": "0.17.1-obsidian-12",
|
||||
"@zsviczian/excalidraw": "0.17.1-obsidian-13",
|
||||
"chroma-js": "^2.4.2",
|
||||
"clsx": "^2.0.0",
|
||||
"colormaster": "^1.2.1",
|
||||
|
||||
@@ -12,13 +12,10 @@ import {
|
||||
import {
|
||||
DEFAULT_MD_EMBED_CSS,
|
||||
fileid,
|
||||
FRONTMATTER_KEY_BORDERCOLOR,
|
||||
FRONTMATTER_KEY_FONT,
|
||||
FRONTMATTER_KEY_FONTCOLOR,
|
||||
FRONTMATTER_KEY_MD_STYLE,
|
||||
IMAGE_TYPES,
|
||||
nanoid,
|
||||
THEME_FILTER,
|
||||
FRONTMATTER_KEYS,
|
||||
} from "./constants/constants";
|
||||
import { createSVG } from "./ExcalidrawAutomate";
|
||||
import { ExcalidrawData, getTransclusion } from "./ExcalidrawData";
|
||||
@@ -748,9 +745,9 @@ export class EmbeddedFilesLoader {
|
||||
let fontName = plugin.settings.mdFont;
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
Boolean(fileCache.frontmatter[FRONTMATTER_KEY_FONT])
|
||||
Boolean(fileCache.frontmatter[FRONTMATTER_KEYS["font"].name])
|
||||
) {
|
||||
fontName = fileCache.frontmatter[FRONTMATTER_KEY_FONT];
|
||||
fontName = fileCache.frontmatter[FRONTMATTER_KEYS["font"].name];
|
||||
}
|
||||
switch (fontName) {
|
||||
case "Virgil":
|
||||
@@ -779,12 +776,12 @@ export class EmbeddedFilesLoader {
|
||||
}
|
||||
|
||||
const fontColor = fileCache?.frontmatter
|
||||
? fileCache.frontmatter[FRONTMATTER_KEY_FONTCOLOR] ??
|
||||
? fileCache.frontmatter[FRONTMATTER_KEYS["font-color"].name] ??
|
||||
plugin.settings.mdFontColor
|
||||
: plugin.settings.mdFontColor;
|
||||
|
||||
let style = fileCache?.frontmatter
|
||||
? fileCache.frontmatter[FRONTMATTER_KEY_MD_STYLE] ?? ""
|
||||
? fileCache.frontmatter[FRONTMATTER_KEYS["md-css"].name] ?? ""
|
||||
: "";
|
||||
let frontmatterCSSisAfile = false;
|
||||
if (style && style != "") {
|
||||
@@ -807,7 +804,7 @@ export class EmbeddedFilesLoader {
|
||||
}
|
||||
|
||||
const borderColor = fileCache?.frontmatter
|
||||
? fileCache.frontmatter[FRONTMATTER_KEY_BORDERCOLOR] ??
|
||||
? fileCache.frontmatter[FRONTMATTER_KEYS["border-color"].name] ??
|
||||
plugin.settings.mdBorderColor
|
||||
: plugin.settings.mdBorderColor;
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ import {
|
||||
} from "./utils/AIUtils";
|
||||
import { EXCALIDRAW_AUTOMATE_INFO, EXCALIDRAW_SCRIPTENGINE_INFO } from "./dialogs/SuggesterInfo";
|
||||
import { CropImage } from "./utils/CropImage";
|
||||
import { has } from "./svgToExcalidraw/attributes";
|
||||
|
||||
extendPlugins([
|
||||
HarmonyPlugin,
|
||||
@@ -588,6 +589,7 @@ export class ExcalidrawAutomate {
|
||||
"excalidraw-linkbutton-opacity"?: number;
|
||||
"excalidraw-autoexport"?: boolean;
|
||||
"excalidraw-mask"?: boolean;
|
||||
"cssclasses"?: string;
|
||||
};
|
||||
plaintext?: string; //text to insert above the `# Text Elements` section
|
||||
}): Promise<string> {
|
||||
@@ -706,7 +708,16 @@ export class ExcalidrawAutomate {
|
||||
outString += `${key}: [[${item.file}]]\n`;
|
||||
}
|
||||
} else {
|
||||
outString += `${key}: ${item.hyperlink}\n`;
|
||||
const hyperlinkSplit = item.hyperlink.split("#");
|
||||
const file = this.plugin.app.vault.getAbstractFileByPath(hyperlinkSplit[0]);
|
||||
if(file && file instanceof TFile) {
|
||||
const hasFileRef = hyperlinkSplit.length === 2
|
||||
outString += hasFileRef
|
||||
? `${key}: [[${file.path}#${hyperlinkSplit[1]}]]\n`
|
||||
: `${key}: [[${file.path}]]\n`;
|
||||
} else {
|
||||
outString += `${key}: ${item.hyperlink}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1413,7 +1424,7 @@ export class ExcalidrawAutomate {
|
||||
async addImage(
|
||||
topX: number,
|
||||
topY: number,
|
||||
imageFile: TFile | string,
|
||||
imageFile: TFile | string, //string may also be an Obsidian filepath with a reference such as folder/path/my.pdf#page=2
|
||||
scale: boolean = true, //default is true which will scale the image to MAX_IMAGE_SIZE, false will insert image at 100% of its size
|
||||
anchor: boolean = true, //only has effect if scale is false. If anchor is true the image path will include |100%, if false the image will be inserted at 100%, but if resized by the user it won't pop back to 100% the next time Excalidraw is opened.
|
||||
): Promise<string> {
|
||||
@@ -1861,6 +1872,7 @@ export class ExcalidrawAutomate {
|
||||
this.elementsDict[el.id] = cloneElement(el);
|
||||
if(el.type === "image") {
|
||||
const ef = this.targetView.excalidrawData.getFile(el.fileId);
|
||||
const imageWithRef = ef && ef.file && ef.linkParts && ef.linkParts.ref;
|
||||
const equation = this.targetView.excalidrawData.getEquation(el.fileId);
|
||||
const sceneFile = sceneFiles?.[el.fileId];
|
||||
this.imagesDict[el.fileId] = {
|
||||
@@ -1869,9 +1881,9 @@ export class ExcalidrawAutomate {
|
||||
dataURL: sceneFile.dataURL,
|
||||
created: sceneFile.created,
|
||||
...ef ? {
|
||||
isHyperLink: ef.isHyperLink,
|
||||
hyperlink: ef.hyperlink,
|
||||
file: ef.file,
|
||||
isHyperLink: ef.isHyperLink || imageWithRef,
|
||||
hyperlink: imageWithRef ? `${ef.file.path}#${ef.linkParts.ref}` : ef.hyperlink,
|
||||
file: imageWithRef ? null : ef.file,
|
||||
hasSVGwithBitmap: ef.isSVGwithBitmap,
|
||||
latex: null,
|
||||
} : {},
|
||||
|
||||
@@ -8,15 +8,7 @@
|
||||
import { App, Notice, TFile } from "obsidian";
|
||||
import {
|
||||
nanoid,
|
||||
FRONTMATTER_KEY_CUSTOM_PREFIX,
|
||||
FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS,
|
||||
FRONTMATTER_KEY_CUSTOM_URL_PREFIX,
|
||||
FRONTMATTER_KEY_DEFAULT_MODE,
|
||||
fileid,
|
||||
FRONTMATTER_KEY_LINKBUTTON_OPACITY,
|
||||
FRONTMATTER_KEY_ONLOAD_SCRIPT,
|
||||
FRONTMATTER_KEY_AUTOEXPORT,
|
||||
FRONTMATTER_KEY_EMBEDDABLE_THEME,
|
||||
DEVICE,
|
||||
EMBEDDABLE_THEME_FRONTMATTER_VALUES,
|
||||
getBoundTextMaxWidth,
|
||||
@@ -25,6 +17,7 @@ import {
|
||||
wrapText,
|
||||
ERROR_IFRAME_CONVERSION_CANCELED,
|
||||
JSON_parse,
|
||||
FRONTMATTER_KEYS,
|
||||
} from "./constants/constants";
|
||||
import { _measureText } from "./ExcalidrawAutomate";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
@@ -1480,9 +1473,9 @@ export class ExcalidrawData {
|
||||
: this.plugin.settings.defaultMode;
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_DEFAULT_MODE] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["default-mode"].name] != null
|
||||
) {
|
||||
mode = fileCache.frontmatter[FRONTMATTER_KEY_DEFAULT_MODE];
|
||||
mode = fileCache.frontmatter[FRONTMATTER_KEYS["default-mode"].name];
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
@@ -1500,9 +1493,9 @@ export class ExcalidrawData {
|
||||
let opacity = this.plugin.settings.linkOpacity;
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_LINKBUTTON_OPACITY] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["linkbutton-opacity"].name] != null
|
||||
) {
|
||||
opacity = fileCache.frontmatter[FRONTMATTER_KEY_LINKBUTTON_OPACITY];
|
||||
opacity = fileCache.frontmatter[FRONTMATTER_KEYS["linkbutton-opacity"].name];
|
||||
}
|
||||
return opacity;
|
||||
}
|
||||
@@ -1511,9 +1504,9 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_ONLOAD_SCRIPT] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["onload-script"].name] != null
|
||||
) {
|
||||
return fileCache.frontmatter[FRONTMATTER_KEY_ONLOAD_SCRIPT];
|
||||
return fileCache.frontmatter[FRONTMATTER_KEYS["onload-script"].name];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1523,9 +1516,9 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_PREFIX] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-prefix"].name] != null
|
||||
) {
|
||||
this.linkPrefix = fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_PREFIX];
|
||||
this.linkPrefix = fileCache.frontmatter[FRONTMATTER_KEYS["link-prefix"].name];
|
||||
} else {
|
||||
this.linkPrefix = this.plugin.settings.linkPrefix;
|
||||
}
|
||||
@@ -1537,9 +1530,9 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_URL_PREFIX] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["url-prefix"].name] != null
|
||||
) {
|
||||
this.urlPrefix = fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_URL_PREFIX];
|
||||
this.urlPrefix = fileCache.frontmatter[FRONTMATTER_KEYS["url-prefix"].name];
|
||||
} else {
|
||||
this.urlPrefix = this.plugin.settings.urlPrefix;
|
||||
}
|
||||
@@ -1550,9 +1543,9 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_AUTOEXPORT] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["autoexport"].name] != null
|
||||
) {
|
||||
switch ((fileCache.frontmatter[FRONTMATTER_KEY_AUTOEXPORT]).toLowerCase()) {
|
||||
switch ((fileCache.frontmatter[FRONTMATTER_KEYS["autoexport"].name]).toLowerCase()) {
|
||||
case "none": this.autoexportPreference = AutoexportPreference.none; break;
|
||||
case "both": this.autoexportPreference = AutoexportPreference.both; break;
|
||||
case "png": this.autoexportPreference = AutoexportPreference.png; break;
|
||||
@@ -1569,9 +1562,9 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EMBEDDABLE_THEME] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["iframe-theme"].name] != null
|
||||
) {
|
||||
this.embeddableTheme = fileCache.frontmatter[FRONTMATTER_KEY_EMBEDDABLE_THEME].toLowerCase();
|
||||
this.embeddableTheme = fileCache.frontmatter[FRONTMATTER_KEYS["iframe-theme"].name].toLowerCase();
|
||||
if (!EMBEDDABLE_THEME_FRONTMATTER_VALUES.includes(this.embeddableTheme)) {
|
||||
this.embeddableTheme = "default";
|
||||
}
|
||||
@@ -1586,10 +1579,10 @@ export class ExcalidrawData {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] != null
|
||||
) {
|
||||
this.showLinkBrackets =
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS] != false;
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["link-brackets"].name] != false;
|
||||
} else {
|
||||
this.showLinkBrackets = this.plugin.settings.showLinkBrackets;
|
||||
}
|
||||
|
||||
@@ -35,16 +35,12 @@ import {
|
||||
ICON_NAME,
|
||||
DISK_ICON_NAME,
|
||||
SCRIPTENGINE_ICON_NAME,
|
||||
FRONTMATTER_KEY,
|
||||
TEXT_DISPLAY_RAW_ICON_NAME,
|
||||
TEXT_DISPLAY_PARSED_ICON_NAME,
|
||||
IMAGE_TYPES,
|
||||
REG_LINKINDEX_INVALIDCHARS,
|
||||
KEYCODE,
|
||||
FRONTMATTER_KEY_EXPORT_PADDING,
|
||||
FRONTMATTER_KEY_EXPORT_PNGSCALE,
|
||||
FRONTMATTER_KEY_EXPORT_DARK,
|
||||
FRONTMATTER_KEY_EXPORT_TRANSPARENT,
|
||||
FRONTMATTER_KEYS,
|
||||
DEVICE,
|
||||
GITHUB_RELEASES,
|
||||
EXPORT_IMG_ICON_NAME,
|
||||
@@ -106,7 +102,7 @@ import {
|
||||
} from "./utils/Utils";
|
||||
import { getLeaf, getParentOfClass, obsidianPDFQuoteWithRef } from "./utils/ObsidianUtils";
|
||||
import { splitFolderAndFilename } from "./utils/FileUtils";
|
||||
import { ConfirmationPrompt, GenericInputPrompt, NewFileActions, Prompt } from "./dialogs/Prompt";
|
||||
import { ConfirmationPrompt, GenericInputPrompt, NewFileActions, Prompt, linkPrompt } from "./dialogs/Prompt";
|
||||
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
|
||||
import { updateEquation } from "./LaTeX";
|
||||
import {
|
||||
@@ -127,7 +123,7 @@ import { anyModifierKeysPressed, emulateKeysForLinkClick, webbrowserDragModifier
|
||||
import { setDynamicStyle } from "./utils/DynamicStyling";
|
||||
import { InsertPDFModal } from "./dialogs/InsertPDFModal";
|
||||
import { CustomEmbeddable, renderWebView } from "./customEmbeddable";
|
||||
import { getLinkTextFromLink, insertEmbeddableToView, insertImageToView } from "./utils/ExcalidrawViewUtils";
|
||||
import { getExcalidrawFileForwardLinks, getLinkTextFromLink, insertEmbeddableToView, insertImageToView, openExternalLink, openTagSearch } from "./utils/ExcalidrawViewUtils";
|
||||
import { imageCache } from "./utils/ImageCache";
|
||||
import { CanvasNodeFactory, ObsidianCanvasNode } from "./utils/CanvasNodeFactory";
|
||||
import { EmbeddableMenu } from "./menu/EmbeddableActionsMenu";
|
||||
@@ -735,14 +731,14 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (!this.compatibilityMode) {
|
||||
const keys:[string,string][] = this.exportDialog?.dirty && this.exportDialog?.saveSettings
|
||||
? [
|
||||
[FRONTMATTER_KEY_EXPORT_PADDING, this.exportDialog.padding.toString()],
|
||||
[FRONTMATTER_KEY_EXPORT_PNGSCALE, this.exportDialog.scale.toString()],
|
||||
[FRONTMATTER_KEY_EXPORT_DARK, this.exportDialog.theme === "dark" ? "true" : "false"],
|
||||
[FRONTMATTER_KEY_EXPORT_TRANSPARENT, this.exportDialog.transparent ? "true" : "false"],
|
||||
[FRONTMATTER_KEY, this.textMode === TextMode.raw ? "raw" : "parsed"]
|
||||
[FRONTMATTER_KEYS["export-padding"].name, this.exportDialog.padding.toString()],
|
||||
[FRONTMATTER_KEYS["export-pngscale"].name, this.exportDialog.scale.toString()],
|
||||
[FRONTMATTER_KEYS["export-dark"].name, this.exportDialog.theme === "dark" ? "true" : "false"],
|
||||
[FRONTMATTER_KEYS["export-transparent"].name, this.exportDialog.transparent ? "true" : "false"],
|
||||
[FRONTMATTER_KEYS["plugin"].name, this.textMode === TextMode.raw ? "raw" : "parsed"]
|
||||
]
|
||||
: [
|
||||
[FRONTMATTER_KEY, this.textMode === TextMode.raw ? "raw" : "parsed"]
|
||||
[FRONTMATTER_KEYS["plugin"].name, this.textMode === TextMode.raw ? "raw" : "parsed"]
|
||||
];
|
||||
|
||||
if(this.exportDialog?.dirty) {
|
||||
@@ -891,84 +887,6 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return false;
|
||||
}
|
||||
|
||||
openExternalLink(link:string, element?: ExcalidrawElement):boolean {
|
||||
if (link.match(/^cmd:\/\/.*/)) {
|
||||
const cmd = link.replace("cmd://", "");
|
||||
//@ts-ignore
|
||||
this.app.commands.executeCommandById(cmd);
|
||||
return true;
|
||||
}
|
||||
if (link.match(REG_LINKINDEX_HYPERLINK)) {
|
||||
window.open(link, "_blank");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
openTagSearch(link:string) {
|
||||
const tags = link
|
||||
.matchAll(/#([\p{Letter}\p{Emoji_Presentation}\p{Number}\/_-]+)/gu)
|
||||
.next();
|
||||
if (!tags.value || tags.value.length < 2) {
|
||||
return;
|
||||
}
|
||||
const search = app.workspace.getLeavesOfType("search");
|
||||
if (search.length == 0) {
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
search[0].view.setQuery(`tag:${tags.value[1]}`);
|
||||
this.app.workspace.revealLeaf(search[0]);
|
||||
|
||||
if (this.isFullscreen()) {
|
||||
this.exitFullscreen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
async linkPrompt(linkText:string):Promise<[file:TFile, linkText:string, subpath: string]> {
|
||||
const partsArray = REGEX_LINK.getResList(linkText);
|
||||
let subpath: string = null;
|
||||
let file: TFile = null;
|
||||
let parts = partsArray[0];
|
||||
if (partsArray.length > 1) {
|
||||
parts = await ScriptEngine.suggester(
|
||||
this.app,
|
||||
partsArray.filter(p=>Boolean(p.value)).map(p => {
|
||||
const alias = REGEX_LINK.getAliasOrLink(p);
|
||||
return alias === "100%" ? REGEX_LINK.getLink(p) : alias;
|
||||
}),
|
||||
partsArray.filter(p=>Boolean(p.value)),
|
||||
"Select link to open"
|
||||
);
|
||||
if(!parts) return;
|
||||
}
|
||||
if(!parts) return;
|
||||
|
||||
if (!parts.value) {
|
||||
this.openTagSearch(linkText);
|
||||
return;
|
||||
}
|
||||
|
||||
linkText = REGEX_LINK.getLink(parts);
|
||||
if(this.openExternalLink(linkText)) return;
|
||||
|
||||
if (linkText.search("#") > -1) {
|
||||
const linkParts = getLinkParts(linkText, this.file);
|
||||
subpath = `#${linkParts.isBlockRef ? "^" : ""}${linkParts.ref}`;
|
||||
linkText = linkParts.path;
|
||||
}
|
||||
if (linkText.match(REG_LINKINDEX_INVALIDCHARS)) {
|
||||
new Notice(t("FILENAME_INVALID_CHARS"), 4000);
|
||||
return;
|
||||
}
|
||||
file = this.app.metadataCache.getFirstLinkpathDest(
|
||||
linkText,
|
||||
this.file.path,
|
||||
);
|
||||
return [file, linkText, subpath];
|
||||
}
|
||||
|
||||
async linkClick(
|
||||
ev: MouseEvent | null,
|
||||
selectedText: SelectedElementWithLink,
|
||||
@@ -1003,9 +921,9 @@ export default class ExcalidrawView extends TextFileView {
|
||||
const id = selectedText.id??selectedElementWithLink.id;
|
||||
const el = this.excalidrawAPI.getSceneElements().filter((el:ExcalidrawElement)=>el.id === id)[0];
|
||||
if(this.handleLinkHookCall(el,linkText,ev)) return;
|
||||
if(this.openExternalLink(linkText)) return;
|
||||
if(openExternalLink(linkText, this.app)) return;
|
||||
|
||||
const result = await this.linkPrompt(linkText);
|
||||
const result = await linkPrompt(linkText, this.app, this);
|
||||
if(!result) return;
|
||||
[file, linkText, subpath] = result;
|
||||
}
|
||||
@@ -1096,6 +1014,10 @@ export default class ExcalidrawView extends TextFileView {
|
||||
secondOrderLinks += linkPaths.join(" ");
|
||||
}
|
||||
|
||||
if(this.plugin.isExcalidrawFile(ef.file)) {
|
||||
secondOrderLinks += getExcalidrawFileForwardLinks(this.app, ef.file);
|
||||
}
|
||||
|
||||
const linkString = (ef.isHyperLink || ef.isLocalLink
|
||||
? `[](${ef.hyperlink}) `
|
||||
: `[[${ef.linkParts.original}]] `
|
||||
@@ -1105,10 +1027,9 @@ export default class ExcalidrawView extends TextFileView {
|
||||
: imageElement.link
|
||||
: "");
|
||||
|
||||
const result = await this.linkPrompt(linkString + secondOrderLinks);
|
||||
const result = await linkPrompt(linkString + secondOrderLinks, this.app, this);
|
||||
if(!result) return;
|
||||
[file, linkText, subpath] = result;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,7 +1063,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
|
||||
try {
|
||||
//@ts-ignore
|
||||
const drawIO = app.plugins.plugins["drawio-obsidian"];
|
||||
const drawIO = this.app.plugins.plugins["drawio-obsidian"];
|
||||
if(drawIO && drawIO._loaded) {
|
||||
if(file.extension === "svg") {
|
||||
const svg = await this.app.vault.cachedRead(file);
|
||||
@@ -3951,7 +3872,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
|
||||
let event = e?.detail?.nativeEvent;
|
||||
if(this.handleLinkHookCall(element,element.link,event)) return;
|
||||
if(this.openExternalLink(element.link, !isSHIFT(event) && !isWinCTRLorMacCMD(event) && !isWinMETAorMacCTRL(event) && !isWinALTorMacOPT(event) ? element : undefined)) return;
|
||||
if(openExternalLink(element.link, this.app, !isSHIFT(event) && !isWinCTRLorMacCMD(event) && !isWinMETAorMacCTRL(event) && !isWinALTorMacOPT(event) ? element : undefined)) return;
|
||||
|
||||
//if element is type text and element has multiple links, then submit the element text to linkClick to trigger link suggester
|
||||
if(element.type === "text") {
|
||||
@@ -5021,7 +4942,6 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return embeddable.leaf.view.editor;
|
||||
}
|
||||
}
|
||||
app.workspace.openLinkText
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
MarkdownPostProcessorContext,
|
||||
MetadataCache,
|
||||
PaneType,
|
||||
TFile,
|
||||
Vault,
|
||||
} from "obsidian";
|
||||
@@ -26,6 +27,8 @@ import { linkClickModifierType } from "./utils/ModifierkeyHelper";
|
||||
import { ImageKey, imageCache } from "./utils/ImageCache";
|
||||
import { FILENAMEPARTS, PreviewImageType } from "./utils/UtilTypes";
|
||||
import { CustomMutationObserver, isDebugMode } from "./utils/DebugHelper";
|
||||
import { getExcalidrawFileForwardLinks } from "./utils/ExcalidrawViewUtils";
|
||||
import { linkPrompt } from "./dialogs/Prompt";
|
||||
|
||||
interface imgElementAttributes {
|
||||
file?: TFile;
|
||||
@@ -356,12 +359,31 @@ const createImgElement = async (
|
||||
if (src) {
|
||||
const srcParts = src.match(/([^#]*)(.*)/);
|
||||
if(!srcParts) return;
|
||||
plugin.openDrawing(
|
||||
vault.getAbstractFileByPath(srcParts[1]) as TFile,
|
||||
linkClickModifierType(ev),
|
||||
true,
|
||||
srcParts[2],
|
||||
);
|
||||
const f = vault.getAbstractFileByPath(srcParts[1]) as TFile;
|
||||
const linkModifier = linkClickModifierType(ev);
|
||||
if (plugin.isExcalidrawFile(f) && isMaskFile(plugin, f)) {
|
||||
(async () => {
|
||||
const linkString = `[[${f.path}${srcParts[2]?"#"+srcParts[2]:""}]] ${getExcalidrawFileForwardLinks(plugin.app, f)}`;
|
||||
const result = await linkPrompt(linkString, plugin.app);
|
||||
if(!result) return;
|
||||
const [file, linkText, subpath] = result;
|
||||
if(plugin.isExcalidrawFile(file)) {
|
||||
plugin.openDrawing(file,linkModifier, true, subpath);
|
||||
return;
|
||||
}
|
||||
let paneType: boolean | PaneType = false;
|
||||
switch(linkModifier) {
|
||||
case "active-pane": paneType = false; break;
|
||||
case "new-pane": paneType = "split"; break;
|
||||
case "popout-window": paneType = "window"; break;
|
||||
case "new-tab": paneType = "tab"; break;
|
||||
case "md-properties": paneType = "tab"; break;
|
||||
}
|
||||
plugin.app.workspace.openLinkText(linkText,"",paneType,subpath ? {eState: {subpath}} : {});
|
||||
})()
|
||||
return;
|
||||
}
|
||||
plugin.openDrawing(f,linkModifier,true,srcParts[2]);
|
||||
} //.ctrlKey||ev.metaKey);
|
||||
};
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1003
|
||||
|
||||
@@ -143,26 +143,29 @@ export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg", "webp", "bmp", "
|
||||
export const ANIMATED_IMAGE_TYPES = ["gif", "webp", "apng", "svg"];
|
||||
export const EXPORT_TYPES = ["svg", "dark.svg", "light.svg", "png", "dark.png", "light.png"];
|
||||
export const MAX_IMAGE_SIZE = 500;
|
||||
export const FRONTMATTER_KEY = "excalidraw-plugin";
|
||||
export const FRONTMATTER_KEY_EXPORT_TRANSPARENT =
|
||||
"excalidraw-export-transparent";
|
||||
export const FRONTMATTER_KEY_MASK = "excalidraw-mask";
|
||||
export const FRONTMATTER_KEY_EXPORT_DARK = "excalidraw-export-dark";
|
||||
export const FRONTMATTER_KEY_EXPORT_SVGPADDING = "excalidraw-export-svgpadding"; //depricated
|
||||
export const FRONTMATTER_KEY_EXPORT_PADDING = "excalidraw-export-padding";
|
||||
export const FRONTMATTER_KEY_EXPORT_PNGSCALE = "excalidraw-export-pngscale";
|
||||
export const FRONTMATTER_KEY_CUSTOM_PREFIX = "excalidraw-link-prefix";
|
||||
export const FRONTMATTER_KEY_CUSTOM_URL_PREFIX = "excalidraw-url-prefix";
|
||||
export const FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS = "excalidraw-link-brackets";
|
||||
export const FRONTMATTER_KEY_ONLOAD_SCRIPT = "excalidraw-onload-script";
|
||||
export const FRONTMATTER_KEY_LINKBUTTON_OPACITY = "excalidraw-linkbutton-opacity";
|
||||
export const FRONTMATTER_KEY_DEFAULT_MODE = "excalidraw-default-mode";
|
||||
export const FRONTMATTER_KEY_FONT = "excalidraw-font";
|
||||
export const FRONTMATTER_KEY_FONTCOLOR = "excalidraw-font-color";
|
||||
export const FRONTMATTER_KEY_BORDERCOLOR = "excalidraw-border-color";
|
||||
export const FRONTMATTER_KEY_MD_STYLE = "excalidraw-css";
|
||||
export const FRONTMATTER_KEY_AUTOEXPORT = "excalidraw-autoexport"
|
||||
export const FRONTMATTER_KEY_EMBEDDABLE_THEME = "excalidraw-iframe-theme";
|
||||
|
||||
export const FRONTMATTER_KEYS:{[key:string]: {name: string, type: string, depricated?:boolean}} = {
|
||||
"plugin": {name: "excalidraw-plugin", type: "text"},
|
||||
"export-transparent": {name: "excalidraw-export-transparent", type: "checkbox"},
|
||||
"mask": {name: "excalidraw-mask", type: "checkbox"},
|
||||
"export-dark": {name: "excalidraw-export-dark", type: "checkbox"},
|
||||
"export-svgpadding": {name: "excalidraw-export-svgpadding", type: "number", depricated: true},
|
||||
"export-padding": {name: "excalidraw-export-padding", type: "number"},
|
||||
"export-pngscale": {name: "excalidraw-export-pngscale", type: "number"},
|
||||
"link-prefix": {name: "excalidraw-link-prefix", type: "text"},
|
||||
"url-prefix": {name: "excalidraw-url-prefix", type: "text"},
|
||||
"link-brackets": {name: "excalidraw-link-brackets", type: "checkbox"},
|
||||
"onload-script": {name: "excalidraw-onload-script", type: "text"},
|
||||
"linkbutton-opacity": {name: "excalidraw-linkbutton-opacity", type: "number"},
|
||||
"default-mode": {name: "excalidraw-default-mode", type: "text"},
|
||||
"font": {name: "excalidraw-font", type: "text"},
|
||||
"font-color": {name: "excalidraw-font-color", type: "text"},
|
||||
"border-color": {name: "excalidraw-border-color", type: "text"},
|
||||
"md-css": {name: "excalidraw-css", type: "text"},
|
||||
"autoexport": {name: "excalidraw-autoexport", type: "checkbox"},
|
||||
"iframe-theme": {name: "excalidraw-iframe-theme", type: "text"},
|
||||
};
|
||||
|
||||
export const EMBEDDABLE_THEME_FRONTMATTER_VALUES = ["light", "dark", "auto", "dafault"];
|
||||
export const VIEW_TYPE_EXCALIDRAW = "excalidraw";
|
||||
export const ICON_NAME = "excalidraw-icon";
|
||||
@@ -176,7 +179,7 @@ export const DARK_BLANK_DRAWING =
|
||||
export const FRONTMATTER = [
|
||||
"---",
|
||||
"",
|
||||
`${FRONTMATTER_KEY}: parsed`,
|
||||
`${FRONTMATTER_KEYS["plugin"].name}: parsed`,
|
||||
"tags: [excalidraw]",
|
||||
"",
|
||||
"---",
|
||||
|
||||
@@ -162,6 +162,19 @@ export class InsertPDFModal extends Modal {
|
||||
numPagesMessage.innerHTML = `There are <b>${numPages}</b> pages in the selected document.`;
|
||||
}
|
||||
|
||||
let pageRangesTextComponent: TextComponent
|
||||
let importPagesMessage: HTMLParagraphElement;
|
||||
|
||||
const rangeOnChange = (value:string) => {
|
||||
const pages = this.createPageListFromString(value);
|
||||
if(pages.length > 15) {
|
||||
importPagesMessage.innerHTML = `You are importing <b>${pages.length}</b> pages. ⚠️ This may take a while. ⚠️`;
|
||||
} else {
|
||||
importPagesMessage.innerHTML = `You are importing <b>${pages.length}</b> pages.`;
|
||||
}
|
||||
importButtonMessages();
|
||||
}
|
||||
|
||||
const setFile = async (file: TFile) => {
|
||||
if(this.pdfDoc) await this.pdfDoc.destroy();
|
||||
this.pdfDoc = null;
|
||||
@@ -171,6 +184,8 @@ export class InsertPDFModal extends Modal {
|
||||
this.pdfFile = file;
|
||||
if(this.pdfDoc) {
|
||||
numPages = this.pdfDoc.numPages;
|
||||
pageRangesTextComponent.setValue(`1-${numPages}`);
|
||||
rangeOnChange(`1-${numPages}`);
|
||||
importButtonMessages();
|
||||
numPagesMessages();
|
||||
this.getPageDimensions(this.pdfDoc);
|
||||
@@ -190,23 +205,14 @@ export class InsertPDFModal extends Modal {
|
||||
|
||||
numPagesMessage = ce.createEl("p", {text: ""});
|
||||
numPagesMessages();
|
||||
let importPagesMessage: HTMLParagraphElement;
|
||||
let pageRangesTextComponent: TextComponent
|
||||
new Setting(ce)
|
||||
.setName("Pages to import")
|
||||
.setDesc("e.g.: 1,3-5,7,9-10")
|
||||
.addText(text => {
|
||||
pageRangesTextComponent = text;
|
||||
text
|
||||
.setPlaceholder("e.g.: 1,3-5,7,9-10")
|
||||
.onChange((value) => {
|
||||
const pages = this.createPageListFromString(value);
|
||||
if(pages.length > 15) {
|
||||
importPagesMessage.innerHTML = `You are importing <b>${pages.length}</b> pages. ⚠️ This may take a while. ⚠️`;
|
||||
} else {
|
||||
importPagesMessage.innerHTML = `You are importing <b>${pages.length}</b> pages.`;
|
||||
}
|
||||
importButtonMessages();
|
||||
})
|
||||
.setValue("")
|
||||
.onChange((value) => rangeOnChange(value))
|
||||
text.inputEl.style.width = "100%";
|
||||
})
|
||||
importPagesMessage = ce.createEl("p", {text: ""});
|
||||
|
||||
@@ -17,6 +17,28 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
|
||||
|
||||
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
|
||||
`,
|
||||
"2.0.19":`
|
||||
<div class="excalidraw-videoWrapper"><div>
|
||||
<iframe src="https://www.youtube.com/embed/4wp6vLiIdGM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div></div>
|
||||
|
||||
## Fixed
|
||||
- When updating Excalidraw, some open drawings weren't automatically reopening. I hope I got this fixed (note this change will only have an effect when you receive the update after this).
|
||||
- In dark mode, the frame header is challenging to see when modified [#1568](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1568).
|
||||
|
||||
## New
|
||||
- Crop PDF pages:
|
||||
- Available in Excalidraw, Markdown Notes, and on the Canvas.
|
||||
- Crop the active page from the embedded PDF viewer and insert the cropped image into the current view, both in Excalidraw and on Canvas.
|
||||
- New Command Palette Action: "Insert active PDF page as image." This action is functional in Excalidraw. If an embedded Obsidian-PDF-viewer is present, executing this command will insert the active page as an image into the Excalidraw scene.
|
||||
- Two new settings introduced:
|
||||
- "Basic" section allows setting the folder for crop files.
|
||||
- "Saving/filename" section enables setting the prefix for crop files.
|
||||
- PDF import now defaults to importing all pages.
|
||||
- Rounded corners now available for images.
|
||||
- Second-order links now encompass forward links from embedded Excalidraw Files.
|
||||
- Clicking a cropped file in a markdown note or on Canvas will prompt to open the original file, not just the cropper.
|
||||
`,
|
||||
"2.0.18":`
|
||||
## New
|
||||
|
||||
|
||||
@@ -11,14 +11,17 @@ import {
|
||||
} from "obsidian";
|
||||
import ExcalidrawView from "../ExcalidrawView";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { escapeRegExp, sleep } from "../utils/Utils";
|
||||
import { escapeRegExp, getLinkParts, sleep } from "../utils/Utils";
|
||||
import { getLeaf } from "../utils/ObsidianUtils";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "src/utils/FileUtils";
|
||||
import { KeyEvent, isWinCTRLorMacCMD } from "src/utils/ModifierkeyHelper";
|
||||
import { t } from "src/lang/helpers";
|
||||
import { ExcalidrawElement, getEA } from "src";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
import { MAX_IMAGE_SIZE } from "src/constants/constants";
|
||||
import { MAX_IMAGE_SIZE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants";
|
||||
import { REGEX_LINK } from "src/ExcalidrawData";
|
||||
import { ScriptEngine } from "src/Scripts";
|
||||
import { openExternalLink, openTagSearch } from "src/utils/ExcalidrawViewUtils";
|
||||
|
||||
export type ButtonDefinition = { caption: string; tooltip?:string; action: Function };
|
||||
|
||||
@@ -693,3 +696,46 @@ export class ConfirmationPrompt extends Modal {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const linkPrompt = async (linkText:string, app: App, view?: ExcalidrawView):Promise<[file:TFile, linkText:string, subpath: string]> => {
|
||||
const partsArray = REGEX_LINK.getResList(linkText);
|
||||
let subpath: string = null;
|
||||
let file: TFile = null;
|
||||
let parts = partsArray[0];
|
||||
if (partsArray.length > 1) {
|
||||
parts = await ScriptEngine.suggester(
|
||||
app,
|
||||
partsArray.filter(p=>Boolean(p.value)).map(p => {
|
||||
const alias = REGEX_LINK.getAliasOrLink(p);
|
||||
return alias === "100%" ? REGEX_LINK.getLink(p) : alias;
|
||||
}),
|
||||
partsArray.filter(p=>Boolean(p.value)),
|
||||
"Select link to open"
|
||||
);
|
||||
if(!parts) return;
|
||||
}
|
||||
if(!parts) return;
|
||||
|
||||
if (!parts.value) {
|
||||
openTagSearch(linkText, app);
|
||||
return;
|
||||
}
|
||||
|
||||
linkText = REGEX_LINK.getLink(parts);
|
||||
if(openExternalLink(linkText, app)) return;
|
||||
|
||||
if (linkText.search("#") > -1) {
|
||||
const linkParts = getLinkParts(linkText, view ? view.file : undefined);
|
||||
subpath = `#${linkParts.isBlockRef ? "^" : ""}${linkParts.ref}`;
|
||||
linkText = linkParts.path;
|
||||
}
|
||||
if (linkText.match(REG_LINKINDEX_INVALIDCHARS)) {
|
||||
new Notice(t("FILENAME_INVALID_CHARS"), 4000);
|
||||
return;
|
||||
}
|
||||
file = app.metadataCache.getFirstLinkpathDest(
|
||||
linkText,
|
||||
view ? view.file.path : "",
|
||||
);
|
||||
return [file, linkText, subpath];
|
||||
}
|
||||
@@ -186,8 +186,23 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
|
||||
},
|
||||
{
|
||||
field: "create",
|
||||
code: 'async create(params?: {filename?: string, foldername?: string, templatePath?: string, onNewPane?: boolean, silent?: boolean, frontmatterKeys?: { "excalidraw-plugin"?: "raw" | "parsed", "excalidraw-link-prefix"?: string, "excalidraw-link-brackets"?: boolean, "excalidraw-url-prefix"?: string,},}): Promise<string>;',
|
||||
desc: "Create a drawing and save it to filename.\nIf filename is null: default filename as defined in Excalidraw settings.\nIf folder is null: default folder as defined in Excalidraw settings\nReturns the path to the created file",
|
||||
code: 'async create(params?: {filename?: string, foldername?: string, templatePath?: string, onNewPane?: boolean, silent?: boolean, frontmatterKeys?: {},}): Promise<string>;',
|
||||
desc: "Create a drawing and save it to filename.\nIf filename is null: default filename as defined in Excalidraw settings.\nIf folder is null: default folder as defined in Excalidraw settings\nReturns the path to the created file.\n" +
|
||||
'frontmatterKeys: {\n' +
|
||||
' "excalidraw-plugin"?: "raw" | "parsed";\n' +
|
||||
' "excalidraw-link-prefix"?: string;\n' +
|
||||
' "excalidraw-link-brackets"?: boolean;\n' +
|
||||
' "excalidraw-url-prefix"?: string;\n' +
|
||||
' "excalidraw-export-transparent"?: boolean;\n' +
|
||||
' "excalidraw-export-dark"?: boolean;\n' +
|
||||
' "excalidraw-export-padding"?: number;\n' +
|
||||
' "excalidraw-export-pngscale"?: number;\n' +
|
||||
' "excalidraw-default-mode"?: "view" | "zen";\n' +
|
||||
' "excalidraw-onload-script"?: string;\n' +
|
||||
' "excalidraw-linkbutton-opacity"?: number;\n' +
|
||||
' "excalidraw-autoexport"?: boolean;\n' +
|
||||
' "excalidraw-mask"?: boolean;\n' +
|
||||
' "cssclasses"?: string;\n}',
|
||||
after: "",
|
||||
},
|
||||
{
|
||||
@@ -264,8 +279,8 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
|
||||
},
|
||||
{
|
||||
field: "addImage",
|
||||
code: "async addImage(topX: number, topY: number, imageFile: TFile, scale?: boolean, anchor?: boolean): Promise<string>;",
|
||||
desc: "set scale to false if you want to embed the image at 100% of its original size. Default is true which will insert a scaled image. anchor will only be evaluated if scale is false. anchor true will add |100% to the end of the filename, resulting in an image that will always pop back to 100% when the source file is updated or when the Excalidraw file is reopened. ",
|
||||
code: "async addImage(topX: number, topY: number, imageFile: TFile|string, scale?: boolean, anchor?: boolean): Promise<string>;",
|
||||
desc: "imageFile may be a TFile or a string that contains a hyperlink. imageFile may also be an obsidian filepath including a reference eg.: 'path/my.pdf#page=3'\nSet scale to false if you want to embed the image at 100% of its original size. Default is true which will insert a scaled image.\nanchor will only be evaluated if scale is false. anchor true will add |100% to the end of the filename, resulting in an image that will always pop back to 100% when the source file is updated or when the Excalidraw file is reopened.",
|
||||
after: "",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import {
|
||||
DEVICE,
|
||||
FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS,
|
||||
FRONTMATTER_KEY_CUSTOM_PREFIX,
|
||||
FRONTMATTER_KEY_CUSTOM_URL_PREFIX,
|
||||
FRONTMATTER_KEYS,
|
||||
} from "src/constants/constants";
|
||||
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
|
||||
@@ -78,6 +76,7 @@ export default {
|
||||
TRAY_MODE: "Toggle property-panel tray-mode",
|
||||
SEARCH: "Search for text in drawing",
|
||||
CROP_IMAGE: "Crop and mask image",
|
||||
INSERT_ACTIVE_PDF_PAGE_AS_IMAGE: "Insert active PDF page as image",
|
||||
RESET_IMG_TO_100: "Set selected image element size to 100% of original",
|
||||
TEMPORARY_DISABLE_AUTOSAVE: "Disable autosave until next time Obsidian starts (only set this if you know what you are doing)",
|
||||
TEMPORARY_ENABLE_AUTOSAVE: "Enable autosave",
|
||||
@@ -126,6 +125,13 @@ export default {
|
||||
FOLDER_NAME: "Excalidraw folder",
|
||||
FOLDER_DESC:
|
||||
"Default location for new drawings. If empty, drawings will be created in the Vault root.",
|
||||
CROP_PREFIX_NAME: "Crop file prefix",
|
||||
CROP_PREFIX_DESC:
|
||||
"The first part of the filename for new drawings created when cropping an image. " +
|
||||
"If empty the default 'cropped_' will be used.",
|
||||
CROP_FOLDER_NAME: "Crop file folder",
|
||||
CROP_FOLDER_DESC:
|
||||
"Default location for new drawings created when cropping an image. If empty, drawings will be created following the Vault attachments settings.",
|
||||
FOLDER_EMBED_NAME:
|
||||
"Use Excalidraw folder when embedding a drawing into the active document",
|
||||
FOLDER_EMBED_DESC:
|
||||
@@ -314,17 +320,17 @@ FILENAME_HEAD: "Filename",
|
||||
LINK_BRACKETS_DESC: `${
|
||||
"In PREVIEW mode, when parsing Text Elements, place brackets around links. " +
|
||||
"You can override this setting for a specific drawing by adding <code>"
|
||||
}${FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS}: true/false</code> to the file's frontmatter.`,
|
||||
}${FRONTMATTER_KEYS["link-brackets"].name}: true/false</code> to the file's frontmatter.`,
|
||||
LINK_PREFIX_NAME: "Link prefix",
|
||||
LINK_PREFIX_DESC: `${
|
||||
"In PREVIEW mode, if the Text Element contains a link, precede the text with these characters. " +
|
||||
"You can override this setting for a specific drawing by adding <code>"
|
||||
}${FRONTMATTER_KEY_CUSTOM_PREFIX}: "📍 "</code> to the file's frontmatter.`,
|
||||
}${FRONTMATTER_KEYS["link-prefix"].name}: "📍 "</code> to the file's frontmatter.`,
|
||||
URL_PREFIX_NAME: "URL prefix",
|
||||
URL_PREFIX_DESC: `${
|
||||
"In PREVIEW mode, if the Text Element contains a URL link, precede the text with these characters. " +
|
||||
"You can override this setting for a specific drawing by adding <code>"
|
||||
}${FRONTMATTER_KEY_CUSTOM_URL_PREFIX}: "🌐 "</code> to the file's frontmatter.`,
|
||||
}${FRONTMATTER_KEYS["url-prefix"].name}: "🌐 "</code> to the file's frontmatter.`,
|
||||
PARSE_TODO_NAME: "Parse todo",
|
||||
PARSE_TODO_DESC: "Convert '- [ ] ' and '- [x] ' to checkbox and tick in the box.",
|
||||
TODO_NAME: "Open TODO icon",
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import {
|
||||
DEVICE,
|
||||
FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS,
|
||||
FRONTMATTER_KEY_CUSTOM_PREFIX,
|
||||
FRONTMATTER_KEY_CUSTOM_URL_PREFIX,
|
||||
FRONTMATTER_KEYS,
|
||||
} from "src/constants/constants";
|
||||
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
|
||||
@@ -313,17 +311,17 @@ FILENAME_HEAD: "文件名",
|
||||
LINK_BRACKETS_DESC: `${
|
||||
"文本元素处于预览(PREVIEW)模式时,在内部链接的两侧显示中括号。<br>" +
|
||||
"您可为某个绘图单独设置此项,方法是在其 frontmatter 中添加形如 <code>"
|
||||
}${FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS}: true/false</code> 的键值对。`,
|
||||
}${FRONTMATTER_KEYS["link-brackets"].name}: true/false</code> 的键值对。`,
|
||||
LINK_PREFIX_NAME: "内部链接的前缀",
|
||||
LINK_PREFIX_DESC: `${
|
||||
"文本元素处于预览(PREVIEW)模式时,如果其中包含链接,则添加此前缀。<br>" +
|
||||
"您可为某个绘图单独设置此项,方法是在其 frontmatter 中添加形如 <code>"
|
||||
}${FRONTMATTER_KEY_CUSTOM_PREFIX}: "📍 "</code> 的键值对。`,
|
||||
}${FRONTMATTER_KEYS["link-prefix"].name}: "📍 "</code> 的键值对。`,
|
||||
URL_PREFIX_NAME: "外部链接的前缀",
|
||||
URL_PREFIX_DESC: `${
|
||||
"文本元素处于预览(PREVIEW)模式时,如果其中包含外部链接,则添加此前缀。<br>" +
|
||||
"您可为某个绘图单独设置此项,方法是在其 frontmatter 中添加形如 <code>"
|
||||
}${FRONTMATTER_KEY_CUSTOM_URL_PREFIX}: "🌐 "</code> 的键值对。`,
|
||||
}${FRONTMATTER_KEYS["url-prefix"].name}: "🌐 "</code> 的键值对。`,
|
||||
PARSE_TODO_NAME: "待办任务(Todo)",
|
||||
PARSE_TODO_DESC: "将文本元素中的 <code>- [ ]</code> 和 <code>- [x]</code> 前缀显示为方框。",
|
||||
TODO_NAME: "未完成项目",
|
||||
|
||||
187
src/main.ts
187
src/main.ts
@@ -29,7 +29,7 @@ import {
|
||||
SCRIPTENGINE_ICON,
|
||||
SCRIPTENGINE_ICON_NAME,
|
||||
RERENDER_EVENT,
|
||||
FRONTMATTER_KEY,
|
||||
FRONTMATTER_KEYS,
|
||||
FRONTMATTER,
|
||||
JSON_parse,
|
||||
nanoid,
|
||||
@@ -78,6 +78,7 @@ import { t } from "./lang/helpers";
|
||||
import {
|
||||
checkAndCreateFolder,
|
||||
download,
|
||||
getCropFileNameAndFolder,
|
||||
getDrawingFilename,
|
||||
getEmbedFilename,
|
||||
getIMGFilename,
|
||||
@@ -97,7 +98,7 @@ import {
|
||||
isCallerFromTemplaterPlugin,
|
||||
decompress,
|
||||
} from "./utils/Utils";
|
||||
import { extractSVGPNGFileName, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { extractSVGPNGFileName, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
import { ExcalidrawElement, ExcalidrawEmbeddableElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { ScriptEngine } from "./Scripts";
|
||||
import {
|
||||
@@ -126,7 +127,7 @@ import { getEA } from "src";
|
||||
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
||||
import { CustomMutationObserver, durationTreshold, isDebugMode } from "./utils/DebugHelper";
|
||||
import { carveOutImage, createImageCropperFile, CROPPED_PREFIX } from "./utils/CarveOut";
|
||||
import { carveOutImage, carveOutPDF, createImageCropperFile, CROPPED_PREFIX } from "./utils/CarveOut";
|
||||
import { ExcalidrawConfig } from "./utils/ExcalidrawConfig";
|
||||
|
||||
declare const EXCALIDRAW_PACKAGES:string;
|
||||
@@ -248,7 +249,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
// Register the modified event
|
||||
super.registerEvent(event);
|
||||
}
|
||||
|
||||
|
||||
async onload() {
|
||||
addIcon(ICON_NAME, EXCALIDRAW_ICON);
|
||||
addIcon(SCRIPTENGINE_ICON_NAME, SCRIPTENGINE_ICON);
|
||||
@@ -281,6 +282,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
this.runStartupScript();
|
||||
this.initializeFonts();
|
||||
this.registerEditorSuggest(new FieldSuggester(this));
|
||||
this.setPropertyTypes();
|
||||
|
||||
//inspiration taken from kanban:
|
||||
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
|
||||
@@ -312,6 +314,17 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
this.taskbone = new Taskbone(this);
|
||||
}
|
||||
|
||||
private setPropertyTypes() {
|
||||
const app = this.app;
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
Object.keys(FRONTMATTER_KEYS).forEach((key) => {
|
||||
if(FRONTMATTER_KEYS[key].depricated === true) return;
|
||||
const {name, type} = FRONTMATTER_KEYS[key];
|
||||
app.metadataTypeManager.setType(name,type);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public initializeFonts() {
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
const font = await getFontDataURL(
|
||||
@@ -1541,6 +1554,44 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: "insert-active-pdfpage",
|
||||
name: t("INSERT_ACTIVE_PDF_PAGE_AS_IMAGE"),
|
||||
checkCallback: (checking:boolean) => {
|
||||
const excalidrawView = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
||||
if(!excalidrawView) return false;
|
||||
const embeddables = excalidrawView.getViewSelectedElements().filter(el=>el.type==="embeddable");
|
||||
if(embeddables.length !== 1) {
|
||||
if(checking) return false;
|
||||
new Notice("Select a single PDF embeddable and try again");
|
||||
return false;
|
||||
}
|
||||
const isPDF = excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view?.getViewType() === "pdf"
|
||||
if(!isPDF) return false;
|
||||
const page = getActivePDFPageNumberFromPDFView(excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view);
|
||||
if(!page) return false;
|
||||
if(checking) return true;
|
||||
|
||||
const embeddableEl = embeddables[0] as ExcalidrawEmbeddableElement;
|
||||
const ea = new ExcalidrawAutomate(this,excalidrawView);
|
||||
//@ts-ignore
|
||||
const pdfFile: TFile = excalidrawView.getEmbeddableLeafElementById(embeddableEl.id)?.leaf?.view?.file;
|
||||
(async () => {
|
||||
const imgID = await ea.addImage(embeddableEl.x + embeddableEl.width + 10, embeddableEl.y, `${pdfFile?.path}#page=${page}`, false, false);
|
||||
const imgEl = ea.getElement(imgID) as Mutable<ExcalidrawImageElement>;
|
||||
const imageAspectRatio = imgEl.width / imgEl.height;
|
||||
if(imageAspectRatio > 1) {
|
||||
imgEl.width = embeddableEl.width;
|
||||
imgEl.height = embeddableEl.width / imageAspectRatio;
|
||||
} else {
|
||||
imgEl.height = embeddableEl.height;
|
||||
imgEl.width = embeddableEl.height * imageAspectRatio;
|
||||
}
|
||||
ea.addElementsToView(false, true, true);
|
||||
})()
|
||||
}
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: "crop-image",
|
||||
name: t("CROP_IMAGE"),
|
||||
@@ -1553,57 +1604,81 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
|
||||
if(excalidrawView) {
|
||||
if(!excalidrawView.excalidrawAPI) return false;
|
||||
const els = excalidrawView.getViewSelectedElements().filter(el=>el.type==="image");
|
||||
if(els.length !== 1) {
|
||||
const embeddables = excalidrawView.getViewSelectedElements().filter(el=>el.type==="embeddable");
|
||||
const imageEls = excalidrawView.getViewSelectedElements().filter(el=>el.type==="image");
|
||||
const isPDF = (imageEls.length === 0 && embeddables.length === 1 && excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view?.getViewType() === "pdf")
|
||||
const isImage = (imageEls.length === 1 && embeddables.length === 0)
|
||||
|
||||
if(!isPDF && !isImage) {
|
||||
if(checking) return false;
|
||||
new Notice("Select a single image element and try again");
|
||||
new Notice("Select a single image element or single PDF embeddable and try again");
|
||||
return false;
|
||||
}
|
||||
const el = els[0] as ExcalidrawImageElement;
|
||||
if(el.type !== "image") return false;
|
||||
|
||||
|
||||
//@ts-ignore
|
||||
const page = isPDF ? getActivePDFPageNumberFromPDFView(excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view) : undefined;
|
||||
if(isPDF && !page) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(checking) return true;
|
||||
|
||||
if(isPDF) {
|
||||
const embeddableEl = embeddables[0] as ExcalidrawEmbeddableElement;
|
||||
const ea = new ExcalidrawAutomate(this,excalidrawView);
|
||||
//@ts-ignore
|
||||
const pdfFile: TFile = excalidrawView.getEmbeddableLeafElementById(embeddableEl.id)?.leaf?.view?.file;
|
||||
carveOutPDF(ea, embeddableEl, `${pdfFile?.path}#page=${page}`, pdfFile);
|
||||
return;
|
||||
}
|
||||
|
||||
const imageEl = imageEls[0] as ExcalidrawImageElement;
|
||||
(async () => {
|
||||
let ef = excalidrawView.excalidrawData.getFile(el.fileId);
|
||||
let ef = excalidrawView.excalidrawData.getFile(imageEl.fileId);
|
||||
|
||||
if(!ef) {
|
||||
await excalidrawView.save();
|
||||
await sleep(500);
|
||||
ef = excalidrawView.excalidrawData.getFile(el.fileId);
|
||||
ef = excalidrawView.excalidrawData.getFile(imageEl.fileId);
|
||||
if(!ef) {
|
||||
new Notice("Select a single image element and try again");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const ea = new ExcalidrawAutomate(this,excalidrawView);
|
||||
carveOutImage(ea, el);
|
||||
carveOutImage(ea, imageEl);
|
||||
})();
|
||||
}
|
||||
|
||||
const carveout = async (isFile: boolean, sourceFile: TFile, imageFile: TFile, imageURL: string, replacer: Function) => {
|
||||
const carveout = async (isFile: boolean, sourceFile: TFile, imageFile: TFile, imageURL: string, replacer: Function, ref?: string) => {
|
||||
const ea = getEA() as ExcalidrawAutomate;
|
||||
const imageID = await ea.addImage(0 , 0, isFile ? imageFile : imageURL, false, false);
|
||||
const imageID = await ea.addImage(
|
||||
0, 0,
|
||||
isFile
|
||||
? ((isFile && imageFile.extension === "pdf" && ref) ? `${imageFile.path}#${ref}` : imageFile)
|
||||
: imageURL,
|
||||
false, false
|
||||
);
|
||||
if(!imageID) {
|
||||
new Notice(`Can't load image\n\n${imageURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let fname = "";
|
||||
let fnBase = "";
|
||||
let imageLink = "";
|
||||
if(isFile) {
|
||||
fname = CROPPED_PREFIX + imageFile.basename + ".md";
|
||||
imageLink = `[[${imageFile.path}]]`;
|
||||
fnBase = imageFile.basename;
|
||||
imageLink = ref
|
||||
? `[[${imageFile.path}#${ref}]]`
|
||||
: `[[${imageFile.path}]]`;
|
||||
} else {
|
||||
imageLink = imageURL;
|
||||
const imagename = imageURL.match(/^.*\/([^?]*)\??.*$/)?.[1];
|
||||
fname = CROPPED_PREFIX + imagename.substring(0,imagename.lastIndexOf(".")) + ".md";
|
||||
fnBase = imagename.substring(0,imagename.lastIndexOf("."));
|
||||
}
|
||||
|
||||
const { folderpath } = isFile
|
||||
? splitFolderAndFilename(imageFile.path)
|
||||
: {folderpath: ((await getAttachmentsFolderAndFilePath(this.app, sourceFile.path, fname)).folder)};
|
||||
const newFile = await createImageCropperFile(ea,imageID,imageLink,folderpath,fname);
|
||||
const {folderpath, filename} = await getCropFileNameAndFolder(this,sourceFile.path,fnBase)
|
||||
const newFile = await createImageCropperFile(ea,imageID,imageLink,folderpath,filename);
|
||||
if(!newFile) return;
|
||||
const link = this.app.metadataCache.fileToLinktext(newFile,sourceFile.path, true);
|
||||
replacer(link, newFile);
|
||||
@@ -1617,24 +1692,29 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if(selectedNodes.length !== 1) return false;
|
||||
const node = selectedNodes[0];
|
||||
let extension = "";
|
||||
let isExcalidraw = false;
|
||||
if(node.file) {
|
||||
extension = node.file.extension;
|
||||
isExcalidraw = this.isExcalidrawFile(node.file);
|
||||
}
|
||||
if(node.url) {
|
||||
extension = getURLImageExtension(node.url);
|
||||
}
|
||||
if(!IMAGE_TYPES.contains(extension)) return false;
|
||||
const page = extension === "pdf" ? getActivePDFPageNumberFromPDFView(node?.child) : undefined;
|
||||
if(!page && !IMAGE_TYPES.contains(extension) && !isExcalidraw) return false;
|
||||
if(checking) return true;
|
||||
|
||||
const replacer = (link:string, file: TFile) => {
|
||||
if(node.file) {
|
||||
node.setFile(file);
|
||||
(node.file.extension === "pdf")
|
||||
? node.canvas.createFileNode({pos:{x:node.x + node.width + 10,y: node.y}, file})
|
||||
: node.setFile(file);
|
||||
}
|
||||
if(node.url) {
|
||||
node.canvas.createFileNode({pos:{x:node.x + 20,y: node.y+20}, file});
|
||||
}
|
||||
}
|
||||
carveout(Boolean(node.file), canvasView.file, node.file, node.url, replacer);
|
||||
carveout(Boolean(node.file), canvasView.file, node.file, node.url, replacer, page ? `page=${page}` : undefined);
|
||||
}
|
||||
|
||||
if (markdownView) {
|
||||
@@ -1644,8 +1724,14 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
const parts = REGEX_LINK.getResList(line);
|
||||
if(parts.length === 0) return false;
|
||||
const imgpath = REGEX_LINK.getLink(parts[0]);
|
||||
const imageFile = this.app.metadataCache.getFirstLinkpathDest(imgpath, markdownView.file.path);
|
||||
const imagePathParts = imgpath.split("#");
|
||||
const hasRef = imagePathParts.length === 2;
|
||||
const imageFile = this.app.metadataCache.getFirstLinkpathDest(
|
||||
hasRef ? imagePathParts[0] : imgpath,
|
||||
markdownView.file.path
|
||||
);
|
||||
const isFile = (imageFile && imageFile instanceof TFile);
|
||||
const isExcalidraw = isFile ? this.isExcalidrawFile(imageFile) : false;
|
||||
let imagepath = isFile ? imageFile.path : "";
|
||||
let extension = isFile ? imageFile.extension : "";
|
||||
if(imgpath.match(/^https?|file/)) {
|
||||
@@ -1653,13 +1739,21 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
extension = getURLImageExtension(imgpath);
|
||||
}
|
||||
if(imagepath === "") return false;
|
||||
if(!IMAGE_TYPES.contains(extension)) return false;
|
||||
if(extension !== "pdf" && !IMAGE_TYPES.contains(extension) && !isExcalidraw) return false;
|
||||
if(checking) return true;
|
||||
const ref = imagePathParts[1];
|
||||
const replacer = (link:string) => {
|
||||
const lineparts = line.split(parts[0].value[0])
|
||||
editor.setLine(cursor.line,lineparts[0] + getLink(this ,{embed: true, path:link}) +lineparts[1]);
|
||||
const pdfLink = isFile && ref
|
||||
? "\n" + getLink(this ,{
|
||||
embed: false,
|
||||
alias: `${imageFile.basename}, ${ref.replace("="," ")}`,
|
||||
path:`${imageFile.path}#${ref}`
|
||||
})
|
||||
: "";
|
||||
editor.setLine(cursor.line,lineparts[0] + getLink(this ,{embed: true, path:link}) + pdfLink + lineparts[1]);
|
||||
}
|
||||
carveout(isFile, markdownView.file, imageFile, imagepath, replacer);
|
||||
carveout(isFile, markdownView.file, imageFile, imagepath, replacer, ref);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1973,7 +2067,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
const leaf = view.leaf;
|
||||
if (!view.file) return;
|
||||
const cache = this.app.metadataCache.getFileCache(file);
|
||||
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEY]) return;
|
||||
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEYS["plugin"].name]) return;
|
||||
|
||||
menu.addItem(item => item
|
||||
.setTitle(t("OPEN_AS_EXCALIDRAW"))
|
||||
@@ -1993,7 +2087,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if (!leaf || !(leaf.view instanceof MarkdownView)) return;
|
||||
if (!(file instanceof TFile)) return;
|
||||
const cache = this.app.metadataCache.getFileCache(file);
|
||||
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEY]) return;
|
||||
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEYS["plugin"].name]) return;
|
||||
|
||||
menu.addItem(item => {
|
||||
item
|
||||
@@ -2047,7 +2141,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
// Then check for the excalidraw frontMatterKey
|
||||
const cache = app.metadataCache.getCache(state.state.file);
|
||||
|
||||
if (cache?.frontmatter && cache.frontmatter[FRONTMATTER_KEY]) {
|
||||
if (cache?.frontmatter && cache.frontmatter[FRONTMATTER_KEYS["plugin"].name]) {
|
||||
// If we have it, force the view type to excalidraw
|
||||
const newState = {
|
||||
...state,
|
||||
@@ -2405,7 +2499,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
metaCache.getCachedFiles().forEach((filename: string) => {
|
||||
const fm = metaCache.getCache(filename)?.frontmatter;
|
||||
if (
|
||||
(fm && typeof fm[FRONTMATTER_KEY] !== "undefined") ||
|
||||
(fm && typeof fm[FRONTMATTER_KEYS["plugin"].name] !== "undefined") ||
|
||||
filename.match(/\.excalidraw$/)
|
||||
) {
|
||||
self.updateFileCache(
|
||||
@@ -2546,7 +2640,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
frontmatter?: FrontMatterCache,
|
||||
deleted: boolean = false,
|
||||
) {
|
||||
if (frontmatter && typeof frontmatter[FRONTMATTER_KEY] !== "undefined") {
|
||||
if (frontmatter && typeof frontmatter[FRONTMATTER_KEYS["plugin"].name] !== "undefined") {
|
||||
this.excalidrawFiles.add(file);
|
||||
return;
|
||||
}
|
||||
@@ -2558,6 +2652,15 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
|
||||
onunload() {
|
||||
const excalidrawLeaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
excalidrawLeaves.forEach(async (leaf) => {
|
||||
const ev: ExcalidrawView = leaf.view as ExcalidrawView;
|
||||
console.log(ev.file.name, ev.semaphores.dirty);
|
||||
await this.setMarkdownView(leaf);
|
||||
//@ts-ignore
|
||||
console.log(leaf?.view?.file);
|
||||
});
|
||||
|
||||
document.body.removeChild(this.textMeasureDiv);
|
||||
this.stylesManager.unload();
|
||||
this.removeFonts();
|
||||
@@ -2583,12 +2686,6 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if (this.fileExplorerObserver) {
|
||||
this.fileExplorerObserver.disconnect();
|
||||
}
|
||||
const excalidrawLeaves =
|
||||
this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
excalidrawLeaves.forEach((leaf) => {
|
||||
this.setMarkdownView(leaf);
|
||||
});
|
||||
|
||||
Object.values(this.packageMap).forEach((p:Packages)=>{
|
||||
delete p.excalidrawLib;
|
||||
delete p.reactDOM;
|
||||
@@ -2890,10 +2987,12 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
public async setMarkdownView(leaf: WorkspaceLeaf) {
|
||||
const state = leaf.view.getState();
|
||||
|
||||
await leaf.setViewState({
|
||||
//Note v2.0.19: I have absolutely no idea why I thought this is necessary. Removing this.
|
||||
//This was added in 1.4.2 but there is no hint in Release notes why.
|
||||
/*await leaf.setViewState({
|
||||
type: VIEW_TYPE_EXCALIDRAW,
|
||||
state: { file: null },
|
||||
});
|
||||
});*/
|
||||
|
||||
await leaf.setViewState(
|
||||
{
|
||||
@@ -2919,7 +3018,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
return true;
|
||||
}
|
||||
const fileCache = f ? this.app.metadataCache.getFileCache(f) : null;
|
||||
return !!fileCache?.frontmatter && !!fileCache.frontmatter[FRONTMATTER_KEY];
|
||||
return !!fileCache?.frontmatter && !!fileCache.frontmatter[FRONTMATTER_KEYS["plugin"].name];
|
||||
}
|
||||
|
||||
public async exportLibrary() {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "src/ExcalidrawData";
|
||||
import { processLinkText, useDefaultExcalidrawFrame } from "src/utils/CustomEmbeddableUtils";
|
||||
import { cleanSectionHeading } from "src/utils/ObsidianUtils";
|
||||
import { EmbeddableSettings } from "src/dialogs/EmbeddableSettings";
|
||||
import { openExternalLink } from "src/utils/ExcalidrawViewUtils";
|
||||
|
||||
export class EmbeddableMenu {
|
||||
|
||||
@@ -257,10 +258,11 @@ export class EmbeddableMenu {
|
||||
key={"Open"}
|
||||
title={t("OPEN_IN_BROWSER")}
|
||||
action={() => {
|
||||
view.openExternalLink(
|
||||
openExternalLink(
|
||||
!iframe.src.startsWith("https://www.youtube.com") && !iframe.src.startsWith("https://player.vimeo.com")
|
||||
? iframe.src
|
||||
: element.link
|
||||
? iframe.src
|
||||
: element.link,
|
||||
view.app
|
||||
);
|
||||
}}
|
||||
icon={ICONS.Globe}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/
|
||||
import { isWinALTorMacOPT, isWinCTRLorMacCMD, isSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
import { InsertPDFModal } from "src/dialogs/InsertPDFModal";
|
||||
import { ExportDialog } from "src/dialogs/ExportDialog";
|
||||
import { openExternalLink } from "src/utils/ExcalidrawViewUtils";
|
||||
|
||||
declare const PLUGIN_VERSION:string;
|
||||
const dark = '<svg style="stroke:#ced4da;#212529;color:#ced4da;fill:#ced4da" ';
|
||||
@@ -505,7 +506,7 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
|
||||
title={t("INSERT_LATEX")}
|
||||
action={(e) => {
|
||||
if(isWinALTorMacOPT(e)) {
|
||||
this.props.view.openExternalLink("https://youtu.be/r08wk-58DPk");
|
||||
openExternalLink("https://youtu.be/r08wk-58DPk", this.props.view.app);
|
||||
return;
|
||||
}
|
||||
this.props.centerPointer();
|
||||
@@ -532,7 +533,7 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
|
||||
title={t("INSERT_LINK_TO_ELEMENT")}
|
||||
action={(e:React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
if(isWinALTorMacOPT(e)) {
|
||||
this.props.view.openExternalLink("https://youtu.be/yZQoJg2RCKI");
|
||||
openExternalLink("https://youtu.be/yZQoJg2RCKI", this.props.view.app);
|
||||
return;
|
||||
}
|
||||
this.props.view.copyLinkToSelectedElementToClipboard(
|
||||
|
||||
@@ -33,9 +33,11 @@ import { EmbeddalbeMDFileCustomDataSettingsComponent } from "./dialogs/Embeddabl
|
||||
import { startupScript } from "./constants/starutpscript";
|
||||
import { ModifierKeySet, ModifierSetType } from "./utils/ModifierkeyHelper";
|
||||
import { ModifierKeySettingsComponent } from "./dialogs/ModifierKeySettings";
|
||||
import { CROPPED_PREFIX } from "./utils/CarveOut";
|
||||
|
||||
export interface ExcalidrawSettings {
|
||||
folder: string;
|
||||
cropFolder: string;
|
||||
embedUseExcalidrawFolder: boolean;
|
||||
templateFilePath: string;
|
||||
scriptFolderPath: string;
|
||||
@@ -49,6 +51,7 @@ export interface ExcalidrawSettings {
|
||||
drawingFilnameEmbedPostfix: string;
|
||||
drawingFilenameDateTime: string;
|
||||
useExcalidrawExtension: boolean;
|
||||
cropPrefix: string;
|
||||
displaySVGInPreview: boolean; //No longer used since 1.9.13
|
||||
previewImageType: PreviewImageType; //Introduced with 1.9.13
|
||||
allowImageCache: boolean;
|
||||
@@ -177,6 +180,7 @@ declare const PLUGIN_VERSION:string;
|
||||
|
||||
export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
folder: "Excalidraw",
|
||||
cropFolder: "",
|
||||
embedUseExcalidrawFolder: false,
|
||||
templateFilePath: "Excalidraw/Template.excalidraw",
|
||||
scriptFolderPath: "Excalidraw/Scripts",
|
||||
@@ -190,6 +194,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
drawingFilnameEmbedPostfix: " ",
|
||||
drawingFilenameDateTime: "YYYY-MM-DD HH.mm.ss",
|
||||
useExcalidrawExtension: true,
|
||||
cropPrefix: CROPPED_PREFIX,
|
||||
displaySVGInPreview: undefined,
|
||||
previewImageType: undefined,
|
||||
allowImageCache: true,
|
||||
@@ -552,6 +557,19 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("CROP_FOLDER_NAME"))
|
||||
.setDesc(fragWithHTML(t("CROP_FOLDER_DESC")))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("e.g.: Excalidraw/Cropped")
|
||||
.setValue(this.plugin.settings.cropFolder)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.cropFolder = value;
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("TEMPLATE_NAME"))
|
||||
.setDesc(fragWithHTML(t("TEMPLATE_DESC")))
|
||||
@@ -749,6 +767,22 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
);
|
||||
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("CROP_PREFIX_NAME"))
|
||||
.setDesc(fragWithHTML(t("CROP_PREFIX_DESC")))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("e.g.: Cropped_ ")
|
||||
.setValue(this.plugin.settings.cropPrefix)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.cropPrefix = value.replaceAll(
|
||||
/[<>:"/\\|?*]/g,
|
||||
"_",
|
||||
);
|
||||
text.setValue(this.plugin.settings.cropPrefix);
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
);
|
||||
//------------------------------------------------
|
||||
// AI Settings
|
||||
//------------------------------------------------
|
||||
|
||||
4
src/types.d.ts
vendored
4
src/types.d.ts
vendored
@@ -35,6 +35,9 @@ declare module "obsidian" {
|
||||
internalPlugins: any;
|
||||
isMobile(): boolean;
|
||||
getObsidianUrl(file:TFile): string;
|
||||
metadataTypeManager: {
|
||||
setType(name:string, type:string): void;
|
||||
};
|
||||
}
|
||||
interface Keymap {
|
||||
getRootScope(): Scope;
|
||||
@@ -60,5 +63,6 @@ declare module "obsidian" {
|
||||
}
|
||||
interface MetadataCache {
|
||||
getBacklinksForFile(file: TFile): any;
|
||||
getLinks(): { [id: string]: Array<{ link: string; displayText: string; original: string; position: any }> };
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { ExcalidrawEmbeddableElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
||||
import { getEA } from "src";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
import { splitFolderAndFilename } from "./FileUtils";
|
||||
import { getCropFileNameAndFolder, splitFolderAndFilename } from "./FileUtils";
|
||||
import { Notice, TFile } from "obsidian";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
|
||||
@@ -34,20 +34,20 @@ export const carveOutImage = async (sourceEA: ExcalidrawAutomate, viewImageEl: E
|
||||
let imageLink = "";
|
||||
let fname = "";
|
||||
if(ef.file) {
|
||||
fname = CROPPED_PREFIX + ef.file.basename;
|
||||
imageLink = `[[${ef.file.path}]]`;
|
||||
fname = ef.file.basename;
|
||||
const ref = ef.linkParts?.ref ? `#${ef.linkParts.ref}` : ``;
|
||||
imageLink = `[[${ef.file.path}${ref}]]`;
|
||||
} else {
|
||||
const imagename = ef.hyperlink?.match(/^.*\/([^?]*)\??.*$/)?.[1];
|
||||
imageLink = ef.hyperlink;
|
||||
fname = viewImageEl
|
||||
? CROPPED_PREFIX + imagename.substring(0,imagename.lastIndexOf("."))
|
||||
: CROPPED_PREFIX + "_image";
|
||||
? imagename.substring(0,imagename.lastIndexOf("."))
|
||||
: "_image";
|
||||
}
|
||||
|
||||
const attachmentPath = await sourceEA.getAttachmentFilepath(fname + ".md");
|
||||
const {folderpath: foldername, filename} = splitFolderAndFilename(attachmentPath);
|
||||
const {folderpath, filename} = await getCropFileNameAndFolder(sourceEA.plugin,sourceEA.targetView.file.path,fname);
|
||||
|
||||
const file = await createImageCropperFile(targetEA, newImage.id, imageLink, foldername, filename);
|
||||
const file = await createImageCropperFile(targetEA, newImage.id, imageLink, folderpath, filename);
|
||||
if(!file) return;
|
||||
|
||||
//console.log(await app.vault.read(file));
|
||||
@@ -65,13 +65,57 @@ export const carveOutImage = async (sourceEA: ExcalidrawAutomate, viewImageEl: E
|
||||
sourceEA.addElementsToView(false, true, true);
|
||||
}
|
||||
|
||||
export const carveOutPDF = async (sourceEA: ExcalidrawAutomate, embeddableEl: ExcalidrawEmbeddableElement, pdfPathWithPage: string, pdfFile: TFile) => {
|
||||
if(!embeddableEl || !pdfPathWithPage || !sourceEA?.targetView) return;
|
||||
|
||||
const targetEA = getEA(sourceEA.targetView) as ExcalidrawAutomate;
|
||||
|
||||
const {height, width} = embeddableEl;
|
||||
|
||||
if(!height || !width || height === 0 || width === 0) return;
|
||||
|
||||
const imageId = await targetEA.addImage(0,0, pdfPathWithPage);
|
||||
const newImage = targetEA.getElement(imageId) as Mutable<ExcalidrawImageElement>;
|
||||
newImage.x = 0;
|
||||
newImage.y = 0;
|
||||
newImage.width = width;
|
||||
newImage.height = height;
|
||||
const angle = embeddableEl.angle;
|
||||
|
||||
const fname = pdfFile.basename;
|
||||
const imageLink = `[[${pdfPathWithPage}]]`;
|
||||
|
||||
const {folderpath, filename} = await getCropFileNameAndFolder(sourceEA.plugin,sourceEA.targetView.file.path,fname);
|
||||
|
||||
const file = await createImageCropperFile(targetEA, newImage.id, imageLink, folderpath, filename);
|
||||
if(!file) return;
|
||||
|
||||
//console.log(await app.vault.read(file));
|
||||
sourceEA.clear();
|
||||
const replacingImageID = await sourceEA.addImage(embeddableEl.x + embeddableEl.width + 10, embeddableEl.y, file, true);
|
||||
const replacingImage = sourceEA.getElement(replacingImageID) as Mutable<ExcalidrawImageElement>;
|
||||
const imageAspectRatio = replacingImage.width / replacingImage.height;
|
||||
if(imageAspectRatio > 1) {
|
||||
replacingImage.width = embeddableEl.width;
|
||||
replacingImage.height = replacingImage.width / imageAspectRatio;
|
||||
} else {
|
||||
replacingImage.height = embeddableEl.height;
|
||||
replacingImage.width = replacingImage.height * imageAspectRatio;
|
||||
}
|
||||
replacingImage.angle = angle;
|
||||
sourceEA.addElementsToView(false, true, true);
|
||||
}
|
||||
|
||||
|
||||
export const createImageCropperFile = async (targetEA: ExcalidrawAutomate, imageID: string, imageLink:string, foldername: string, filename: string): Promise<TFile> => {
|
||||
const workspace = targetEA.plugin.app.workspace;
|
||||
const vault = targetEA.plugin.app.vault;
|
||||
const newImage = targetEA.getElement(imageID) as Mutable<ExcalidrawImageElement>;
|
||||
const { width, height } = newImage;
|
||||
const isPDF = imageLink.match(/\[\[([^#]*)#.*]]/)?.[1]?.endsWith(".pdf");
|
||||
|
||||
newImage.opacity = 100;
|
||||
newImage.locked = true;
|
||||
newImage.link = imageLink;
|
||||
|
||||
const frameID = targetEA.addFrame(0,0,width,height,"Adjust frame to crop image. Add elements for mask: White shows, Black hides.");
|
||||
const frame = targetEA.getElement(frameID) as Mutable<ExcalidrawFrameElement>;
|
||||
@@ -87,7 +131,7 @@ export const createImageCropperFile = async (targetEA: ExcalidrawAutomate, image
|
||||
targetEA.style.roughness = 0;
|
||||
targetEA.style.roundness = null;
|
||||
targetEA.canvas.theme = "light";
|
||||
targetEA.canvas.viewBackgroundColor = "#3d3d3d";
|
||||
targetEA.canvas.viewBackgroundColor = isPDF ? "#5d5d5d" : "#3d3d3d";
|
||||
|
||||
const templateFile = app.vault.getAbstractFileByPath(targetEA.plugin.settings.templateFilePath);
|
||||
if(templateFile && templateFile instanceof TFile) {
|
||||
@@ -107,6 +151,7 @@ export const createImageCropperFile = async (targetEA: ExcalidrawAutomate, image
|
||||
"excalidraw-export-dark": false,
|
||||
"excalidraw-export-padding": 0,
|
||||
"excalidraw-export-transparent": true,
|
||||
...isPDF ? {"cssclasses": "excalidraw-cropped-pdfpage"} : {},
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ export const setDynamicStyle = (
|
||||
[`--color-gray-50`]: str(text), //frame
|
||||
[`--color-surface-highlight`]: str(gray1()),
|
||||
//[`--color-gray-30`]: str(gray1),
|
||||
[`--color-gray-80`]: str(isDark?text.lighterBy(15):text.darkerBy(15)), //frame
|
||||
[`--color-gray-80`]: str(isDark?text.darkerBy(40):text.lighterBy(40)), //frame
|
||||
[`--sidebar-border-color`]: str(gray1()),
|
||||
[`--color-primary-light`]: str(accent().lighterBy(step)),
|
||||
[`--button-hover-bg`]: str(gray1()),
|
||||
@@ -130,7 +130,7 @@ export const setDynamicStyle = (
|
||||
const frameColor = {
|
||||
stroke: str(isDark?gray2().lighterBy(15):gray2().darkerBy(15)),
|
||||
fill: str((isDark?gray2().lighterBy(30):gray2().darkerBy(30)).alphaTo(0.2)),
|
||||
nameColor: str(isDark?gray2().lighterBy(40):gray2().darkerBy(40)),
|
||||
nameColor: str(isDark?gray2().lighterBy(50):gray2().darkerBy(50)),
|
||||
}
|
||||
const scene = api.getSceneElements();
|
||||
scene.filter(el=>el.type==="frame").forEach((e:ExcalidrawFrameElement)=>{
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
|
||||
import { MAX_IMAGE_SIZE, IMAGE_TYPES, ANIMATED_IMAGE_TYPES } from "src/constants/constants";
|
||||
import { TFile } from "obsidian";
|
||||
import { App, TFile } from "obsidian";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "src/ExcalidrawData";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
import { getLinkParts } from "./Utils";
|
||||
|
||||
export const insertImageToView = async (
|
||||
ea: ExcalidrawAutomate,
|
||||
@@ -61,4 +64,56 @@ export const getLinkTextFromLink = (text: string): string => {
|
||||
if (linktext.match(REG_LINKINDEX_HYPERLINK)) return;
|
||||
|
||||
return linktext;
|
||||
}
|
||||
|
||||
export const openTagSearch = (link:string, app: App, view?: ExcalidrawView) => {
|
||||
const tags = link
|
||||
.matchAll(/#([\p{Letter}\p{Emoji_Presentation}\p{Number}\/_-]+)/gu)
|
||||
.next();
|
||||
if (!tags.value || tags.value.length < 2) {
|
||||
return;
|
||||
}
|
||||
const search = app.workspace.getLeavesOfType("search");
|
||||
if (search.length == 0) {
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
search[0].view.setQuery(`tag:${tags.value[1]}`);
|
||||
app.workspace.revealLeaf(search[0]);
|
||||
|
||||
if (view && view.isFullscreen()) {
|
||||
view.exitFullscreen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
export const openExternalLink = (link:string, app: App, element?: ExcalidrawElement):boolean => {
|
||||
if (link.match(/^cmd:\/\/.*/)) {
|
||||
const cmd = link.replace("cmd://", "");
|
||||
//@ts-ignore
|
||||
app.commands.executeCommandById(cmd);
|
||||
return true;
|
||||
}
|
||||
if (link.match(REG_LINKINDEX_HYPERLINK)) {
|
||||
window.open(link, "_blank");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile):string => {
|
||||
let secondOrderLinks = "";
|
||||
const forwardLinks = app.metadataCache.getLinks()[excalidrawFile.path];
|
||||
if(forwardLinks && forwardLinks.length > 0) {
|
||||
const linkset = new Set<string>();
|
||||
forwardLinks.forEach(link => {
|
||||
const linkparts = getLinkParts(link.link);
|
||||
const f = app.metadataCache.getFirstLinkpathDest(linkparts.path, excalidrawFile.path);
|
||||
if(f && f.path !== excalidrawFile.path) {
|
||||
linkset.add(`[[${f.path}${linkparts.ref?"#"+linkparts.ref:""}|Second Order Link: ${f.basename}]]`);
|
||||
}
|
||||
});
|
||||
secondOrderLinks = [...linkset].join(" ");
|
||||
}
|
||||
return secondOrderLinks;
|
||||
}
|
||||
@@ -5,6 +5,9 @@ import { IMAGE_MIME_TYPES, MimeType } from "src/EmbeddedFileLoader";
|
||||
import { ExcalidrawSettings } from "src/settings";
|
||||
import { errorlog, getDataURL } from "./Utils";
|
||||
import ExcalidrawPlugin from "src/main";
|
||||
import ExcalidrawView from "src/ExcalidrawView";
|
||||
import { CROPPED_PREFIX } from "./CarveOut";
|
||||
import { getAttachmentsFolderAndFilePath } from "./ObsidianUtils";
|
||||
|
||||
/**
|
||||
* Splits a full path including a folderpath and a filename into separate folderpath and filename components
|
||||
@@ -370,4 +373,17 @@ export const getLink = (
|
||||
return plugin.settings.embedWikiLink
|
||||
? `${embed ? "!" : ""}[[${path}${alias ? `|${alias}` : ""}]]`
|
||||
: `${embed ? "!" : ""}[${alias ?? ""}](${encodeURI(path)})`
|
||||
}
|
||||
|
||||
export const getCropFileNameAndFolder = async (plugin: ExcalidrawPlugin, hostPath: string, baseNewFileName: string):Promise<{folderpath: string, filename: string}> => {
|
||||
let prefix = plugin.settings.cropPrefix;
|
||||
if(!prefix || prefix.trim() === "") prefix = CROPPED_PREFIX;
|
||||
const filename = prefix + baseNewFileName + ".md";
|
||||
if(!plugin.settings.cropFolder || plugin.settings.cropFolder.trim() === "") {
|
||||
const folderpath = (await getAttachmentsFolderAndFilePath(plugin.app, hostPath, filename)).folder;
|
||||
return {folderpath, filename};
|
||||
}
|
||||
const folderpath = normalizePath(plugin.settings.cropFolder);
|
||||
await checkAndCreateFolder(folderpath);
|
||||
return {folderpath, filename};
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
App,
|
||||
normalizePath, parseFrontMatterEntry, TFile, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
normalizePath, parseFrontMatterEntry, TFile, View, Workspace, WorkspaceLeaf, WorkspaceSplit
|
||||
} from "obsidian";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "./FileUtils";
|
||||
@@ -254,4 +254,7 @@ export const getFileCSSClasses = (
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
export const getActivePDFPageNumberFromPDFView = (view: View): number => view?.viewer?.child?.pdfViewer?.page;
|
||||
@@ -13,15 +13,10 @@ import {
|
||||
VIRGIL_FONT,
|
||||
} from "src/constants/constFonts";
|
||||
import {
|
||||
FRONTMATTER_KEY_EXPORT_DARK,
|
||||
FRONTMATTER_KEY_EXPORT_TRANSPARENT,
|
||||
FRONTMATTER_KEY_EXPORT_SVGPADDING,
|
||||
FRONTMATTER_KEY_EXPORT_PNGSCALE,
|
||||
FRONTMATTER_KEY_EXPORT_PADDING,
|
||||
exportToSvg,
|
||||
exportToBlob,
|
||||
IMAGE_TYPES,
|
||||
FRONTMATTER_KEY_MASK
|
||||
FRONTMATTER_KEYS,
|
||||
} from "../constants/constants";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
||||
@@ -548,9 +543,9 @@ export const isMaskFile = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_MASK] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name] != null
|
||||
) {
|
||||
return Boolean(fileCache.frontmatter[FRONTMATTER_KEY_MASK]);
|
||||
return Boolean(fileCache.frontmatter[FRONTMATTER_KEYS["mask"].name]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -564,7 +559,7 @@ export const hasExportTheme = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_DARK] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] != null
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -581,9 +576,9 @@ export const getExportTheme = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_DARK] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name] != null
|
||||
) {
|
||||
return fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_DARK]
|
||||
return fileCache.frontmatter[FRONTMATTER_KEYS["export-dark"].name]
|
||||
? "dark"
|
||||
: "light";
|
||||
}
|
||||
@@ -599,7 +594,7 @@ export const hasExportBackground = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_TRANSPARENT] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] != null
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -615,9 +610,9 @@ export const getWithBackground = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_TRANSPARENT] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name] != null
|
||||
) {
|
||||
return !fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_TRANSPARENT];
|
||||
return !fileCache.frontmatter[FRONTMATTER_KEYS["export-transparent"].name];
|
||||
}
|
||||
}
|
||||
return plugin.settings.exportWithBackground;
|
||||
@@ -631,9 +626,9 @@ export const getExportPadding = (
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if(!fileCache?.frontmatter) return plugin.settings.exportPaddingSVG;
|
||||
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PADDING] != null) {
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name] != null) {
|
||||
const val = parseInt(
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PADDING],
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-padding"].name],
|
||||
);
|
||||
if (!isNaN(val)) {
|
||||
return val;
|
||||
@@ -641,9 +636,9 @@ export const getExportPadding = (
|
||||
}
|
||||
|
||||
//depricated. Retained for backward compatibility
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_SVGPADDING] != null) {
|
||||
if (fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name] != null) {
|
||||
const val = parseInt(
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_SVGPADDING],
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-svgpadding"].name],
|
||||
);
|
||||
if (!isNaN(val)) {
|
||||
return val;
|
||||
@@ -659,10 +654,10 @@ export const getPNGScale = (plugin: ExcalidrawPlugin, file: TFile): number => {
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PNGSCALE] != null
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name] != null
|
||||
) {
|
||||
const val = parseFloat(
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_EXPORT_PNGSCALE],
|
||||
fileCache.frontmatter[FRONTMATTER_KEYS["export-pngscale"].name],
|
||||
);
|
||||
if (!isNaN(val) && val > 0) {
|
||||
return val;
|
||||
|
||||
10
styles.css
10
styles.css
@@ -546,4 +546,14 @@ hr.excalidraw-setting-hr {
|
||||
.excalidraw__embeddable-container .canvas-node.is-selected.is-themed .canvas-node-container,
|
||||
.excalidraw__embeddable-container .canvas-node.is-focused.is-themed .canvas-node-container {
|
||||
border-color: var(--canvas-color);
|
||||
}
|
||||
|
||||
img.excalidraw-cropped-pdfpage,
|
||||
.excalidraw-cropped-pdfpage svg {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.excalidraw .pdf-toolbar,
|
||||
.excalidraw .pdf-container {
|
||||
width: 100%;
|
||||
}
|
||||
Reference in New Issue
Block a user