74 lines
2.6 KiB
TypeScript
74 lines
2.6 KiB
TypeScript
import { Plugin, MarkdownPostProcessorContext, TFile, Vault } from 'obsidian';
|
|
|
|
// Node.js shell module for opening files/folders
|
|
const { shell } = require('electron');
|
|
|
|
export default class MenuPlugin extends Plugin {
|
|
async onload() {
|
|
this.registerMarkdownCodeBlockProcessor('menu', this.menuProcessor.bind(this));
|
|
}
|
|
|
|
async menuProcessor(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) {
|
|
// Parse optional class from first line
|
|
let lines = source.split('\n').map(l => l.trim()).filter(Boolean);
|
|
let menuClass = 'menu-container';
|
|
if (lines[0]?.startsWith('class:')) {
|
|
menuClass += ' ' + lines[0].replace('class:', '').trim();
|
|
lines = lines.slice(1);
|
|
}
|
|
const container = el.createDiv({ cls: menuClass });
|
|
|
|
for (const line of lines) {
|
|
let match;
|
|
// Internal Obsidian link: [[file|alias]]
|
|
if ((match = line.match(/^\[\[(.+?)(\|(.+?))?]]$/))) {
|
|
const fileName = match[1];
|
|
const alias = match[3] || match[1];
|
|
const a = container.createEl('a', { text: alias, cls: 'internal-link' });
|
|
a.setAttr('data-href', fileName);
|
|
a.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
this.app.workspace.openLinkText(fileName, ctx.sourcePath);
|
|
});
|
|
continue;
|
|
}
|
|
// Markdown link: [text](url)
|
|
if ((match = line.match(/^\[(.+?)]\((.+?)\)$/))) {
|
|
const text = match[1];
|
|
const url = match[2];
|
|
// Local file/folder (file:/// or absolute path)
|
|
if (url.startsWith('file:///') || url.match(/^([a-zA-Z]:\\|\\\\)/)) {
|
|
const a = container.createEl('a', { text });
|
|
a.style.cursor = 'pointer';
|
|
a.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
// Remove file:/// if present
|
|
let path = url.replace('file:///', '');
|
|
// Decode URI
|
|
path = decodeURIComponent(path);
|
|
shell.openPath(path);
|
|
});
|
|
} else if (url.startsWith('http')) {
|
|
// Web link
|
|
const a = container.createEl('a', { text });
|
|
a.href = url;
|
|
a.target = '_blank';
|
|
a.rel = 'noopener noreferrer';
|
|
a.style.cursor = 'pointer';
|
|
} else {
|
|
// Try to open as vault file
|
|
const a = container.createEl('a', { text });
|
|
a.style.cursor = 'pointer';
|
|
a.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
this.app.workspace.openLinkText(url, ctx.sourcePath);
|
|
});
|
|
}
|
|
continue;
|
|
}
|
|
// Plain text fallback
|
|
container.createEl('span', { text: line });
|
|
}
|
|
}
|
|
}
|