Move the externalLinkTarget and externalLinkRel options to PDFLinkService options

This removes the `PDFJS.externalLinkTarget`/`PDFJS.externalLinkRel` dependency from the viewer components, but please note that as a *temporary* solution the default viewer still uses it.
This commit is contained in:
Jonas Jenwald 2018-02-13 14:03:52 +01:00
parent c45c394364
commit 3a6f6d23d6
8 changed files with 62 additions and 120 deletions

View File

@ -281,17 +281,21 @@ class LinkAnnotationElement extends AnnotationElement {
render() { render() {
this.container.className = 'linkAnnotation'; this.container.className = 'linkAnnotation';
let { data, linkService, } = this;
let link = document.createElement('a'); let link = document.createElement('a');
addLinkAttributes(link, { addLinkAttributes(link, {
url: this.data.url, url: data.url,
target: (this.data.newWindow ? LinkTarget.BLANK : undefined), target: (data.newWindow ?
LinkTarget.BLANK : linkService.externalLinkTarget),
rel: linkService.externalLinkRel,
}); });
if (!this.data.url) { if (!data.url) {
if (this.data.action) { if (data.action) {
this._bindNamedAction(link, this.data.action); this._bindNamedAction(link, data.action);
} else { } else {
this._bindLink(link, this.data.dest); this._bindLink(link, data.dest);
} }
} }

View File

@ -274,7 +274,7 @@ var RenderingCancelledException = (function RenderingCancelledException() {
return RenderingCancelledException; return RenderingCancelledException;
})(); })();
var LinkTarget = { const LinkTarget = {
NONE: 0, // Default value. NONE: 0, // Default value.
SELF: 1, SELF: 1,
BLANK: 2, BLANK: 2,
@ -282,7 +282,7 @@ var LinkTarget = {
TOP: 4, TOP: 4,
}; };
var LinkTargetStringMap = [ const LinkTargetStringMap = [
'', '',
'_self', '_self',
'_blank', '_blank',
@ -294,8 +294,10 @@ var LinkTargetStringMap = [
* @typedef ExternalLinkParameters * @typedef ExternalLinkParameters
* @typedef {Object} ExternalLinkParameters * @typedef {Object} ExternalLinkParameters
* @property {string} url - An absolute URL. * @property {string} url - An absolute URL.
* @property {LinkTarget} target - The link target. * @property {LinkTarget} target - (optional) The link target.
* @property {string} rel - The link relationship. * The default value is `LinkTarget.NONE`.
* @property {string} rel - (optional) The link relationship.
* The default value is `DEFAULT_LINK_REL`.
*/ */
/** /**
@ -303,22 +305,16 @@ var LinkTargetStringMap = [
* @param {HTMLLinkElement} link - The link element. * @param {HTMLLinkElement} link - The link element.
* @param {ExternalLinkParameters} params * @param {ExternalLinkParameters} params
*/ */
function addLinkAttributes(link, params) { function addLinkAttributes(link, { url, target, rel, } = {}) {
var url = params && params.url;
link.href = link.title = (url ? removeNullCharacters(url) : ''); link.href = link.title = (url ? removeNullCharacters(url) : '');
if (url) { if (url) {
var target = params.target; const LinkTargetValues = Object.values(LinkTarget);
if (typeof target === 'undefined') { let targetIndex =
target = getDefaultSetting('externalLinkTarget'); LinkTargetValues.includes(target) ? target : LinkTarget.NONE;
} link.target = LinkTargetStringMap[targetIndex];
link.target = LinkTargetStringMap[target];
var rel = params.rel; link.rel = (typeof rel === 'string' ? rel : DEFAULT_LINK_REL);
if (typeof rel === 'undefined') {
rel = getDefaultSetting('externalLinkRel');
}
link.rel = rel;
} }
} }
@ -365,25 +361,6 @@ function getDefaultSetting(id) {
return globalSettings ? globalSettings.maxImageSize : -1; return globalSettings ? globalSettings.maxImageSize : -1;
case 'isEvalSupported': case 'isEvalSupported':
return globalSettings ? globalSettings.isEvalSupported : true; return globalSettings ? globalSettings.isEvalSupported : true;
case 'externalLinkTarget':
if (!globalSettings) {
return LinkTarget.NONE;
}
switch (globalSettings.externalLinkTarget) {
case LinkTarget.NONE:
case LinkTarget.SELF:
case LinkTarget.BLANK:
case LinkTarget.PARENT:
case LinkTarget.TOP:
return globalSettings.externalLinkTarget;
}
warn('PDFJS.externalLinkTarget is invalid: ' +
globalSettings.externalLinkTarget);
// Reset the external link target, to suppress further warnings.
globalSettings.externalLinkTarget = LinkTarget.NONE;
return LinkTarget.NONE;
case 'externalLinkRel':
return globalSettings ? globalSettings.externalLinkRel : DEFAULT_LINK_REL;
case 'enableStats': case 'enableStats':
return !!(globalSettings && globalSettings.enableStats); return !!(globalSettings && globalSettings.enableStats);
default: default:
@ -391,19 +368,6 @@ function getDefaultSetting(id) {
} }
} }
function isExternalLinkTargetSet() {
var externalLinkTarget = getDefaultSetting('externalLinkTarget');
switch (externalLinkTarget) {
case LinkTarget.NONE:
return false;
case LinkTarget.SELF:
case LinkTarget.BLANK:
case LinkTarget.PARENT:
case LinkTarget.TOP:
return true;
}
}
class StatTimer { class StatTimer {
constructor(enable = true) { constructor(enable = true) {
this.enabled = !!enable; this.enabled = !!enable;
@ -481,7 +445,6 @@ class DummyStatTimer {
export { export {
RenderingCancelledException, RenderingCancelledException,
addLinkAttributes, addLinkAttributes,
isExternalLinkTargetSet,
getFilenameFromUrl, getFilenameFromUrl,
LinkTarget, LinkTarget,
getDefaultSetting, getDefaultSetting,

View File

@ -13,10 +13,6 @@
* limitations under the License. * limitations under the License.
*/ */
import {
addLinkAttributes, DEFAULT_LINK_REL, getFilenameFromUrl,
isExternalLinkTargetSet, isValidUrl, LinkTarget
} from './dom_utils';
import { import {
createBlob, createObjectURL, createPromiseCapability, getVerbosityLevel, createBlob, createObjectURL, createPromiseCapability, getVerbosityLevel,
InvalidPDFException, isLittleEndian, MissingPDFException, OPS, PageViewport, InvalidPDFException, isLittleEndian, MissingPDFException, OPS, PageViewport,
@ -24,6 +20,7 @@ import {
shadow, UnexpectedResponseException, UnknownErrorException, shadow, UnexpectedResponseException, UnknownErrorException,
UNSUPPORTED_FEATURES, Util, VERBOSITY_LEVELS UNSUPPORTED_FEATURES, Util, VERBOSITY_LEVELS
} from '../shared/util'; } from '../shared/util';
import { DEFAULT_LINK_REL, getFilenameFromUrl, LinkTarget } from './dom_utils';
import { import {
getDocument, LoopbackPort, PDFDataRangeTransport, PDFWorker getDocument, LoopbackPort, PDFDataRangeTransport, PDFWorker
} from './api'; } from './api';
@ -67,7 +64,6 @@ Object.defineProperty(PDFJS, 'verbosity', {
PDFJS.VERBOSITY_LEVELS = VERBOSITY_LEVELS; PDFJS.VERBOSITY_LEVELS = VERBOSITY_LEVELS;
PDFJS.OPS = OPS; PDFJS.OPS = OPS;
PDFJS.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; PDFJS.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;
PDFJS.isValidUrl = isValidUrl;
PDFJS.shadow = shadow; PDFJS.shadow = shadow;
PDFJS.createBlob = createBlob; PDFJS.createBlob = createBlob;
PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) { PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) {
@ -193,7 +189,7 @@ PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
/** /**
* Specifies the |target| attribute for external links. * Specifies the |target| attribute for external links.
* The constants from PDFJS.LinkTarget should be used: * The constants from {LinkTarget} should be used:
* - NONE [default] * - NONE [default]
* - SELF * - SELF
* - BLANK * - BLANK
@ -225,10 +221,7 @@ PDFJS.LoopbackPort = LoopbackPort;
PDFJS.PDFDataRangeTransport = PDFDataRangeTransport; PDFJS.PDFDataRangeTransport = PDFDataRangeTransport;
PDFJS.PDFWorker = PDFWorker; PDFJS.PDFWorker = PDFWorker;
PDFJS.LinkTarget = LinkTarget;
PDFJS.addLinkAttributes = addLinkAttributes;
PDFJS.getFilenameFromUrl = getFilenameFromUrl; PDFJS.getFilenameFromUrl = getFilenameFromUrl;
PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet;
PDFJS.AnnotationLayer = AnnotationLayer; PDFJS.AnnotationLayer = AnnotationLayer;

View File

@ -91,4 +91,5 @@ exports.createBlob = pdfjsSharedUtil.createBlob;
exports.RenderingCancelledException = exports.RenderingCancelledException =
pdfjsDisplayDOMUtils.RenderingCancelledException; pdfjsDisplayDOMUtils.RenderingCancelledException;
exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl; exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl;
exports.LinkTarget = pdfjsDisplayDOMUtils.LinkTarget;
exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes; exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes;

View File

@ -13,11 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { DOMSVGFactory, getFilenameFromUrl } from '../../src/display/dom_utils';
DOMSVGFactory, getFilenameFromUrl, isExternalLinkTargetSet, LinkTarget
} from '../../src/display/dom_utils';
import isNodeJS from '../../src/shared/is_node'; import isNodeJS from '../../src/shared/is_node';
import { PDFJS } from '../../src/display/global';
describe('dom_utils', function() { describe('dom_utils', function() {
describe('DOMSVGFactory', function() { describe('DOMSVGFactory', function() {
@ -95,37 +92,4 @@ describe('dom_utils', function() {
expect(result).toEqual(expected); expect(result).toEqual(expected);
}); });
}); });
describe('isExternalLinkTargetSet', function() {
var savedExternalLinkTarget;
beforeAll(function (done) {
savedExternalLinkTarget = PDFJS.externalLinkTarget;
done();
});
afterAll(function () {
PDFJS.externalLinkTarget = savedExternalLinkTarget;
});
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);
}
});
});
}); });

View File

@ -22,7 +22,7 @@ import {
} from './ui_utils'; } from './ui_utils';
import { import {
build, createBlob, getDocument, getFilenameFromUrl, InvalidPDFException, build, createBlob, getDocument, getFilenameFromUrl, InvalidPDFException,
MissingPDFException, OPS, PDFJS, PDFWorker, shadow, LinkTarget, MissingPDFException, OPS, PDFJS, PDFWorker, shadow,
UnexpectedResponseException, UNSUPPORTED_FEATURES, version UnexpectedResponseException, UNSUPPORTED_FEATURES, version
} from 'pdfjs-lib'; } from 'pdfjs-lib';
import { CursorTool, PDFCursorTools } from './pdf_cursor_tools'; import { CursorTool, PDFCursorTools } from './pdf_cursor_tools';
@ -184,10 +184,11 @@ let PDFViewerApplication = {
this.eventBus.dispatch('localized'); this.eventBus.dispatch('localized');
}); });
if (this.isViewerEmbedded && !PDFJS.isExternalLinkTargetSet()) { if (this.isViewerEmbedded &&
PDFJS.externalLinkTarget === LinkTarget.NONE) {
// Prevent external links from "replacing" the viewer, // Prevent external links from "replacing" the viewer,
// when it's embedded in e.g. an iframe or an object. // when it's embedded in e.g. an iframe or an object.
PDFJS.externalLinkTarget = PDFJS.LinkTarget.TOP; PDFJS.externalLinkTarget = LinkTarget.TOP;
} }
this.initialized = true; this.initialized = true;
@ -250,7 +251,7 @@ let PDFViewerApplication = {
PDFJS.useOnlyCssZoom = value; PDFJS.useOnlyCssZoom = value;
}), }),
preferences.get('externalLinkTarget').then(function resolved(value) { preferences.get('externalLinkTarget').then(function resolved(value) {
if (PDFJS.isExternalLinkTargetSet()) { if (PDFJS.externalLinkTarget !== LinkTarget.NONE) {
return; return;
} }
PDFJS.externalLinkTarget = value; PDFJS.externalLinkTarget = value;
@ -378,6 +379,8 @@ let PDFViewerApplication = {
let pdfLinkService = new PDFLinkService({ let pdfLinkService = new PDFLinkService({
eventBus, eventBus,
externalLinkTarget: PDFJS.externalLinkTarget,
externalLinkRel: PDFJS.externalLinkRel,
}); });
this.pdfLinkService = pdfLinkService; this.pdfLinkService = pdfLinkService;

View File

@ -19,6 +19,11 @@ import { parseQueryString } from './ui_utils';
/** /**
* @typedef {Object} PDFLinkServiceOptions * @typedef {Object} PDFLinkServiceOptions
* @property {EventBus} eventBus - The application event bus. * @property {EventBus} eventBus - The application event bus.
* @property {number} externalLinkTarget - (optional) Specifies the `target`
* attribute for external links. Must use one of the values from {LinkTarget}.
* Defaults to using no target.
* @property {string} externalLinkRel - (optional) Specifies the `rel` attribute
* for external links. Defaults to stripping the referrer.
*/ */
/** /**
@ -30,8 +35,12 @@ class PDFLinkService {
/** /**
* @param {PDFLinkServiceOptions} options * @param {PDFLinkServiceOptions} options
*/ */
constructor({ eventBus, } = {}) { constructor({ eventBus, externalLinkTarget = null,
externalLinkRel = null, } = {}) {
this.eventBus = eventBus || getGlobalEventBus(); this.eventBus = eventBus || getGlobalEventBus();
this.externalLinkTarget = externalLinkTarget;
this.externalLinkRel = externalLinkRel;
this.baseUrl = null; this.baseUrl = null;
this.pdfDocument = null; this.pdfDocument = null;
this.pdfViewer = null; this.pdfViewer = null;
@ -409,6 +418,11 @@ function isValidExplicitDestination(dest) {
} }
class SimpleLinkService { class SimpleLinkService {
constructor() {
this.externalLinkTarget = null;
this.externalLinkRel = null;
}
/** /**
* @returns {number} * @returns {number}
*/ */

View File

@ -13,9 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { addLinkAttributes, LinkTarget, removeNullCharacters } from 'pdfjs-lib';
addLinkAttributes, PDFJS, removeNullCharacters
} from 'pdfjs-lib';
const DEFAULT_TITLE = '\u2013'; const DEFAULT_TITLE = '\u2013';
@ -68,20 +66,22 @@ class PDFOutlineViewer {
/** /**
* @private * @private
*/ */
_bindLink(element, item) { _bindLink(element, { url, newWindow, dest, }) {
if (item.url) { let { linkService, } = this;
if (url) {
addLinkAttributes(element, { addLinkAttributes(element, {
url: item.url, url,
target: (item.newWindow ? PDFJS.LinkTarget.BLANK : undefined), target: (newWindow ? LinkTarget.BLANK : linkService.externalLinkTarget),
rel: linkService.externalLinkRel,
}); });
return; return;
} }
let destination = item.dest;
element.href = this.linkService.getDestinationHash(destination); element.href = this.linkService.getDestinationHash(dest);
element.onclick = () => { element.onclick = () => {
if (destination) { if (dest) {
this.linkService.navigateTo(destination); this.linkService.navigateTo(dest);
} }
return false; return false;
}; };
@ -90,12 +90,12 @@ class PDFOutlineViewer {
/** /**
* @private * @private
*/ */
_setStyles(element, item) { _setStyles(element, { bold, italic, }) {
let styleStr = ''; let styleStr = '';
if (item.bold) { if (bold) {
styleStr += 'font-weight: bold;'; styleStr += 'font-weight: bold;';
} }
if (item.italic) { if (italic) {
styleStr += 'font-style: italic;'; styleStr += 'font-style: italic;';
} }