mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
ready to release
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zsviczian/excalidraw": "0.11.0-obsidian-11",
|
||||
"@zsviczian/excalidraw": "0.11.0-obsidian-16",
|
||||
"monkey-around": "^2.3.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
@@ -162,7 +162,6 @@ export class EmbeddedFile {
|
||||
|
||||
export class EmbeddedFilesLoader {
|
||||
private plugin: ExcalidrawPlugin;
|
||||
private processedFiles: Map<string, number> = new Map<string, number>();
|
||||
private isDark: boolean;
|
||||
public terminate = false;
|
||||
public uid: string;
|
||||
@@ -173,7 +172,7 @@ export class EmbeddedFilesLoader {
|
||||
this.uid = nanoid();
|
||||
}
|
||||
|
||||
public async getObsidianImage(inFile: TFile | EmbeddedFile): Promise<{
|
||||
public async getObsidianImage(inFile: TFile | EmbeddedFile, depth: number): Promise<{
|
||||
mimeType: MimeType;
|
||||
fileId: FileId;
|
||||
dataURL: DataURL;
|
||||
@@ -196,15 +195,7 @@ export class EmbeddedFilesLoader {
|
||||
width: this.plugin.settings.mdSVGwidth,
|
||||
height: this.plugin.settings.mdSVGmaxHeight,
|
||||
};
|
||||
//to block infinite loop of recursive loading of images
|
||||
const count = this.processedFiles.has(file.path)
|
||||
? this.processedFiles.get(file.path)
|
||||
: 0;
|
||||
if (file.extension === "md" && count > 2) {
|
||||
new Notice(t("INFINITE_LOOP_WARNING") + file.path, 6000);
|
||||
return null;
|
||||
}
|
||||
this.processedFiles.set(file.path, count + 1);
|
||||
|
||||
let hasSVGwithBitmap = false;
|
||||
const app = this.plugin.app;
|
||||
const isExcalidrawFile = this.plugin.isExcalidrawFile(file);
|
||||
@@ -240,6 +231,7 @@ export class EmbeddedFilesLoader {
|
||||
null,
|
||||
[],
|
||||
this.plugin,
|
||||
depth+1,
|
||||
getSVGPadding(this.plugin, file),
|
||||
);
|
||||
//https://stackoverflow.com/questions/51154171/remove-css-filter-on-child-elements
|
||||
@@ -315,7 +307,12 @@ export class EmbeddedFilesLoader {
|
||||
public async loadSceneFiles(
|
||||
excalidrawData: ExcalidrawData,
|
||||
addFiles: Function,
|
||||
depth:number
|
||||
) {
|
||||
if(depth > 4) {
|
||||
new Notice(t("INFINITE_LOOP_WARNING")+depth.toString(), 6000);
|
||||
return;
|
||||
}
|
||||
const entries = excalidrawData.getFileEntries();
|
||||
//debug({where:"EmbeddedFileLoader.loadSceneFiles",uid:this.uid,isDark:this.isDark,sceneTheme:excalidrawData.scene.appState.theme});
|
||||
if (this.isDark === undefined) {
|
||||
@@ -327,7 +324,7 @@ export class EmbeddedFilesLoader {
|
||||
const embeddedFile: EmbeddedFile = entry.value[1];
|
||||
if (!embeddedFile.isLoaded(this.isDark)) {
|
||||
//debug({where:"EmbeddedFileLoader.loadSceneFiles",uid:this.uid,status:"embedded Files are not loaded"});
|
||||
const data = await this.getObsidianImage(embeddedFile);
|
||||
const data = await this.getObsidianImage(embeddedFile, depth);
|
||||
if (data) {
|
||||
files.push({
|
||||
mimeType: data.mimeType,
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
ExcalidrawElement,
|
||||
ExcalidrawBindableElement,
|
||||
FileId,
|
||||
NonDeletedExcalidrawElement,
|
||||
} from "@zsviczian/excalidraw/types/element/types";
|
||||
import { normalizePath, TFile, WorkspaceLeaf } from "obsidian";
|
||||
import ExcalidrawView, { ExportSettings, TextMode } from "./ExcalidrawView";
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
MAX_IMAGE_SIZE,
|
||||
PLUGIN_ID,
|
||||
COLOR_NAMES,
|
||||
fileid,
|
||||
} from "./Constants";
|
||||
import { getDrawingFilename, } from "./utils/FileUtils";
|
||||
import {
|
||||
@@ -202,6 +204,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
templatePath,
|
||||
false,
|
||||
new EmbeddedFilesLoader(this.plugin),
|
||||
0
|
||||
)
|
||||
: null;
|
||||
let elements = template ? template.elements : [];
|
||||
@@ -253,6 +256,11 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
"excalidraw-link-prefix"?: string;
|
||||
"excalidraw-link-brackets"?: boolean;
|
||||
"excalidraw-url-prefix"?: string;
|
||||
"excalidraw-export-transparent"?: boolean;
|
||||
"excalidraw-export-dark"?: boolean;
|
||||
"excalidraw-export-svgpadding"?: number;
|
||||
"excalidraw-export-pngscale"?: number;
|
||||
"excalidraw-default-mode"?: "view" | "zen";
|
||||
};
|
||||
}): Promise<string> {
|
||||
const template = params?.templatePath
|
||||
@@ -261,6 +269,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
params.templatePath,
|
||||
true,
|
||||
new EmbeddedFilesLoader(this.plugin),
|
||||
0
|
||||
)
|
||||
: null;
|
||||
let elements = template ? template.elements : [];
|
||||
@@ -341,7 +350,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
|
||||
return this.plugin.createAndOpenDrawing(
|
||||
params?.filename
|
||||
? `${params.filename}.excalidraw.md`
|
||||
? params.filename + (params.filename.endsWith(".md") ? "": ".excalidraw.md")
|
||||
: getDrawingFilename(this.plugin.settings),
|
||||
params?.onNewPane ? params.onNewPane : false,
|
||||
params?.foldername ? params.foldername : this.plugin.settings.folder,
|
||||
@@ -400,6 +409,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
this.canvas.viewBackgroundColor,
|
||||
this.getElements(),
|
||||
this.plugin,
|
||||
0
|
||||
);
|
||||
};
|
||||
|
||||
@@ -451,6 +461,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
this.canvas.viewBackgroundColor,
|
||||
this.getElements(),
|
||||
this.plugin,
|
||||
0
|
||||
);
|
||||
};
|
||||
|
||||
@@ -497,6 +508,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
groupIds: [] as any,
|
||||
boundElements: [] as any,
|
||||
link: null as string,
|
||||
locked: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -842,13 +854,14 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
this.plugin,
|
||||
this.canvas.theme === "dark",
|
||||
);
|
||||
const image = await loader.getObsidianImage(imageFile);
|
||||
const image = await loader.getObsidianImage(imageFile,0);
|
||||
if (!image) {
|
||||
return null;
|
||||
}
|
||||
this.imagesDict[image.fileId] = {
|
||||
const fileId = imageFile.extension === "md" ? fileid() as FileId : image.fileId;
|
||||
this.imagesDict[fileId] = {
|
||||
mimeType: image.mimeType,
|
||||
id: image.fileId,
|
||||
id: fileId,
|
||||
dataURL: image.dataURL,
|
||||
created: image.created,
|
||||
file: imageFile.path,
|
||||
@@ -869,7 +882,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
image.size.width,
|
||||
image.size.height,
|
||||
);
|
||||
this.elementsDict[id].fileId = image.fileId;
|
||||
this.elementsDict[id].fileId = fileId;
|
||||
this.elementsDict[id].scale = [1, 1];
|
||||
return id;
|
||||
};
|
||||
@@ -1311,7 +1324,54 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
};
|
||||
|
||||
/**
|
||||
* if set Excalidraw will call this function onDrop events
|
||||
* Register instance of EA to use for hooks with TargetView
|
||||
* By default ExcalidrawViews will check window.ExcalidrawAutomate for event hooks.
|
||||
* Using this event you can set a different instance of Excalidraw Automate for hooks
|
||||
*/
|
||||
registerThisAsViewEA() {
|
||||
//@ts-ignore
|
||||
if (!this.targetView || !this.targetView?._loaded) {
|
||||
errorMessage("targetView not set", "addElementsToView()");
|
||||
return false;
|
||||
}
|
||||
this.targetView.hookServer = this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If set, this callback is triggered, when the user changes the view mode.
|
||||
* You can use this callback in case you want to do something additional when the user switches to view mode and back.
|
||||
*/
|
||||
onViewModeChangeHook: (isViewModeEnabled:boolean) => void = null;
|
||||
|
||||
/**
|
||||
* If set, this callback is triggered, when the user hovers a link in the scene.
|
||||
* You can use this callback in case you want to do something additional when the onLinkHover event occurs.
|
||||
* This callback must return a boolean value.
|
||||
* In case you want to prevent the excalidraw onLinkHover action you must return false, it will stop the native excalidraw onLinkHover management flow.
|
||||
*/
|
||||
onLinkHoverHook: (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
linkText: string,
|
||||
) => boolean = null;
|
||||
|
||||
/**
|
||||
* If set, this callback is triggered, when the user click a link in the scene.
|
||||
* You can use this callback in case you want to do something additional when the onLinkClick event occurs.
|
||||
* This callback must return a boolean value.
|
||||
* In case you want to prevent the excalidraw onLinkClick action you must return false, it will stop the native excalidraw onLinkClick management flow.
|
||||
*/
|
||||
onLinkClickHook:(
|
||||
element: ExcalidrawElement,
|
||||
linkText: string,
|
||||
event: MouseEvent
|
||||
) => boolean = null;
|
||||
|
||||
/**
|
||||
* If set, this callback is triggered, when Excalidraw receives an onDrop event.
|
||||
* You can use this callback in case you want to do something additional when the onDrop event occurs.
|
||||
* This callback must return a boolean value.
|
||||
* In case you want to prevent the excalidraw onDrop action you must return false, it will stop the native excalidraw onDrop management flow.
|
||||
*/
|
||||
onDropHook: (data: {
|
||||
ea: ExcalidrawAutomate;
|
||||
@@ -1776,6 +1836,7 @@ async function getTemplate(
|
||||
fileWithPath: string,
|
||||
loadFiles: boolean = false,
|
||||
loader: EmbeddedFilesLoader,
|
||||
depth: number
|
||||
): Promise<{
|
||||
elements: any;
|
||||
appState: any;
|
||||
@@ -1839,7 +1900,7 @@ async function getTemplate(
|
||||
};
|
||||
}
|
||||
scene = scaleLoadedImage(excalidrawData.scene, fileArray).scene;
|
||||
});
|
||||
}, depth);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -1869,12 +1930,13 @@ export async function createPNG(
|
||||
canvasBackgroundColor: string = undefined,
|
||||
automateElements: ExcalidrawElement[] = [],
|
||||
plugin: ExcalidrawPlugin,
|
||||
depth: number
|
||||
) {
|
||||
if (!loader) {
|
||||
loader = new EmbeddedFilesLoader(plugin);
|
||||
}
|
||||
const template = templatePath
|
||||
? await getTemplate(plugin, templatePath, true, loader)
|
||||
? await getTemplate(plugin, templatePath, true, loader, depth)
|
||||
: null;
|
||||
let elements = template?.elements ?? [];
|
||||
elements = elements.concat(automateElements);
|
||||
@@ -1910,13 +1972,14 @@ export async function createSVG(
|
||||
canvasBackgroundColor: string = undefined,
|
||||
automateElements: ExcalidrawElement[] = [],
|
||||
plugin: ExcalidrawPlugin,
|
||||
depth: number,
|
||||
padding?: number,
|
||||
): Promise<SVGSVGElement> {
|
||||
if (!loader) {
|
||||
loader = new EmbeddedFilesLoader(plugin);
|
||||
}
|
||||
const template = templatePath
|
||||
? await getTemplate(plugin, templatePath, true, loader)
|
||||
? await getTemplate(plugin, templatePath, true, loader, depth)
|
||||
: null;
|
||||
let elements = template?.elements ?? [];
|
||||
elements = elements.concat(automateElements);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
FRONTMATTER_KEY_DEFAULT_MODE,
|
||||
fileid,
|
||||
REG_BLOCK_REF_CLEAN,
|
||||
FRONTMATTER_KEY_LINKBUTTON_OPACITY,
|
||||
} from "./Constants";
|
||||
import { _measureText } from "./ExcalidrawAutomate";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
@@ -1021,6 +1022,35 @@ export class ExcalidrawData {
|
||||
return false;
|
||||
}
|
||||
|
||||
//assing new fileId to duplicate equation and markdown files
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/601
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/593
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/297
|
||||
const processedIds = new Set<string>();
|
||||
fileIds.forEach(fileId=>{
|
||||
if(processedIds.has(fileId)) {
|
||||
const file = this.files.get(fileId as FileId);
|
||||
const equation = this.equations.get(fileId as FileId);
|
||||
//images should have a single reference, but equations and markdown embeds should have as many as instances of the file in the scene
|
||||
if(file && file.file.extension !== "md") {
|
||||
return;
|
||||
}
|
||||
const newId = fileid();
|
||||
//scene.files[newId] = {...scene.files[fileId]};
|
||||
(scene.elements.filter((el:ExcalidrawImageElement)=>el.fileId === fileId)[0] as any).fileId = newId;
|
||||
dirty = true;
|
||||
processedIds.add(newId);
|
||||
if(file) {
|
||||
this.files.set(newId as FileId,new EmbeddedFile(this.plugin,this.file.path,file.linkParts.original))
|
||||
}
|
||||
if(equation) {
|
||||
this.equations.set(newId as FileId, equation);
|
||||
}
|
||||
}
|
||||
processedIds.add(fileId);
|
||||
});
|
||||
|
||||
|
||||
for (const key of Object.keys(scene.files)) {
|
||||
if (!(this.hasFile(key as FileId) || this.hasEquation(key as FileId))) {
|
||||
dirty = true;
|
||||
@@ -1069,7 +1099,7 @@ export class ExcalidrawData {
|
||||
}
|
||||
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/297
|
||||
const equations = new Set<string>();
|
||||
/*const equations = new Set<string>();
|
||||
const duplicateEqs = new Set<string>();
|
||||
for (const key of fileIds) {
|
||||
if (this.hasEquation(key as FileId)) {
|
||||
@@ -1095,7 +1125,7 @@ export class ExcalidrawData {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return dirty;
|
||||
}
|
||||
@@ -1225,6 +1255,18 @@ export class ExcalidrawData {
|
||||
}
|
||||
}
|
||||
|
||||
public getLinkOpacity(): number {
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
let opacity = this.plugin.settings.linkOpacity;
|
||||
if (
|
||||
fileCache?.frontmatter &&
|
||||
fileCache.frontmatter[FRONTMATTER_KEY_LINKBUTTON_OPACITY] != null
|
||||
) {
|
||||
opacity = fileCache.frontmatter[FRONTMATTER_KEY_LINKBUTTON_OPACITY];
|
||||
}
|
||||
return opacity;
|
||||
}
|
||||
|
||||
private setLinkPrefix(): boolean {
|
||||
const linkPrefix = this.linkPrefix;
|
||||
const fileCache = this.app.metadataCache.getFileCache(this.file);
|
||||
@@ -1425,11 +1467,17 @@ export const getTransclusion = async (
|
||||
let startPos: number = null;
|
||||
let lineNum: number = 0;
|
||||
let endPos: number = null;
|
||||
let depth:number = 1;
|
||||
for (let i = 0; i < headings.length; i++) {
|
||||
if (startPos && !endPos) {
|
||||
let j = i;
|
||||
while (j<headings.length && headings[j].node.depth>depth) {j++};
|
||||
if(j === headings.length && headings[j-1].node.depth > depth) {
|
||||
return { contents: "#".repeat(depth)+" "+contents.substring(startPos).trim(), lineNum };
|
||||
}
|
||||
endPos = headings[i].node.position.start.offset - 1;
|
||||
return {
|
||||
contents: contents.substring(startPos, endPos).trim(),
|
||||
contents: "#".repeat(depth)+" "+contents.substring(startPos, endPos).trim(),
|
||||
lineNum,
|
||||
};
|
||||
}
|
||||
@@ -1446,11 +1494,12 @@ export const getTransclusion = async (
|
||||
: false))
|
||||
) {
|
||||
startPos = headings[i].node.children[0]?.position.start.offset; //
|
||||
depth = headings[i].node.depth;
|
||||
lineNum = headings[i].node.children[0]?.position.start.line; //
|
||||
}
|
||||
}
|
||||
if (startPos) {
|
||||
return { contents: contents.substring(startPos).trim(), lineNum };
|
||||
return { contents: "#".repeat(depth)+" "+contents.substring(startPos).trim(), lineNum };
|
||||
}
|
||||
return { contents: linkParts.original.trim(), lineNum: 0 };
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
LOCAL_PROTOCOL,
|
||||
} from "./Constants";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
import { repositionElementsToCursor } from "./ExcalidrawAutomate";
|
||||
import { repositionElementsToCursor, ExcalidrawAutomate } from "./ExcalidrawAutomate";
|
||||
import { t } from "./lang/helpers";
|
||||
import {
|
||||
ExcalidrawData,
|
||||
@@ -180,6 +180,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
public toolsPanelRef: React.MutableRefObject<any> = null;
|
||||
private parentMoveObserver: MutationObserver;
|
||||
public linksAlwaysOpenInANewPane: boolean = false; //override the need for SHIFT+CTRL+click
|
||||
public hookServer: ExcalidrawAutomate;
|
||||
|
||||
public semaphores: {
|
||||
//The role of justLoaded is to capture the Excalidraw.onChange event that fires right after the canvas was loaded for the first time to
|
||||
@@ -242,6 +243,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
super(leaf);
|
||||
this.plugin = plugin;
|
||||
this.excalidrawData = new ExcalidrawData(plugin);
|
||||
this.hookServer = plugin.ea;
|
||||
}
|
||||
|
||||
preventAutozoom() {
|
||||
@@ -640,6 +642,19 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return;
|
||||
}
|
||||
linkText = linkText.replaceAll("\n", ""); //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/187
|
||||
|
||||
if(this.hookServer?.onLinkClickHook) {
|
||||
const id = selectedText.id??selectedElementWithLink.id;
|
||||
const el = this.excalidrawAPI.getSceneElements().filter((el:ExcalidrawElement)=>el.id === id)[0];
|
||||
try {
|
||||
if(!this.hookServer.onLinkClickHook(el,linkText,ev)) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog({where: "ExcalidrawView.handleLinkClick selectedText.id!==null", fn: this.hookServer.onLinkClickHook, error: e});
|
||||
}
|
||||
}
|
||||
|
||||
if (linkText.match(REG_LINKINDEX_HYPERLINK)) {
|
||||
window.open(linkText, "_blank");
|
||||
return;
|
||||
@@ -753,6 +768,18 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.hookServer?.onLinkClickHook) {
|
||||
const id = selectedImage.id??selectedText.id??selectedElementWithLink.id;
|
||||
const el = this.excalidrawAPI.getSceneElements().filter((el:ExcalidrawElement)=>el.id === id)[0];
|
||||
try {
|
||||
if(!this.hookServer.onLinkClickHook(el,linkText,ev)) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog({where: "ExcalidrawView.handleLinkClick selectedText.id===null", fn: this.hookServer.onLinkClickHook, error: e});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (ev.shiftKey && this.isFullscreen()) {
|
||||
this.exitFullscreen();
|
||||
@@ -1233,7 +1260,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (this.nextLoader) {
|
||||
runLoader(this.nextLoader);
|
||||
}
|
||||
},
|
||||
},0
|
||||
);
|
||||
};
|
||||
if (!this.activeLoader) {
|
||||
@@ -1277,7 +1304,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
...excalidrawData.appState,
|
||||
zenModeEnabled,
|
||||
viewModeEnabled,
|
||||
linkOpacity: this.plugin.settings.linkOpacity,
|
||||
linkOpacity: this.excalidrawData.getLinkOpacity(),
|
||||
trayModeEnabled: this.plugin.settings.defaultTrayMode,
|
||||
penMode: penEnabled,
|
||||
penDetected: penEnabled,
|
||||
@@ -1305,7 +1332,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
...excalidrawData.appState,
|
||||
zenModeEnabled: om.zenModeEnabled,
|
||||
viewModeEnabled: om.viewModeEnabled,
|
||||
linkOpacity: this.plugin.settings.linkOpacity,
|
||||
linkOpacity: this.excalidrawData.getLinkOpacity(),
|
||||
trayModeEnabled: this.plugin.settings.defaultTrayMode,
|
||||
penMode: penEnabled,
|
||||
penDetected: penEnabled,
|
||||
@@ -1764,6 +1791,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.addText = async (
|
||||
text: string,
|
||||
fontFamily?: 1 | 2 | 3 | 4,
|
||||
save: boolean = true
|
||||
): Promise<string> => {
|
||||
const api = this.excalidrawAPI;
|
||||
if (!excalidrawRef?.current || !api) {
|
||||
@@ -1778,7 +1806,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
ea.style.fontSize = st.currentItemFontSize ?? 20;
|
||||
ea.style.textAlign = st.currentItemTextAlign ?? "left";
|
||||
const id = ea.addText(currentPosition.x, currentPosition.y, text);
|
||||
await this.addElements(ea.getElements(), false, true);
|
||||
await this.addElements(ea.getElements(), false, save);
|
||||
return id;
|
||||
};
|
||||
|
||||
@@ -1997,6 +2025,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
});
|
||||
this.handleLinkClick(this, event);
|
||||
selectedTextElement = null;
|
||||
return;
|
||||
}
|
||||
selectedImageElement = getImageElementAtPointer(currentPosition, this);
|
||||
if (selectedImageElement && selectedImageElement.id) {
|
||||
@@ -2008,6 +2037,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
});
|
||||
this.handleLinkClick(this, event);
|
||||
selectedImageElement = null;
|
||||
return;
|
||||
}
|
||||
|
||||
selectedElementWithLink = getElementWithLinkAtPointer(currentPosition, this);
|
||||
@@ -2020,18 +2050,21 @@ export default class ExcalidrawView extends TextFileView {
|
||||
});
|
||||
this.handleLinkClick(this, event);
|
||||
selectedElementWithLink = null;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mouseEvent: any = null;
|
||||
|
||||
const showHoverPreview = (linktext?: string) => {
|
||||
const showHoverPreview = (linktext?: string, element?: ExcalidrawElement) => {
|
||||
if (!linktext) {
|
||||
if(!currentPosition) return;
|
||||
linktext = "";
|
||||
const selectedElement = getTextElementAtPointer(currentPosition, this);
|
||||
if (!selectedElement || !selectedElement.text) {
|
||||
const selectedImgElement =
|
||||
getImageElementAtPointer(currentPosition, this);
|
||||
element = this.excalidrawAPI.getSceneElements().filter((el:ExcalidrawElement)=>el.id === selectedImgElement.id)[0];
|
||||
if (!selectedImgElement || !selectedImgElement.fileId) {
|
||||
return;
|
||||
}
|
||||
@@ -2046,6 +2079,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.excalidrawData.getFile(selectedImgElement.fileId).file.path +
|
||||
ref;
|
||||
} else {
|
||||
element = this.excalidrawAPI.getSceneElements().filter((el:ExcalidrawElement)=>el.id === selectedElement.id)[0];
|
||||
const text: string =
|
||||
this.textMode === TextMode.parsed
|
||||
? this.excalidrawData.getRawText(selectedElement.id)
|
||||
@@ -2069,12 +2103,22 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
}
|
||||
|
||||
if(this.hookServer?.onLinkHoverHook) {
|
||||
try {
|
||||
if(!this.hookServer.onLinkHoverHook(element,linktext)) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog({where: "ExcalidrawView.showHoverPreview", fn: this.hookServer.onLinkHoverHook, error: e});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.semaphores.hoverSleep) {
|
||||
return;
|
||||
}
|
||||
|
||||
const f = this.app.metadataCache.getFirstLinkpathDest(
|
||||
linktext,
|
||||
linktext.split("#")[0],
|
||||
this.file.path,
|
||||
);
|
||||
if (!f) {
|
||||
@@ -2221,7 +2265,10 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (p.button === "up") {
|
||||
blockOnMouseButtonDown = false;
|
||||
}
|
||||
if (this.plugin.ctrlKeyDown) {
|
||||
if (this.plugin.ctrlKeyDown ||
|
||||
(this.excalidrawAPI.getAppState().isViewModeEnabled &&
|
||||
this.plugin.settings.hoverPreviewWithoutCTRL)) {
|
||||
|
||||
showHoverPreview();
|
||||
}
|
||||
},
|
||||
@@ -2305,11 +2352,11 @@ export default class ExcalidrawView extends TextFileView {
|
||||
files: TFile[],
|
||||
text: string,
|
||||
): boolean => {
|
||||
if (this.plugin.ea.onDropHook) {
|
||||
if (this.hookServer.onDropHook) {
|
||||
try {
|
||||
return this.plugin.ea.onDropHook({
|
||||
return this.hookServer.onDropHook({
|
||||
//@ts-ignore
|
||||
ea: this.plugin.ea, //the Excalidraw Automate object
|
||||
ea: this.hookServer, //the ExcalidrawAutomate object
|
||||
event, //React.DragEvent<HTMLDivElement>
|
||||
draggable, //Obsidian draggable object
|
||||
type, //"file"|"text"
|
||||
@@ -2331,6 +2378,8 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
};
|
||||
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/468
|
||||
event[CTRL_OR_CMD] = event.shiftKey || event[CTRL_OR_CMD];
|
||||
switch (draggable?.type) {
|
||||
case "file":
|
||||
if (!onDropHook("file", [draggable.file], null)) {
|
||||
@@ -2339,10 +2388,8 @@ export default class ExcalidrawView extends TextFileView {
|
||||
new Notice(t("FILENAME_INVALID_CHARS"), 4000);
|
||||
return false;
|
||||
}
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/468
|
||||
event[CTRL_OR_CMD] = event.shiftKey || event[CTRL_OR_CMD];
|
||||
if (
|
||||
event[CTRL_OR_CMD] && //.ctrlKey||event.metaKey)
|
||||
event[CTRL_OR_CMD] &&
|
||||
(IMAGE_TYPES.contains(draggable.file.extension) ||
|
||||
draggable.file.extension === "md")
|
||||
) {
|
||||
@@ -2371,16 +2418,38 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return false;
|
||||
case "files":
|
||||
if (!onDropHook("file", draggable.files, null)) {
|
||||
for (const f of draggable.files) {
|
||||
this.addText(
|
||||
`[[${this.app.metadataCache.fileToLinktext(
|
||||
f,
|
||||
this.file.path,
|
||||
true,
|
||||
)}]]`,
|
||||
);
|
||||
currentPosition.y += st.currentItemFontSize * 2;
|
||||
}
|
||||
(async () => {
|
||||
if (event[CTRL_OR_CMD]) {
|
||||
const ea = this.plugin.ea;
|
||||
ea.reset();
|
||||
ea.setView(this);
|
||||
ea.canvas.theme = api.getAppState().theme;
|
||||
let counter:number = 0;
|
||||
for (const f of draggable.files) {
|
||||
if ((IMAGE_TYPES.contains(f.extension) || f.extension === "md")) {
|
||||
await ea.addImage(
|
||||
currentPosition.x + counter*50,
|
||||
currentPosition.y + counter*50,
|
||||
f,
|
||||
);
|
||||
counter++;
|
||||
await ea.addElementsToView(false, false, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (const f of draggable.files) {
|
||||
await this.addText(
|
||||
`[[${this.app.metadataCache.fileToLinktext(
|
||||
f,
|
||||
this.file.path,
|
||||
true,
|
||||
)}]]`, undefined,false
|
||||
);
|
||||
currentPosition.y += st.currentItemFontSize * 2;
|
||||
}
|
||||
this.save(false);
|
||||
})();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2418,6 +2487,22 @@ export default class ExcalidrawView extends TextFileView {
|
||||
})();
|
||||
return false;
|
||||
}
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/599
|
||||
if(text.startsWith("obsidian://open?vault=")) {
|
||||
const html = event.dataTransfer.getData("text/html");
|
||||
if(html) {
|
||||
const path = html.match(/href="app:\/\/obsidian\.md\/(.*?)"/);
|
||||
if(path.length === 2) {
|
||||
this.addText(`[[${decodeURIComponent(path[1])}]]`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const path = text.split("file=");
|
||||
if(path.length === 2) {
|
||||
this.addText(`[[${decodeURIComponent(path[1])}]]`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.addText(text.replace(/(!\[\[.*#[^\]]*\]\])/g, "$1{40}"));
|
||||
}
|
||||
return false;
|
||||
@@ -2527,6 +2612,15 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return;
|
||||
}
|
||||
const event = e?.detail?.nativeEvent;
|
||||
if(this.hookServer?.onLinkClickHook) {
|
||||
try {
|
||||
if(!this.hookServer.onLinkClickHook(element,element.link,event)) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
errorlog({where: "ExcalidrawView.onLinkOpen", fn: this.hookServer.onLinkClickHook, error: e});
|
||||
}
|
||||
}
|
||||
if (link.startsWith(LOCAL_PROTOCOL) || link.startsWith("[[")) {
|
||||
(async () => {
|
||||
const linkMatch = link.match(/(md:\/\/)?\[\[(?<link>.*?)\]\]/);
|
||||
@@ -2617,10 +2711,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return;
|
||||
}
|
||||
let linkText = linkMatch.groups.link;
|
||||
if (linkText.search("#") > -1) {
|
||||
linkText = linkText.substring(0, linkText.search("#"));
|
||||
}
|
||||
showHoverPreview(linkText);
|
||||
showHoverPreview(linkText, element);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2628,6 +2719,14 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.toolsPanelRef?.current?.setExcalidrawViewMode(
|
||||
isViewModeEnabled,
|
||||
);
|
||||
if(this.hookServer?.onViewModeChangeHook) {
|
||||
try {
|
||||
this.hookServer.onViewModeChangeHook(isViewModeEnabled);
|
||||
} catch(e) {
|
||||
errorlog({where: "ExcalidrawView.onViewModeChange", fn: this.hookServer.onViewModeChangeHook, error: e});
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
}),
|
||||
React.createElement(ToolsPanel, {
|
||||
|
||||
@@ -129,6 +129,7 @@ const getIMG = async (
|
||||
null,
|
||||
[],
|
||||
plugin,
|
||||
0
|
||||
));
|
||||
if (!png) {
|
||||
return null;
|
||||
@@ -152,6 +153,7 @@ const getIMG = async (
|
||||
null,
|
||||
[],
|
||||
plugin,
|
||||
0,
|
||||
getSVGPadding(plugin, file),
|
||||
)
|
||||
).outerHTML;
|
||||
|
||||
@@ -30,6 +30,7 @@ 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_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";
|
||||
|
||||
@@ -17,6 +17,24 @@ I develop this plugin as a hobby, spending most of my free time doing this. If y
|
||||
|
||||
<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>
|
||||
`,
|
||||
"1.6.26": `
|
||||
## Fixed
|
||||
- Dragging multiple files onto the canvas will now correctly [#589](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/589)
|
||||
- add multiple links
|
||||
- or if you hold the CTRL/(SHIFT on Mac) while dropping the files, then adding multiple images
|
||||
- Dropped images and links were not selectable with the selection tool until the file was saved. This is now fixed.
|
||||
- Display the linked block/section on link-hover instead of the full page. [#597](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/597)
|
||||
- Hover preview without CTRL/CMD works again. Requires configuration in plugin settings. [#595](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/595)
|
||||
- If you embed the same markdown document into a drawing multiple times, you can now display different sections of the documents in each embedded object. [#601](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/601).
|
||||
- If you make a copy of an equation and edit this copy, the original equation will remain unchanged [#593](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/593)
|
||||
|
||||
## New Features
|
||||
- When you drag files from dataview results onto the canvas the obsidian urls will be converted into wiki links.[#599](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/599)
|
||||
- I added one more frontmatter key: ${String.fromCharCode(96)}excalidraw-linkbutton-opacity: 0.5${String.fromCharCode(96)}. This sets the opacity of the blue link-button in the top right corner of the element, overriding the respective setting in plugin settings. Valid values are numbers between 0 and 1, where 0 means the button is fully transparent.
|
||||
|
||||
## New Excalidraw Automate Features
|
||||
- As part of building the new ExcaliBrain plugin, I've added a number of integration features. See the GitHub [Release Notes](https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/1.6.26) for details.
|
||||
`,
|
||||
"1.6.25": `
|
||||
## Fixed
|
||||
- Pinch-zoom in view mode was broken ([#5001](https://github.com/excalidraw/excalidraw/pull/5001))
|
||||
|
||||
@@ -525,6 +525,13 @@ export const FRONTMATTER_KEYS_INFO: SuggesterInfo[] = [
|
||||
desc: "Specifies how Excalidraw should open by default. Valid values are: view|zen",
|
||||
after: ": view",
|
||||
},
|
||||
{
|
||||
field: "linkbutton-opacity",
|
||||
code: null,
|
||||
desc: "The opacity of the blue link button in the top right of the element overriding the respective setting in plugin settings. "+
|
||||
"Valid values are between 0 and 1, where 0 means the button is transparent.",
|
||||
after: ": 0.5",
|
||||
},
|
||||
{
|
||||
field: "font",
|
||||
code: null,
|
||||
|
||||
@@ -210,7 +210,9 @@ export default {
|
||||
}${FRONTMATTER_KEY_CUSTOM_URL_PREFIX}: "🌐 "</code> to the file's frontmatter.`,
|
||||
HOVERPREVIEW_NAME: "Hover preview without CTRL/CMD key",
|
||||
HOVERPREVIEW_DESC:
|
||||
"Toggle On: Hover preview for [[wiki links]] is shown immediately, without the need to hold the CTRL/CMD key.<br>Toggle Off: Hover preview is shown only when you hold the CTRL/CMD key while hovering the link.",
|
||||
"<b>Toggle On</b>: In Exalidraw <u>view mode</u> the hover preview for [[wiki links]] will be shown immediately, without the need to hold the CTRL/CMD key. " +
|
||||
"In Excalidraw <u>normal mode</u>, the preview will be shown immediately only when hovering the blue link icon in the top right of the element.<br> " +
|
||||
"<b>Toggle Off</b>: Hover preview is shown only when you hold the CTRL/CMD key while hovering the link.",
|
||||
LINKOPACITY_NAME: "Opacity of link icon",
|
||||
LINKOPACITY_DESC:
|
||||
"Opacity of the link indicator icon in the top right corner of an element. 1 is opaque, 0 is transparent.",
|
||||
|
||||
@@ -539,7 +539,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
el.style.textAlign = "right";
|
||||
el.innerText = ` ${this.plugin.settings.zoomToFitMaxLevel.toString()}`;
|
||||
});
|
||||
|
||||
|
||||
this.containerEl.createEl("h1", { text: t("LINKS_HEAD") });
|
||||
this.containerEl.createEl(
|
||||
"span",
|
||||
|
||||
@@ -542,9 +542,7 @@ export const errorlog = (data: {}) => {
|
||||
console.error({ plugin: "Excalidraw", ...data });
|
||||
};
|
||||
|
||||
export const sleep = async (ms: number) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
};
|
||||
export const sleep = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export const log = console.log.bind(window.console);
|
||||
export const debug = console.log.bind(window.console);
|
||||
|
||||
@@ -2215,10 +2215,10 @@
|
||||
dependencies:
|
||||
"@zerollup/ts-helpers" "^1.7.18"
|
||||
|
||||
"@zsviczian/excalidraw@0.11.0-obsidian-11":
|
||||
"integrity" "sha512-XlT8F7tQfKDXFUQWddGH+w7GTn5doWq3R0mTemuVqL0q5RhwiiNxHc1SNWmKMj/DVF0M3H5bjX/72gvWlRUDLQ=="
|
||||
"resolved" "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.11.0-obsidian-11.tgz"
|
||||
"version" "0.11.0-obsidian-11"
|
||||
"@zsviczian/excalidraw@0.11.0-obsidian-16":
|
||||
"integrity" "sha512-KVCWC7T31tXo6xfXY6AnGsDEl1j7BVwh3eSwoyn4MTS5UbhD5X0rwB8F6Yl1bdxKbrmnqQV98IKLsdgtfuHoVQ=="
|
||||
"resolved" "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.11.0-obsidian-16.tgz"
|
||||
"version" "0.11.0-obsidian-16"
|
||||
dependencies:
|
||||
"dotenv" "10.0.0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user