Merge pull request #16983 from calixteman/alt_text_tooltip
[Editor] Add a tooltip showing the alt text when hovering the alt-text button (bug 1844952)
This commit is contained in:
		
						commit
						b7fa4fb0f7
					
				@ -265,9 +265,9 @@ editor_ink2_aria_label=Draw Editor
 | 
				
			|||||||
editor_ink_canvas_aria_label=User-created image
 | 
					editor_ink_canvas_aria_label=User-created image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Alt-text dialog
 | 
					# Alt-text dialog
 | 
				
			||||||
# LOCALIZATION NOTE (alt_text_button_label): Alternative text (alt text) helps
 | 
					# LOCALIZATION NOTE (editor_alt_text_button_label): Alternative text (alt text) helps
 | 
				
			||||||
# when people can't see the image.
 | 
					# when people can't see the image.
 | 
				
			||||||
alt_text_button_label=Alt text
 | 
					editor_alt_text_button_label=Alt text
 | 
				
			||||||
editor_alt_text_dialog_label=Choose an option
 | 
					editor_alt_text_dialog_label=Choose an option
 | 
				
			||||||
editor_alt_text_dialog_description=Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.
 | 
					editor_alt_text_dialog_description=Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.
 | 
				
			||||||
editor_alt_text_enter_description_label=Enter a description
 | 
					editor_alt_text_enter_description_label=Enter a description
 | 
				
			||||||
@ -276,3 +276,4 @@ editor_alt_text_mark_decorative_label=Mark as decorative
 | 
				
			|||||||
editor_alt_text_mark_decorative_description=This is best for images that aren’t informative, like borders or stylistic elements.
 | 
					editor_alt_text_mark_decorative_description=This is best for images that aren’t informative, like borders or stylistic elements.
 | 
				
			||||||
editor_alt_text_cancel_button=Cancel
 | 
					editor_alt_text_cancel_button=Cancel
 | 
				
			||||||
editor_alt_text_save_button=Save
 | 
					editor_alt_text_save_button=Save
 | 
				
			||||||
 | 
					editor_alt_text_decorative_tooltip=Marked as decorative
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,9 @@ class AnnotationEditor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #altTextButton = null;
 | 
					  #altTextButton = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #altTextAriaDescription = null;
 | 
					  #altTextTooltip = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #altTextTooltipTimeout = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #keepAspectRatio = false;
 | 
					  #keepAspectRatio = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -142,7 +144,10 @@ class AnnotationEditor {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  static initialize(l10n, options = null) {
 | 
					  static initialize(l10n, options = null) {
 | 
				
			||||||
    AnnotationEditor._l10nPromise ||= new Map(
 | 
					    AnnotationEditor._l10nPromise ||= new Map(
 | 
				
			||||||
      ["alt_text_button_label"].map(str => [str, l10n.get(str)])
 | 
					      [
 | 
				
			||||||
 | 
					        "editor_alt_text_button_label",
 | 
				
			||||||
 | 
					        "editor_alt_text_decorative_tooltip",
 | 
				
			||||||
 | 
					      ].map(str => [str, l10n.get(str)])
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    if (options?.strings) {
 | 
					    if (options?.strings) {
 | 
				
			||||||
      for (const str of options.strings) {
 | 
					      for (const str of options.strings) {
 | 
				
			||||||
@ -818,7 +823,9 @@ class AnnotationEditor {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const altText = (this.#altTextButton = document.createElement("button"));
 | 
					    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("editor_alt_text_button_label")
 | 
				
			||||||
 | 
					      .then(msg => {
 | 
				
			||||||
        altText.textContent = msg;
 | 
					        altText.textContent = msg;
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    altText.tabIndex = "0";
 | 
					    altText.tabIndex = "0";
 | 
				
			||||||
@ -836,6 +843,18 @@ class AnnotationEditor {
 | 
				
			|||||||
        this._uiManager.editAltText(this);
 | 
					        this._uiManager.editAltText(this);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    const DELAY_TO_SHOW_TOOLTIP = 500;
 | 
				
			||||||
 | 
					    altText.addEventListener("mouseenter", () => {
 | 
				
			||||||
 | 
					      this.#altTextTooltipTimeout = setTimeout(() => {
 | 
				
			||||||
 | 
					        this.#altTextTooltipTimeout = null;
 | 
				
			||||||
 | 
					        this.#altTextTooltip?.classList.add("show");
 | 
				
			||||||
 | 
					      }, DELAY_TO_SHOW_TOOLTIP);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    altText.addEventListener("mouseleave", () => {
 | 
				
			||||||
 | 
					      clearTimeout(this.#altTextTooltipTimeout);
 | 
				
			||||||
 | 
					      this.#altTextTooltipTimeout = null;
 | 
				
			||||||
 | 
					      this.#altTextTooltip?.classList.remove("show");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    this.#setAltTextButtonState();
 | 
					    this.#setAltTextButtonState();
 | 
				
			||||||
    this.div.append(altText);
 | 
					    this.div.append(altText);
 | 
				
			||||||
    if (!AnnotationEditor.SMALL_EDITOR_SIZE) {
 | 
					    if (!AnnotationEditor.SMALL_EDITOR_SIZE) {
 | 
				
			||||||
@ -849,36 +868,30 @@ class AnnotationEditor {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #setAltTextButtonState() {
 | 
					  async #setAltTextButtonState() {
 | 
				
			||||||
    const button = this.#altTextButton;
 | 
					    const button = this.#altTextButton;
 | 
				
			||||||
    if (!button) {
 | 
					    if (!button || (!this.#altTextDecorative && !this.#altText)) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // TODO: remove the aria-describedby once the tooltip stuff is implemented:
 | 
					    let tooltip = this.#altTextTooltip;
 | 
				
			||||||
    // the tooltip willl contain a span with the description, hence we could use
 | 
					    if (!tooltip) {
 | 
				
			||||||
    // it.
 | 
					      this.#altTextTooltip = tooltip = document.createElement("span");
 | 
				
			||||||
    if (this.#altTextDecorative) {
 | 
					      tooltip.className = "tooltip";
 | 
				
			||||||
      button.classList.add("done");
 | 
					      tooltip.setAttribute("role", "tooltip");
 | 
				
			||||||
      button.title = "";
 | 
					      const id = (tooltip.id = `alt-text-tooltip-${this.id}`);
 | 
				
			||||||
      if (this.#altTextAriaDescription) {
 | 
					      button.append(tooltip);
 | 
				
			||||||
        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);
 | 
					      button.setAttribute("aria-describedby", id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
      description.innerText = this.#altText;
 | 
					    button.classList.add("done");
 | 
				
			||||||
 | 
					    if (this.#altTextDecorative) {
 | 
				
			||||||
 | 
					      tooltip.innerText = await AnnotationEditor._l10nPromise.get(
 | 
				
			||||||
 | 
					        "editor_alt_text_decorative_tooltip"
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      tooltip.classList.add("decorative");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    tooltip.innerText = this.#altText;
 | 
				
			||||||
 | 
					    tooltip.classList.remove("decorative");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getClientDimensions() {
 | 
					  getClientDimensions() {
 | 
				
			||||||
 | 
				
			|||||||
@ -529,13 +529,53 @@
 | 
				
			|||||||
    mask-image: var(--alt-text-done-image);
 | 
					    mask-image: var(--alt-text-done-image);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  & .description {
 | 
					  & .tooltip {
 | 
				
			||||||
    position: absolute;
 | 
					 | 
				
			||||||
    top: 0;
 | 
					 | 
				
			||||||
    left: 0;
 | 
					 | 
				
			||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
    width: 0;
 | 
					
 | 
				
			||||||
    height: 0;
 | 
					    &.decorative {
 | 
				
			||||||
 | 
					      font-style: italic;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.show {
 | 
				
			||||||
 | 
					      --alt-text-tooltip-bg: #f0f0f4;
 | 
				
			||||||
 | 
					      --alt-text-tooltip-fg: #15141a;
 | 
				
			||||||
 | 
					      --alt-text-tooltip-border: #8f8f9d;
 | 
				
			||||||
 | 
					      --alt-text-tooltip-shadow: 0px 2px 6px 0px rgba(58, 57, 68, 0.2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @media (prefers-color-scheme: dark) {
 | 
				
			||||||
 | 
					        --alt-text-tooltip-bg: #1c1b22;
 | 
				
			||||||
 | 
					        --alt-text-tooltip-fg: #fbfbfe;
 | 
				
			||||||
 | 
					        --alt-text-tooltip-shadow: 0px 2px 6px 0px #15141a;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @media screen and (forced-colors: active) {
 | 
				
			||||||
 | 
					        --alt-text-tooltip-bg: Canvas;
 | 
				
			||||||
 | 
					        --alt-text-tooltip-fg: CanvasText;
 | 
				
			||||||
 | 
					        --alt-text-tooltip-border: CanvasText;
 | 
				
			||||||
 | 
					        --alt-text-tooltip-shadow: none;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      display: inline-flex;
 | 
				
			||||||
 | 
					      flex-direction: column;
 | 
				
			||||||
 | 
					      align-items: center;
 | 
				
			||||||
 | 
					      justify-content: center;
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      top: calc(100% + 2px);
 | 
				
			||||||
 | 
					      inset-inline-start: 0;
 | 
				
			||||||
 | 
					      padding-block: 2px 3px;
 | 
				
			||||||
 | 
					      padding-inline: 3px;
 | 
				
			||||||
 | 
					      max-width: 300px;
 | 
				
			||||||
 | 
					      width: max-content;
 | 
				
			||||||
 | 
					      height: auto;
 | 
				
			||||||
 | 
					      font-size: 12px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      border: 0.5px solid var(--alt-text-tooltip-border);
 | 
				
			||||||
 | 
					      background: var(--alt-text-tooltip-bg);
 | 
				
			||||||
 | 
					      box-shadow: var(--alt-text-tooltip-shadow);
 | 
				
			||||||
 | 
					      color: var(--alt-text-tooltip-fg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      pointer-events: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -82,7 +82,8 @@ const DEFAULT_L10N_STRINGS = {
 | 
				
			|||||||
  editor_free_text2_aria_label: "Text Editor",
 | 
					  editor_free_text2_aria_label: "Text Editor",
 | 
				
			||||||
  editor_ink2_aria_label: "Draw Editor",
 | 
					  editor_ink2_aria_label: "Draw Editor",
 | 
				
			||||||
  editor_ink_canvas_aria_label: "User-created image",
 | 
					  editor_ink_canvas_aria_label: "User-created image",
 | 
				
			||||||
  alt_text_button_label: "Alt text",
 | 
					  editor_alt_text_button_label: "Alt text",
 | 
				
			||||||
 | 
					  editor_alt_text_decorative_tooltip: "Marked as decorative",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
 | 
					if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
 | 
				
			||||||
  DEFAULT_L10N_STRINGS.print_progress_percent = "{{progress}}%";
 | 
					  DEFAULT_L10N_STRINGS.print_progress_percent = "{{progress}}%";
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user