diff --git a/src/core/xfa/template.js b/src/core/xfa/template.js index 5619a964d..a778eccc8 100644 --- a/src/core/xfa/template.js +++ b/src/core/xfa/template.js @@ -1094,7 +1094,6 @@ class Button extends XFAObject { if (!href) { continue; } - const target = jsURL.newWindow ? "_blank" : undefined; // we've an url so generate a htmlButton.children.push({ @@ -1102,7 +1101,7 @@ class Button extends XFAObject { attributes: { id: "link" + this[$uid], href, - target, + newWindow: jsURL.newWindow, class: ["xfaLink"], style: {}, }, diff --git a/src/display/xfa_layer.js b/src/display/xfa_layer.js index 88c2bada3..346a5b0e9 100644 --- a/src/display/xfa_layer.js +++ b/src/display/xfa_layer.js @@ -13,6 +13,7 @@ * limitations under the License. */ +import { addLinkAttributes, LinkTarget } from "./display_utils.js"; import { XfaText } from "./xfa_text.js"; class XfaLayer { @@ -84,8 +85,10 @@ class XfaLayer { } } - static setAttributes(html, element, storage, intent) { + static setAttributes({ html, element, storage = null, intent, linkService }) { const { attributes } = element; + const isHTMLAnchorElement = html instanceof HTMLAnchorElement; + if (attributes.type === "radio") { // Avoid to have a radio group when printing with the same as one // already displayed. @@ -105,6 +108,9 @@ class XfaLayer { } else if (key === "class") { html.setAttribute(key, value.join(" ")); } else { + if (isHTMLAnchorElement && (key === "href" || key === "newWindow")) { + continue; // Handled below. + } html.setAttribute(key, value); } } else { @@ -112,6 +118,17 @@ class XfaLayer { } } + if (isHTMLAnchorElement) { + addLinkAttributes(html, { + url: attributes.href, + target: attributes.newWindow + ? LinkTarget.BLANK + : linkService.externalLinkTarget, + rel: linkService.externalLinkRel, + enabled: linkService.externalLinkEnabled, + }); + } + // Set the value after the others to be sure overwrite // any other values. if (storage && attributes.dataId) { @@ -121,11 +138,17 @@ class XfaLayer { static render(parameters) { const storage = parameters.annotationStorage; + const linkService = parameters.linkService; const root = parameters.xfa; const intent = parameters.intent || "display"; const rootHtml = document.createElement(root.name); if (root.attributes) { - this.setAttributes(rootHtml, root); + this.setAttributes({ + html: rootHtml, + element: root, + intent, + linkService, + }); } const stack = [[root, -1, rootHtml]]; @@ -169,7 +192,13 @@ class XfaLayer { html.appendChild(childHtml); if (child.attributes) { - this.setAttributes(childHtml, child, storage, intent); + this.setAttributes({ + html: childHtml, + element: child, + storage, + intent, + linkService, + }); } if (child.children && child.children.length > 0) { diff --git a/test/driver.js b/test/driver.js index e89cb8da3..13d4882eb 100644 --- a/test/driver.js +++ b/test/driver.js @@ -334,6 +334,7 @@ var rasterizeXfaLayer = (function rasterizeXfaLayerClosure() { div, viewport: viewport.clone({ dontFlip: true }), annotationStorage, + linkService: new SimpleLinkService(), intent: isPrint ? "print" : "display", }); diff --git a/test/unit/xfa_tohtml_spec.js b/test/unit/xfa_tohtml_spec.js index eccf75a1d..e9ba898bb 100644 --- a/test/unit/xfa_tohtml_spec.js +++ b/test/unit/xfa_tohtml_spec.js @@ -640,10 +640,10 @@ describe("XFAFactory", function () { const pages = factory.getPages(); let a = searchHtmlNode(pages, "name", "a"); expect(a.attributes.href).toEqual("https://github.com/mozilla/pdf.js"); - expect(a.attributes.target).toEqual("_blank"); + expect(a.attributes.newWindow).toEqual(true); a = searchHtmlNode(pages, "name", "a", false, [1]); expect(a.attributes.href).toEqual("https://github.com/allizom/pdf.js"); - expect(a.attributes.target).toBe(undefined); + expect(a.attributes.newWindow).toEqual(false); }); }); diff --git a/web/base_viewer.js b/web/base_viewer.js index b1b1086da..3ce5d9197 100644 --- a/web/base_viewer.js +++ b/web/base_viewer.js @@ -1358,6 +1358,7 @@ class BaseViewer { * @param {PDFPage} pdfPage * @param {AnnotationStorage} [annotationStorage] - Storage for annotation * data in forms. + * @property {IPDFLinkService} linkService * @returns {XfaLayerBuilder} */ createXfaLayerBuilder(pageDiv, pdfPage, annotationStorage = null) { @@ -1366,6 +1367,7 @@ class BaseViewer { pdfPage, annotationStorage: annotationStorage || this.pdfDocument?.annotationStorage, + linkService: this.linkService, }); } diff --git a/web/interfaces.js b/web/interfaces.js index efc66145d..ebe1ad518 100644 --- a/web/interfaces.js +++ b/web/interfaces.js @@ -191,9 +191,16 @@ class IPDFXfaLayerFactory { /** * @param {HTMLDivElement} pageDiv * @param {PDFPage} pdfPage + * @param {AnnotationStorage} [annotationStorage] + * @param {Object} [xfaHtml] * @returns {XfaLayerBuilder} */ - createXfaLayerBuilder(pageDiv, pdfPage) {} + createXfaLayerBuilder( + pageDiv, + pdfPage, + annotationStorage = null, + xfaHtml = null + ) {} } /** diff --git a/web/xfa_layer_builder.js b/web/xfa_layer_builder.js index b08c4e3b4..fdab0c901 100644 --- a/web/xfa_layer_builder.js +++ b/web/xfa_layer_builder.js @@ -15,6 +15,7 @@ /** @typedef {import("./interfaces").IPDFXfaLayerFactory} IPDFXfaLayerFactory */ +import { SimpleLinkService } from "./pdf_link_service.js"; import { XfaLayer } from "pdfjs-lib"; /** @@ -22,6 +23,7 @@ import { XfaLayer } from "pdfjs-lib"; * @property {HTMLDivElement} pageDiv * @property {PDFPage} pdfPage * @property {AnnotationStorage} [annotationStorage] + * @property {IPDFLinkService} linkService * @property {Object} [xfaHtml] */ @@ -29,10 +31,11 @@ class XfaLayerBuilder { /** * @param {XfaLayerBuilderOptions} options */ - constructor({ pageDiv, pdfPage, annotationStorage, xfaHtml }) { + constructor({ pageDiv, pdfPage, annotationStorage, linkService, xfaHtml }) { this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.annotationStorage = annotationStorage; + this.linkService = linkService; this.xfaHtml = xfaHtml; this.div = null; @@ -54,6 +57,7 @@ class XfaLayerBuilder { xfa: this.xfaHtml, page: null, annotationStorage: this.annotationStorage, + linkService: this.linkService, intent, }; @@ -80,6 +84,7 @@ class XfaLayerBuilder { xfa, page: this.pdfPage, annotationStorage: this.annotationStorage, + linkService: this.linkService, intent, }; @@ -129,6 +134,7 @@ class DefaultXfaLayerFactory { pageDiv, pdfPage, annotationStorage, + linkService: new SimpleLinkService(), xfaHtml, }); }