From c9e90417ee3ff3ecd429577ae502c2d3e75d2731 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 16 May 2020 02:00:25 -0400 Subject: [PATCH] Improve zotero://open-pdf handling - Support Adobe Acrobat on macOS, with page number support via System Events. Tested with Acrobat Reader, but hopefully functional with non-Reader versions as well - Use full path to configured .app via AppleScript rather than a hard-coded name, in case there are multiple versions on the system - Simplify code and improve logging --- chrome/content/zotero/xpcom/openPDF.js | 121 +++++++++++++++---------- 1 file changed, 74 insertions(+), 47 deletions(-) diff --git a/chrome/content/zotero/xpcom/openPDF.js b/chrome/content/zotero/xpcom/openPDF.js index 3076eda554..f653dc9237 100644 --- a/chrome/content/zotero/xpcom/openPDF.js +++ b/chrome/content/zotero/xpcom/openPDF.js @@ -27,37 +27,30 @@ Zotero.OpenPDF = { openToPage: async function (path, page) { var handler = Zotero.Prefs.get("fileHandler.pdf"); var opened = false; + + if (handler) { + Zotero.debug(`Custom handler is ${handler}`); + } + if (Zotero.isMac) { - if (handler.includes('Preview')) { - this._openWithPreview(path, page); - } - else if (handler.includes('Skim')) { - this._openWithSkim(path, page); - } - else if (handler.includes('PDF Expert')) { - this._openWithPDFExpert(path, page); - } - else { + if (!this._openWithHandlerMac(handler, path, page)) { // Try to detect default app handler = this._getPDFHandlerName(); - Zotero.debug(`Handler is ${handler}`); - if (handler && handler == 'Skim') { - this._openWithSkim(path, page); - } - else if (handler && handler == 'PDF Expert') { - this._openWithPDFExpert(path, page); - } - // Fall back to Preview - else { + if (!this._openWithHandlerMac(handler, path, page)) { + // Fall back to Preview this._openWithPreview(path, page); } } opened = true; } else if (Zotero.isWin) { - handler = handler || this._getPDFHandlerWindows(); + if (!handler) { + handler = this._getPDFHandlerWindows(); + if (handler) { + Zotero.debug(`Default handler is ${handler}`); + } + } if (handler) { - Zotero.debug("Handler is " + handler); // Include flags to open the PDF on a given page in various apps // // Adobe Acrobat: http://partners.adobe.com/public/developer/en/acrobat/PDFOpenParameters.pdf @@ -71,28 +64,27 @@ Zotero.OpenPDF = { } } else if (Zotero.isLinux) { - if (handler.includes('evince') || handler.includes('okular')) { + if (!handler) { + handler = await this._getPDFHandlerLinux(); + if (handler) { + Zotero.debug(`Resolved handler is ${handler}`); + } + } + if (handler && (handler.includes('evince') || handler.includes('okular'))) { this._openWithEvinceOrOkular(handler, path, page); opened = true; } + // Fall back to okular and then evince if unknown handler + else if (await OS.File.exists('/usr/bin/okular')) { + this._openWithEvinceOrOkular('/usr/bin/okular', path, page); + opened = true; + } + else if (await OS.File.exists('/usr/bin/evince')) { + this._openWithEvinceOrOkular('/usr/bin/evince', path, page); + opened = true; + } else { - let handler = await this._getPDFHandlerLinux(); - if (handler.includes('evince') || handler.includes('okular')) { - this._openWithEvinceOrOkular(handler, path, page); - opened = true; - } - // Fall back to okular and then evince if unknown handler - else if (await OS.File.exists('/usr/bin/okular')) { - this._openWithEvinceOrOkular('/usr/bin/okular', path, page); - opened = true; - } - else if (await OS.File.exists('/usr/bin/evince')) { - this._openWithEvinceOrOkular('/usr/bin/evince', path, page); - opened = true; - } - else { - Zotero.debug("No handler found"); - } + Zotero.debug("No handler found"); } } return opened; @@ -140,8 +132,31 @@ Zotero.OpenPDF = { // // Mac // + _openWithHandlerMac: function (handler, path, page) { + if (!handler) { + return false; + } + if (handler.includes('Preview')) { + this._openWithPreview(path, page); + return true; + } + if (handler.includes('Adobe Acrobat')) { + this._openWithAcrobat(handler, path, page); + return true; + } + if (handler.includes('Skim')) { + this._openWithSkim(handler, path, page); + return true; + } + if (handler.includes('PDF Expert')) { + this._openWithPDFExpert(handler, path, page); + return true; + } + return false; + }, + _openWithPreview: async function (filePath, page) { - await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', 'Preview', filePath]); + await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', "Preview", filePath]); // Go to page using AppleScript let args = [ '-e', 'tell app "Preview" to activate', @@ -152,24 +167,36 @@ Zotero.OpenPDF = { await Zotero.Utilities.Internal.exec('/usr/bin/osascript', args); }, - _openWithSkim: async function (filePath, page) { + _openWithAcrobat: async function (appPath, filePath, page) { + await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', appPath, filePath]); + // Go to page using AppleScript + let args = [ + '-e', `tell app "${appPath}" to activate`, + '-e', 'tell app "System Events" to keystroke "n" using {command down, shift down}', + '-e', `tell app "System Events" to keystroke "${page}"`, + '-e', 'tell app "System Events" to keystroke return' + ]; + await Zotero.Utilities.Internal.exec('/usr/bin/osascript', args); + }, + + _openWithSkim: async function (appPath, filePath, page) { // Escape double-quotes in path var quoteRE = /"/g; filePath = filePath.replace(quoteRE, '\\"'); let filename = OS.Path.basename(filePath).replace(quoteRE, '\\"'); let args = [ - '-e', 'tell app "Skim" to activate', - '-e', `tell app "Skim" to open "${filePath}"` + '-e', `tell app "${appPath}" to activate`, + '-e', `tell app "${appPath}" to open "${filePath}"` ]; - args.push('-e', `tell document "${filename}" of application "Skim" to go to page ${page}`); + args.push('-e', `tell document "${filename}" of application "${appPath}" to go to page ${page}`); await Zotero.Utilities.Internal.exec('/usr/bin/osascript', args); }, - _openWithPDFExpert: async function (filePath, page) { - await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', 'PDF Expert', filePath]); + _openWithPDFExpert: async function (appPath, filePath, page) { + await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', handlers, filePath]); // Go to page using AppleScript (same as Preview) let args = [ - '-e', 'tell app "PDF Expert" to activate', + '-e', `tell app "${appPath}" to activate`, '-e', 'tell app "System Events" to keystroke "g" using {option down, command down}', '-e', `tell app "System Events" to keystroke "${page}"`, '-e', 'tell app "System Events" to keystroke return'