diff --git a/src/main.ts b/src/main.ts index 0457163..7a7982b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,6 +21,7 @@ import { InsertCitationModal, InsertNoteLinkModal, InsertNoteContentModal, + InsertZoteroLinkModal, OpenNoteModal, } from './modals'; import { VaultExt } from './obsidian-extensions.d'; @@ -171,6 +172,15 @@ export default class CitationPlugin extends Plugin { }, }); + this.addCommand({ + id: 'insert-zotero-link', + name: 'Insert Zotero link to pdf or entry', + callback: () => { + const modal = new InsertZoteroLinkModal(this.app, this); + modal.open(); + }, + }); + this.addCommand({ id: 'insert-markdown-citation', name: 'Insert Markdown citation', @@ -334,6 +344,16 @@ export default class CitationPlugin extends Plugin { ); } + getEntryZoteroLinkForCitekey(citekey: string): string { + return `[${citekey}](zotero://select/items/${citekey})`; + } + + getPdfZoteroLinkForCitekey(citekey: string): string { + const variables = this.library.getTemplateVariablesForCitekey(citekey); + return `[${citekey}:pdf](${variables.zoteroPdfURI})`; + } + + /** * Run a case-insensitive search for the literature note file corresponding to * the given citekey. If no corresponding file is found, create one. @@ -417,4 +437,16 @@ export default class CitationPlugin extends Plugin { this.editor.replaceRange(citation, this.editor.getCursor()); } + + async insertZoteroLink( + citekey: string, + alternative = false, + ): Promise { + const func = alternative + ? this.getEntryZoteroLinkForCitekey + : this.getPdfZoteroLinkForCitekey; + const link = func.bind(this)(citekey); + + this.editor.replaceRange(link, this.editor.getCursor()); + } } diff --git a/src/modals.ts b/src/modals.ts index 68c0279..11d186e 100644 --- a/src/modals.ts +++ b/src/modals.ts @@ -258,6 +258,30 @@ export class InsertNoteContentModal extends SearchModal { } } +export class InsertZoteroLinkModal extends SearchModal { + constructor(app: App, plugin: CitationPlugin) { + super(app, plugin); + + this.setInstructions([ + { command: '↑↓', purpose: 'to navigate' }, + { + command: '↵', + purpose: 'to insert Zotero Link to pdf', + }, + { command: 'shift ↵', purpose: 'to insert Zoter Link to entry' }, + { command: 'esc', purpose: 'to dismiss' }, + ]); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + onChooseItem(item: Entry, evt: MouseEvent | KeyboardEvent): void { + const isAlternative = evt instanceof KeyboardEvent && evt.shiftKey; + this.plugin + .insertZoteroLink(item.id, isAlternative) + .catch(console.error); + } +} + export class InsertCitationModal extends SearchModal { constructor(app: App, plugin: CitationPlugin) { super(app, plugin); diff --git a/src/types.ts b/src/types.ts index f185b09..00e5a2f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,6 @@ import * as BibTeXParser from '@retorquere/bibtex-parser'; import { Entry as EntryDataBibLaTeX } from '@retorquere/bibtex-parser'; +import { has } from 'lodash'; // Also make EntryDataBibLaTeX available to other modules export { Entry as EntryDataBibLaTeX } from '@retorquere/bibtex-parser'; @@ -31,6 +32,8 @@ export const TEMPLATE_VARIABLES = { URL: '', year: 'Publication year', zoteroSelectURI: 'URI to open the reference in Zotero', + zoteroPdfURI: 'URI to open the PDF attachment in Zotero', + zoteroPdfHash: 'Hash of the PDF attachment', }; export class Library { @@ -65,6 +68,8 @@ export class Library { URL: entry.URL, year: entry.year?.toString(), zoteroSelectURI: entry.zoteroSelectURI, + zoteroPdfURI: entry.zoteroPdfURI, + zoteroPdfHash: entry.zoteroPdfHash, }; return { entry: entry.toJSON(), ...shortcuts }; @@ -199,6 +204,28 @@ export abstract class Entry { return `zotero://select/items/@${this.id}`; } + public get zoteroPdfHash(): string { + const files = this.files || []; + + const pdfPath = files.find((f) => f.toLowerCase().endsWith('.pdf')); + + if (!pdfPath) { + return null; + } + const idxStorage = pdfPath.toLowerCase().indexOf('/storage/'); + const pdfHash = pdfPath.substring(idxStorage + 9, idxStorage + 9 + 8); + return pdfHash; + } + + public get zoteroPdfURI(): string { + const hashPdf = this.zoteroPdfHash; + if (hashPdf) { + return `zotero://open-pdf/library/items/${hashPdf}`; + } else { + return null; + } + } + toJSON(): Record { const jsonObj: Record = Object.assign({}, this);