Skip to content

Commit

Permalink
support multiple md files per zotero item
Browse files Browse the repository at this point in the history
  • Loading branch information
daeh committed Jan 19, 2022
1 parent a69f28b commit 032c545
Showing 7 changed files with 117 additions and 42 deletions.
25 changes: 8 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@ Currently this add-on is primarily designed to be a minimal companion to the [ob

Please post any bugs, questions, or feature requests in the Github repository.


## Plugin Functions

Adds a colored tag to Zotero items for which there are associated reading notes in an external folder.
@@ -20,30 +19,26 @@ Opens an existing Markdown note in [Obsidian](https://obsidian.md) from the cont

![ZoteroObsidianCitationsMenu](ZoteroObsidianCitationsMenu.png)


## Instalation

- Download the add-on (the .xpi file) from the latest release: https://github.com/daeh/zotero-obsidian-citations/releases
- To download the .xpi file, right click it and select 'Save link as'
- Run Zotero (version 5.x)
- Go to `Tools -> Add-ons`
- `Install Add-on From File`
- Choose the file `zotero-obsidian-citations-0.0.11.xpi`
- Choose the file `zotero-obsidian-citations-0.0.12.xpi`
- Restart Zotero


## Setup

_ZoteroObsidianCitations_ presumes that a given Zotero item corresponds to single Markdown file. A Markdown file can specify which Zotero item it's linked to using either a [Better BibTex](https://retorque.re/zotero-better-bibtex/) citekey or a Zotero-Item-Key.

_ZoteroObsidianCitations_ presumes that a given Zotero item corresponds to single Markdown file. A Markdown file can specify which Zotero item it's linked to using either a [Better BibTex](https://retorque.re/zotero-better-bibtex/) citekey or a Zotero-Item-Key.

1. Link Markdown files to Zotero items using **Better BibTex citekeys**.

- This is recommended if you created the Markdown notes with [obsidian-citation-plugin](https://github.com/hans/obsidian-citation-plugin).

- The Markdown file names should start with `@mycitekey` but can include extra information after it (e.g. a reading note might have the file name `@shepard1987science.md` or `@shepard1987science Toward a universal law of generalization for psychological science.md`, where `shepard1987science` is the BetterBibTex citekey).


2. Link Markdown files to Zotero items using **Zotero Item Keys**.

- This is recommended if you created the Markdown notes with the `Export Note` feature of Zotero.
@@ -53,19 +48,18 @@ _ZoteroObsidianCitations_ presumes that a given Zotero item corresponds to singl

---


### Option 1: Using BetterBibTex citekeys

_ZoteroObsidianCitations_ can extract the BetterBibTex citekey that specifies which Zotero Item a Markdown note corresponds to. The BetterBibTex citekey can be taken from the Markdown filename or yaml metadata.

- In `ZoteroObsidianCitations Preferences...` (under the `Tools` menu),

- Specify the location of the folder that contains your Markdown reading notes (e.g. `/Users/me/Documents/ObsVault/ReadingNotes/`). The _ZoteroObsidianCitations_ add-on will recursively search this path for Markdown files beginning with `@`.

- Select the `Match notes based on BetterBibTex citekey` option.

- _ZoteroObsidianCitations_ expects that the filenames of your Markdown reading note files begin with `@mycitekey` but can include extra information after it (e.g. a reading note might have the file name `@shepard1987science.md` or `@shepard1987science Toward a universal law of generalization for psychological science.md`, where `shepard1987science` is the BetterBibTex citekey).

- Optionally, you can have _ZoteroObsidianCitations_ read the metadata of your Markdown notes and extract the citekey from one of the fields. To enable this, specify the metadata ID (`citekey` is a common value).

- This is necessary if the file names do not begin with the correct citekey, which may happen if the citekeys include special characters (e.g. if a citekey contains `:`, it will probably need to be taken from the yaml metadata rather than the filename).
@@ -79,36 +73,33 @@ _ZoteroObsidianCitations_ can extract the BetterBibTex citekey that specifies wh
### Option 2: Using Zotero Item Keys

_ZoteroObsidianCitations_ can extract the Zotero-Item-Key that specifies which Zotero Item a Markdown note corresponds to. The Zotero-Item-Key is taken from the Markdown file contents using a custom RegEx pattern.
Zotero automatically generates Item Keys, they take the form of `ABCD1234`, as in `zotero://select/library/items/ABCD1234`. NB this is not the same as the BetterBibTex citekey you assigned an item (e.g. `mycitekey` in `zotero://select/items/@mycitekey`).

Zotero automatically generates Item Keys, they take the form of `ABCD1234`, as in `zotero://select/library/items/ABCD1234`. NB this is not the same as the BetterBibTex citekey you assigned an item (e.g. `mycitekey` in `zotero://select/items/@mycitekey`).

- In `ZoteroObsidianCitations Preferences...` (under the `Tools` menu),

- Specify the location of the folder that contains your Markdown reading notes (e.g. `/Users/me/Documents/ObsVault/ReadingNotes/`). The _ZoteroObsidianCitations_ add-on will recursively search this path for Markdown files beginning with `@`.

- Select the `Match notes based on Zotero-Item-Key` option.

- Specify a RegEx pattern to extract the Zotero-Item-Key from the Markdown contents.

E.g. if your note has the line

`- local:: [local zotero](zotero://select/library/items/GZ9DQ2AM)`

you could extract the Zotero key (`GZ9DQ2AM`) using this RegEx pattern:

`^- local::.+\/items\/(\w+)\)`

- Run the synchronization function from `Tools -> ZoteroObsidianCitations Sync Tags`.
- This will add a tag (`ObsCite`) to every Zotero item for which there exists a reading note in the external folder you specified.
- In the `Tags` plane of Zotero, right-click on the `ObsCite` tag and assign it a color, which will mark the tagged items in the preview plane of Zotero.


## Notes

[GitHub](https://github.com/daeh/zotero-obsidian-citations): Source code repository

Code for this extension is based on [ZotFile](https://github.com/jlegewie/zotfile) and [Zotero Citationcounts](https://github.com/eschnett/zotero-citationcounts) (which is based on [Zotero DOI Manager](https://github.com/bwiernik/zotero-shortdoi), which is based in part on [Zotero Google Scholar Citations](https://github.com/beloglazov/zotero-scholar-citations)).


## License

Distributed under the MIT License.
Distributed under the MIT License.
2 changes: 1 addition & 1 deletion bin/build.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

version='0.0.11'
version='0.0.12'

rm -f zotero-obsidian-citations-${version}.xpi
zip -r zotero-obsidian-citations-${version}.xpi chrome/* defaults/* chrome.manifest install.rdf
29 changes: 27 additions & 2 deletions chrome/content/overlay.xul
Original file line number Diff line number Diff line change
@@ -21,8 +21,33 @@
</menupopup>

<menupopup id="zotero-itemmenu" onpopupshowing="Zotero.ObsCite.buildItemContextMenu();">
<menuitem id="id-obscite-itemmenu-open-obsidian" label="&obscite.item-menu.open-obsidian-label;" hidden="false" oncommand="Zotero.ObsCite.openSelectedItemsObsidian()"/>
<menuitem id="id-obscite-itemmenu-show-md" label="&obscite.item-menu.show-md-label;" hidden="false" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem()"/>
<menuseparator id="id-obscite-itemmenu-separator-top"/>
<menuitem id="id-obscite-itemmenu-open-obsidian" label="&obscite.item-menu.open-obsidian-label;" hidden="false" oncommand="Zotero.ObsCite.openSelectedItemsObsidian(0)"/>
<menuitem id="id-obscite-itemmenu-show-md" label="&obscite.item-menu.show-md-label;" hidden="false" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(0)"/>


<menu id="id-obscite-itemmenu-listmd-restrict" label="&obscite.item-menu.list-md-label;" >
<menupopup id="id-obscite-itemmenu-listmd-menu" onpopupshowing="Zotero.ObsCite.buildItemContextMenuListMD();">
<menuitem id="id-obscite-itemmenu-listmd-file-00" hidden="true" label="menu1" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(0);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-01" hidden="true" label="menu1" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(1);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-02" hidden="true" label="menu2" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(2);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-03" hidden="true" label="menu3" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(3);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-04" hidden="true" label="menu4" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(4);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-05" hidden="true" label="menu5" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(5);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-06" hidden="true" label="menu6" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(6);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-07" hidden="true" label="menu7" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(7);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-08" hidden="true" label="menu8" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(8);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-09" hidden="true" label="menu9" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(9);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-10" hidden="true" label="menu10" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(10);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-11" hidden="true" label="menu11" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(11);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-12" hidden="true" label="menu12" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(12);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-13" hidden="true" label="menu13" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(13);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-14" hidden="true" label="menu14" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(14);"/>
<menuitem id="id-obscite-itemmenu-listmd-file-15" hidden="true" label="menu15" tooltiptext="" oncommand="Zotero.ObsCite.showSelectedItemMarkdownInFilesystem(15);"/>
</menupopup>
</menu>


</menupopup>


95 changes: 76 additions & 19 deletions chrome/content/scripts/zoteroobscite.js
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ if (typeof Zotero === 'undefined') {
}

Zotero.ObsCite = {
version: '0.0.11',
version: '0.0.12',
folderSep: null,
cleanrun: true,
suppressNotifications: false,
@@ -194,7 +194,7 @@ Zotero.ObsCite = {

if (matchstrategy === 'bbtcitekey') {
const bbtactive = await this._checkBBTinstalled();
if (!bbtactive) return false;
if (!bbtactive || !bbtactive[0]) return false;
if (this._getParam_metadatakeyword() == null) return false;
} else if (matchstrategy === 'zotitemkey') {
const zotkeyregex = this._getParam_zotkeyregex();
@@ -651,16 +651,16 @@ Zotero.ObsCite = {
let deferred = Zotero.Promise.defer();

function _checkBTT(addon) {
let found = false;
let res = [];
if (addon === null || !addon.isActive) {
found = false;
res.push(false);
} else {
let win = Services.wm.getMostRecentWindow("navigator:browser");
found = win.Zotero.BetterBibTeX.ready.then(() => {
found = true;
win.Zotero.BetterBibTeX.ready.then(() => {
res.push(true);
});
}
deferred.resolve(found);
deferred.resolve(res);
}

AddonManager.getAddonByID("better-bibtex@iris-advies.com", _checkBTT);
@@ -998,29 +998,83 @@ Zotero.ObsCite = {
//// Controls for Item menu

buildItemContextMenu: function () {
let show = false;
let found_single = false;
let found_multiple = false;
const pane = Services.wm.getMostRecentWindow("navigator:browser").ZoteroPane;
const doc = pane.document;
const items = pane.getSelectedItems();
for (const item of items) {
if (this.dataKeys.includes(item.id)) {
show = true;
show_single = true;
if (this.data[item.id.toString()].length > 1) {
found_multiple = true;
} else {
found_single = true;
}
/// only process first item if multiple selected
break;
}
}

if (found_multiple) {
doc.getElementById("id-obscite-itemmenu-separator-top").hidden = false;
doc.getElementById("id-obscite-itemmenu-open-obsidian").hidden = true;
doc.getElementById("id-obscite-itemmenu-show-md").hidden = true;
doc.getElementById("id-obscite-itemmenu-listmd-restrict").hidden = false;
} else if (found_single) {
doc.getElementById("id-obscite-itemmenu-separator-top").hidden = false;
doc.getElementById("id-obscite-itemmenu-open-obsidian").hidden = false;
doc.getElementById("id-obscite-itemmenu-show-md").hidden = false;
doc.getElementById("id-obscite-itemmenu-listmd-restrict").hidden = true;
} else {
doc.getElementById("id-obscite-itemmenu-separator-top").hidden = true;
doc.getElementById("id-obscite-itemmenu-open-obsidian").hidden = true;
doc.getElementById("id-obscite-itemmenu-show-md").hidden = true;
doc.getElementById("id-obscite-itemmenu-listmd-restrict").hidden = true;
}

},

buildItemContextMenuListMD: function () {
let win = Services.wm.getMostRecentWindow('navigator:browser');
let nodes = win.ZoteroPane.document.getElementById('id-obscite-itemmenu-listmd-menu').childNodes;
// hide all items by default
for (let i = 0; i < nodes.length; i++) nodes[i].setAttribute('hidden', true);

const items = Services.wm.getMostRecentWindow("navigator:browser").ZoteroPane.getSelectedItems();
for (const item of items) {
if (this.dataKeys.includes(item.id)) {
const entry_res_list = this.data[item.id.toString()];
let ii = 0;
for (const entry_res of entry_res_list) {
if (ii < entry_res_list.length) {
// set attributes of menu item
nodes[ii].setAttribute('label', entry_res.name);
// nodes[ii].setAttribute('tooltiptext', this.ZFgetString('menu.collection.tooltip', [folder.path]));
// show menu item
nodes[ii].setAttribute('hidden', false);
} else {
break;
}
ii++;
}
/// only process first item if multiple selected
break;
}
}
doc.getElementById("id-obscite-itemmenu-open-obsidian").hidden = !show;
doc.getElementById("id-obscite-itemmenu-show-md").hidden = !show;
},

openSelectedItemsObsidian: function () {
openSelectedItemsObsidian: function (idx) {
idx = idx || 0;
const items = Services.wm.getMostRecentWindow("navigator:browser").ZoteroPane.getSelectedItems();
const vaultName = ''; ///TODO add preference to specify vault
const vaultKey = (vaultName.length > 0) ? 'vault=' + vaultName + '&' : '';
for (const item of items) {
if (this.dataKeys.includes(item.id)) {
const entry_res_list = this.data[item.id.toString()];
/// NB ignore all be first file entry associated with an itemID
const entry_res = entry_res_list[0];

idx = (idx < entry_res_list.length) ? idx : 0;
const entry_res = entry_res_list[idx];

const uriEncoded = encodeURIComponent(entry_res.path);
Zotero.launchURL("obsidian://open?" + vaultKey + "path=" + uriEncoded);
@@ -1029,19 +1083,22 @@ Zotero.ObsCite = {
// const uriEncoded = encodeURIComponent(entry_res.name);
// Zotero.launchURL("obsidian://open?" + vaultKey + "file=" + uriEncoded);

/// only open first item note
/// only process first item if multiple selected
break;
}
}
},

showSelectedItemMarkdownInFilesystem: function () {
showSelectedItemMarkdownInFilesystem: function (idx) {
idx = idx || 0;
const items = Services.wm.getMostRecentWindow("navigator:browser").ZoteroPane.getSelectedItems();
for (const item of items) {
if (this.dataKeys.includes(item.id)) {
const entry_res_list = this.data[item.id.toString()];
/// NB ignore all be firs file entry associated with an itemID
const entry_res = entry_res_list[0];

idx = (idx < entry_res_list.length) ? idx : 0;
const entry_res = entry_res_list[idx];

let file = new FileUtils.File(OS.Path.normalize(entry_res.path));
if (file.exists()) {
try {
@@ -1053,7 +1110,7 @@ Zotero.ObsCite = {
Zotero.launchFile(file.parent);
}
}
/// only open first item note
/// only process first item if multiple selected
break;
}
}
2 changes: 2 additions & 0 deletions chrome/locale/en-US/overlay.dtd
Original file line number Diff line number Diff line change
@@ -3,3 +3,5 @@

<!ENTITY obscite.item-menu.open-obsidian-label "Open ObsidianMD Note">
<!ENTITY obscite.item-menu.show-md-label "Show Markdown File">

<!ENTITY obscite.item-menu.list-md-label "Linked Markdown Files">
2 changes: 1 addition & 1 deletion install.rdf
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>daeda@mit.edu</em:id>
<em:name>ZoteroObsidianCitations</em:name>
<em:version>0.0.11</em:version>
<em:version>0.0.12</em:version>
<em:type>2</em:type>
<em:creator>Dae Houlihan</em:creator>
<em:description>Add a tag to Zotero items that have a external note.</em:description>
4 changes: 2 additions & 2 deletions update.rdf
Original file line number Diff line number Diff line change
@@ -6,13 +6,13 @@
<rdf:Seq>
<rdf:li>
<rdf:Description>
<em:version>0.0.11</em:version>
<em:version>0.0.12</em:version>
<em:targetApplication>
<rdf:Description>
<em:id>zotero@chnm.gmu.edu</em:id>
<em:minVersion>5.0.0</em:minVersion>
<em:maxVersion>5.*</em:maxVersion>
<em:updateLink>https://github.com/daeh/zotero-obsidian-citations/releases/download/v0.0.11/zotero-obsidian-citations-0.0.11.xpi</em:updateLink>
<em:updateLink>https://github.com/daeh/zotero-obsidian-citations/releases/download/v0.0.12/zotero-obsidian-citations-0.0.12.xpi</em:updateLink>
</rdf:Description>
</em:targetApplication>

0 comments on commit 032c545

Please sign in to comment.