mirror of
https://github.com/scotttomaszewski/obsidian-disciples-journal.git
synced 2026-07-22 05:42:13 +00:00
95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
import { ViewUpdate, EditorView, ViewPlugin, Decoration, DecorationSet } from "@codemirror/view";
|
|
import {RangeSetBuilder} from "@codemirror/state";
|
|
import { syntaxTree } from "@codemirror/language";
|
|
import { BibleReference } from "src/core/BibleReference";
|
|
import { BibleEventHandlers } from "src/core/BibleEventHandlers";
|
|
import { BibleReferenceRenderer } from "./BibleReferenceRenderer";
|
|
import {editorLivePreviewField, Notice} from "obsidian";
|
|
import {BibleContentService} from "../services/BibleContentService";
|
|
|
|
// Plugin/Extension to handle live-preview rendering of Inline Admonitions.
|
|
// Reference: https://github.com/liamcain/obsidian-lapel/blob/main/src/headingWidget.ts
|
|
export function createInlineReferenceExtension(renderer: BibleReferenceRenderer, contentService: BibleContentService) {
|
|
return ViewPlugin.fromClass(
|
|
class {
|
|
decorations: DecorationSet;
|
|
|
|
constructor(view: EditorView) {
|
|
this.decorations = this.buildDecorations(view);
|
|
}
|
|
|
|
update(update: ViewUpdate) {
|
|
if (update.docChanged || update.viewportChanged) {
|
|
this.decorations = this.buildDecorations(update.view);
|
|
}
|
|
}
|
|
|
|
buildDecorations(view: EditorView): DecorationSet {
|
|
if (!view.state.field(editorLivePreviewField)) {
|
|
return Decoration.none;
|
|
}
|
|
const builder = new RangeSetBuilder<Decoration>();
|
|
|
|
for (const { from, to } of view.visibleRanges) {
|
|
syntaxTree(view.state).iterate({
|
|
from,
|
|
to,
|
|
enter: (node) => {
|
|
if (node.type.name.contains("inline-code")) {
|
|
const content = view.state.doc.sliceString(node.from, node.to);
|
|
// Try to parse as a Bible reference
|
|
try {
|
|
const reference = BibleReference.parse(content);
|
|
if (reference) {
|
|
const decor = Decoration.mark({
|
|
inclusive: true,
|
|
attributes: { class: "bible-reference" }
|
|
});
|
|
builder.add(node.from, node.to, decor);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error parsing Bible reference in editor: ${content}`, error);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
return builder.finish();
|
|
}
|
|
},
|
|
{
|
|
decorations: v => v.decorations,
|
|
eventHandlers: {
|
|
mouseover: (e, view) => {
|
|
const t = e.target as HTMLElement;
|
|
if (t.classList.contains("bible-reference")) {
|
|
if (!t.textContent) {
|
|
new Notice("No text content found for Bible reference", 10000);
|
|
return;
|
|
}
|
|
const reference = BibleReference.parse(t.textContent);
|
|
if (!reference) {
|
|
new Notice("Invalid Bible reference: " + t.textContent, 10000);
|
|
return;
|
|
}
|
|
|
|
void contentService.getBibleContent(reference).then(response => {
|
|
if (response.isError()) {
|
|
new Notice(response.errorMessage, 10000);
|
|
return;
|
|
}
|
|
void new BibleEventHandlers(renderer).handleBibleReferenceHover(e, response.passage);
|
|
});
|
|
}
|
|
},
|
|
mouseout: (e, view) => {
|
|
const t = e.target as HTMLElement;
|
|
if (t.classList.contains("bible-reference")) {
|
|
new BibleEventHandlers(renderer).handleBibleReferenceMouseOut(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|