Skip to content

Instantly share code, notes, and snippets.

@acsr
Last active April 3, 2024 12:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acsr/7fced5d3f238dc6180fcdb76c9f82803 to your computer and use it in GitHub Desktop.
Save acsr/7fced5d3f238dc6180fcdb76c9f82803 to your computer and use it in GitHub Desktop.
Enhanced eta-template to export multiple Zotero items for pasting into Logseq including title, url, creators, tags, select link, abstractNote, multiple notes, multiple relations and the rights. Code completely rewritten after support by Emiliano Heyns and his update of the code of his Zotero AddOn BetterBibTeX
<%- for (const item of it.items) {
const [ , kind, lib, key ] = item.uri.match(/^https?:\/\/zotero\.org\/(users|groups)\/((?:local\/)?[^/]+)\/items\/(.+)/)
const select = (kind === 'users') ? `zotero://select/library/items/${key}` : `zotero://select/groups/${lib}/items/${key}`
const relations = []
if (item.relations) {
for (const [kind, rels] of Object.entries(item.relations)) {
for (const rel of rels) {
relations.push(rel)
}
}
}
-%>
- ### <%= item.title %>
<%- if (item.creators.length) { -%>
<%= "\n" %>creators:: <% item.creators.forEach((creator, i) => { %><%= creator.creatorType %>: <%= creator.name || `${creator.firstName || ''} ${creator.lastName || ''}`.trim() %><% if (i < item.creators.length - 1) { %>, <% } %><% }) %>
<%- } -%>
<%- if (item.url) { -%>
<%= "\n" %>url:: <%= item.url %>
<%- } -%>
<%- if (item.tags.length) { -%>
<%= "\n" %>tags:: <% item.tags.forEach((tag, i) => { %>#[[<%= tag.tag %>]]<% if (i < item.tags.length - 1){%>, <%}%><% }) %>
<%- } -%>
<%- if (item.citationKey) { -%>
<%= "\n" %>zotero:: [@<%= item.citationKey %>](<%= select %>)
<%- } -%>
<%= "\n" %>
<%- if (item.abstractNote) { -%>
<%= "\r" %> - #### abstractNote
<%="\r"%><%=item.abstractNote%>
<%- } -%>
<%- if (item.notes.length) { -%>
<%= "\r" %> - #### Notes
<%- for (const note of item.notes) { -%>
<%= "\r" %> - ##### Note [<%= note.key %>](<%= note.uri %> "URI Link")
<%~ note.note %>
<%- } -%>
<%- } -%>
<%- if (relations.length) { -%>
<%= "\r" %> - #### Relations
<%- for (const rel of relations) { -%>
<%= "\r" %> - <%= rel %>
<%- } -%>
<%- } -%>
<%- if (item.rights) { -%>
<%= "\r" %> - #### Rights
<%= "\r" %> - <%= item.rights %>
<%- } -%>
<% } %>
@acsr
Copy link
Author

acsr commented Oct 9, 2023

For further enhancement visit the BetterBibTex docs at https://retorque.re/zotero-better-bibtex/installation/preferences/export/#eta-template, the eta docs at https://eta.js.org/ and make sure to follow the hint in the BetterBibTex eta-template docs suggesting to create an example Zotero export with some items as [[BetterBibTeX]] [[JSON]].

Tipp: To find more sample code search for EJS template instead of eta template!
[[eta-template]] is more robust than [[EJS-Template]], but most of the JavaScript Code is identical.

@acsr
Copy link
Author

acsr commented Nov 5, 2023

Rev2 now adds the abstractNote at the end as Block (due to LineFeeds). The block has a h4 heading and is indented.

@acsr
Copy link
Author

acsr commented Nov 19, 2023

Rev3 fixes an issue in Rev2 failing to properly iterate through the selection and collecting the abstractNotes. Only the first item was copied properly, listing only the abstractNotes for the remaining items.

@acsr
Copy link
Author

acsr commented Feb 6, 2024

Code Revison 6 completely rewritten to support notes, relations and rights after support by Emiliano Heyns and his update of the code of his Zotero AddOn BetterBibTeX. See github issue retorquere/zotero-better-bibtex#2779.

Note: The relation section can list additional hidden relations pointing to the original item, when the item was copied over from another group library.

other known issues:

  • Links in notes and relations are still pointing at http://zotero.org (no https) due to relying on the current JSON output by BetterBibTex yet. This is subject to change by me asap as a transform in the template if not in the JSON.
  • For me these links are more useful as internal select item links in the zotero://select/... schema

TODO: Add processing of attachments and add PDF open links beyond the links provided by notes generated from PDF annotations using the item context menu for PDF attachment Create note from annotations

@acsr
Copy link
Author

acsr commented Feb 6, 2024

As I see now an empty abstractNote creates an TypeError: item.abstractNote is undefined if the abstractNote is empty.
Need to investigate the different approach @retorquere used for the if clauses to check if the value is present.

Note: This issue is fixed in Rev 7 after hints by @retorquere in the following comments!

@retorquere
Copy link

retorquere commented Feb 6, 2024

Links in notes and relations are still pointing at http://zotero.org/ (no https) due to relying on the current JSON output by BetterBibTeX

This is due to Zotero storing it this way, it is not due to BetterBibTeX doing or not doing anything. The "current JSON output by BBT" is just BBT outputting what is in your library, unaltered; BBT is the conduit of this data, it is not the originator.

@retorquere
Copy link

retorquere commented Feb 6, 2024

TypeError: item.abstractNote is undefined if the abstractNote is empty.

Replace it with item.abstractNote. The .length is only relevant for array type fields, not text fields. edit: also item.citationKey, although that will in practice always be filled.

@retorquere
Copy link

As I see now an empty abstractNote creates an TypeError: item.abstractNote is undefined if the abstractNote is empty. Need to investigate the different approach @retorquere used for the if clauses to check if the value is present.

For reference: item.X tests whether item.X is "truthy". Objects and arrays are always "truthy", regardless of their content, so for those you need a further check whether they have any data. Strings are "truthy" unless it is the empty string, numbers are "truthy" unless the number is 0.

So for a string, you can test either item.X (tests whether the string is empty) or item.X.length (which tests whether its length is non-0). The full check for a string is item.X != ''.

Since arrays are always "truthy" themselves, you need to check for contents, for which the full check is item.X.length > 0, but since lengths cannot be negative, it suffices to check for item.X.length != 0, but since 0 is "falsy" and all other number values aren't, you can shortcut that to item.X.length.

@retorquere
Copy link

<%= "\n" %>creators::

this is the same as


creators::

Is \r special to Obsidian in some way? Line endings are usually either \r\n (windows) or \n (all the rest).

@acsr
Copy link
Author

acsr commented Feb 13, 2024

@retorquere First: thanks for your general help with the validation of the field content before writing out stuff in the template. I will update my code and test this.

-> Validation Fixed -> DONE! in Rev 7 20240213_212748-acsr

on Zotero Select Links

Links in notes and relations are still pointing at http://zotero.org/ (no https) due to relying on the current JSON output by BetterBibTeX

@retorquere wrote:

This is due to Zotero storing it this way, it is not due to BetterBibTeX doing or not doing anything. The "current JSON output by BBT" is just BBT outputting what is in your library, unaltered; BBT is the conduit of this data, it is not the originator.

Got it. Sure. I am aware that there is no responsibility for BetterBibTeX if you just dump the raw Zotero content.

Roadmap to fix Zotero select links (for me)

I am not sure if it is a proper approach to write a transformation function in eta to convert the link formats and put it into the eta-template in BetterBibTex. It is just a workaround.

On the other hand I need to investigate Zotero 7 first if there is already a solution coming up. Integrating this into the main Zotero API would be much better and then call it from BetterBibTeX or a different solution (see below).

Other Approaches

Is the serialized JSON Exportv already a part of Zoteros API or a product by BetterBibTeX?
For me there is the need for more variations for export translators.

This may go beyond the purpose of BetterBibTeX. Then I have to investigate other ways…

Zutilo Plugin

It can be added to Zutilo, but there is only one eta-template from BetterBibTeX usable at a time.
You can add hotkeys for multiple alternative QuickCopy export translators, but only one using the one eta-template if selected in BetterBibTeX. see: https://github.com/wshanks/Zutilo/blob/master/docs/COMMANDS.md#item-menu-functions -> QuickCopy items:

Python

writing a Jupyter Notebook for developing this in Python using pyzotero. I have some expertise in using Python and Jinja2 templates.

Javascript

My javascript skills are current not sufficient to write stuff from scratch. The eta-template stuff seems OK for me.

@acsr
Copy link
Author

acsr commented Feb 13, 2024

@retorquere wrote

Is \r special to Obsidian in some way? Line endings are usually either \r\n (windows) or \n (all the rest).

My Challenge

I am using Logseq not Obsidian! They use similar Markdown in data on rest (in a file) – but, there is (maybe) a difference how the insertion via clipboard can be handled, because there is some postprocessing of the code from the clipboard trying to interpret tables, lists, links etc. and hiccup syntax as well (a clojurescript dialect to represent html) and so on. I also use a plugin that tries to interpret more clipboard flavors. But this can be deactivated if necessary.

Purpose: adding properties in Logseq Style

Logseq uses ASCII char 10 for regular newlines issued by the Return key.
Every Return usually creates a new block = paragraph.
To add properties line by line inside the same paragraph (similar to the
in html you enter an initial Shift-Return key (ASCII char 13). Inside the paragraph the return key is interpreted different, when the line already contains a property. Then a regular Return is sufficient.

The challenge is that Logseq behaves different if Markdown is typed by hand or pasted from the clipboard.

If you do not provide the proper order and finalize the properties with a regular return, the last property is interpreted different by Logseq. It simply does not catch the clue (or different as expected).

On quoted placeholders

Note: The original purpose of the quoted \r \n \t placeholders (like in regex) ist NOT to mimick the OS flavor of default text file line endings! Is an abstraction to avoid it.
I am not sure if Javascript has a OS abstraction like the Python os module. But this is actually the reason to use seperate placeholders \r and \n for different purposes: \r for the end of a paragraph and \n for a newline inside a paragraph.

Background: Whitespace can hurt!

There is a natural difference between a Line Feed and a Carriage Return since the ages of typewriters.
Why the hell the different Operating Systems have different approaches is another thing.

This is also one of the reasons not every Markdown dialect is offering newlines inside a table cell. some accept a raw <br > some not. Its just to difficult to explain how different OS and keyboards enter ASCII Decimal 10 or ASCII Decimal 13 characters.

A nice wrapup of the topic can be found here: https://blog.codinghorror.com/the-great-newline-schism/

@acsr
Copy link
Author

acsr commented Feb 13, 2024

On the select links for Zotero

I was involved in the translation of the manual for the Zutilo Plugin and proposing some enhancements. I heavily use the Zutilo Plugin to catch Zotero select item links and those to link to collections in Zotero groups. It is not trivial to manage the lifecycle of links spanning more than 20 years.

There was an issue with the select links in your report customizer plugin because of differences in links for groups or the main library. You fixed it soon. I am missing it currently a lot. It has provided those links as well going beyond standard Zotero.

When pasting those links without any dynamic updates, there is also a challenge when the target is gone or moved, changed context or ID and you have no clue left where it belongs to. Using full UUIDs for references like in Logseq does not protect against link loss just against ambigous IDs. Keeping a full history of changes and previous parents or origin UUID bloats the data up, but there is no workaround.

Content Lifecycle Management

I use Zotero since 2009 and try to keep my data alive over long lifecycles. I use my data archives and migrate them to be readable since the 1980ties. It is not trivial and challenging.

The transformation of links and keeping the history is a challenge you also have to tackle with your citations. Reorganizing items can lead to lots of broken relations. They are human readable. But editing useless titles can break everything.

We also have this challenge in Logseq with links across knowledge graphs. Using both Logseq and Zotero is crucial for me today. The referenced data and metadata is stored in Zotero first, the the contents abstractions and notes are exposed into Logseq and complex relations, tags and queries with backlinks and crossreferences can be created there. So the postprocessing of the cited stuff is going beyond Zotero. And it should be kept seperated. Then publishing workflows start and the nightmare continues.

Saving comments over the lifecycle of documents and sharing with different users

When it comes to commenting website content there were nice features in the early Zotero versions. Today we have commenting / Annotations back for PDF. But the workflwos are challenging, when you have to maintain research over decades. On paper ist was more reliable but not so efficient. But to be effective you need to create content that is reliable over time. Or we may loose serious results of the current scientific research.

@acsr
Copy link
Author

acsr commented Feb 21, 2024

Revison 8 fixes the missing separator between multiple selected Zotero items in the created markdown.
There is maybe another issue with relations, I need to test in a second step. See retorquere/zotero-better-bibtex#2791 (comment) and followup for more details

@acsr
Copy link
Author

acsr commented Apr 2, 2024

Revision 10 fixes an obsolete added leading space char in abstract notes (Rev 9 contained a remaining space too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment