From 9ab896e30793926d8b6b4c6ad471852d8b4d611c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 19 Apr 2015 12:27:51 +0200 Subject: [PATCH 1/3] [api-minor] Add an option to PDFJS for specifying the |target| attribute of external links Replaces `PDFJS.openExternalLinksInNewWindow` with a more generic configuration option. *Note:* `PDFJS.openExternalLinksInNewWindow = true;` is equal to `PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK;`. --- src/display/annotation_helper.js | 7 +++--- src/display/api.js | 17 +++++++++++-- src/shared/util.js | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/display/annotation_helper.js b/src/display/annotation_helper.js index 922535960cd1a..13d1db69a8992 100644 --- a/src/display/annotation_helper.js +++ b/src/display/annotation_helper.js @@ -15,7 +15,7 @@ * limitations under the License. */ /* globals PDFJS, Util, AnnotationType, AnnotationBorderStyleType, warn, - CustomStyle */ + CustomStyle, isExternalLinkTargetSet, LinkTargetStringMap */ 'use strict'; @@ -261,8 +261,9 @@ var AnnotationUtils = (function AnnotationUtilsClosure() { var link = document.createElement('a'); link.href = link.title = item.url || ''; - if (item.url && PDFJS.openExternalLinksInNewWindow) { - link.target = '_blank'; + + if (item.url && isExternalLinkTargetSet()) { + link.target = LinkTargetStringMap[PDFJS.externalLinkTarget]; } container.appendChild(link); diff --git a/src/display/api.js b/src/display/api.js index 5d7f8093b3b36..c89c931a85537 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -169,14 +169,27 @@ PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ? 16777216 : PDFJS.maxCanvasPixels); /** - * Opens external links in a new window if enabled. The default behavior opens - * external links in the PDF.js window. + * (Deprecated) Opens external links in a new window if enabled. + * The default behavior opens external links in the PDF.js window. * @var {boolean} */ PDFJS.openExternalLinksInNewWindow = ( PDFJS.openExternalLinksInNewWindow === undefined ? false : PDFJS.openExternalLinksInNewWindow); +/** + * Specifies the |target| attribute for external links. + * The constants from PDFJS.LinkTarget should be used: + * - NONE [default] + * - SELF + * - BLANK + * - PARENT + * - TOP + * @var {number} + */ +PDFJS.externalLinkTarget = (PDFJS.externalLinkTarget === undefined ? + PDFJS.LinkTarget.NONE : PDFJS.externalLinkTarget); + /** * Determines if we can eval strings as JS. Primarily used to improve * performance for font rendering. diff --git a/src/shared/util.js b/src/shared/util.js index b003b4a92c042..f4821bcc9307a 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -328,6 +328,49 @@ function shadow(obj, prop, value) { } PDFJS.shadow = shadow; +var LinkTarget = PDFJS.LinkTarget = { + NONE: 0, // Default value. + SELF: 1, + BLANK: 2, + PARENT: 3, + TOP: 4, +}; +var LinkTargetStringMap = [ + '', + '_self', + '_blank', + '_parent', + '_top' +]; + +function isExternalLinkTargetSet() { +//#if GENERIC + if (PDFJS.openExternalLinksInNewWindow) { + warn('PDFJS.openExternalLinksInNewWindow is deprecated, ' + + 'use PDFJS.externalLinkTarget instead.'); + if (PDFJS.externalLinkTarget === LinkTarget.NONE) { + PDFJS.externalLinkTarget = LinkTarget.BLANK; + } + // Reset the deprecated parameter, to suppress further warnings. + PDFJS.openExternalLinksInNewWindow = false; + } +//#endif + switch (PDFJS.externalLinkTarget) { + case LinkTarget.NONE: + return false; + case LinkTarget.SELF: + case LinkTarget.BLANK: + case LinkTarget.PARENT: + case LinkTarget.TOP: + return true; + } + warn('PDFJS.externalLinkTarget is invalid: ' + PDFJS.externalLinkTarget); + // Reset the external link target, to suppress further warnings. + PDFJS.externalLinkTarget = LinkTarget.NONE; + return false; +} +PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet; + var PasswordResponses = PDFJS.PasswordResponses = { NEED_PASSWORD: 1, INCORRECT_PASSWORD: 2 From 39b962e3b0bf22c65f239c7e82fff13be0494174 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 30 Sep 2015 12:59:50 +0200 Subject: [PATCH 2/3] Add unit-tests for `isExternalLinkTargetSet` --- test/unit/util_spec.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/test/unit/util_spec.js b/test/unit/util_spec.js index 2973ec1d044d3..5c4b838f69f83 100644 --- a/test/unit/util_spec.js +++ b/test/unit/util_spec.js @@ -1,7 +1,7 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* globals expect, it, describe, combineUrl, Dict, isDict, Name, - stringToPDFString */ +/* globals expect, it, describe, combineUrl, Dict, isDict, Name, PDFJS, + stringToPDFString, isExternalLinkTargetSet, LinkTarget */ 'use strict'; @@ -99,4 +99,32 @@ describe('util', function() { expect(stringToPDFString(str2)).toEqual(''); }); }); + + describe('isExternalLinkTargetSet', function() { + // Save the current state, to avoid interfering with other tests. + var previousExternalLinkTarget = PDFJS.externalLinkTarget; + + it('handles the predefined LinkTargets', function() { + for (var key in LinkTarget) { + var linkTarget = LinkTarget[key]; + PDFJS.externalLinkTarget = linkTarget; + + expect(isExternalLinkTargetSet()).toEqual(!!linkTarget); + } + }); + + it('handles incorrect LinkTargets', function() { + var targets = [true, '', false, -1, '_blank', null]; + + for (var i = 0, ii = targets.length; i < ii; i++) { + var linkTarget = targets[i]; + PDFJS.externalLinkTarget = linkTarget; + + expect(isExternalLinkTargetSet()).toEqual(false); + } + }); + + // Reset the state. + PDFJS.externalLinkTarget = previousExternalLinkTarget; + }); }); From 610df45bad214e3edab140978a3988dab4d28d81 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 19 Apr 2015 12:40:46 +0200 Subject: [PATCH 3/3] Prevent external links from "replacing" the viewer when it's embedded (bug 976541) Fixes https://bugzilla.mozilla.org/show_bug.cgi?id=976541. This patch also adds a `externalLinkTarget` preference, to make the behaviour user configurable. --- web/default_preferences.js | 3 ++- web/viewer.js | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/web/default_preferences.js b/web/default_preferences.js index 10474144a7dec..ea2d4ae2246e4 100644 --- a/web/default_preferences.js +++ b/web/default_preferences.js @@ -32,5 +32,6 @@ var DEFAULT_PREFERENCES = { disableAutoFetch: false, disableFontFace: false, disableTextLayer: false, - useOnlyCssZoom: false + useOnlyCssZoom: false, + externalLinkTarget: 0, }; diff --git a/web/viewer.js b/web/viewer.js index 514e0c3949108..4b25ffe3cc6a0 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -288,12 +288,24 @@ var PDFViewerApplication = { }), Preferences.get('useOnlyCssZoom').then(function resolved(value) { PDFJS.useOnlyCssZoom = value; - }) + }), + Preferences.get('externalLinkTarget').then(function resolved(value) { + if (PDFJS.isExternalLinkTargetSet()) { + return; + } + PDFJS.externalLinkTarget = value; + }), // TODO move more preferences and other async stuff here ]).catch(function (reason) { }); return initializedPromise.then(function () { - PDFViewerApplication.initialized = true; + if (self.isViewerEmbedded && !PDFJS.isExternalLinkTargetSet()) { + // Prevent external links from "replacing" the viewer, + // when it's embedded in e.g. an iframe or an object. + PDFJS.externalLinkTarget = PDFJS.LinkTarget.TOP; + } + + self.initialized = true; }); },