Skip to content

Commit

Permalink
Merge pull request #18492 from calixteman/new_stamp_dialog
Browse files Browse the repository at this point in the history
[Editor] Implement the new alt text flow (bug 1909604)
  • Loading branch information
calixteman authored Jul 30, 2024
2 parents 7199c96 + ed22d93 commit 8f45374
Show file tree
Hide file tree
Showing 22 changed files with 1,365 additions and 90 deletions.
2 changes: 2 additions & 0 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ function createWebpackAlias(defines) {
"web-annotation_editor_params": "web/annotation_editor_params.js",
"web-download_manager": "",
"web-external_services": "",
"web-new_alt_text_manager": "web/new_alt_text_manager.js",
"web-null_l10n": "",
"web-pdf_attachment_viewer": "web/pdf_attachment_viewer.js",
"web-pdf_cursor_tools": "web/pdf_cursor_tools.js",
Expand Down Expand Up @@ -1097,6 +1098,7 @@ function buildComponents(defines, dir) {
"web/images/loading-icon.gif",
"web/images/altText_*.svg",
"web/images/editor-toolbar-*.svg",
"web/images/messageBar_*.svg",
"web/images/toolbarButton-{editorHighlight,menuArrow}.svg",
"web/images/cursor-*.svg",
];
Expand Down
49 changes: 49 additions & 0 deletions l10n/en-US/viewer.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,52 @@ pdfjs-editor-colorpicker-red =
pdfjs-editor-highlight-show-all-button-label = Show all
pdfjs-editor-highlight-show-all-button =
.title = Show all
## New alt-text dialog
## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.

# Modal header positioned above a text box where users can edit the alt text.
pdfjs-editor-new-alt-text-dialog-edit-label = Edit alt text (image description)
# Modal header positioned above a text box where users can add the alt text.
pdfjs-editor-new-alt-text-dialog-add-label = Add alt text (image description)
pdfjs-editor-new-alt-text-textarea =
.placeholder = Write your description here…
# This text refers to the alt text box above this description. It offers a definition of alt text.
pdfjs-editor-new-alt-text-description = Short description for people who can’t see the image or when the image doesn’t load.
# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
pdfjs-editor-new-alt-text-disclaimer = This alt text was created automatically.
pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Learn more
pdfjs-editor-new-alt-text-create-automatically-button-label = Create alt text automatically
pdfjs-editor-new-alt-text-not-now-button = Not now
pdfjs-editor-new-alt-text-error-title = Couldn’t create alt text automatically
pdfjs-editor-new-alt-text-error-description = Please write your own alt text or try again later.
pdfjs-editor-new-alt-text-error-close-button = Close
# Variables:
# $totalSize (Number) - the total size (in MB) of the AI model.
# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
# $percent (Number) - the percentage of the downloaded size.
pdfjs-editor-new-alt-text-ai-model-downloading-progress =
.aria-valuemin = 0
.aria-valuemax = { $totalSize }
.aria-valuenow = { $downloadedSize }
.aria-valuetext = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
# This is a button that users can click to edit the alt text they have already added.
pdfjs-editor-new-alt-text-added-button-label = Alt text added
# This is a button that users can click to open the alt text editor and add alt text when it is not present.
pdfjs-editor-new-alt-text-missing-button-label = Missing alt text
# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
pdfjs-editor-new-alt-text-to-review-button-label = Review alt text
# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
# Variables:
# $generatedAltText (String) - the generated alt-text.
pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Created automatically: { $generatedAltText }
148 changes: 131 additions & 17 deletions src/display/editor/alt_text.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import { noContextMenu } from "../display_utils.js";

class AltText {
#altText = "";
#altText = null;

#altTextDecorative = false;

Expand All @@ -28,12 +28,21 @@ class AltText {

#altTextWasFromKeyBoard = false;

#badge = null;

#editor = null;

#guessedText = null;

#textWithDisclaimer = null;

#useNewAltTextFlow = false;

static _l10nPromise = null;

constructor(editor) {
this.#editor = editor;
this.#useNewAltTextFlow = editor._uiManager.useNewAltTextFlow;
}

static initialize(l10nPromise) {
Expand All @@ -43,9 +52,17 @@ class AltText {
async render() {
const altText = (this.#altTextButton = document.createElement("button"));
altText.className = "altText";
const msg = await AltText._l10nPromise.get(
"pdfjs-editor-alt-text-button-label"
);
let msg;
if (this.#useNewAltTextFlow) {
altText.classList.add("new");
msg = await AltText._l10nPromise.get(
"pdfjs-editor-new-alt-text-missing-button-label"
);
} else {
msg = await AltText._l10nPromise.get(
"pdfjs-editor-alt-text-button-label"
);
}
altText.textContent = msg;
altText.setAttribute("aria-label", msg);
altText.tabIndex = "0";
Expand Down Expand Up @@ -84,9 +101,62 @@ class AltText {
}

isEmpty() {
if (this.#useNewAltTextFlow) {
return this.#altText === null;
}
return !this.#altText && !this.#altTextDecorative;
}

hasData() {
if (this.#useNewAltTextFlow) {
return this.#altText !== null || !!this.#guessedText;
}
return this.isEmpty();
}

get guessedText() {
return this.#guessedText;
}

async setGuessedText(guessedText) {
if (this.#altText !== null) {
// The user provided their own alt text, so we don't want to overwrite it.
return;
}
this.#guessedText = guessedText;
this.#textWithDisclaimer = await AltText._l10nPromise.get(
"pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer"
)({ generatedAltText: guessedText });
this.#setState();
}

toggleAltTextBadge(visibility = false) {
if (!this.#useNewAltTextFlow || this.#altText) {
this.#badge?.remove();
this.#badge = null;
return;
}
if (!this.#badge) {
const badge = (this.#badge = document.createElement("div"));
badge.className = "noAltTextBadge";
this.#editor.div.append(badge);
}
this.#badge.classList.toggle("hidden", !visibility);
}

serialize(isForCopying) {
let altText = this.#altText;
if (!isForCopying && this.#guessedText === altText) {
altText = this.#textWithDisclaimer;
}
return {
altText,
decorative: this.#altTextDecorative,
guessedText: this.#guessedText,
textWithDisclaimer: this.#textWithDisclaimer,
};
}

get data() {
return {
altText: this.#altText,
Expand All @@ -97,12 +167,24 @@ class AltText {
/**
* Set the alt text data.
*/
set data({ altText, decorative }) {
set data({
altText,
decorative,
guessedText,
textWithDisclaimer,
cancel = false,
}) {
if (guessedText) {
this.#guessedText = guessedText;
this.#textWithDisclaimer = textWithDisclaimer;
}
if (this.#altText === altText && this.#altTextDecorative === decorative) {
return;
}
this.#altText = altText;
this.#altTextDecorative = decorative;
if (!cancel) {
this.#altText = altText;
this.#altTextDecorative = decorative;
}
this.#setState();
}

Expand All @@ -121,25 +203,57 @@ class AltText {
this.#altTextButton?.remove();
this.#altTextButton = null;
this.#altTextTooltip = null;
this.#badge?.remove();
this.#badge = null;
}

async #setState() {
const button = this.#altTextButton;
if (!button) {
return;
}
if (!this.#altText && !this.#altTextDecorative) {
button.classList.remove("done");
this.#altTextTooltip?.remove();
return;

if (this.#useNewAltTextFlow) {
// If we've an alt text, we get an "added".
// If we've a guessed text and the alt text has never been set, we get a
// "to-review" been set.
// Otherwise, we get a "missing".
const type =
(this.#altText && "added") ||
(this.#altText === null && this.guessedText && "to-review") ||
"missing";
button.classList.toggle("done", !!this.#altText);
AltText._l10nPromise
.get(`pdfjs-editor-new-alt-text-${type}-button-label`)
.then(msg => {
button.setAttribute("aria-label", msg);
// We can't just use button.textContent here, because it would remove
// the existing tooltip element.
for (const child of button.childNodes) {
if (child.nodeType === Node.TEXT_NODE) {
child.textContent = msg;
break;
}
}
});
if (!this.#altText) {
this.#altTextTooltip?.remove();
return;
}
} else {
if (!this.#altText && !this.#altTextDecorative) {
button.classList.remove("done");
this.#altTextTooltip?.remove();
return;
}
button.classList.add("done");
AltText._l10nPromise
.get("pdfjs-editor-alt-text-edit-button-label")
.then(msg => {
button.setAttribute("aria-label", msg);
});
}
button.classList.add("done");

AltText._l10nPromise
.get("pdfjs-editor-alt-text-edit-button-label")
.then(msg => {
button.setAttribute("aria-label", msg);
});
let tooltip = this.#altTextTooltip;
if (!tooltip) {
this.#altTextTooltip = tooltip = document.createElement("span");
Expand Down
Loading

0 comments on commit 8f45374

Please sign in to comment.