[Editor] When an annotation is added, announce it if the user is using a screen reader (bug 1975264)
This commit is contained in:
parent
f4043b03e2
commit
c22a425b04
@ -533,6 +533,14 @@ pdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor r
|
||||
pdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.
|
||||
pdfjs-editor-alt-text-settings-close-button = Close
|
||||
|
||||
## Accessibility labels (announced by screen readers) for objects added to the editor.
|
||||
|
||||
pdfjs-editor-highlight-added-alert = Highlight added
|
||||
pdfjs-editor-freetext-added-alert = Text added
|
||||
pdfjs-editor-ink-added-alert = Drawing added
|
||||
pdfjs-editor-stamp-added-alert = Image added
|
||||
pdfjs-editor-signature-added-alert = Signature added
|
||||
|
||||
## "Annotations removed" bar
|
||||
|
||||
pdfjs-editor-undo-bar-message-highlight = Highlight removed
|
||||
|
||||
@ -106,6 +106,9 @@ class DrawingEditor extends AnnotationEditor {
|
||||
#createDrawOutlines({ drawOutlines, drawId, drawingOptions }) {
|
||||
this.#drawOutlines = drawOutlines;
|
||||
this._drawingOptions ||= drawingOptions;
|
||||
if (!this.annotationElementId) {
|
||||
this._uiManager.a11yAlert(`pdfjs-editor-${this.editorType}-added-alert`);
|
||||
}
|
||||
|
||||
if (drawId >= 0) {
|
||||
this._drawId = drawId;
|
||||
|
||||
@ -180,6 +180,7 @@ class AnnotationEditor {
|
||||
this._willKeepAspectRatio = false;
|
||||
this._initialOptions.isCentered = parameters.isCentered;
|
||||
this._structTreeParentId = null;
|
||||
this.annotationElementId = parameters.annotationElementId || null;
|
||||
|
||||
const {
|
||||
rotation,
|
||||
@ -427,6 +428,9 @@ class AnnotationEditor {
|
||||
* Commit the data contained in this editor.
|
||||
*/
|
||||
commit() {
|
||||
if (!this.isInEditMode()) {
|
||||
return;
|
||||
}
|
||||
this.addToAnnotationStorage();
|
||||
}
|
||||
|
||||
@ -1641,6 +1645,7 @@ class AnnotationEditor {
|
||||
parent,
|
||||
id: parent.getNextId(),
|
||||
uiManager,
|
||||
annotationElementId: data.annotationElementId,
|
||||
});
|
||||
editor.rotation = data.rotation;
|
||||
editor.#accessibilityData = data.accessibilityData;
|
||||
|
||||
@ -131,6 +131,9 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
FreeTextEditor._defaultColor ||
|
||||
AnnotationEditor._defaultLineColor;
|
||||
this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize;
|
||||
if (!this.annotationElementId) {
|
||||
this._uiManager.a11yAlert("pdfjs-editor-freetext-added-alert");
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@ -782,6 +785,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
pageIndex: pageNumber - 1,
|
||||
rect: rect.slice(0),
|
||||
rotation,
|
||||
annotationElementId: id,
|
||||
id,
|
||||
deleted: false,
|
||||
popupRef,
|
||||
@ -791,7 +795,6 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
editor.#fontSize = data.fontSize;
|
||||
editor.#color = Util.makeHexColor(...data.color);
|
||||
editor.#content = FreeTextEditor.#deserializeContent(data.value);
|
||||
editor.annotationElementId = data.id || null;
|
||||
editor._initialData = initialData;
|
||||
|
||||
return editor;
|
||||
|
||||
@ -126,6 +126,10 @@ class HighlightEditor extends AnnotationEditor {
|
||||
this.#addToDrawLayer();
|
||||
this.rotate(this.rotation);
|
||||
}
|
||||
|
||||
if (!this.annotationElementId) {
|
||||
this._uiManager.a11yAlert("pdfjs-editor-highlight-added-alert");
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@ -876,6 +880,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
pageIndex: pageNumber - 1,
|
||||
rect: rect.slice(0),
|
||||
rotation,
|
||||
annotationElementId: id,
|
||||
id,
|
||||
deleted: false,
|
||||
popupRef,
|
||||
@ -904,6 +909,7 @@ class HighlightEditor extends AnnotationEditor {
|
||||
pageIndex: pageNumber - 1,
|
||||
rect: rect.slice(0),
|
||||
rotation,
|
||||
annotationElementId: id,
|
||||
id,
|
||||
deleted: false,
|
||||
popupRef,
|
||||
@ -918,7 +924,6 @@ class HighlightEditor extends AnnotationEditor {
|
||||
if (inkLists) {
|
||||
editor.#thickness = data.thickness;
|
||||
}
|
||||
editor.annotationElementId = data.id || null;
|
||||
editor._initialData = initialData;
|
||||
|
||||
const [pageWidth, pageHeight] = editor.pageDimensions;
|
||||
|
||||
@ -164,6 +164,7 @@ class InkEditor extends DrawingEditor {
|
||||
pageIndex: pageNumber - 1,
|
||||
rect: rect.slice(0),
|
||||
rotation,
|
||||
annotationElementId: id,
|
||||
id,
|
||||
deleted: false,
|
||||
popupRef,
|
||||
@ -171,7 +172,6 @@ class InkEditor extends DrawingEditor {
|
||||
}
|
||||
|
||||
const editor = await super.deserialize(data, parent, uiManager);
|
||||
editor.annotationElementId = data.id || null;
|
||||
editor._initialData = initialData;
|
||||
|
||||
return editor;
|
||||
|
||||
@ -484,6 +484,9 @@ class StampEditor extends AnnotationEditor {
|
||||
if (this.#bitmapFileName) {
|
||||
this.div.setAttribute("aria-description", this.#bitmapFileName);
|
||||
}
|
||||
if (!this.annotationElementId) {
|
||||
this._uiManager.a11yAlert("pdfjs-editor-stamp-added-alert");
|
||||
}
|
||||
}
|
||||
|
||||
copyCanvas(maxDataDimension, maxPreviewDimension, createImageData = false) {
|
||||
@ -781,6 +784,7 @@ class StampEditor extends AnnotationEditor {
|
||||
pageIndex: pageNumber - 1,
|
||||
rect: rect.slice(0),
|
||||
rotation,
|
||||
annotationElementId: id,
|
||||
id,
|
||||
deleted: false,
|
||||
accessibilityData: {
|
||||
@ -812,7 +816,6 @@ class StampEditor extends AnnotationEditor {
|
||||
editor.width = (rect[2] - rect[0]) / parentWidth;
|
||||
editor.height = (rect[3] - rect[1]) / parentHeight;
|
||||
|
||||
editor.annotationElementId = data.id || null;
|
||||
if (accessibilityData) {
|
||||
editor.altTextData = accessibilityData;
|
||||
}
|
||||
|
||||
@ -676,6 +676,8 @@ class AnnotationEditorUIManager {
|
||||
|
||||
#viewer = null;
|
||||
|
||||
#viewerAlert = null;
|
||||
|
||||
#updateModeCapability = null;
|
||||
|
||||
static TRANSLATE_SMALL = 1; // page units.
|
||||
@ -818,6 +820,7 @@ class AnnotationEditorUIManager {
|
||||
constructor(
|
||||
container,
|
||||
viewer,
|
||||
viewerAlert,
|
||||
altTextManager,
|
||||
signatureManager,
|
||||
eventBus,
|
||||
@ -834,6 +837,7 @@ class AnnotationEditorUIManager {
|
||||
const signal = (this._signal = this.#abortController.signal);
|
||||
this.#container = container;
|
||||
this.#viewer = viewer;
|
||||
this.#viewerAlert = viewerAlert;
|
||||
this.#altTextManager = altTextManager;
|
||||
this.#signatureManager = signatureManager;
|
||||
this._eventBus = eventBus;
|
||||
@ -1175,6 +1179,19 @@ class AnnotationEditorUIManager {
|
||||
}
|
||||
}
|
||||
|
||||
a11yAlert(messageId, args = null) {
|
||||
const viewerAlert = this.#viewerAlert;
|
||||
if (!viewerAlert) {
|
||||
return;
|
||||
}
|
||||
viewerAlert.setAttribute("data-l10n-id", messageId);
|
||||
if (args) {
|
||||
viewerAlert.setAttribute("data-l10n-args", JSON.stringify(args));
|
||||
} else {
|
||||
viewerAlert.removeAttribute("data-l10n-args");
|
||||
}
|
||||
}
|
||||
|
||||
#selectionChange() {
|
||||
const selection = document.getSelection();
|
||||
if (!selection || selection.isCollapsed) {
|
||||
|
||||
@ -110,6 +110,9 @@ describe("FreeText Editor", () => {
|
||||
await waitForSelectedEditor(page, editorSelector);
|
||||
await waitForStorageEntries(page, 1);
|
||||
|
||||
const alert = await page.$eval("#viewer-alert", el => el.textContent);
|
||||
expect(alert).toEqual("Text added");
|
||||
|
||||
let content = await page.$eval(editorSelector, el =>
|
||||
el.innerText.trimEnd()
|
||||
);
|
||||
|
||||
@ -78,6 +78,9 @@ describe("Highlight Editor", () => {
|
||||
|
||||
await page.waitForSelector(`${getEditorSelector(0)}`);
|
||||
|
||||
const alert = await page.$eval("#viewer-alert", el => el.textContent);
|
||||
expect(alert).toEqual("Highlight added");
|
||||
|
||||
const oneToOne = Array.from(new Array(13).keys(), n => n + 2).concat(
|
||||
Array.from(new Array(13).keys(), n => 13 - n)
|
||||
);
|
||||
|
||||
@ -84,6 +84,9 @@ describe("Ink Editor", () => {
|
||||
await commit(page);
|
||||
}
|
||||
|
||||
const alert = await page.$eval("#viewer-alert", el => el.textContent);
|
||||
expect(alert).toEqual("Drawing added");
|
||||
|
||||
await clearAll(page);
|
||||
|
||||
await kbUndo(page);
|
||||
|
||||
@ -181,6 +181,9 @@ describe("Signature Editor", () => {
|
||||
{ visible: true }
|
||||
);
|
||||
|
||||
const alert = await page.$eval("#viewer-alert", el => el.textContent);
|
||||
expect(alert).toEqual("Signature added");
|
||||
|
||||
// Check the tooltip.
|
||||
await page.waitForSelector(
|
||||
`.altText.editDescription[title="Hello World"]`
|
||||
|
||||
@ -125,6 +125,9 @@ describe("Stamp Editor", () => {
|
||||
const editorSelector = getEditorSelector(0);
|
||||
await waitForImage(page, editorSelector);
|
||||
|
||||
const alert = await page.$eval("#viewer-alert", el => el.textContent);
|
||||
expect(alert).toEqual("Image added");
|
||||
|
||||
const { width } = await getEditorDimensions(page, editorSelector);
|
||||
|
||||
// The image is bigger than the page, so it has been scaled down to
|
||||
|
||||
@ -49,22 +49,6 @@
|
||||
--new-alt-text-warning-image: url(images/altText_warning.svg);
|
||||
}
|
||||
|
||||
/* The following class is used to hide an element but keep it available to
|
||||
* for screen readers. */
|
||||
.visuallyHidden {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.textLayer {
|
||||
&.highlighting {
|
||||
cursor: var(--editorFreeHighlight-editing-cursor);
|
||||
|
||||
@ -492,6 +492,7 @@ const PDFViewerApplication = {
|
||||
const pdfViewer = (this.pdfViewer = new PDFViewer({
|
||||
container,
|
||||
viewer,
|
||||
viewerAlert: appConfig.viewerAlert,
|
||||
eventBus,
|
||||
renderingQueue,
|
||||
linkService,
|
||||
|
||||
@ -278,6 +278,8 @@ class PDFViewer {
|
||||
|
||||
#textLayerMode = TextLayerMode.ENABLE;
|
||||
|
||||
#viewerAlert = null;
|
||||
|
||||
/**
|
||||
* @param {PDFViewerOptions} options
|
||||
*/
|
||||
@ -291,6 +293,7 @@ class PDFViewer {
|
||||
}
|
||||
this.container = options.container;
|
||||
this.viewer = options.viewer || options.container.firstElementChild;
|
||||
this.#viewerAlert = options.viewerAlert || null;
|
||||
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||
if (this.container?.tagName !== "DIV" || this.viewer?.tagName !== "DIV") {
|
||||
@ -927,6 +930,7 @@ class PDFViewer {
|
||||
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
|
||||
this.container,
|
||||
viewer,
|
||||
this.#viewerAlert,
|
||||
this.#altTextManager,
|
||||
this.#signatureManager,
|
||||
eventBus,
|
||||
|
||||
@ -229,6 +229,22 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/* The following class is used to hide an element but keep it available to
|
||||
* for screen readers. */
|
||||
.visuallyHidden {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.hidden,
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
|
||||
@ -98,6 +98,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
</head>
|
||||
|
||||
<body tabindex="0">
|
||||
<span id="viewer-alert" class="visuallyHidden" role="alert"></span>
|
||||
<div id="outerContainer">
|
||||
|
||||
<div id="sidebarContainer">
|
||||
|
||||
@ -33,6 +33,7 @@ function getViewerConfiguration() {
|
||||
principalContainer: document.getElementById("mainContainer"),
|
||||
mainContainer: document.getElementById("viewerContainer"),
|
||||
viewerContainer: document.getElementById("viewer"),
|
||||
viewerAlert: document.getElementById("viewer-alert"),
|
||||
toolbar: {
|
||||
container: document.getElementById("toolbarContainer"),
|
||||
numPages: document.getElementById("numPages"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user