|
1 | | -import { Plugin, TFile, MarkdownView, Notice, arrayBufferToBase64 } from 'obsidian'; |
| 1 | +import { Plugin, TFile, MarkdownView, Notice, arrayBufferToBase64, ObsidianProtocolData } from 'obsidian'; |
2 | 2 | import { AnkiService } from './anki-service'; |
3 | 3 | import { ObsidianNote, ProcessedMediaResult } from './types'; |
4 | 4 | import { DEFAULT_SETTINGS, SimpleAnkiSyncSettingTab, SimpleAnkiSyncSettings } from './settings'; |
@@ -114,6 +114,40 @@ export default class SimpleAnkiSyncPlugin extends Plugin { |
114 | 114 | return; |
115 | 115 | }, |
116 | 116 | }); |
| 117 | + |
| 118 | + this.registerObsidianProtocolHandler('simple-anki-sync', this.handleCustomProtocol.bind(this)); |
| 119 | + } |
| 120 | + |
| 121 | + private async handleCustomProtocol(params: ObsidianProtocolData) { |
| 122 | + if (params.action === 'simple-anki-sync') { |
| 123 | + const { file, noteId } = params; |
| 124 | + if (!file || !noteId) return; |
| 125 | + |
| 126 | + const abstractFile = this.app.vault.getAbstractFileByPath(file); |
| 127 | + if (!(abstractFile instanceof TFile)) return; |
| 128 | + |
| 129 | + const leaf = this.app.workspace.getLeaf(false); |
| 130 | + await leaf.openFile(abstractFile); |
| 131 | + |
| 132 | + const content = await this.app.vault.read(abstractFile); |
| 133 | + const lines = content.split('\n'); |
| 134 | + |
| 135 | + const searchFor = `<!--ANKI_NOTE_ID:${noteId}-->`; |
| 136 | + const lineNumber = lines.findIndex(line => line.includes(searchFor)); |
| 137 | + |
| 138 | + if (lineNumber !== -1) { |
| 139 | + // Find where the trailing Anki comment or `<br>` tags start, so we can place the cursor exactly there |
| 140 | + const line = lines[lineNumber]; |
| 141 | + const match = line.match(/(?:<br\s*\/?>\s*)*<!--ANKI_NOTE_ID:\d+-->/i); |
| 142 | + const column = match ? match.index || 0 : 0; |
| 143 | + |
| 144 | + const view = this.app.workspace.getActiveViewOfType(MarkdownView); |
| 145 | + if (view && view.editor) { // only if in edit mode |
| 146 | + view.editor.setCursor(lineNumber, column); |
| 147 | + view.editor.scrollIntoView({ from: { line: lineNumber, ch: 0 }, to: { line: lineNumber, ch: 0 } }, true); |
| 148 | + } |
| 149 | + } |
| 150 | + } |
117 | 151 | } |
118 | 152 |
|
119 | 153 | onunload() { |
@@ -472,9 +506,13 @@ export default class SimpleAnkiSyncPlugin extends Plugin { |
472 | 506 |
|
473 | 507 | // Obsidian-Link |
474 | 508 | const vault = this.app.vault.getName(); |
475 | | - const url = `obsidian://open?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent( |
476 | | - file.path |
477 | | - )}`; |
| 509 | + let url = ''; |
| 510 | + if (note.noteId) { |
| 511 | + url = `obsidian://simple-anki-sync?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent(file.path)}¬eId=${note.noteId}`; |
| 512 | + } else { |
| 513 | + url = `obsidian://open?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent(file.path)}`; |
| 514 | + } |
| 515 | + |
478 | 516 | backHtml += `<br><small><a href="${url}" style="text-decoration:none;color:grey;font-size:0.8em;">Obsidian Note</a></small>`; |
479 | 517 |
|
480 | 518 | const fields = { Front: frontHtml, Back: backHtml }; |
|
0 commit comments