Merge pull request #20231 from calixteman/xfa_render_richtext
Add a new function renderRichText to be used in the annotation layer
This commit is contained in:
commit
2a93ade197
@ -41,12 +41,12 @@ import {
|
|||||||
applyOpacity,
|
applyOpacity,
|
||||||
changeLightness,
|
changeLightness,
|
||||||
PDFDateString,
|
PDFDateString,
|
||||||
|
renderRichText,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
} from "./display_utils.js";
|
} from "./display_utils.js";
|
||||||
import { AnnotationStorage } from "./annotation_storage.js";
|
import { AnnotationStorage } from "./annotation_storage.js";
|
||||||
import { ColorConverters } from "../shared/scripting_utils.js";
|
import { ColorConverters } from "../shared/scripting_utils.js";
|
||||||
import { DOMSVGFactory } from "./svg_factory.js";
|
import { DOMSVGFactory } from "./svg_factory.js";
|
||||||
import { XfaLayer } from "./xfa_layer.js";
|
|
||||||
|
|
||||||
const DEFAULT_FONT_SIZE = 9;
|
const DEFAULT_FONT_SIZE = 9;
|
||||||
const GetElementsByNameSet = new WeakSet();
|
const GetElementsByNameSet = new WeakSet();
|
||||||
@ -2491,18 +2491,15 @@ class PopupElement {
|
|||||||
header.append(modificationDate);
|
header.append(modificationDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = this.#html;
|
renderRichText(
|
||||||
if (html) {
|
{
|
||||||
XfaLayer.render({
|
html: this.#html || this.#contentsObj.str,
|
||||||
xfaHtml: html,
|
dir: this.#contentsObj.dir,
|
||||||
intent: "richText",
|
className: "popupContent",
|
||||||
div: popup,
|
},
|
||||||
});
|
popup
|
||||||
popup.lastChild.classList.add("richText", "popupContent");
|
);
|
||||||
} else {
|
|
||||||
const contents = this._formatContents(this.#contentsObj);
|
|
||||||
popup.append(contents);
|
|
||||||
}
|
|
||||||
this.#container.append(popup);
|
this.#container.append(popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2561,29 +2558,6 @@ class PopupElement {
|
|||||||
return popupContent;
|
return popupContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the contents of the popup by adding newlines where necessary.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object<string, string>} contentsObj
|
|
||||||
* @memberof PopupElement
|
|
||||||
* @returns {HTMLParagraphElement}
|
|
||||||
*/
|
|
||||||
_formatContents({ str, dir }) {
|
|
||||||
const p = document.createElement("p");
|
|
||||||
p.classList.add("popupContent");
|
|
||||||
p.dir = dir;
|
|
||||||
const lines = str.split(/(?:\r\n?|\n)/);
|
|
||||||
for (let i = 0, ii = lines.length; i < ii; ++i) {
|
|
||||||
const line = lines[i];
|
|
||||||
p.append(document.createTextNode(line));
|
|
||||||
if (i < ii - 1) {
|
|
||||||
p.append(document.createElement("br"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
#keyDown(event) {
|
#keyDown(event) {
|
||||||
if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) {
|
if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
Util,
|
Util,
|
||||||
warn,
|
warn,
|
||||||
} from "../shared/util.js";
|
} from "../shared/util.js";
|
||||||
|
import { XfaLayer } from "./xfa_layer.js";
|
||||||
|
|
||||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||||
|
|
||||||
@ -829,6 +830,31 @@ function applyOpacity(r, g, b, opacity) {
|
|||||||
return [r, g, b];
|
return [r, g, b];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderRichText({ html, dir, className }, container) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
if (typeof html === "string") {
|
||||||
|
const p = document.createElement("p");
|
||||||
|
p.dir = dir || "auto";
|
||||||
|
const lines = html.split(/(?:\r\n?|\n)/);
|
||||||
|
for (let i = 0, ii = lines.length; i < ii; ++i) {
|
||||||
|
const line = lines[i];
|
||||||
|
p.append(document.createTextNode(line));
|
||||||
|
if (i < ii - 1) {
|
||||||
|
p.append(document.createElement("br"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment.append(p);
|
||||||
|
} else {
|
||||||
|
XfaLayer.render({
|
||||||
|
xfaHtml: html,
|
||||||
|
div: fragment,
|
||||||
|
intent: "richText",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fragment.firstChild.classList.add("richText", className);
|
||||||
|
container.append(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
applyOpacity,
|
applyOpacity,
|
||||||
changeLightness,
|
changeLightness,
|
||||||
@ -851,6 +877,7 @@ export {
|
|||||||
PDFDateString,
|
PDFDateString,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
StatTimer,
|
StatTimer,
|
||||||
stopEvent,
|
stopEvent,
|
||||||
|
|||||||
@ -59,6 +59,7 @@ import {
|
|||||||
PDFDateString,
|
PDFDateString,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
stopEvent,
|
stopEvent,
|
||||||
SupportedImageMimeTypes,
|
SupportedImageMimeTypes,
|
||||||
@ -132,6 +133,7 @@ globalThis.pdfjsLib = {
|
|||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
ResponseException,
|
ResponseException,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
shadow,
|
shadow,
|
||||||
@ -189,6 +191,7 @@ export {
|
|||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
ResponseException,
|
ResponseException,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
shadow,
|
shadow,
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import {
|
|||||||
getRGB,
|
getRGB,
|
||||||
isValidFetchUrl,
|
isValidFetchUrl,
|
||||||
PDFDateString,
|
PDFDateString,
|
||||||
|
renderRichText,
|
||||||
} from "../../src/display/display_utils.js";
|
} from "../../src/display/display_utils.js";
|
||||||
import { isNodeJS, toBase64Util } from "../../src/shared/util.js";
|
import { isNodeJS, toBase64Util } from "../../src/shared/util.js";
|
||||||
|
|
||||||
@ -342,4 +343,67 @@ describe("display_utils", function () {
|
|||||||
expect(applyOpacity(123, 45, 67, ctx.globalAlpha)).toEqual([r, g, b]);
|
expect(applyOpacity(123, 45, 67, ctx.globalAlpha)).toEqual([r, g, b]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("renderRichText", function () {
|
||||||
|
// Unlike other tests we cannot simply compare the HTML-strings since
|
||||||
|
// Chrome and Firefox produce different results. Instead we compare sets
|
||||||
|
// containing the individual parts of the HTML-strings.
|
||||||
|
const splitParts = s => new Set(s.split(/[<>/ ]+/).filter(x => x));
|
||||||
|
|
||||||
|
it("should render plain text", function () {
|
||||||
|
if (isNodeJS) {
|
||||||
|
pending("DOM is not supported in Node.js.");
|
||||||
|
}
|
||||||
|
const container = document.createElement("div");
|
||||||
|
renderRichText(
|
||||||
|
{
|
||||||
|
html: "Hello world!\nThis is a test.",
|
||||||
|
dir: "ltr",
|
||||||
|
className: "foo",
|
||||||
|
},
|
||||||
|
container
|
||||||
|
);
|
||||||
|
expect(splitParts(container.innerHTML)).toEqual(
|
||||||
|
splitParts(
|
||||||
|
'<p dir="ltr" class="richText foo">Hello world!<br>This is a test.</p>'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render XFA rich text", function () {
|
||||||
|
if (isNodeJS) {
|
||||||
|
pending("DOM is not supported in Node.js.");
|
||||||
|
}
|
||||||
|
const container = document.createElement("div");
|
||||||
|
const xfaHtml = {
|
||||||
|
name: "div",
|
||||||
|
attributes: { style: { color: "red" } },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: "p",
|
||||||
|
attributes: { style: { fontSize: "20px" } },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: "span",
|
||||||
|
attributes: { style: { fontWeight: "bold" } },
|
||||||
|
value: "Hello",
|
||||||
|
},
|
||||||
|
{ name: "#text", value: " world!" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
renderRichText(
|
||||||
|
{ html: xfaHtml, dir: "ltr", className: "foo" },
|
||||||
|
container
|
||||||
|
);
|
||||||
|
expect(splitParts(container.innerHTML)).toEqual(
|
||||||
|
splitParts(
|
||||||
|
'<div style="color: red;" class="richText foo">' +
|
||||||
|
'<p style="font-size: 20px;">' +
|
||||||
|
'<span style="font-weight: bold;">Hello</span> world!</p></div>'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -50,6 +50,7 @@ import {
|
|||||||
PDFDateString,
|
PDFDateString,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
stopEvent,
|
stopEvent,
|
||||||
SupportedImageMimeTypes,
|
SupportedImageMimeTypes,
|
||||||
@ -116,6 +117,7 @@ const expectedAPI = Object.freeze({
|
|||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
ResponseException,
|
ResponseException,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
shadow,
|
shadow,
|
||||||
|
|||||||
@ -55,6 +55,7 @@ const {
|
|||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
ResponseException,
|
ResponseException,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
shadow,
|
shadow,
|
||||||
@ -112,6 +113,7 @@ export {
|
|||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
RenderingCancelledException,
|
RenderingCancelledException,
|
||||||
|
renderRichText,
|
||||||
ResponseException,
|
ResponseException,
|
||||||
setLayerDimensions,
|
setLayerDimensions,
|
||||||
shadow,
|
shadow,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user