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) {
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'