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