mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-19 06:38:07 +02:00
Pop open a message when user deletes an annotation
When a user deletes any number of annotations, they are notified of the action by a popup message with an undo button. Besides that, this change reuses the existing messageBar CSS class from the new alt-text dialog as much as possible.
This commit is contained in:
parent
962eb6206a
commit
dd82d78a2d
11 changed files with 321 additions and 3 deletions
|
@ -1148,6 +1148,7 @@ function buildComponents(defines, dir) {
|
|||
"web/images/messageBar_*.svg",
|
||||
"web/images/toolbarButton-{editorHighlight,menuArrow}.svg",
|
||||
"web/images/cursor-*.svg",
|
||||
"web/images/secondaryToolbarButton-documentProperties.svg",
|
||||
];
|
||||
|
||||
return ordered([
|
||||
|
|
|
@ -503,3 +503,24 @@ pdfjs-editor-alt-text-settings-editor-title = Alt text editor
|
|||
pdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image
|
||||
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
|
||||
|
||||
## "Annotations removed" bar
|
||||
|
||||
pdfjs-editor-undo-bar-message-highlight = Highlight removed
|
||||
pdfjs-editor-undo-bar-message-freetext = Text removed
|
||||
pdfjs-editor-undo-bar-message-ink = Drawing removed
|
||||
pdfjs-editor-undo-bar-message-stamp = Image removed
|
||||
# Variables:
|
||||
# $count (Number) - the number of removed annotations.
|
||||
pdfjs-editor-undo-bar-message-multiple =
|
||||
{ $count ->
|
||||
[one] { $count } annotation removed
|
||||
*[other] { $count } annotations removed
|
||||
}
|
||||
|
||||
pdfjs-editor-undo-bar-undo-button =
|
||||
.title = Undo
|
||||
pdfjs-editor-undo-bar-undo-button-label = Undo
|
||||
pdfjs-editor-undo-bar-close-button =
|
||||
.title = Close
|
||||
pdfjs-editor-undo-bar-close-button-label = Close
|
||||
|
|
|
@ -676,6 +676,7 @@ class DrawingEditor extends AnnotationEditor {
|
|||
signal,
|
||||
});
|
||||
parent.toggleDrawing();
|
||||
uiManager._editorUndoBar?.hide();
|
||||
|
||||
if (this._currentDraw) {
|
||||
parent.drawLayer.updateProperties(
|
||||
|
|
|
@ -1142,6 +1142,8 @@ class AnnotationEditor {
|
|||
|
||||
bindEvents(this, this.div, ["pointerdown"]);
|
||||
|
||||
this._uiManager._editorUndoBar?.hide();
|
||||
|
||||
return this.div;
|
||||
}
|
||||
|
||||
|
|
|
@ -620,6 +620,8 @@ class AnnotationEditorUIManager {
|
|||
|
||||
#editorsToRescale = new Set();
|
||||
|
||||
_editorUndoBar = null;
|
||||
|
||||
#enableHighlightFloatingButton = false;
|
||||
|
||||
#enableUpdatedAddImage = false;
|
||||
|
@ -829,7 +831,8 @@ class AnnotationEditorUIManager {
|
|||
enableHighlightFloatingButton,
|
||||
enableUpdatedAddImage,
|
||||
enableNewAltTextWhenAddingImage,
|
||||
mlManager
|
||||
mlManager,
|
||||
editorUndoBar
|
||||
) {
|
||||
const signal = (this._signal = this.#abortController.signal);
|
||||
this.#container = container;
|
||||
|
@ -864,6 +867,7 @@ class AnnotationEditorUIManager {
|
|||
rotation: 0,
|
||||
};
|
||||
this.isShiftKeyDown = false;
|
||||
this._editorUndoBar = editorUndoBar || null;
|
||||
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
||||
Object.defineProperty(this, "reset", {
|
||||
|
@ -904,6 +908,7 @@ class AnnotationEditorUIManager {
|
|||
clearTimeout(this.#translationTimeoutId);
|
||||
this.#translationTimeoutId = null;
|
||||
}
|
||||
this._editorUndoBar?.destroy();
|
||||
}
|
||||
|
||||
combinedSignal(ac) {
|
||||
|
@ -1656,6 +1661,8 @@ class AnnotationEditorUIManager {
|
|||
this.setEditingState(false);
|
||||
this.#disableAll();
|
||||
|
||||
this._editorUndoBar?.hide();
|
||||
|
||||
this.#updateModeCapability.resolve();
|
||||
return;
|
||||
}
|
||||
|
@ -2038,6 +2045,7 @@ class AnnotationEditorUIManager {
|
|||
hasSomethingToRedo: true,
|
||||
isEmpty: this.#isEmpty(),
|
||||
});
|
||||
this._editorUndoBar?.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2099,6 +2107,10 @@ class AnnotationEditorUIManager {
|
|||
? [drawingEditor]
|
||||
: [...this.#selectedEditors];
|
||||
const cmd = () => {
|
||||
this._editorUndoBar?.show(
|
||||
undo,
|
||||
editors.length === 1 ? editors[0].editorType : editors.length
|
||||
);
|
||||
for (const editor of editors) {
|
||||
editor.remove();
|
||||
}
|
||||
|
|
37
web/app.js
37
web/app.js
|
@ -69,6 +69,7 @@ import { AltTextManager } from "web-alt_text_manager";
|
|||
import { AnnotationEditorParams } from "web-annotation_editor_params";
|
||||
import { CaretBrowsingMode } from "./caret_browsing.js";
|
||||
import { DownloadManager } from "web-download_manager";
|
||||
import { EditorUndoBar } from "./editor_undo_bar.js";
|
||||
import { OverlayManager } from "./overlay_manager.js";
|
||||
import { PasswordPrompt } from "./password_prompt.js";
|
||||
import { PDFAttachmentViewer } from "web-pdf_attachment_viewer";
|
||||
|
@ -192,6 +193,7 @@ const PDFViewerApplication = {
|
|||
_isCtrlKeyDown: false,
|
||||
_caretBrowsing: null,
|
||||
_isScrolling: false,
|
||||
editorUndoBar: null,
|
||||
|
||||
// Called once when the document is loaded.
|
||||
async initialize(appConfig) {
|
||||
|
@ -461,6 +463,10 @@ const PDFViewerApplication = {
|
|||
: null;
|
||||
}
|
||||
|
||||
if (appConfig.editorUndoBar) {
|
||||
this.editorUndoBar = new EditorUndoBar(appConfig.editorUndoBar, eventBus);
|
||||
}
|
||||
|
||||
const enableHWA = AppOptions.get("enableHWA");
|
||||
const pdfViewer = new PDFViewer({
|
||||
container,
|
||||
|
@ -470,6 +476,7 @@ const PDFViewerApplication = {
|
|||
linkService: pdfLinkService,
|
||||
downloadManager,
|
||||
altTextManager,
|
||||
editorUndoBar: this.editorUndoBar,
|
||||
findController,
|
||||
scriptingManager:
|
||||
AppOptions.get("enableScripting") && pdfScriptingManager,
|
||||
|
@ -2732,7 +2739,7 @@ function onTouchEnd(evt) {
|
|||
this._isPinching = false;
|
||||
}
|
||||
|
||||
function onClick(evt) {
|
||||
function closeSecondaryToolbar(evt) {
|
||||
if (!this.secondaryToolbar?.isOpen) {
|
||||
return;
|
||||
}
|
||||
|
@ -2749,6 +2756,20 @@ function onClick(evt) {
|
|||
}
|
||||
}
|
||||
|
||||
function closeEditorUndoBar(evt) {
|
||||
if (!this.editorUndoBar?.isOpen) {
|
||||
return;
|
||||
}
|
||||
if (this.appConfig.secondaryToolbar?.toolbar.contains(evt.target)) {
|
||||
this.editorUndoBar.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(evt) {
|
||||
closeSecondaryToolbar.call(this, evt);
|
||||
closeEditorUndoBar.call(this, evt);
|
||||
}
|
||||
|
||||
function onKeyUp(evt) {
|
||||
// evt.ctrlKey is false hence we use evt.key.
|
||||
if (evt.key === "Control") {
|
||||
|
@ -2759,6 +2780,20 @@ function onKeyUp(evt) {
|
|||
function onKeyDown(evt) {
|
||||
this._isCtrlKeyDown = evt.key === "Control";
|
||||
|
||||
if (
|
||||
this.editorUndoBar?.isOpen &&
|
||||
evt.keyCode !== 9 &&
|
||||
evt.keyCode !== 16 &&
|
||||
!(
|
||||
(evt.keyCode === 13 || evt.keyCode === 32) &&
|
||||
getActiveOrFocusedElement() === this.appConfig.editorUndoBar.undoButton
|
||||
)
|
||||
) {
|
||||
// Hide undo bar on keypress except for Shift, Tab, Shift+Tab.
|
||||
// Also avoid hiding if the undo button is triggered.
|
||||
this.editorUndoBar.hide();
|
||||
}
|
||||
|
||||
if (this.overlayManager.active) {
|
||||
return;
|
||||
}
|
||||
|
|
128
web/editor_undo_bar.js
Normal file
128
web/editor_undo_bar.js
Normal file
|
@ -0,0 +1,128 @@
|
|||
/* Copyright 2024 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.
|
||||
*/
|
||||
|
||||
import { noContextMenu } from "pdfjs-lib";
|
||||
|
||||
class EditorUndoBar {
|
||||
#closeButton = null;
|
||||
|
||||
#container;
|
||||
|
||||
#eventBus = null;
|
||||
|
||||
#focusTimeout = null;
|
||||
|
||||
#initController = null;
|
||||
|
||||
isOpen = false;
|
||||
|
||||
#message;
|
||||
|
||||
#showController = null;
|
||||
|
||||
#undoButton;
|
||||
|
||||
static #l10nMessages = Object.freeze({
|
||||
highlight: "pdfjs-editor-undo-bar-message-highlight",
|
||||
freetext: "pdfjs-editor-undo-bar-message-freetext",
|
||||
stamp: "pdfjs-editor-undo-bar-message-stamp",
|
||||
ink: "pdfjs-editor-undo-bar-message-ink",
|
||||
_multiple: "pdfjs-editor-undo-bar-message-multiple",
|
||||
});
|
||||
|
||||
constructor({ container, message, undoButton, closeButton }, eventBus) {
|
||||
this.#container = container;
|
||||
this.#message = message;
|
||||
this.#undoButton = undoButton;
|
||||
this.#closeButton = closeButton;
|
||||
this.#eventBus = eventBus;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.#initController?.abort();
|
||||
this.#initController = null;
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
show(undoAction, messageData) {
|
||||
if (!this.#initController) {
|
||||
this.#initController = new AbortController();
|
||||
const opts = { signal: this.#initController.signal };
|
||||
const boundHide = this.hide.bind(this);
|
||||
|
||||
this.#container.addEventListener("contextmenu", noContextMenu, opts);
|
||||
this.#closeButton.addEventListener("click", boundHide, opts);
|
||||
this.#eventBus._on("beforeprint", boundHide, opts);
|
||||
this.#eventBus._on("download", boundHide, opts);
|
||||
}
|
||||
|
||||
this.hide();
|
||||
|
||||
if (typeof messageData === "string") {
|
||||
this.#message.setAttribute(
|
||||
"data-l10n-id",
|
||||
EditorUndoBar.#l10nMessages[messageData]
|
||||
);
|
||||
} else {
|
||||
this.#message.setAttribute(
|
||||
"data-l10n-id",
|
||||
EditorUndoBar.#l10nMessages._multiple
|
||||
);
|
||||
this.#message.setAttribute(
|
||||
"data-l10n-args",
|
||||
JSON.stringify({ count: messageData })
|
||||
);
|
||||
}
|
||||
this.isOpen = true;
|
||||
this.#container.hidden = false;
|
||||
|
||||
this.#showController = new AbortController();
|
||||
|
||||
this.#undoButton.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
undoAction();
|
||||
this.hide();
|
||||
},
|
||||
{ signal: this.#showController.signal }
|
||||
);
|
||||
|
||||
// Without the setTimeout, VoiceOver will read out the document title
|
||||
// instead of the popup label.
|
||||
this.#focusTimeout = setTimeout(() => {
|
||||
this.#container.focus();
|
||||
this.#focusTimeout = null;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
hide() {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.#container.hidden = true;
|
||||
|
||||
this.#showController?.abort();
|
||||
this.#showController = null;
|
||||
|
||||
if (this.#focusTimeout) {
|
||||
clearTimeout(this.#focusTimeout);
|
||||
this.#focusTimeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { EditorUndoBar };
|
|
@ -125,3 +125,97 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#editorUndoBar {
|
||||
--text-primary-color: #15141a;
|
||||
|
||||
--message-bar-icon: url(images/secondaryToolbarButton-documentProperties.svg);
|
||||
--message-bar-icon-color: #0060df;
|
||||
--message-bar-bg-color: #deeafc;
|
||||
--message-bar-fg-color: var(--text-primary-color);
|
||||
--message-bar-border-color: rgb(0 0 0 / 0.08);
|
||||
|
||||
--undo-button-bg-color: rgb(21 20 26 / 0.07);
|
||||
--undo-button-bg-color-hover: rgb(21 20 26 / 0.14);
|
||||
--undo-button-bg-color-active: rgb(21 20 26 / 0.21);
|
||||
|
||||
--undo-button-fg-color: var(--message-bar-fg-color);
|
||||
--undo-button-fg-color-hover: var(--undo-button-fg-color);
|
||||
--undo-button-fg-color-active: var(--undo-button-fg-color);
|
||||
|
||||
--focus-ring-color: #0060df;
|
||||
--focus-ring-outline: 2px solid var(--focus-ring-color);
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--text-primary-color: #fbfbfe;
|
||||
|
||||
--message-bar-icon-color: #73a7f3;
|
||||
--message-bar-bg-color: #003070;
|
||||
--message-bar-border-color: rgb(255 255 255 / 0.08);
|
||||
|
||||
--undo-button-bg-color: rgb(255 255 255 / 0.08);
|
||||
--undo-button-bg-color-hover: rgb(255 255 255 / 0.14);
|
||||
--undo-button-bg-color-active: rgb(255 255 255 / 0.21);
|
||||
}
|
||||
|
||||
@media screen and (forced-colors: active) {
|
||||
--text-primary-color: CanvasText;
|
||||
|
||||
--message-bar-icon-color: CanvasText;
|
||||
--message-bar-bg-color: Canvas;
|
||||
--message-bar-border-color: CanvasText;
|
||||
|
||||
--undo-button-bg-color: ButtonText;
|
||||
--undo-button-bg-color-hover: SelectedItem;
|
||||
--undo-button-bg-color-active: SelectedItem;
|
||||
|
||||
--undo-button-fg-color: ButtonFace;
|
||||
--undo-button-fg-color-hover: SelectedItemText;
|
||||
--undo-button-fg-color-active: SelectedItemText;
|
||||
|
||||
--focus-ring-color: CanvasText;
|
||||
}
|
||||
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 10;
|
||||
|
||||
padding-block: 8px;
|
||||
padding-inline: 16px 8px;
|
||||
|
||||
font: menu;
|
||||
font-size: 15px;
|
||||
|
||||
cursor: default;
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#editorUndoBarUndoButton {
|
||||
border-radius: 4px;
|
||||
font-weight: 590;
|
||||
line-height: 19.5px;
|
||||
color: var(--undo-button-fg-color);
|
||||
border: none;
|
||||
padding: 4px 16px;
|
||||
margin-inline-start: 8px;
|
||||
height: 32px;
|
||||
|
||||
background-color: var(--undo-button-bg-color);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--undo-button-bg-color-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--undo-button-bg-color-active);
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,6 +214,8 @@ class PDFViewer {
|
|||
|
||||
#containerTopLeft = null;
|
||||
|
||||
#editorUndoBar = null;
|
||||
|
||||
#enableHWA = false;
|
||||
|
||||
#enableHighlightFloatingButton = false;
|
||||
|
@ -281,6 +283,7 @@ class PDFViewer {
|
|||
this.downloadManager = options.downloadManager || null;
|
||||
this.findController = options.findController || null;
|
||||
this.#altTextManager = options.altTextManager || null;
|
||||
this.#editorUndoBar = options.editorUndoBar || null;
|
||||
|
||||
if (this.findController) {
|
||||
this.findController.onIsPageVisible = pageNumber =>
|
||||
|
@ -907,7 +910,8 @@ class PDFViewer {
|
|||
this.#enableHighlightFloatingButton,
|
||||
this.#enableUpdatedAddImage,
|
||||
this.#enableNewAltTextWhenAddingImage,
|
||||
this.#mlManager
|
||||
this.#mlManager,
|
||||
this.#editorUndoBar
|
||||
);
|
||||
eventBus.dispatch("annotationeditoruimanager", {
|
||||
source: this,
|
||||
|
|
|
@ -688,6 +688,20 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
<!--#endif-->
|
||||
</div> <!-- dialogContainer -->
|
||||
|
||||
<div id="editorUndoBar" class="messageBar" role="status" aria-labelledby="editorUndoBarMessage" tabindex="-1" hidden>
|
||||
<div>
|
||||
<div>
|
||||
<span id="editorUndoBarMessage" class="description"></span>
|
||||
</div>
|
||||
<button id="editorUndoBarUndoButton" class="undoButton" type="button" tabindex="0" title="Undo" data-l10n-id="pdfjs-editor-undo-bar-undo-button">
|
||||
<span data-l10n-id="pdfjs-editor-undo-bar-undo-button-label">Undo</span>
|
||||
</button>
|
||||
<button id="editorUndoBarCloseButton" class="closeButton" type="button" tabindex="0" title="Close" data-l10n-id="pdfjs-editor-undo-bar-close-button">
|
||||
<span data-l10n-id="pdfjs-editor-undo-bar-close-button-label">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div> <!-- editorUndoBar -->
|
||||
|
||||
</div> <!-- outerContainer -->
|
||||
<div id="printContainer"></div>
|
||||
</body>
|
||||
|
|
|
@ -223,6 +223,12 @@ function getViewerConfiguration() {
|
|||
editorHighlightShowAll: document.getElementById("editorHighlightShowAll"),
|
||||
},
|
||||
printContainer: document.getElementById("printContainer"),
|
||||
editorUndoBar: {
|
||||
container: document.getElementById("editorUndoBar"),
|
||||
message: document.getElementById("editorUndoBarMessage"),
|
||||
undoButton: document.getElementById("editorUndoBarUndoButton"),
|
||||
closeButton: document.getElementById("editorUndoBarCloseButton"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue