Files
obsidian-excalidraw-plugin/src/utils/CanvasNodeFactory.ts
zsviczian 4ac0a4c565 2.1.8
2024-05-13 22:49:32 +02:00

138 lines
4.6 KiB
TypeScript

/*
l = app.workspace.activeLeaf
canvas = app.internalPlugins.plugins["canvas"].views.canvas(l)
f = app.vault.getAbstractFileByPath("Daily Notes/2022-03-18 Friday.md")
node = canvas.canvas.createFileNode({pos: {x:0,y:0}, file:f, subpath: "#Work", save: false})
node.setFilePath("Daily Notes/2022-03-18 Friday.md","#Work");
node.render();
container.appendChild(node.contentEl)
*/
import { TFile, WorkspaceLeaf, WorkspaceSplit } from "obsidian";
import ExcalidrawView from "src/ExcalidrawView";
import { getContainerForDocument, ConstructableWorkspaceSplit, isObsidianThemeDark } from "./ObsidianUtils";
import { CustomMutationObserver, isDebugMode } from "./DebugHelper";
declare module "obsidian" {
interface Workspace {
floatingSplit: any;
}
interface WorkspaceSplit {
containerEl: HTMLDivElement;
}
}
interface ObsidianCanvas {
createFileNode: Function;
removeNode: Function;
}
export interface ObsidianCanvasNode {
startEditing: Function;
child: any;
isEditing: boolean;
file: TFile;
}
export class CanvasNodeFactory {
leaf: WorkspaceLeaf;
canvas: ObsidianCanvas;
nodes = new Map<string, ObsidianCanvasNode>();
initialized: boolean = false;
public isInitialized = () => this.initialized;
constructor(
private view: ExcalidrawView,
) {
}
public async initialize() {
//@ts-ignore
const canvasPlugin = app.internalPlugins.plugins["canvas"];
if(!canvasPlugin._loaded) {
await canvasPlugin.load();
}
const doc = this.view.ownerDocument;
const rootSplit:WorkspaceSplit = new (WorkspaceSplit as ConstructableWorkspaceSplit)(app.workspace, "vertical");
rootSplit.getRoot = () => app.workspace[doc === document ? 'rootSplit' : 'floatingSplit'];
rootSplit.getContainer = () => getContainerForDocument(doc);
this.leaf = app.workspace.createLeafInParent(rootSplit, 0);
this.canvas = canvasPlugin.views.canvas(this.leaf).canvas;
this.initialized = true;
}
public createFileNote(file: TFile, subpath: string, containerEl: HTMLDivElement, elementId: string): ObsidianCanvasNode {
if(!this.initialized) return;
subpath = subpath ?? "";
if(this.nodes.has(elementId)) {
this.canvas.removeNode(this.nodes.get(elementId));
this.nodes.delete(elementId);
}
const node = this.canvas.createFileNode({pos: {x:0,y:0}, file, subpath, save: false});
node.setFilePath(file.path,subpath);
node.render();
//containerEl.style.background = "var(--background-primary)";
node.containerEl.querySelector(".canvas-node-content-blocker")?.remove();
containerEl.appendChild(node.containerEl)
this.nodes.set(elementId, node);
return node;
}
public async startEditing(node: ObsidianCanvasNode, theme: string) {
if (!this.initialized || !node) return;
if (node.file === this.view.file) {
await this.view.setEmbeddableIsEditingSelf();
}
node.startEditing();
const obsidianTheme = isObsidianThemeDark() ? "theme-dark" : "theme-light";
if (obsidianTheme === theme) return;
(async () => {
let counter = 0;
while (!node.child.editor?.containerEl?.parentElement?.parentElement && counter++ < 100) {
await sleep(25);
}
if (!node.child.editor?.containerEl?.parentElement?.parentElement) return;
node.child.editor.containerEl.parentElement.parentElement.classList.remove(obsidianTheme);
node.child.editor.containerEl.parentElement.parentElement.classList.add(theme);
const nodeObserverFn: MutationCallback = (mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
const targetElement = mutation.target as HTMLElement;
if (targetElement.classList.contains(obsidianTheme)) {
targetElement.classList.remove(obsidianTheme);
targetElement.classList.add(theme);
}
}
}
};
const observer = isDebugMode()
? new CustomMutationObserver(nodeObserverFn, "CanvasNodeFactory")
: new MutationObserver(nodeObserverFn);
observer.observe(node.child.editor.containerEl.parentElement.parentElement, { attributes: true });
})();
}
public stopEditing(node: ObsidianCanvasNode) {
if(!this.initialized || !node) return;
if(!node.child.editMode) return;
if(node.file === this.view.file) {
this.view.clearEmbeddableIsEditingSelf();
}
node.child.showPreview();
}
public purgeNodes() {
if(!this.initialized) return;
this.nodes.forEach(node => {
this.canvas.removeNode(node);
});
this.nodes.clear();
}
}