1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-20 15:18:08 +02:00

[Editor] Make the text layer focusable before the editors (bug 1881746)

Keep the different layers in a constant order to avoid the use of a z-index
and a tab-index.
This commit is contained in:
Calixte Denizet 2024-03-11 17:03:44 +01:00
parent 0022310b9c
commit 1b00511301
14 changed files with 187 additions and 36 deletions

View file

@ -109,7 +109,6 @@
font-size: calc(100px * var(--scale-factor));
transform-origin: 0 0;
cursor: auto;
z-index: 4;
}
.annotationEditorLayer.waiting {

View file

@ -30,13 +30,13 @@ import { GenericL10n } from "web-null_l10n";
/**
* @typedef {Object} AnnotationEditorLayerBuilderOptions
* @property {AnnotationEditorUIManager} [uiManager]
* @property {HTMLDivElement} pageDiv
* @property {PDFPageProxy} pdfPage
* @property {IL10n} [l10n]
* @property {TextAccessibilityManager} [accessibilityManager]
* @property {AnnotationLayer} [annotationLayer]
* @property {TextLayer} [textLayer]
* @property {DrawLayer} [drawLayer]
* @property {function} [onAppend]
*/
class AnnotationEditorLayerBuilder {
@ -44,6 +44,8 @@ class AnnotationEditorLayerBuilder {
#drawLayer = null;
#onAppend = null;
#textLayer = null;
#uiManager;
@ -52,7 +54,6 @@ class AnnotationEditorLayerBuilder {
* @param {AnnotationEditorLayerBuilderOptions} options
*/
constructor(options) {
this.pageDiv = options.pageDiv;
this.pdfPage = options.pdfPage;
this.accessibilityManager = options.accessibilityManager;
this.l10n = options.l10n;
@ -66,6 +67,7 @@ class AnnotationEditorLayerBuilder {
this.#annotationLayer = options.annotationLayer || null;
this.#textLayer = options.textLayer || null;
this.#drawLayer = options.drawLayer || null;
this.#onAppend = options.onAppend || null;
}
/**
@ -91,10 +93,9 @@ class AnnotationEditorLayerBuilder {
// Create an AnnotationEditor layer div
const div = (this.div = document.createElement("div"));
div.className = "annotationEditorLayer";
div.tabIndex = 0;
div.hidden = true;
div.dir = this.#uiManager.direction;
this.pageDiv.append(div);
this.#onAppend?.(div);
this.annotationEditorLayer = new AnnotationEditorLayer({
uiManager: this.#uiManager,
@ -125,7 +126,6 @@ class AnnotationEditorLayerBuilder {
if (!this.div) {
return;
}
this.pageDiv = null;
this.annotationEditorLayer.destroy();
this.div.remove();
}

View file

@ -76,7 +76,6 @@
left: 0;
pointer-events: none;
transform-origin: 0 0;
z-index: 3;
&[data-main-rotation="90"] .norotate {
transform: rotate(270deg) translateX(-100%);

View file

@ -28,7 +28,6 @@ import { PresentationModeState } from "./ui_utils.js";
/**
* @typedef {Object} AnnotationLayerBuilderOptions
* @property {HTMLDivElement} pageDiv
* @property {PDFPageProxy} pdfPage
* @property {AnnotationStorage} [annotationStorage]
* @property {string} [imageResourcesPath] - Path for image resources, mainly
@ -42,16 +41,18 @@ import { PresentationModeState } from "./ui_utils.js";
* [fieldObjectsPromise]
* @property {Map<string, HTMLCanvasElement>} [annotationCanvasMap]
* @property {TextAccessibilityManager} [accessibilityManager]
* @property {function} [onAppend]
*/
class AnnotationLayerBuilder {
#onAppend = null;
#onPresentationModeChanged = null;
/**
* @param {AnnotationLayerBuilderOptions} options
*/
constructor({
pageDiv,
pdfPage,
linkService,
downloadManager,
@ -63,8 +64,8 @@ class AnnotationLayerBuilder {
fieldObjectsPromise = null,
annotationCanvasMap = null,
accessibilityManager = null,
onAppend = null,
}) {
this.pageDiv = pageDiv;
this.pdfPage = pdfPage;
this.linkService = linkService;
this.downloadManager = downloadManager;
@ -76,6 +77,7 @@ class AnnotationLayerBuilder {
this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null);
this._annotationCanvasMap = annotationCanvasMap;
this._accessibilityManager = accessibilityManager;
this.#onAppend = onAppend;
this.annotationLayer = null;
this.div = null;
@ -115,7 +117,7 @@ class AnnotationLayerBuilder {
// if there is at least one annotation.
const div = (this.div = document.createElement("div"));
div.className = "annotationLayer";
this.pageDiv.append(div);
this.#onAppend?.(div);
if (annotations.length === 0) {
this.hide();

View file

@ -99,6 +99,14 @@ const DEFAULT_LAYER_PROPERTIES =
},
};
const LAYERS_ORDER = new Map([
["canvasWrapper", 0],
["textLayer", 1],
["annotationLayer", 2],
["annotationEditorLayer", 3],
["xfaLayer", 2],
]);
/**
* @implements {IRenderableView}
*/
@ -127,6 +135,8 @@ class PDFPageView {
#viewportMap = new WeakMap();
#layers = [null, null, null, null];
/**
* @param {PDFPageViewOptions} options
*/
@ -223,6 +233,19 @@ class PDFPageView {
}
}
#addLayer(div, name) {
const pos = LAYERS_ORDER.get(name);
this.#layers[pos] = div;
for (let i = pos - 1; i >= 0; i--) {
const layer = this.#layers[i];
if (layer) {
layer.after(div);
return;
}
}
this.div.prepend(div);
}
get renderingState() {
return this.#renderingState;
}
@ -392,7 +415,7 @@ class PDFPageView {
if (this.xfaLayer?.div) {
// Pause translation when inserting the xfaLayer in the DOM.
this.l10n.pause();
this.div.append(this.xfaLayer.div);
this.#addLayer(this.xfaLayer.div, "xfaLayer");
this.l10n.resume();
}
@ -531,6 +554,10 @@ class PDFPageView {
continue;
}
node.remove();
const layerIndex = this.#layers.indexOf(node);
if (layerIndex >= 0) {
this.#layers[layerIndex] = null;
}
}
div.removeAttribute("data-loaded");
@ -877,7 +904,8 @@ class PDFPageView {
// overflow will be hidden in Firefox.
const canvasWrapper = document.createElement("div");
canvasWrapper.classList.add("canvasWrapper");
div.append(canvasWrapper);
canvasWrapper.setAttribute("aria-hidden", true);
this.#addLayer(canvasWrapper, "canvasWrapper");
if (
!this.textLayer &&
@ -891,13 +919,13 @@ class PDFPageView {
accessibilityManager: this._accessibilityManager,
enablePermissions:
this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS,
onAppend: textLayerDiv => {
// Pause translation when inserting the textLayer in the DOM.
this.l10n.pause();
this.#addLayer(textLayerDiv, "textLayer");
this.l10n.resume();
},
});
this.textLayer.onAppend = textLayerDiv => {
// Pause translation when inserting the textLayer in the DOM.
this.l10n.pause();
this.div.append(textLayerDiv);
this.l10n.resume();
};
}
if (
@ -915,7 +943,6 @@ class PDFPageView {
this._annotationCanvasMap ||= new Map();
this.annotationLayer = new AnnotationLayerBuilder({
pageDiv: div,
pdfPage,
annotationStorage,
imageResourcesPath: this.imageResourcesPath,
@ -927,6 +954,9 @@ class PDFPageView {
fieldObjectsPromise,
annotationCanvasMap: this._annotationCanvasMap,
accessibilityManager: this._accessibilityManager,
onAppend: annotationLayerDiv => {
this.#addLayer(annotationLayerDiv, "annotationLayer");
},
});
}
@ -1042,13 +1072,15 @@ class PDFPageView {
if (!this.annotationEditorLayer) {
this.annotationEditorLayer = new AnnotationEditorLayerBuilder({
uiManager: annotationEditorUIManager,
pageDiv: div,
pdfPage,
l10n,
accessibilityManager: this._accessibilityManager,
annotationLayer: this.annotationLayer?.annotationLayer,
textLayer: this.textLayer,
drawLayer: this.drawLayer.getDrawLayer(),
onAppend: annotationEditorLayerDiv => {
this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer");
},
});
}
this.#renderAnnotationEditorLayer();

View file

@ -75,7 +75,6 @@
overflow: hidden;
width: 100%;
height: 100%;
z-index: 1;
}
.pdfViewer .page {

View file

@ -23,7 +23,6 @@
text-size-adjust: none;
forced-color-adjust: none;
transform-origin: 0 0;
z-index: 2;
caret-color: CanvasText;
&.highlighting {

View file

@ -28,6 +28,7 @@ import { removeNullCharacters } from "./ui_utils.js";
* @property {TextHighlighter} highlighter - Optional object that will handle
* highlighting text from the find controller.
* @property {TextAccessibilityManager} [accessibilityManager]
* @property {function} [onAppend]
*/
/**
@ -38,6 +39,8 @@ import { removeNullCharacters } from "./ui_utils.js";
class TextLayerBuilder {
#enablePermissions = false;
#onAppend = null;
#rotation = 0;
#scale = 0;
@ -48,6 +51,7 @@ class TextLayerBuilder {
highlighter = null,
accessibilityManager = null,
enablePermissions = false,
onAppend = null,
}) {
this.textContentItemsStr = [];
this.renderingDone = false;
@ -57,14 +61,10 @@ class TextLayerBuilder {
this.highlighter = highlighter;
this.accessibilityManager = accessibilityManager;
this.#enablePermissions = enablePermissions === true;
/**
* Callback used to attach the textLayer to the DOM.
* @type {function}
*/
this.onAppend = null;
this.#onAppend = onAppend;
this.div = document.createElement("div");
this.div.tabIndex = 0;
this.div.className = "textLayer";
}
@ -132,7 +132,7 @@ class TextLayerBuilder {
this.#rotation = rotation;
// Ensure that the textLayer is appended to the DOM *before* handling
// e.g. a pending search operation.
this.onAppend(this.div);
this.#onAppend?.(this.div);
this.highlighter?.enable();
this.accessibilityManager?.enable();
}