diff --git a/manifest.json b/manifest.json index 25dbad2..bad2960 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-zotero-desktop-connector", "name": "Zotero Integration", - "version": "3.0.1", + "version": "3.0.2", "minAppVersion": "1.1.1", "description": "Insert and import citations, bibliographies, notes, and PDF annotations from Zotero.", "author": "mgmeyers", diff --git a/src/bbt/cayw.ts b/src/bbt/cayw.ts index d27f46f..fe2a5c7 100644 --- a/src/bbt/cayw.ts +++ b/src/bbt/cayw.ts @@ -17,6 +17,7 @@ export function getCiteKeyFromAny(item: any): CiteKey | null { let cachedIsRunning = false; let lastCheck = 0; + export async function isZoteroRunning( database: DatabaseWithPort, silent?: boolean diff --git a/src/bbt/getCiteKeyExport.ts b/src/bbt/getCiteKeyExport.ts deleted file mode 100644 index c42766a..0000000 --- a/src/bbt/getCiteKeyExport.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { request } from 'obsidian'; -import { CiteKeyExport, DatabaseWithPort } from 'src/types'; - -import { isZoteroRunning } from './cayw'; -import { defaultHeaders, getPort } from './helpers'; - -const translatorId = 'f4b52ab0-f878-4556-85a0-c7aeedd09dfc'; -export async function getCiteKeyExport( - database: DatabaseWithPort, - groupId: string, - groupName: string -) { - try { - const res = await request({ - method: 'GET', - url: `http://127.0.0.1:${getPort( - database.database, - database.port - )}/better-bibtex/export/library?/${groupId}/${groupName}.${translatorId}`, - headers: defaultHeaders, - }); - - const entries = JSON.parse(res); - - return Array.isArray(entries) - ? entries - .map((e) => { - const out: Record = { - libraryID: Number(groupId), - }; - - if (e['citation-key']) { - out.citekey = e['citation-key']; - } else { - return null; - } - - if (e['title']) { - out.title = e['title']; - } else { - return null; - } - - return out as { libraryID: number; citekey: string; title: string }; - }) - .filter((k) => !!k) - : null; - } catch (e) { - return null; - } -} - -export async function getUserGroups(database: DatabaseWithPort) { - let res: string; - try { - res = await request({ - method: 'POST', - url: `http://127.0.0.1:${getPort( - database.database, - database.port - )}/better-bibtex/json-rpc`, - body: JSON.stringify({ - jsonrpc: '2.0', - method: 'user.groups', - params: [], - }), - headers: defaultHeaders, - }); - } catch (e) { - console.error(e); - return null; - } - - try { - return JSON.parse(res).result; - } catch (e) { - console.error(e); - return null; - } -} - -let cachedKeys: CiteKeyExport[] = []; -let lastCheck = 0; - -export async function getAllCiteKeys( - database: DatabaseWithPort, - force?: boolean -) { - if (!force && cachedKeys.length && Date.now() - lastCheck < 1000 * 60 * 60) { - return { citekeys: cachedKeys, fromCache: true }; - } - - if (!(await isZoteroRunning(database, true))) { - return { citekeys: cachedKeys, fromCache: true }; - } - - const allKeys: CiteKeyExport[] = []; - const userGroups = await getUserGroups(database); - - if (!userGroups) { - return { citekeys: cachedKeys, fromCache: true }; - } - - for (const group of userGroups) { - const keys = await getCiteKeyExport(database, group.id, group.name); - - if (keys) { - allKeys.push(...keys); - } - } - - cachedKeys = allKeys; - lastCheck = Date.now(); - - return { citekeys: allKeys, fromCache: false }; -} diff --git a/src/bbt/jsonRPC.ts b/src/bbt/jsonRPC.ts index 1ac4030..5eed1ec 100644 --- a/src/bbt/jsonRPC.ts +++ b/src/bbt/jsonRPC.ts @@ -1,9 +1,9 @@ import { Notice, htmlToMarkdown, moment, request } from 'obsidian'; import { padNumber } from '../helpers'; -import { DatabaseWithPort } from '../types'; +import { CiteKeyExport, DatabaseWithPort } from '../types'; import { LoadingModal } from './LoadingModal'; -import { CiteKey, getCiteKeyFromAny } from './cayw'; +import { CiteKey, getCiteKeyFromAny, isZoteroRunning } from './cayw'; import { defaultHeaders, getPort } from './helpers'; export async function getNotesFromCiteKeys( @@ -521,3 +521,115 @@ export async function execSearch(term: string, database: DatabaseWithPort) { return null; } } + + +const translatorId = 'f4b52ab0-f878-4556-85a0-c7aeedd09dfc'; +export async function getCiteKeyExport( + database: DatabaseWithPort, + groupId: string, + groupName: string +) { + try { + const res = await request({ + method: 'GET', + url: `http://127.0.0.1:${getPort( + database.database, + database.port + )}/better-bibtex/export/library?/${groupId}/${groupName}.${translatorId}`, + headers: defaultHeaders, + }); + + const entries = JSON.parse(res); + + return Array.isArray(entries) + ? entries + .map((e) => { + const out: Record = { + libraryID: Number(groupId), + }; + + if (e['citation-key']) { + out.citekey = e['citation-key']; + } else { + return null; + } + + if (e['title']) { + out.title = e['title']; + } else { + return null; + } + + return out as { libraryID: number; citekey: string; title: string }; + }) + .filter((k) => !!k) + : null; + } catch (e) { + return null; + } +} + +export async function getUserGroups(database: DatabaseWithPort) { + let res: string; + try { + res = await request({ + method: 'POST', + url: `http://127.0.0.1:${getPort( + database.database, + database.port + )}/better-bibtex/json-rpc`, + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'user.groups', + params: [], + }), + headers: defaultHeaders, + }); + } catch (e) { + console.error(e); + return null; + } + + try { + return JSON.parse(res).result; + } catch (e) { + console.error(e); + return null; + } +} + +let cachedKeys: CiteKeyExport[] = []; +let lastCheck = 0; + +export async function getAllCiteKeys( + database: DatabaseWithPort, + force?: boolean +) { + if (!force && cachedKeys.length && Date.now() - lastCheck < 1000 * 60 * 60) { + return { citekeys: cachedKeys, fromCache: true }; + } + + if (!(await isZoteroRunning(database, true))) { + return { citekeys: cachedKeys, fromCache: true }; + } + + const allKeys: CiteKeyExport[] = []; + const userGroups = await getUserGroups(database); + + if (!userGroups) { + return { citekeys: cachedKeys, fromCache: true }; + } + + for (const group of userGroups) { + const keys = await getCiteKeyExport(database, group.id, group.name); + + if (keys) { + allKeys.push(...keys); + } + } + + cachedKeys = allKeys; + lastCheck = Date.now(); + + return { citekeys: allKeys, fromCache: false }; +} diff --git a/src/citeSuggest/citeSuggest.ts b/src/citeSuggest/citeSuggest.ts index 26c2e1d..4eb4ce1 100644 --- a/src/citeSuggest/citeSuggest.ts +++ b/src/citeSuggest/citeSuggest.ts @@ -12,7 +12,7 @@ import { debounce, } from 'obsidian'; import { isZoteroRunning } from 'src/bbt/cayw'; -import { getAllCiteKeys } from 'src/bbt/getCiteKeyExport'; +import { getAllCiteKeys } from 'src/bbt/jsonRPC'; import ZoteroConnector from 'src/main'; import { CiteKeyExport } from 'src/types'; diff --git a/src/main.ts b/src/main.ts index 62fcc1d..4273e49 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,7 +10,6 @@ import { insertNotesIntoCurrentDoc, noteExportPrompt, } from './bbt/exportNotes'; -import { getAllCiteKeys } from './bbt/getCiteKeyExport'; import './bbt/template.helpers'; import { CiteSuggest } from './citeSuggest/citeSuggest'; import { @@ -27,6 +26,7 @@ import { TooltipManager } from './pandocReference/tooltip'; import { currentVersion, downloadAndExtract } from './settings/AssetDownloader'; import { ZoteroConnectorSettingsTab } from './settings/settings'; import { CitationFormat, ExportFormat, ZoteroConnectorSettings } from './types'; +import { getAllCiteKeys } from './bbt/jsonRPC'; const commandPrefix = 'obsidian-zotero-desktop-connector:'; const citationCommandIDPrefix = 'zdc-'; @@ -95,14 +95,6 @@ export default class ZoteroConnector extends Plugin { this.addExportCommand(f); }); - this.registerEvent( - this.app.vault.on('modify', (file) => { - if (file instanceof TFile) { - this.emitter.trigger('fileUpdated', file); - } - }) - ); - this.addCommand({ id: 'zdc-insert-notes', name: 'Insert notes into current document', @@ -145,25 +137,10 @@ export default class ZoteroConnector extends Plugin { id: 'show-zotero-debug-view', name: 'Data explorer', callback: () => { - this.activateView(); + this.activateDataExplorer(); }, }); - this.registerEditorSuggest(new CiteSuggest(this.app, this)); - this.registerMarkdownPostProcessor(processCiteKeys(this)); - this.registerEditorExtension([ - viewManagerField.init(() => this.view?.viewManager || null), - citeKeyCacheField, - citeKeyPlugin, - ]); - - this.tooltipManager = new TooltipManager(this); - - document.body.toggleClass( - 'pwc-tooltips', - !!this.settings.shouldShowCitekeyTooltips - ); - this.addCommand({ id: 'show-reference-list-view', name: 'Show pandoc references', @@ -171,11 +148,17 @@ export default class ZoteroConnector extends Plugin { if (checking) { return this.view === null; } - this.initLeaf(); + this.activateReferenceList(); }, }); - app.workspace.trigger('parse-style-settings'); + this.registerEvent( + this.app.vault.on('modify', (file) => { + if (file instanceof TFile) { + this.emitter.trigger('fileUpdated', file); + } + }) + ); this.addCommand({ id: 'update-cite-keys', @@ -191,6 +174,23 @@ export default class ZoteroConnector extends Plugin { }, }); + this.registerEditorSuggest(new CiteSuggest(this.app, this)); + this.registerMarkdownPostProcessor(processCiteKeys(this)); + this.registerEditorExtension([ + viewManagerField.init(() => this.view?.viewManager || null), + citeKeyCacheField, + citeKeyPlugin, + ]); + + this.tooltipManager = new TooltipManager(this); + + document.body.toggleClass( + 'pwc-tooltips', + !!this.settings.shouldShowCitekeyTooltips + ); + + app.workspace.trigger('parse-style-settings'); + fixPath(); if (this.settings.shouldShowCiteSuggest) { @@ -201,15 +201,6 @@ export default class ZoteroConnector extends Plugin { } } - initLeaf(): void { - if (this.view) { - return; - } - this.app.workspace.getRightLeaf(false).setViewState({ - type: RLViewType, - }); - } - onunload() { this.settings.citeFormats.forEach((f) => { this.removeFormatCommand(f); @@ -339,12 +330,12 @@ export default class ZoteroConnector extends Plugin { await this.saveData(this.settings); } - deactivateView() { + deactivateDataExplorer() { this.app.workspace.detachLeavesOfType(viewType); } - async activateView() { - this.deactivateView(); + async activateDataExplorer() { + this.deactivateDataExplorer(); const leaf = this.app.workspace.createLeafBySplit( this.app.workspace.activeLeaf, 'vertical' @@ -355,6 +346,19 @@ export default class ZoteroConnector extends Plugin { }); } + activateReferenceList(): void { + if (this.view) { + return; + } + this.app.workspace.getRightLeaf(false).setViewState({ + type: RLViewType, + }); + } + + deactivateReferenceList() { + this.app.workspace.detachLeavesOfType(RLViewType); + } + async updatePDFUtility() { if ( !this.settings.exeOverridePath && diff --git a/src/pandocReference/ViewManager.ts b/src/pandocReference/ViewManager.ts index 2dd4d77..040af6d 100644 --- a/src/pandocReference/ViewManager.ts +++ b/src/pandocReference/ViewManager.ts @@ -1,7 +1,6 @@ import { LRUCache } from 'lru-cache'; import { TFile } from 'obsidian'; -import { getAllCiteKeys } from 'src/bbt/getCiteKeyExport'; -import { getBibFromCiteKeys } from 'src/bbt/jsonRPC'; +import { getAllCiteKeys, getBibFromCiteKeys } from 'src/bbt/jsonRPC'; import ZoteroConnector from 'src/main'; import { areSetsEqual, extractCiteKeys } from './helpers'; diff --git a/src/pandocReference/tooltip.ts b/src/pandocReference/tooltip.ts index da2bc92..9db4179 100644 --- a/src/pandocReference/tooltip.ts +++ b/src/pandocReference/tooltip.ts @@ -1,5 +1,6 @@ import { LRUCache } from 'lru-cache'; import { TFile } from 'obsidian'; +import { isZoteroRunning } from 'src/bbt/cayw'; import { getBibFromCiteKey, getLibForCiteKey } from 'src/bbt/jsonRPC'; import ZoteroConnector from 'src/main'; @@ -102,8 +103,15 @@ export class TooltipManager { return this.populateTooltip(this.cache.get(citekey), rect, citekey); } + if (!(await isZoteroRunning(database, true))) { + return this.populateTooltip(null, rect, citekey, true); + } + const libraryID = await getLibForCiteKey(citekey, database); if (!this.tooltip) return; + if (libraryID === null) { + return this.populateTooltip(null, rect, citekey); + } const content = await getBibFromCiteKey( { key: citekey, library: libraryID }, @@ -114,7 +122,9 @@ export class TooltipManager { ); if (!this.tooltip) return; - if (!content) return this.hideTooltip(); + if (!content) { + return this.populateTooltip(null, rect, citekey); + } const parser = new DOMParser(); const html = parser.parseFromString(content, 'text/html'); @@ -124,7 +134,7 @@ export class TooltipManager { this.populateTooltip(bib, rect, citekey); } - populateTooltip(bib: HTMLElement, rect: DOMRect, citekey: string) { + populateTooltip(bib: HTMLElement, rect: DOMRect, citekey: string, notRunning?: boolean) { const { tooltip } = this; tooltip.empty(); @@ -137,7 +147,7 @@ export class TooltipManager { } else { tooltip.addClass('is-missing'); tooltip.createEl('em', { - text: 'No citation found for ' + citekey, + text: notRunning ? 'Cannot connect to Zotero' : 'No citation found for ' + citekey, }); }