[Editor] Allow the user to add and save an alt-text for images (bug 1844952)
This commit is contained in:
parent
daae6589b6
commit
c12049db07
@ -34,8 +34,14 @@ import { FeatureTest, shadow, unreachable } from "../../shared/util.js";
|
|||||||
* Base class for editors.
|
* Base class for editors.
|
||||||
*/
|
*/
|
||||||
class AnnotationEditor {
|
class AnnotationEditor {
|
||||||
|
#altText = "";
|
||||||
|
|
||||||
|
#altTextDecorative = false;
|
||||||
|
|
||||||
#altTextButton = null;
|
#altTextButton = null;
|
||||||
|
|
||||||
|
#altTextAriaDescription = null;
|
||||||
|
|
||||||
#keepAspectRatio = false;
|
#keepAspectRatio = false;
|
||||||
|
|
||||||
#resizersDiv = null;
|
#resizersDiv = null;
|
||||||
@ -810,7 +816,7 @@ class AnnotationEditor {
|
|||||||
if (this.#altTextButton) {
|
if (this.#altTextButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const altText = (this.#altTextButton = document.createElement("span"));
|
const altText = (this.#altTextButton = document.createElement("button"));
|
||||||
altText.className = "altText";
|
altText.className = "altText";
|
||||||
AnnotationEditor._l10nPromise.get("alt_text_button_label").then(msg => {
|
AnnotationEditor._l10nPromise.get("alt_text_button_label").then(msg => {
|
||||||
altText.textContent = msg;
|
altText.textContent = msg;
|
||||||
@ -820,14 +826,17 @@ class AnnotationEditor {
|
|||||||
"click",
|
"click",
|
||||||
event => {
|
event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
this._uiManager.editAltText(this);
|
||||||
},
|
},
|
||||||
{ capture: true }
|
{ capture: true }
|
||||||
);
|
);
|
||||||
altText.addEventListener("keydown", event => {
|
altText.addEventListener("keydown", event => {
|
||||||
if (event.target === altText && event.key === "Enter") {
|
if (event.target === altText && event.key === "Enter") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
this._uiManager.editAltText(this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.#setAltTextButtonState();
|
||||||
this.div.append(altText);
|
this.div.append(altText);
|
||||||
if (!AnnotationEditor.SMALL_EDITOR_SIZE) {
|
if (!AnnotationEditor.SMALL_EDITOR_SIZE) {
|
||||||
// We take the width of the alt text button and we add 40% to it to be
|
// We take the width of the alt text button and we add 40% to it to be
|
||||||
@ -840,6 +849,55 @@ class AnnotationEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#setAltTextButtonState() {
|
||||||
|
const button = this.#altTextButton;
|
||||||
|
if (!button) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: remove the aria-describedby once the tooltip stuff is implemented:
|
||||||
|
// the tooltip willl contain a span with the description, hence we could use
|
||||||
|
// it.
|
||||||
|
if (this.#altTextDecorative) {
|
||||||
|
button.classList.add("done");
|
||||||
|
button.title = "";
|
||||||
|
if (this.#altTextAriaDescription) {
|
||||||
|
button.removeAttribute("aria-describedby");
|
||||||
|
this.#altTextAriaDescription.remove();
|
||||||
|
this.#altTextAriaDescription = null;
|
||||||
|
}
|
||||||
|
} else if (this.#altText) {
|
||||||
|
button.classList.add("done");
|
||||||
|
button.title = this.#altText;
|
||||||
|
let description = this.#altTextAriaDescription;
|
||||||
|
if (!description) {
|
||||||
|
this.#altTextAriaDescription = description =
|
||||||
|
document.createElement("span");
|
||||||
|
description.className = "description";
|
||||||
|
const id = (description.id = `${this.id}-alt-text`);
|
||||||
|
button.append(description);
|
||||||
|
button.setAttribute("aria-describedby", id);
|
||||||
|
}
|
||||||
|
description.innerText = this.#altText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getClientDimensions() {
|
||||||
|
return this.div.getBoundingClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
get altTextData() {
|
||||||
|
return {
|
||||||
|
altText: this.#altText,
|
||||||
|
decorative: this.#altTextDecorative,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
set altTextData({ altText, decorative }) {
|
||||||
|
this.#altText = altText;
|
||||||
|
this.#altTextDecorative = decorative;
|
||||||
|
this.#setAltTextButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render this editor in a div.
|
* Render this editor in a div.
|
||||||
* @returns {HTMLDivElement}
|
* @returns {HTMLDivElement}
|
||||||
|
@ -484,7 +484,7 @@ class StampEditor extends AnnotationEditor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const editor = super.deserialize(data, parent, uiManager);
|
const editor = super.deserialize(data, parent, uiManager);
|
||||||
const { rect, bitmapUrl, bitmapId, isSvg } = data;
|
const { rect, bitmapUrl, bitmapId, isSvg, accessibilityData } = data;
|
||||||
if (bitmapId && uiManager.imageManager.isValidId(bitmapId)) {
|
if (bitmapId && uiManager.imageManager.isValidId(bitmapId)) {
|
||||||
editor.#bitmapId = bitmapId;
|
editor.#bitmapId = bitmapId;
|
||||||
} else {
|
} else {
|
||||||
@ -496,6 +496,10 @@ class StampEditor extends AnnotationEditor {
|
|||||||
editor.width = (rect[2] - rect[0]) / parentWidth;
|
editor.width = (rect[2] - rect[0]) / parentWidth;
|
||||||
editor.height = (rect[3] - rect[1]) / parentHeight;
|
editor.height = (rect[3] - rect[1]) / parentHeight;
|
||||||
|
|
||||||
|
if (accessibilityData) {
|
||||||
|
editor.altTextData = accessibilityData;
|
||||||
|
}
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,9 +524,15 @@ class StampEditor extends AnnotationEditor {
|
|||||||
// of this annotation and the clipboard doesn't support ImageBitmaps,
|
// of this annotation and the clipboard doesn't support ImageBitmaps,
|
||||||
// hence we serialize the bitmap to a data url.
|
// hence we serialize the bitmap to a data url.
|
||||||
serialized.bitmapUrl = this.#serializeBitmap(/* toUrl = */ true);
|
serialized.bitmapUrl = this.#serializeBitmap(/* toUrl = */ true);
|
||||||
|
serialized.accessibilityData = this.altTextData;
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { decorative, altText } = this.altTextData;
|
||||||
|
if (!decorative && altText) {
|
||||||
|
serialized.accessibilityData = { type: "Figure", alt: altText };
|
||||||
|
}
|
||||||
|
|
||||||
if (context === null) {
|
if (context === null) {
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
@ -525,6 +525,8 @@ class AnnotationEditorUIManager {
|
|||||||
|
|
||||||
#allLayers = new Map();
|
#allLayers = new Map();
|
||||||
|
|
||||||
|
#altTextManager = null;
|
||||||
|
|
||||||
#annotationStorage = null;
|
#annotationStorage = null;
|
||||||
|
|
||||||
#commandManager = new CommandManager();
|
#commandManager = new CommandManager();
|
||||||
@ -693,9 +695,17 @@ class AnnotationEditorUIManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(container, viewer, eventBus, pdfDocument, pageColors) {
|
constructor(
|
||||||
|
container,
|
||||||
|
viewer,
|
||||||
|
altTextManager,
|
||||||
|
eventBus,
|
||||||
|
pdfDocument,
|
||||||
|
pageColors
|
||||||
|
) {
|
||||||
this.#container = container;
|
this.#container = container;
|
||||||
this.#viewer = viewer;
|
this.#viewer = viewer;
|
||||||
|
this.#altTextManager = altTextManager;
|
||||||
this.#eventBus = eventBus;
|
this.#eventBus = eventBus;
|
||||||
this.#eventBus._on("editingaction", this.#boundOnEditingAction);
|
this.#eventBus._on("editingaction", this.#boundOnEditingAction);
|
||||||
this.#eventBus._on("pagechanging", this.#boundOnPageChanging);
|
this.#eventBus._on("pagechanging", this.#boundOnPageChanging);
|
||||||
@ -711,7 +721,7 @@ class AnnotationEditorUIManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.#removeKeyboardManager();
|
this.removeKeyboardManager();
|
||||||
this.#removeFocusManager();
|
this.#removeFocusManager();
|
||||||
this.#eventBus._off("editingaction", this.#boundOnEditingAction);
|
this.#eventBus._off("editingaction", this.#boundOnEditingAction);
|
||||||
this.#eventBus._off("pagechanging", this.#boundOnPageChanging);
|
this.#eventBus._off("pagechanging", this.#boundOnPageChanging);
|
||||||
@ -726,6 +736,7 @@ class AnnotationEditorUIManager {
|
|||||||
this.#activeEditor = null;
|
this.#activeEditor = null;
|
||||||
this.#selectedEditors.clear();
|
this.#selectedEditors.clear();
|
||||||
this.#commandManager.destroy();
|
this.#commandManager.destroy();
|
||||||
|
this.#altTextManager.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
get hcmFilter() {
|
get hcmFilter() {
|
||||||
@ -749,6 +760,10 @@ class AnnotationEditorUIManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editAltText(editor) {
|
||||||
|
this.#altTextManager?.editAltText(this, editor);
|
||||||
|
}
|
||||||
|
|
||||||
onPageChanging({ pageNumber }) {
|
onPageChanging({ pageNumber }) {
|
||||||
this.#currentPageIndex = pageNumber - 1;
|
this.#currentPageIndex = pageNumber - 1;
|
||||||
}
|
}
|
||||||
@ -860,13 +875,13 @@ class AnnotationEditorUIManager {
|
|||||||
lastActiveElement.focus();
|
lastActiveElement.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
#addKeyboardManager() {
|
addKeyboardManager() {
|
||||||
// The keyboard events are caught at the container level in order to be able
|
// The keyboard events are caught at the container level in order to be able
|
||||||
// to execute some callbacks even if the current page doesn't have focus.
|
// to execute some callbacks even if the current page doesn't have focus.
|
||||||
window.addEventListener("keydown", this.#boundKeydown, { capture: true });
|
window.addEventListener("keydown", this.#boundKeydown, { capture: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
#removeKeyboardManager() {
|
removeKeyboardManager() {
|
||||||
window.removeEventListener("keydown", this.#boundKeydown, {
|
window.removeEventListener("keydown", this.#boundKeydown, {
|
||||||
capture: true,
|
capture: true,
|
||||||
});
|
});
|
||||||
@ -1039,7 +1054,7 @@ class AnnotationEditorUIManager {
|
|||||||
setEditingState(isEditing) {
|
setEditingState(isEditing) {
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
this.#addFocusManager();
|
this.#addFocusManager();
|
||||||
this.#addKeyboardManager();
|
this.addKeyboardManager();
|
||||||
this.#addCopyPasteListeners();
|
this.#addCopyPasteListeners();
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
isEditing: this.#mode !== AnnotationEditorType.NONE,
|
isEditing: this.#mode !== AnnotationEditorType.NONE,
|
||||||
@ -1050,7 +1065,7 @@ class AnnotationEditorUIManager {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.#removeFocusManager();
|
this.#removeFocusManager();
|
||||||
this.#removeKeyboardManager();
|
this.removeKeyboardManager();
|
||||||
this.#removeCopyPasteListeners();
|
this.#removeCopyPasteListeners();
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
|
190
web/alt_text_manager.js
Normal file
190
web/alt_text_manager.js
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/* Copyright 2023 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AltTextManager {
|
||||||
|
#boundUpdateUIState = this.#updateUIState.bind(this);
|
||||||
|
|
||||||
|
#boundSetPosition = this.#setPosition.bind(this);
|
||||||
|
|
||||||
|
#currentEditor = null;
|
||||||
|
|
||||||
|
#dialog;
|
||||||
|
|
||||||
|
#eventBus = null;
|
||||||
|
|
||||||
|
#optionDescription;
|
||||||
|
|
||||||
|
#optionDecorative;
|
||||||
|
|
||||||
|
#overlayManager;
|
||||||
|
|
||||||
|
#saveButton;
|
||||||
|
|
||||||
|
#textarea;
|
||||||
|
|
||||||
|
#uiManager;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
{
|
||||||
|
dialog,
|
||||||
|
optionDescription,
|
||||||
|
optionDecorative,
|
||||||
|
textarea,
|
||||||
|
cancelButton,
|
||||||
|
saveButton,
|
||||||
|
},
|
||||||
|
overlayManager,
|
||||||
|
eventBus
|
||||||
|
) {
|
||||||
|
this.#dialog = dialog;
|
||||||
|
this.#optionDescription = optionDescription;
|
||||||
|
this.#optionDecorative = optionDecorative;
|
||||||
|
this.#textarea = textarea;
|
||||||
|
this.#saveButton = saveButton;
|
||||||
|
this.#overlayManager = overlayManager;
|
||||||
|
this.#eventBus = eventBus;
|
||||||
|
|
||||||
|
dialog.addEventListener("close", this.#close.bind(this));
|
||||||
|
cancelButton.addEventListener("click", this.#finish.bind(this));
|
||||||
|
saveButton.addEventListener("click", this.#save.bind(this));
|
||||||
|
optionDescription.addEventListener("change", this.#boundUpdateUIState);
|
||||||
|
optionDecorative.addEventListener("change", this.#boundUpdateUIState);
|
||||||
|
textarea.addEventListener("input", this.#boundUpdateUIState);
|
||||||
|
|
||||||
|
this.#overlayManager.register(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
async editAltText(uiManager, editor) {
|
||||||
|
if (this.#currentEditor || !editor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { altText, decorative } = editor.altTextData;
|
||||||
|
if (decorative === true) {
|
||||||
|
this.#optionDecorative.checked = true;
|
||||||
|
this.#optionDescription.checked = false;
|
||||||
|
} else {
|
||||||
|
this.#optionDecorative.checked = false;
|
||||||
|
this.#optionDescription.checked = true;
|
||||||
|
}
|
||||||
|
this.#textarea.value = altText?.trim() || "";
|
||||||
|
this.#updateUIState();
|
||||||
|
|
||||||
|
this.#currentEditor = editor;
|
||||||
|
this.#uiManager = uiManager;
|
||||||
|
this.#uiManager.removeKeyboardManager();
|
||||||
|
this.#eventBus._on("resize", this.#boundSetPosition);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.#overlayManager.open(this.#dialog);
|
||||||
|
this.#setPosition();
|
||||||
|
} catch (ex) {
|
||||||
|
this.#close();
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#setPosition() {
|
||||||
|
if (!this.#currentEditor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dialog = this.#dialog;
|
||||||
|
const { style } = dialog;
|
||||||
|
const { innerWidth: windowW, innerHeight: windowH } = window;
|
||||||
|
const { width: dialogW, height: dialogH } = dialog.getBoundingClientRect();
|
||||||
|
const { x, y, width, height } = this.#currentEditor.getClientDimensions();
|
||||||
|
const MARGIN = 10;
|
||||||
|
const isLTR = this.#uiManager.direction === "ltr";
|
||||||
|
|
||||||
|
let left = null;
|
||||||
|
let top = Math.max(0, y - MARGIN);
|
||||||
|
top += Math.min(windowH - (top + dialogH), 0);
|
||||||
|
|
||||||
|
if (isLTR) {
|
||||||
|
// Prefer to position the dialog "after" (so on the right) the editor.
|
||||||
|
if (x + width + MARGIN + dialogW < windowW) {
|
||||||
|
left = x + width + MARGIN;
|
||||||
|
} else if (x > dialogW + MARGIN) {
|
||||||
|
left = x - dialogW - MARGIN;
|
||||||
|
}
|
||||||
|
} else if (x > dialogW + MARGIN) {
|
||||||
|
left = x - dialogW - MARGIN;
|
||||||
|
} else if (x + width + MARGIN + dialogW < windowW) {
|
||||||
|
left = x + width + MARGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left === null) {
|
||||||
|
top = null;
|
||||||
|
left = Math.max(0, x - MARGIN);
|
||||||
|
left += Math.min(windowW - (left + dialogW), 0);
|
||||||
|
if (y > dialogH + MARGIN) {
|
||||||
|
top = y - dialogH - MARGIN;
|
||||||
|
} else if (y + height + MARGIN + dialogH < windowH) {
|
||||||
|
top = y + height + MARGIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top !== null) {
|
||||||
|
dialog.classList.add("positioned");
|
||||||
|
if (isLTR) {
|
||||||
|
style.left = `${left}px`;
|
||||||
|
} else {
|
||||||
|
style.right = `${windowW - left - dialogW}px`;
|
||||||
|
}
|
||||||
|
style.top = `${top}px`;
|
||||||
|
} else {
|
||||||
|
dialog.classList.remove("positioned");
|
||||||
|
style.left = "";
|
||||||
|
style.top = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#finish() {
|
||||||
|
if (this.#dialog) {
|
||||||
|
this.#overlayManager.close(this.#dialog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#close() {
|
||||||
|
this.#uiManager?.addKeyboardManager();
|
||||||
|
this.#eventBus._off("resize", this.#boundSetPosition);
|
||||||
|
this.#currentEditor = null;
|
||||||
|
this.#uiManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#updateUIState() {
|
||||||
|
const hasAltText = !!this.#textarea.value.trim();
|
||||||
|
const decorative = this.#optionDecorative.checked;
|
||||||
|
|
||||||
|
this.#textarea.disabled = decorative;
|
||||||
|
this.#saveButton.disabled = !decorative && !hasAltText;
|
||||||
|
}
|
||||||
|
|
||||||
|
#save() {
|
||||||
|
this.#currentEditor.altTextData = {
|
||||||
|
altText: this.#textarea.value.trim(),
|
||||||
|
decorative: this.#optionDecorative.checked,
|
||||||
|
};
|
||||||
|
this.#finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.#currentEditor = null;
|
||||||
|
this.#uiManager = null;
|
||||||
|
this.#finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AltTextManager };
|
@ -528,6 +528,15 @@
|
|||||||
&.done::before {
|
&.done::before {
|
||||||
mask-image: var(--alt-text-done-image);
|
mask-image: var(--alt-text-done-image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& .description {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: none;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#altTextDialog {
|
#altTextDialog {
|
||||||
@ -622,6 +631,10 @@
|
|||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
box-shadow: var(--dialog-shadow);
|
box-shadow: var(--dialog-shadow);
|
||||||
|
|
||||||
|
&.positioned {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
& #altTextContainer {
|
& #altTextContainer {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
@ -728,6 +741,7 @@
|
|||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ import {
|
|||||||
import { AppOptions, OptionKind } from "./app_options.js";
|
import { AppOptions, OptionKind } from "./app_options.js";
|
||||||
import { AutomationEventBus, EventBus } from "./event_utils.js";
|
import { AutomationEventBus, EventBus } from "./event_utils.js";
|
||||||
import { LinkTarget, PDFLinkService } from "./pdf_link_service.js";
|
import { LinkTarget, PDFLinkService } from "./pdf_link_service.js";
|
||||||
|
import { AltTextManager } from "./alt_text_manager.js";
|
||||||
import { AnnotationEditorParams } from "web-annotation_editor_params";
|
import { AnnotationEditorParams } from "web-annotation_editor_params";
|
||||||
import { OverlayManager } from "./overlay_manager.js";
|
import { OverlayManager } from "./overlay_manager.js";
|
||||||
import { PasswordPrompt } from "./password_prompt.js";
|
import { PasswordPrompt } from "./password_prompt.js";
|
||||||
@ -505,6 +506,13 @@ const PDFViewerApplication = {
|
|||||||
foreground: AppOptions.get("pageColorsForeground"),
|
foreground: AppOptions.get("pageColorsForeground"),
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
const altTextManager = appConfig.altTextDialog
|
||||||
|
? new AltTextManager(
|
||||||
|
appConfig.altTextDialog,
|
||||||
|
this.overlayManager,
|
||||||
|
eventBus
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
const pdfViewer = new PDFViewer({
|
const pdfViewer = new PDFViewer({
|
||||||
container,
|
container,
|
||||||
@ -513,6 +521,7 @@ const PDFViewerApplication = {
|
|||||||
renderingQueue: pdfRenderingQueue,
|
renderingQueue: pdfRenderingQueue,
|
||||||
linkService: pdfLinkService,
|
linkService: pdfLinkService,
|
||||||
downloadManager,
|
downloadManager,
|
||||||
|
altTextManager,
|
||||||
findController,
|
findController,
|
||||||
scriptingManager:
|
scriptingManager:
|
||||||
AppOptions.get("enableScripting") && pdfScriptingManager,
|
AppOptions.get("enableScripting") && pdfScriptingManager,
|
||||||
|
@ -199,6 +199,8 @@ class PDFPageViewBuffer {
|
|||||||
class PDFViewer {
|
class PDFViewer {
|
||||||
#buffer = null;
|
#buffer = null;
|
||||||
|
|
||||||
|
#altTextManager = null;
|
||||||
|
|
||||||
#annotationEditorMode = AnnotationEditorType.NONE;
|
#annotationEditorMode = AnnotationEditorType.NONE;
|
||||||
|
|
||||||
#annotationEditorUIManager = null;
|
#annotationEditorUIManager = null;
|
||||||
@ -261,6 +263,7 @@ class PDFViewer {
|
|||||||
this.linkService = options.linkService || new SimpleLinkService();
|
this.linkService = options.linkService || new SimpleLinkService();
|
||||||
this.downloadManager = options.downloadManager || null;
|
this.downloadManager = options.downloadManager || null;
|
||||||
this.findController = options.findController || null;
|
this.findController = options.findController || null;
|
||||||
|
this.#altTextManager = options.altTextManager || null;
|
||||||
|
|
||||||
if (this.findController) {
|
if (this.findController) {
|
||||||
this.findController.onIsPageVisible = pageNumber =>
|
this.findController.onIsPageVisible = pageNumber =>
|
||||||
@ -854,6 +857,7 @@ class PDFViewer {
|
|||||||
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
|
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
|
||||||
this.container,
|
this.container,
|
||||||
this.viewer,
|
this.viewer,
|
||||||
|
this.#altTextManager,
|
||||||
this.eventBus,
|
this.eventBus,
|
||||||
pdfDocument,
|
pdfDocument,
|
||||||
this.pageColors
|
this.pageColors
|
||||||
|
@ -157,6 +157,14 @@ function getViewerConfiguration() {
|
|||||||
linearized: document.getElementById("linearizedField"),
|
linearized: document.getElementById("linearizedField"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
altTextDialog: {
|
||||||
|
dialog: document.getElementById("altTextDialog"),
|
||||||
|
optionDescription: document.getElementById("descriptionButton"),
|
||||||
|
optionDecorative: document.getElementById("decorativeButton"),
|
||||||
|
textarea: document.getElementById("descriptionTextarea"),
|
||||||
|
cancelButton: document.getElementById("altTextCancel"),
|
||||||
|
saveButton: document.getElementById("altTextSave"),
|
||||||
|
},
|
||||||
annotationEditorParams: {
|
annotationEditorParams: {
|
||||||
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
||||||
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user