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
This commit is contained in:
Dan Stillman 2020-05-16 02:00:25 -04:00
parent 6676ece3e4
commit c9e90417ee

View file

@ -27,37 +27,30 @@ Zotero.OpenPDF = {
openToPage: async function (path, page) { openToPage: async function (path, page) {
var handler = Zotero.Prefs.get("fileHandler.pdf"); var handler = Zotero.Prefs.get("fileHandler.pdf");
var opened = false; var opened = false;
if (handler) {
Zotero.debug(`Custom handler is ${handler}`);
}
if (Zotero.isMac) { if (Zotero.isMac) {
if (handler.includes('Preview')) { if (!this._openWithHandlerMac(handler, path, page)) {
this._openWithPreview(path, page);
}
else if (handler.includes('Skim')) {
this._openWithSkim(path, page);
}
else if (handler.includes('PDF Expert')) {
this._openWithPDFExpert(path, page);
}
else {
// Try to detect default app // Try to detect default app
handler = this._getPDFHandlerName(); handler = this._getPDFHandlerName();
Zotero.debug(`Handler is ${handler}`); if (!this._openWithHandlerMac(handler, path, page)) {
if (handler && handler == 'Skim') {
this._openWithSkim(path, page);
}
else if (handler && handler == 'PDF Expert') {
this._openWithPDFExpert(path, page);
}
// Fall back to Preview // Fall back to Preview
else {
this._openWithPreview(path, page); this._openWithPreview(path, page);
} }
} }
opened = true; opened = true;
} }
else if (Zotero.isWin) { else if (Zotero.isWin) {
handler = handler || this._getPDFHandlerWindows(); if (!handler) {
handler = this._getPDFHandlerWindows();
if (handler) {
Zotero.debug(`Default handler is ${handler}`);
}
}
if (handler) { if (handler) {
Zotero.debug("Handler is " + handler);
// Include flags to open the PDF on a given page in various apps // 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 // Adobe Acrobat: http://partners.adobe.com/public/developer/en/acrobat/PDFOpenParameters.pdf
@ -71,13 +64,13 @@ Zotero.OpenPDF = {
} }
} }
else if (Zotero.isLinux) { else if (Zotero.isLinux) {
if (handler.includes('evince') || handler.includes('okular')) { if (!handler) {
this._openWithEvinceOrOkular(handler, path, page); handler = await this._getPDFHandlerLinux();
opened = true; if (handler) {
Zotero.debug(`Resolved handler is ${handler}`);
} }
else { }
let handler = await this._getPDFHandlerLinux(); if (handler && (handler.includes('evince') || handler.includes('okular'))) {
if (handler.includes('evince') || handler.includes('okular')) {
this._openWithEvinceOrOkular(handler, path, page); this._openWithEvinceOrOkular(handler, path, page);
opened = true; opened = true;
} }
@ -94,7 +87,6 @@ Zotero.OpenPDF = {
Zotero.debug("No handler found"); Zotero.debug("No handler found");
} }
} }
}
return opened; return opened;
}, },
@ -140,8 +132,31 @@ Zotero.OpenPDF = {
// //
// Mac // 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) { _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 // Go to page using AppleScript
let args = [ let args = [
'-e', 'tell app "Preview" to activate', '-e', 'tell app "Preview" to activate',
@ -152,24 +167,36 @@ Zotero.OpenPDF = {
await Zotero.Utilities.Internal.exec('/usr/bin/osascript', args); 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 // Escape double-quotes in path
var quoteRE = /"/g; var quoteRE = /"/g;
filePath = filePath.replace(quoteRE, '\\"'); filePath = filePath.replace(quoteRE, '\\"');
let filename = OS.Path.basename(filePath).replace(quoteRE, '\\"'); let filename = OS.Path.basename(filePath).replace(quoteRE, '\\"');
let args = [ let args = [
'-e', 'tell app "Skim" to activate', '-e', `tell app "${appPath}" to activate`,
'-e', `tell app "Skim" to open "${filePath}"` '-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); await Zotero.Utilities.Internal.exec('/usr/bin/osascript', args);
}, },
_openWithPDFExpert: async function (filePath, page) { _openWithPDFExpert: async function (appPath, filePath, page) {
await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', 'PDF Expert', filePath]); await Zotero.Utilities.Internal.exec('/usr/bin/open', ['-a', handlers, filePath]);
// Go to page using AppleScript (same as Preview) // Go to page using AppleScript (same as Preview)
let args = [ 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 "g" using {option down, command down}',
'-e', `tell app "System Events" to keystroke "${page}"`, '-e', `tell app "System Events" to keystroke "${page}"`,
'-e', 'tell app "System Events" to keystroke return' '-e', 'tell app "System Events" to keystroke return'