diff --git a/chrome/content/zotero/standalone/standalone.js b/chrome/content/zotero/standalone/standalone.js
index 117102006d..36f628ed2c 100644
--- a/chrome/content/zotero/standalone/standalone.js
+++ b/chrome/content/zotero/standalone/standalone.js
@@ -289,21 +289,28 @@ const ZoteroStandalone = new function () {
this.onManageAttachmentsMenuOpen = function () {
// Convert Linked Files to Stored Files
- var active = false;
+ var enableConvertToStored = false;
try {
- let zp = Zotero.getActiveZoteroPane();
- if (zp) {
- active = !!zp.getSelectedItems().filter((item) => {
- return item.isLinkedFileAttachment()
- || (item.isRegularItem()
- && item.getAttachments()
- .map(id => Zotero.Items.get(id))
- .some(att => att.isLinkedFileAttachment()));
- }).length;
- }
+ enableConvertToStored = ZoteroPane.getSelectedItems().some((item) => {
+ return item.isLinkedFileAttachment()
+ || (item.isRegularItem()
+ && Zotero.Items.get(item.getAttachments())
+ .some(att => att.isLinkedFileAttachment()));
+ });
}
catch (e) {}
- this.updateMenuItemEnabled('file-menuitem-convert-to-stored', active);
+ this.updateMenuItemEnabled('file-menuitem-convert-to-stored', enableConvertToStored);
+
+ var enableNormalizeAttachmentTitles = false;
+ try {
+ enableNormalizeAttachmentTitles = ZoteroPane.getSelectedItems()
+ .some(item => item.isFileAttachment()
+ || (item.isRegularItem()
+ && Zotero.Items.get(item.getAttachments())
+ .some(att => att.isFileAttachment())));
+ }
+ catch (e) {}
+ this.updateMenuItemEnabled('file-menuitem-normalize-attachment-titles', enableNormalizeAttachmentTitles);
};
@@ -320,6 +327,9 @@ const ZoteroStandalone = new function () {
case 'convert-to-stored':
ZoteroPane.convertLinkedFilesToStoredFiles();
break;
+ case 'normalize-attachment-titles':
+ ZoteroPane.normalizeAttachmentTitles();
+ break;
}
};
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
index e4635632ed..6a71edf4eb 100644
--- a/chrome/content/zotero/xpcom/data/item.js
+++ b/chrome/content/zotero/xpcom/data/item.js
@@ -4009,7 +4009,7 @@ Zotero.Item.prototype._getDefaultTitleForAttachmentContentType = function () {
};
-Zotero.Item.prototype.setAutoAttachmentTitle = function ({ ignoreAutoRenamePrefs } = {}) {
+Zotero.Item.prototype.setAutoAttachmentTitle = function ({ ignoreAutoRenamePrefs, forceFirstOfType } = {}) {
if (!this.isAttachment()) {
throw new Error("setAutoAttachmentTitle() can only be called on attachment items");
}
@@ -4019,9 +4019,12 @@ Zotero.Item.prototype.setAutoAttachmentTitle = function ({ ignoreAutoRenamePrefs
// If this is the only attachment of its type on the parent item and the
// file is being renamed, give it a default title ("PDF", "Webpage", etc.)
- let isFirstOfType = this.parentItemID
- && this.parentItem.getFileAttachmentsWithContentType(this.attachmentContentType)
- .every(item => item === this);
+ let isFirstOfType = forceFirstOfType === undefined
+ ? (this.parentItemID
+ && this.parentItem.getFileAttachmentsWithContentType(this.attachmentContentType)
+ .every(item => item === this)
+ )
+ : forceFirstOfType;
let isBeingRenamed = ignoreAutoRenamePrefs || Zotero.Attachments.shouldAutoRenameAttachment(this);
if (isFirstOfType && isBeingRenamed) {
let defaultTitle = this._getDefaultTitleForAttachmentContentType();
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index 7befc13501..e8f92151b8 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -6325,6 +6325,45 @@ var ZoteroPane = new function () {
}
};
+ this.normalizeAttachmentTitles = async function () {
+ let result = Zotero.Prompt.confirm({
+ title: Zotero.getString('normalize-attachment-titles-title'),
+ text: Zotero.getString('normalize-attachment-titles-text'),
+ button0: Zotero.getString('general-continue'),
+ button1: Zotero.Prompt.BUTTON_TITLE_CANCEL,
+ button2: Zotero.getString('general.moreInformation'),
+ });
+ if (result == 1) {
+ return;
+ }
+ if (result == 2) {
+ Zotero.launchURL('https://www.zotero.org/support/kb/attachment_title_vs_filename');
+ return;
+ }
+ let attachments = new Set(this.getSelectedItems().flatMap((item) => {
+ if (item.isRegularItem()) {
+ return Zotero.Items.get(item.getAttachments());
+ }
+ if (item.isAttachment()) {
+ return [item];
+ }
+ return [];
+ }));
+ await Zotero.DB.executeTransaction(async () => {
+ for (let attachment of attachments) {
+ if (attachment.getField('title').replace(/\.[^.]+$/, '') !== attachment.attachmentFilename.replace(/\.[^.]+$/, '')) {
+ Zotero.debug(`Skipping attachment with modified title: ${attachment.getField('title')}`);
+ continue;
+ }
+
+ let forceFirstOfType = !!attachment.parentItemID
+ && await attachment.parentItem.getBestAttachment() === attachment;
+ attachment.setAutoAttachmentTitle({ forceFirstOfType });
+ await attachment.save();
+ }
+ });
+ };
+
var itemReadTimeout = null;
this.startItemReadTimeout = function (feedItemID) {
if (itemReadTimeout) {
diff --git a/chrome/content/zotero/zoteroPane.xhtml b/chrome/content/zotero/zoteroPane.xhtml
index fc83745c7f..05f44865e2 100644
--- a/chrome/content/zotero/zoteroPane.xhtml
+++ b/chrome/content/zotero/zoteroPane.xhtml
@@ -743,6 +743,9 @@
+
diff --git a/chrome/locale/en-US/zotero/zotero.ftl b/chrome/locale/en-US/zotero/zotero.ftl
index 9a191bdeee..8fa9ca827c 100644
--- a/chrome/locale/en-US/zotero/zotero.ftl
+++ b/chrome/locale/en-US/zotero/zotero.ftl
@@ -62,6 +62,7 @@ general-next = Next
general-learn-more = Learn More
general-warning = Warning
general-type-to-continue = Type “{ $text }” to continue.
+general-continue = Continue
general-red = Red
general-orange = Orange
@@ -808,3 +809,12 @@ long-tag-fixer-window-title =
.title = Split Tags
long-tag-fixer-button-dont-split =
.label = Don’t Split
+
+menu-normalize-attachment-titles =
+ .label = Normalize Attachment Titles…
+normalize-attachment-titles-title = Normalize Attachment Titles
+normalize-attachment-titles-text = { -app-name } automatically renames files on disk using parent item metadata, but it uses separate, simpler titles such as “Full Text PDF”, “Preprint PDF”, or “PDF” for primary attachments to keep the items list cleaner and avoid duplicating information.
+
+ In older versions of { -app-name }, as well as when using certain plugins, attachment titles could be changed unnecessarily to match the filenames.
+
+ Would you like to update the selected attachments to use simpler titles? Only primary attachments with titles that match the filename will be changed.