[Share] Copy Zotero link #115
Replies: 30 comments 42 replies
-
Firstly, thank you for your amazing plugins! Can someone implement copying the item link to show the item inside of a specific collection? Preferably automatically the one i selected the item from? I was able to construct the functioning select link using the collection-key found in the browser version, but every way i try to implement grabbing it into the script it gives the error "collection is not defined". Can someone more knowledgable help? I just recently moved to Zotero and it is still quite disorienting to see everything i ever saved at once when i click on an item link in obsidian. I can only really function inside of collections and smaller projects. |
Beta Was this translation helpful? Give feedback.
-
Thank you for your efforts! Could someone also implement the ability to copy multiple item links when multiple items are selected? |
Beta Was this translation helpful? Give feedback.
-
This action supports both |
Beta Was this translation helpful? Give feedback.
-
if (linkAction === "auto") {
if (item.isPDFAttachment() && !item.isAnnotation()) {
linkAction = "open-pdf"; Should it be this instead? if (linkAction === "auto") {
if (item.isPDFAttachment() || item.isAnnotation()) {
linkAction = "open-pdf"; |
Beta Was this translation helpful? Give feedback.
-
If I drag and drop a highlight annotation from the PDF viewer to a Zotero note, I get a citations that looks like:
The Is it possible to get a |
Beta Was this translation helpful? Give feedback.
-
Thank you very much. This is great. |
Beta Was this translation helpful? Give feedback.
-
The copy collection link is not working anymore for me. When I run the exact script as above, and use it from a right-click on a collection, I get the link to an item in the collection instead of the collection link.
Is it a Zotero bug? |
Beta Was this translation helpful? Give feedback.
-
I am having the same problem @mjtoraval reported Dec. 10. I also thought I recalled testing this successfully when the script was first written, so I'm not sure what's happened. When I right-click on a collection and choose this script, it creates a link to the first item in the collection, rather than to the collection itself. I use these links internally--to connect one item to a collection of items that relate or support it. |
Beta Was this translation helpful? Give feedback.
-
@mjthoraval and @DonnaCoxBaker, if I understand correctly, you want a link to the collection--not an item in the collection, but the collection itself. If that's correct, I think this will fix the issue. That said, I wasn't able to reproduce the TypeError mentioned here.
|
Beta Was this translation helpful? Give feedback.
-
Zotero7, how to set up an action implementation for actions&tags? After adding an entry to a category, it will automatically add a label with the same category name. When removing this entry, it will not be deleted |
Beta Was this translation helpful? Give feedback.
-
I am not able to copy the link to a saved search collection or any special collection (My Publications, Duplicate Items, Retracted Items, Unfiled Items). Is it possible to get it to work there also? |
Beta Was this translation helpful? Give feedback.
-
I don't know why, but this isn't working for me anymore - in that it creates a link (eg zotero://open-pdf/library/items/CXTEB3BQ) but clicking just switches to Zotero (or opens it), but doesn't open a pdf or take me to an item. Is this a Zotero problem (I'm using version 7.0.0-beta.63+965149fe0)? |
Beta Was this translation helpful? Give feedback.
-
I want to ask that how we can paste a link shown as a picture? |
Beta Was this translation helpful? Give feedback.
-
I adapted this script to also copy the annotation text and comment, when used on annotations. Furthermore, I added the It's necessary to leave Demo: From Zotero to ObsidianIn the demo, the Obsidian plugin Pandoc Reference List is rendering the citekeys as formatted citations in my chosen citation style (APA 7th edition), and opening a tooltip with the formatted bibliography when hovering over the citekey. Other changes
The adapted script// @author windingwind, garth74, FeralFlora
// @link https://github.com/windingwind/zotero-actions-tags/discussions/115
// @usage Select an item in the library and press the assigned shortcut keys
// @update Mon, 22 Jan 2024 00:10:18 GMT (by new Date().toGMTString())
// EDIT THESE SETTINGS
/** @type {string} Name of the field to use as the link text. To use the citation key, set this to "citationKey". */
let linkTextField = "citationKey";
/** @type {'html' | 'md' | 'plain'} What type of link to create. */
let linkType = "md";
/** @type {boolean} If true, make the link specific to the currently selected collection. */
let useColl = false;
/** @type {boolean} If true, use Better Notes zotero://note link when the selected item is a note. */
let useNoteLink = false;
/** @type {'select' | 'open-pdf' | 'auto'} Action of link*/
let linkAction = "auto"; // auto = open-pdf for PDFs and annotations, select for everything else
// END OF EDITABLE SETTINGS
// For efficiency, only execute once for all selected items
if (item) return;
item = items[0];
if (!item && !collection) return "[Copy Zotero Link] item is empty";
if (collection) {
linkAction = "select";
useColl = true;
}
if (linkAction === "auto") {
if (item.isPDFAttachment() || item.isAnnotation()) {
linkAction = "open-pdf";
} else {
linkAction = "select";
}
}
const uriParts = [];
let uriParams = "";
let pageIndex;
let targetItem = item;
if (linkAction === "open-pdf") {
uriParts.push("zotero://open-pdf");
if (item.isRegularItem()) {
targetItem = (await item.getBestAttachments()).find((att) =>
att.isPDFAttachment()
);
} else if (item.isAnnotation()) {
targetItem = item.parentItem;
// If the item is an annotation, we want to open the PDF at the page of the annotation
pageIndex = 1;
try {
pageIndex = JSON.parse(item.annotationPosition).pageIndex + 1;
} catch (e) {
Zotero.warn(e);
}
uriParams = `?page=${pageIndex}&annotation=${item.key}`;
}
} else {
uriParts.push("zotero://select");
if (item?.isAnnotation()) {
targetItem = item.parentItem;
}
}
if (!targetItem && !collection) return "[Copy Zotero Link] item is invalid";
// Get the link text using the `link_text_field` argument
let linkText;
let annotation = "";
let comment = "";
if (collection) {
// When `collection` is truthy, this script was triggered in the collection menu.
// Use collection name if this is a collection link
linkText = collection.name;
} else if (item.isAttachment()) {
// Try to use top-level item for link text
linkText = Zotero.Items.getTopLevel([item])[0].getField(linkTextField);
} else if (item.isAnnotation()) {
// Format link text as Pandoc citation with citekey and pagenumber
linkText = `@${Zotero.Items.getTopLevel([item])[0].getField(linkTextField)}${item.annotationPageLabel ? `, p. ${item.annotationPageLabel}` : `, p. ${pageIndex}`}`;
// Define comment and annotation, if present, including trailing space - otherwise empty string.
comment = item.annotationComment ? `**${item.annotationComment}**: ` : "";
annotation = item.annotationText ? `${item.annotationText} ` : "";
} else {
// Use the item's field
linkText = item.getField(linkTextField);
}
// Add the library or group URI part (collection must go first)
let libraryType = (collection || item).library.libraryType;
if (libraryType === "user") {
uriParts.push("library");
} else {
uriParts.push(
`groups/${Zotero.Libraries.get((collection || item).libraryID).groupID}`
);
}
// If useColl, make the link collection specific
if (useColl) {
// see https://forums.zotero.org/discussion/73893/zotero-select-for-collections
let coll = collection || Zotero.getActiveZoteroPane().getSelectedCollection();
// It's possible that a collection isn't selected. When that's the case,
// this will fall back to the typical library behavior.
// If a collection is selected, add the collections URI part
if (!!coll) uriParts.push(`collections/${coll.key}`);
}
if (!collection) {
// Add the item URI part
uriParts.push(`items/${targetItem.key}`);
}
// Join the parts together
let uri = uriParts.join("/");
// Add the URI parameters
if (uriParams) {
uri += uriParams;
}
if (useNoteLink && item?.isNote() && Zotero.BetterNotes) {
uri = Zotero.BetterNotes.api.convert.note2link(item);
}
// Format the link and copy it to the clipboard
const clipboard = new Zotero.ActionsTags.api.utils.ClipboardHelper();
if (linkType == "html") {
clipboard.addText(`<a href="${uri}">${linkText}</a>`, "text/unicode");
} else if (linkType == "md") {
clipboard.addText(`${comment}${annotation}[${linkText}](${uri})`, "text/unicode");
} else {
clipboard.addText(uri, "text/unicode");
}
clipboard.copy();
return `[Copy Zotero Link] link ${uri} copied.`; |
Beta Was this translation helpful? Give feedback.
-
Major RewriteGiven that Zotero is making its URL protocol more powerful and adding more document types, I've rewritten the script to make it easier to extend and edit. It is a major rewrite, though, so if people can test it out to ensure it works as expected, that'd be great. Additional feature
A note about annotationsI added the New Script// @author windingwind, garth74, FeralFlora, kassiansun
// @link https://github.com/windingwind/zotero-actions-tags/discussions/115
// @usage Select an item in the library and press the assigned shortcut keys
// @update Tue, 30 Apr 2024 15:42:21 GMT (by new Date().toGMTString())
// @note https://github.com/zotero/zotero/blob/main/components/zotero-protocol-handler.js
// Only execute once for all selected items
if (item) return;
// EDIT THESE SETTINGS
/** Name of the field to use as the link text. If '@citationKey' is used, the
* link will be formatted using a pandoc compatible style.
* @type {string} */
const linkTextField = "@citationKey";
/** @type {'html' | 'md' | 'plain'} What type of link to create. */
const linkType = "md";
/** @type {boolean} If true, make the link specific to the selected collection. */
const useColl = true;
/** @type {boolean} If true, use Better Notes zotero://note link when the selected item is a note. */
const useNoteLink = false;
/** @type {'select' | 'open-pdf' | 'auto'} Action of link */
const linkAction = "auto"; // auto = open-pdf for PDFs and annotations, select for everything else
// END OF EDITABLE SETTINGS
// ========================================================================== //
// Functions used to create a uniform object
// ========================================================================== //
async function _create_HandledObject(item, coll) {
if (coll) {
// When `collection` is truthy, this script has been triggered from the
// collection menu, implying that the link should be to the collection. However,
// `item` can still have a value, so let's just handle `collection` links
// separately.
return _handleCollection(coll);
}
if (item) {
let path = "items";
if (useColl) {
let coll = Zotero.getActiveZoteroPane().getSelectedCollection();
if (coll) path = `collections/${coll.key}/items`;
}
path = `${_getLibraryOrGroupPart(item)}/${path}`;
// Is it a regular item?
if (item.isRegularItem()) return await _handleRegularItem(item, path);
// Is it a note?
if (item.isNote()) return _handleNote(item, path);
// Is it a pdf?
if (item.isPDFAttachment()) return _handlePDF(item, path);
// Is it an annotation?
if (item.isAnnotation()) return _handleAnnotation(item, path);
// Extend with new types
throw `[Copy Zotero Link] unknown item type: ${item.itemType}`;
}
// How'd you get here?
throw "[Copy Zotero Link] item is empty";
}
/*
The functions in this section return a _HandledObject to simplify all the other
functions.
*/
class _HandledObject {
constructor({ obj, type, link, linkText }) {
this.obj = obj;
this.type = type;
this.link = link;
this.linkText = linkText;
}
}
function _handleCollection(obj) {
let libOrGroup = _getLibraryOrGroupPart(obj);
return new _HandledObject({
obj: obj,
type: "collection",
link: `zotero://select/${libOrGroup}/collections/${obj.key}`,
linkText: obj.name,
});
}
async function _handleRegularItem(obj, path) {
let action = _inferLinkAction("select");
let pdf;
if (action === "open-pdf") {
pdf = (await obj.getBestAttachments()).find((att) => att.isPDFAttachment());
if (!pdf) throw "[Copy Zotero Link] item does not have a PDF.";
}
return new _HandledObject({
obj: obj,
type: "item",
link: `zotero://${action}/${path}/${(pdf || obj).key}`,
linkText: _getField(obj, linkTextField),
});
}
function _handleNote(obj, path) {
let action = _inferLinkAction("select");
return new _HandledObject({
obj: obj,
type: "note",
link:
useNoteLink && Zotero.BetterNotes // top-level
? Zotero.BetterNotes.api.convert.note2link(obj)
: `zotero://${action}/${path}/${obj.key}`,
linkText: _getField(obj, linkTextField),
});
}
function _handlePDF(obj, path) {
let action = _inferLinkAction("open-pdf");
return new _HandledObject({
obj: obj,
type: "pdf",
link: `zotero://${action}/${path}/${obj.key}`,
linkText: _getField(obj, linkTextField),
});
}
function _handleAnnotation(obj, path) {
let action = _inferLinkAction("open-pdf");
let pageIndex = 1;
try {
pageIndex = JSON.parse(obj.annotationPosition).pageIndex + 1;
} catch (e) {
Zotero.warn(e);
}
let pageParam = `page=${pageIndex}`;
if (Number.isNaN(pageIndex)) {
pageParam = `cfi=${JSON.parse(obj.annotationPosition).pageIndex}`;
}
return new _HandledObject({
obj: obj,
type: "annotation",
link: `zotero://${action}/${path}/${obj.parentItem.key}?${pageParam}&annotation=${obj.key}`,
linkText: _getAnnotationText(obj),
});
}
function _getAnnotationText(item) {
switch (linkTextField) {
case "@citationKey":
// pandoc compatible formatting
let page = item.annotationPageLabel || item.pageIndex;
return `${_getField(item, "@citationKey")}, p. ${page}`;
default:
return `${item.parentItem.getField(linkTextField)}(${
item.annotationComment || item.annotationText || "annotation"
})`;
}
}
// ========================================================================== //
// helpers
function _inferLinkAction(fallback) {
return linkAction === "auto" ? fallback : linkAction;
}
function _getLibraryOrGroupPart(obj) {
if (obj.library.libraryType === "user") return "library";
return `groups/${Zotero.Libraries.get(obj.libraryID).groupID}`;
}
function _getField(item, field) {
if (item.isAttachment() || item.isAnnotation())
item = Zotero.Items.getTopLevel([item])[0];
if (field === "@citationKey") return "@" + item.getField("citationKey");
return item.getField(field);
}
function _getFormattedLink(handledObject) {
let rawLink = handledObject.link;
let linkText = handledObject.linkText;
switch (linkType) {
case "html":
return `<a href="${rawLink}">${linkText}</a>`;
case "md":
return `[${linkText}](${rawLink})`;
case "plain":
return rawLink;
default:
throw `[Copy Zotero Link] Unrecognized linkType: ${linkType}`;
}
}
// ========================================================================== //
// Main Invocation
async function copyLink(item, coll) {
try {
let handledObject = await _create_HandledObject(item, coll);
let formattedLink = _getFormattedLink(handledObject);
const clipboard = new Zotero.ActionsTags.api.utils.ClipboardHelper();
clipboard.addText(formattedLink, "text/unicode");
clipboard.copy();
return `[Copy Zotero Link] ${handledObject.link}`;
} catch (err) {
return err;
}
}
return await copyLink(items[0], collection); |
Beta Was this translation helpful? Give feedback.
-
There is a strange behaviour I stumbled upon. I can copy a dircet link for annotations via right click menu but when I use shortcut it just gives me the link to the PDF. Earlier this was working. My editable settings are as follows: ` // @author windingwind, garth74 // EDIT THESE SETTINGS /** @type {string} Name of the field to use as the link text. To use the citation key, set this to "citationKey". */ /** @type {'html' | 'md' | 'plain'} What type of link to create. */ /** @type {boolean} If true, make the link specific to the currently selected collection. */ /** @type {boolean} If true, use Better Notes zotero://note link when the selected item is a note. */ /** @type {'select' | 'open-pdf' | 'auto'} Action of link*/ |
Beta Was this translation helpful? Give feedback.
-
@windingwind. I see that there have been a lot of code changes presented in the discussion. Are we to assume the code at the top is the one to use, or should we be taking code from the discussions? |
Beta Was this translation helpful? Give feedback.
-
The link to an annotation copied from a collection does not work: Is that a bug from the script, the plugin or Zotero? A click on the link generates the following output: |
Beta Was this translation helpful? Give feedback.
-
I have a simplier version of this action. Unlike highlighting, when I quick-copy Zotero 7's underlined annotation, I can only obtain a link to the literature but not the annotation itself. Therefore, I have simplified this action to a version that extracts the link for any type of item in Zotero:
Then, I can apply this action on any item (like a underlined annotation), extract its link, then copy its to other APPs so that I can seamlessly jump to that specific item from any other application. For efficient note-taking, I designed a Quicker action that utilizes the link stored in the clipboard to replace the link within a Zotero quick-copy style markdown format HERE. Free to use my solution if you like. |
Beta Was this translation helpful? Give feedback.
-
In this code snippet, it seems I haven't come across how to get the currently selected text in a PDF file. How can one implement getting the 'selected text'? |
Beta Was this translation helpful? Give feedback.
-
As I seem to be a complete layman but really would like to add some features to the new version of ZOTERO, I would be very very very grateful, if any one of you would be kind enough to help me with a set that I could simply copy and paste into the »data«-field? The following actions I would like to integrate with my own shortcuts to speed up my work: (a) »create link of marked item« (such as titles, notes etc.) to connect data inside my database Best regards from Germany, where it is so hot, that my English is even worse than usually (cheap excuse, I know) :) |
Beta Was this translation helpful? Give feedback.
-
Greetings I am using Action Tags 2.0.0, Zotero 7.0.1, and a Mac with Sonoma 14.5. When I try to use Copy Zotero Link I get this error: Script Error: redeclaration of let linkTextField Any thoughts? |
Beta Was this translation helpful? Give feedback.
-
OK never mind - I see the issue. I accidentally pasted the script twice into the Data field.. works fine now. Thanks for a great script. |
Beta Was this translation helpful? Give feedback.
-
The Actions Tags extension/ecosystem is such a useful resource, thank you. Just an FYI in case something's happened since the upgrade to Zotero 7, but this particular script doesn't seem to work for me - I've tried the first and last code versions listed in the threads above, and neither shows the I can't script, sorry, so not sure if it's a mistake I'm making (though I've successfully made a couple of other Action Tags scripts work), or something about Zotero 7. |
Beta Was this translation helpful? Give feedback.
-
Hi Garrett,
Thanks so much for your help with this. I’ve copied your code at line 115 (using the ‘Copy’ button in the thread) and pasted it into the Action in Zotero > Settings > Actions & Tags.
Still no luck unfortunately. When I try pasting (into TextEdit on my Mac), it’s returning the script text, presumably because the clipboard hasn’t been overwritten by any output from the Action.
This seems to be similar to the issue reported by mjthoraval on April 13.
Am I making a mistake in the way I’m supposed to use the Action?
FYI I’m using Zotero 7.0.2 and Actions & Tags 2.0.0 (22 August 2024) on Mac Sonoma 14.6.1.
Thanks again for all your help!
On 26 Aug 2024, at 7:01 AM, Garrett Shipley ***@***.***> wrote:
Try using the major rewrite one that I posted a few months ago. The URL is #115 (comment)<#115 (comment)>.
If that doesn't work, let me know.
—
Reply to this email directly, view it on GitHub<#115 (reply in thread)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/BKXCUEYC7DGYKNZ3UDY26HLZTJA4LAVCNFSM6AAAAAA4XXGQ56VHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTANBUGUYDENY>.
You are receiving this because you commented.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Hello, I am using the 115 refactored version, The normal format is as follows:
I used AI to modify the code, but there was no actual effect. The following is a little information I collected `` ` For EPUB, it is best to use CFI ( annotation.position.value). For snapshots, we should use JSON.stringify(annotation.position).Large noise but essential -Pagelabel for EPUB, it is usually empty (and can be changed), and for snapshots, it is always empty. `` ` Can you update the code to meet the needs of replication? |
Beta Was this translation helpful? Give feedback.
-
Hello, I am using the 115 refactored version, I load the generated link into my obsidian note. When I'm clicking on the link it will open only the biblography but not the pdf instead. How can I handle this issue? best regards! |
Beta Was this translation helpful? Give feedback.
-
Hello,I'm using the 115 version script。When I copy the link from zotero, the anchor text is always "@",just as shown below:
Could the anchor text be the selected item's title or the selected annotation text? |
Beta Was this translation helpful? Give feedback.
-
Hello - if this is off topic please let me know. Everything is working fine for me with the plugin. The features I really want are a) when a link is greated, have an additional context menu item that formats the link in text only, so it can be pasted in to a rtf document. b) when the zotero://open-pdf/library/items/9EAWYJY8?page=2&annotation=12345 link is clicked in another application, it actually selects the annotation 12345 as opposed to merely to navigating to it, and lastly c) similarly with web pages - the format is - zotero://open-pdf/library/items/9EAWYJY8?page=NaN&annotation=67890 and the action merely seems to open the web page capture where it was last opened. Maybe there is a way of the plugin having a way of doing as per b) above without having to change Zotero itself ? |
Beta Was this translation helpful? Give feedback.
-
Description
Copy Zotero link of the selected item/PDF/note/annotation/collection.
zotero://select
,zotero://open-pdf
, and Better Notes linkzotero://note
markdown
/html
/plain-text
Action Settings
Operation: Script
Data:
Beta Was this translation helpful? Give feedback.
All reactions