diff --git a/chrome/content/zotero/preferences/preferences_general.js b/chrome/content/zotero/preferences/preferences_general.js
index 28d16f9ac5..cf0f48ed78 100644
--- a/chrome/content/zotero/preferences/preferences_general.js
+++ b/chrome/content/zotero/preferences/preferences_general.js
@@ -40,8 +40,10 @@ Zotero_Preferences.General = {
'zotero.preferences.launchNonNativeFiles', Zotero.appName
);
}
- var menuitem = document.getElementById('fileHandler-internal');
- menuitem.setAttribute('label', Zotero.appName);
+ var menuitems = document.querySelectorAll('.fileHandler-internal');
+ for (let menuitem of menuitems) {
+ menuitem.setAttribute('label', Zotero.appName);
+ }
// Set OpenURL resolver drop-down to last-known name
if (Zotero.Prefs.get('openURL.resolver')) {
@@ -168,62 +170,65 @@ Zotero_Preferences.General = {
},
_updateFileHandlerUI: function () {
- var handler = Zotero.Prefs.get('fileHandler.pdf');
- var menulist = document.getElementById('fileHandler-pdf');
- var customMenuItem = document.getElementById('fileHandler-custom');
- var inNewWindowCheckbox = document.getElementById('open-reader-in-new-window');
-
- // System default
- if (handler == 'system') {
- customMenuItem.hidden = true;
- menulist.selectedIndex = 1;
- inNewWindowCheckbox.disabled = true;
- }
- // Custom handler
- else if (handler) {
- let icon;
- try {
- let urlspec = Zotero.File.pathToFileURI(handler);
- icon = "moz-icon://" + urlspec + "?size=16";
- }
- catch (e) {
- Zotero.logError(e);
- }
+ function update(type) {
+ let handler = Zotero.Prefs.get('fileHandler.' + type);
+ let menulist = document.getElementById('fileHandler-' + type);
+ var customMenuItem = menulist.querySelector('.fileHandler-custom');
- let handlerFilename = OS.Path.basename(handler);
- if (Zotero.isMac) {
- handlerFilename = handlerFilename.replace(/\.app$/, '');
+ // System default
+ if (handler == 'system') {
+ customMenuItem.hidden = true;
+ menulist.selectedIndex = 1;
}
- customMenuItem.setAttribute('label', handlerFilename);
- if (icon) {
- customMenuItem.className = 'menuitem-iconic';
- customMenuItem.setAttribute('image', icon);
- }
- else {
- customMenuItem.className = '';
- }
- customMenuItem.hidden = false;
- menulist.selectedIndex = 2;
- inNewWindowCheckbox.disabled = true;
+ // Custom handler
+ else if (handler) {
+ let icon;
+ try {
+ let urlspec = Zotero.File.pathToFileURI(handler);
+ icon = "moz-icon://" + urlspec + "?size=16";
+ }
+ catch (e) {
+ Zotero.logError(e);
+ }
- // There's almost certainly a better way to do this...
- // but why doesn't the icon just behave by default?
- menulist.shadowRoot.querySelector('[part="icon"]').style.height = '16px';
- }
- // Zotero
- else {
- let menuitem = document.getElementById('fileHandler-internal');
- menulist.selectedIndex = 0;
- customMenuItem.hidden = true;
- inNewWindowCheckbox.disabled = false;
+ let handlerFilename = OS.Path.basename(handler);
+ if (Zotero.isMac) {
+ handlerFilename = handlerFilename.replace(/\.app$/, '');
+ }
+ customMenuItem.setAttribute('label', handlerFilename);
+ if (icon) {
+ customMenuItem.className = 'menuitem-iconic';
+ customMenuItem.setAttribute('image', icon);
+ }
+ else {
+ customMenuItem.className = '';
+ }
+ customMenuItem.hidden = false;
+ menulist.selectedIndex = 2;
+
+ // There's almost certainly a better way to do this...
+ // but why doesn't the icon just behave by default?
+ menulist.shadowRoot.querySelector('[part="icon"]').style.height = '16px';
+ }
+ // Zotero
+ else {
+ menulist.selectedIndex = 0;
+ customMenuItem.hidden = true;
+ }
}
+
+ update('pdf');
+ update('epub');
+ update('snapshot');
+ var inNewWindowCheckbox = document.getElementById('open-reader-in-new-window');
+ inNewWindowCheckbox.disabled = ['pdf', 'epub', 'snapshot'].every(type => Zotero.Prefs.get('fileHandler.' + type));
},
_getFileHandlerPref: function (type) {
- if (type != 'pdf') {
+ if (type != 'pdf' && type != 'epub' && type != 'snapshot') {
throw new Error(`Unknown file type ${type}`);
}
- return 'fileHandler.pdf';
+ return 'fileHandler.' + type;
},
handleOpenURLPopupShowing: async function (event) {
diff --git a/chrome/content/zotero/preferences/preferences_general.xhtml b/chrome/content/zotero/preferences/preferences_general.xhtml
index 9cea897658..a36d6e74ea 100644
--- a/chrome/content/zotero/preferences/preferences_general.xhtml
+++ b/chrome/content/zotero/preferences/preferences_general.xhtml
@@ -49,26 +49,48 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ &zotero.preferences.fileHandler.openPDFsUsing;
+
+
+
+
+
+
+
+
+ &zotero.preferences.fileHandler.openEbooksUsing;
+
+
+
+
+
+
+
+
+ &zotero.preferences.fileHandler.openSnapshotsUsing;
+
+
+
+
+
+
+
+
+
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index 21b14e171a..5ff5eed13a 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -4722,9 +4722,20 @@ var ZoteroPane = new function()
if (['application/pdf', 'application/epub+zip', 'text/html'].includes(contentType)) {
let item = await Zotero.Items.getAsync(itemID);
let library = Zotero.Libraries.get(item.libraryID);
- let pdfHandler = Zotero.Prefs.get("fileHandler.pdf");
+ let type;
+ if (contentType === 'application/pdf') {
+ type = 'pdf';
+ }
+ else if (contentType === 'application/epub+zip') {
+ type = 'epub';
+ }
+ else {
+ type = 'snapshot';
+ }
+ let handler = Zotero.Prefs.get('fileHandler.' + type);
+
// Zotero PDF reader
- if (!pdfHandler) {
+ if (!handler) {
let openInWindow = Zotero.Prefs.get('openReaderInNewWindow');
let useAlternateWindowBehavior = event?.shiftKey || extraData?.forceAlternateWindowBehavior;
if (useAlternateWindowBehavior) {
@@ -4740,8 +4751,9 @@ var ZoteroPane = new function()
);
return;
}
- // Try to open external reader to page number if specified
- else {
+ // Try to open external PDF reader to page number if specified
+ // TODO: Implement for EPUBs if readers support it
+ else if (type == 'pdf') {
let pageIndex = extraData?.location?.position?.pageIndex;
if (pageIndex !== undefined) {
await Zotero.OpenPDF.openToPage(
@@ -4753,17 +4765,17 @@ var ZoteroPane = new function()
}
// Custom PDF handler
// TODO: Remove this and unify with Zotero.OpenPDF
- if (pdfHandler != 'system') {
+ if (handler != 'system') {
try {
- if (await OS.File.exists(pdfHandler)) {
- Zotero.launchFileWithApplication(path, pdfHandler);
+ if (await OS.File.exists(handler)) {
+ Zotero.launchFileWithApplication(path, handler);
return;
}
}
catch (e) {
Zotero.logError(e);
}
- Zotero.logError(`${pdfHandler} not found -- launching file normally`);
+ Zotero.logError(`${handler} not found -- launching file normally`);
}
}
Zotero.launchFile(path);
diff --git a/chrome/locale/en-US/zotero/preferences.dtd b/chrome/locale/en-US/zotero/preferences.dtd
index 143ad8ca69..ea3590bc8f 100644
--- a/chrome/locale/en-US/zotero/preferences.dtd
+++ b/chrome/locale/en-US/zotero/preferences.dtd
@@ -17,8 +17,10 @@
+
+
-
+
diff --git a/chrome/skin/default/zotero/preferences.css b/chrome/skin/default/zotero/preferences.css
index 0a491fdf65..b7605120f7 100644
--- a/chrome/skin/default/zotero/preferences.css
+++ b/chrome/skin/default/zotero/preferences.css
@@ -278,6 +278,15 @@ button {
margin-inline-start: 2em;
}
+.fileHandler-menus {
+ display: grid;
+ grid-template-columns: max-content max-content;
+ align-items: center;
+ justify-content: start;
+ column-gap: 1em;
+ margin-top: 0.5em;
+}
+
.fileHandler-menu .menulist-icon {
height: 16px;
}
diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js
index 913fd1c02e..46c8fae615 100644
--- a/defaults/preferences/zotero.js
+++ b/defaults/preferences/zotero.js
@@ -186,6 +186,8 @@ pref("extensions.zotero.purge.tags", false);
pref("extensions.zotero.pane.persist", "");
pref("extensions.zotero.fileHandler.pdf", "");
+pref("extensions.zotero.fileHandler.epub", "");
+pref("extensions.zotero.fileHandler.snapshot", "");
pref("extensions.zotero.openReaderInNewWindow", false);
// File/URL opening executable if launch() fails