-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Annotation deletion popup (bug 1899731) #18900
base: master
Are you sure you want to change the base?
Conversation
ebf8d04
to
ae79bee
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will need tests in the various editors, in https://github.com/mozilla/pdf.js/tree/master/test/integration, or maybe its own new test file that tests that the toast is properly shown in the various cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this perhaps related to https://bugzilla.mozilla.org/show_bug.cgi?id=1899731, since there seems to be no mention of that bug here?
Please note that we'll need a "full" design specification before implementing this, and given its current state the code will also require a fair amount of work here (as far as I can tell).
I added a link to the Figma specs in the bug. It should be accessible to all of you (let me know if you don't have access, and I'll get you added). |
bottom: 100px; | ||
left: 50%; | ||
transform: translateX(-50%); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you test that everything is rendering fine when switching to HCM mode on Windows ?
@calixteman @Snuffleupagus Please wait to review until when this PR is marked as ready -- I am giving some feedback to @ryzokuken to make sure that it matches correctly what is defined in the figma doc :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving just a few high-level comments regarding things/patterns that should be improved.
src/display/editor/tools.js
Outdated
this.#toastManager.show( | ||
undo, | ||
editors.length > 1 | ||
? `${editors.length} annotations` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't be possible to localize properly, since it hard-codes the word "annotations".
web/message_bar.css
Outdated
--message-bar-icon-color: #0060DF; | ||
--message-bar-bg-color: #deeafc; | ||
--message-bar-fg-color: #15141a; | ||
--text-primary-color: #15141a; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this not be using different colours depending on light/dark/HCM mode?
This is a temporary commit on this branch that aims to address some of the review comments from the PR at mozilla#18900.
First off, thanks everyone for all the comments it's nice to have a stronger sense of direction as to where I need to take this patch. I addressed some of the comments y'all made and marked the appropriate suggestions as "resolved" although please feel free to re-raise anything. To respond to the questions:
Yes it is! Thanks @marco-c for the clarification and sharing the spec. Regarding the code, I hope the bigger pain points have either already been addressed or I'd be hacking on them shortly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on looking at the code, I believe that there's various cases where the notification won't be closed immediately as I believe is intended when:
- Restoring the editor with Ctrl+Z (i.e. using the keyboard).
- Toggling editing-mode off.
- The entire editorLayer is being destroyed (i.e. when closing the current PDF document).
Apologies, I misunderstood your comment at first. Applied the fix that you'd ultimately suggested. I've marked a number of your comments as resolved, please take a look and let me know if I missed something from my latest commit while I work on addressing the remaining issues. Thanks again for your patience. |
@Snuffleupagus thanks for the last slew of suggestions especially, it taught me a lot about the code and fixed the l10n bug. The code should ideally look much more manageable now. While I make more improvements and add tests, please let me know if you have any further comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing that I think should be supported is closing the undo-bar with the Esc key, and the easiest solution would be to (after implementing the comments below) also add the following code just after this existing code:
if (this.editorUndoBar?.isOpen) {
this.editorUndoBar.hide();
handled = true;
}
I added the ESC key dismiss thingie but note that it's not part of the Figma spec which says:
Maybe we should get the ESC key condition added there. |
Note also the other cases mentioned previously in #18900 (review), maybe those should be added to that list as well? |
Absolutely, I'll mention this to the UX folks. |
Good point, I cleaned up the class fields and simplified the constructor a bit. |
a4130d0
to
13d7c53
Compare
8e291bb
to
51d6d9e
Compare
web/app.js
Outdated
let editorUndoBar = null; | ||
if (appConfig.editorUndoBar) { | ||
editorUndoBar = new EditorUndoBar( | ||
appConfig.editorUndoBar, | ||
eventBus, | ||
l10n | ||
); | ||
} | ||
this.editorUndoBar = editorUndoBar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can now be simplified, see also the next comment.
let editorUndoBar = null; | |
if (appConfig.editorUndoBar) { | |
editorUndoBar = new EditorUndoBar( | |
appConfig.editorUndoBar, | |
eventBus, | |
l10n | |
); | |
} | |
this.editorUndoBar = editorUndoBar; | |
if (appConfig.editorUndoBar) { | |
this.editorUndoBar = new EditorUndoBar( | |
appConfig.editorUndoBar, | |
eventBus | |
); | |
} |
web/app.js
Outdated
@@ -460,6 +472,7 @@ const PDFViewerApplication = { | |||
linkService: pdfLinkService, | |||
downloadManager, | |||
altTextManager, | |||
editorUndoBar, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
editorUndoBar, | |
editorUndoBar: this.editorUndoBar, |
web/editor_undo_bar.js
Outdated
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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't a single underscore suffice here?
web/editor_undo_bar.js
Outdated
async show(undoAction, messageData) { | ||
this.hide(); | ||
this.isOpen = true; | ||
this.#controller = new AbortController(); | ||
|
||
this.#message.textContent = | ||
typeof messageData === "string" | ||
? await this.#l10n.get(EditorUndoBar.#l10nMessages[messageData]) | ||
: await this.#l10n.get(EditorUndoBar.#l10nMessages.__multiple, { | ||
count: messageData, | ||
}); | ||
this.#container.hidden = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to translate this "manually", since that should only be done as a last resort?
Also, the introduction of await here could lead to intermittent bugs with the bar reshowing after having been hidden elsewhere.
async show(undoAction, messageData) { | |
this.hide(); | |
this.isOpen = true; | |
this.#controller = new AbortController(); | |
this.#message.textContent = | |
typeof messageData === "string" | |
? await this.#l10n.get(EditorUndoBar.#l10nMessages[messageData]) | |
: await this.#l10n.get(EditorUndoBar.#l10nMessages.__multiple, { | |
count: messageData, | |
}); | |
this.#container.hidden = false; | |
show(undoAction, messageData) { | |
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; | |
his.#container.hidden = false; | |
this.#controller = new AbortController(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, thank you!
a0c05d3
to
a7b37b7
Compare
@@ -404,6 +404,9 @@ class AnnotationEditorLayer { | |||
// Do nothing on right click. | |||
return; | |||
} | |||
|
|||
this.#uiManager._eventBus.dispatch("annotationstart", { source: this }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment applies elsewhere as well.
- Is there possibly a more "central" spot where this can be done, since having this code in a bunch of places seems potentially error prone (since it's easy to miss adding a case)?
- The event name isn't very specific, as far as I'm concerned. (But please see below.)
- Ideally the undo-bar hiding would, in my opinion, be placed within the
src/display/editor/
-code as much as possible. (With events only used for features that are clearly outside of that folder.)
With that in mind, could we change this to the following instead?Suggested changethis.#uiManager._eventBus.dispatch("annotationstart", { source: this }); this.#uiManager._editorUndoBar?.hide()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there possibly a more "central" spot where this can be done, since having this code in a bunch of places seems potentially error prone (since it's easy to miss adding a case)?
We originally tried looking for a central place but couldn't find a good one. The problem is some of the editors are created when they are "enabled" by clicking on the toolbar (example: the ink one), while others are created only when the user actually starts writing in them (example: the freetext one).
src/display/editor/tools.js
Outdated
@@ -804,6 +807,7 @@ class AnnotationEditorUIManager { | |||
rotation: 0, | |||
}; | |||
this.isShiftKeyDown = false; | |||
this.#editorUndoBar = editorUndoBar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To support the suggestion above.
this.#editorUndoBar = editorUndoBar; | |
this._editorUndoBar = editorUndoBar; |
eventBus._on("beforeprint", boundHide); | ||
eventBus._on("download", boundHide); | ||
eventBus._on("annotationstart", boundHide); | ||
eventBus._on("secondarytoolbaraction", boundHide); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this suggestion would be slight abuse of notation, do we really need a new event just for this or could we use the already existing one instead?
eventBus._on("secondarytoolbaraction", boundHide); | |
eventBus._on("reporttelemetry", evt => { | |
if (evt?.details?.type === "buttons") { | |
boundHide(); | |
} | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We originally considered this, but yeah it felt a bit too much abusing an event for something that's not meant to. Ideally an event called "reporttelemetry"
should not have UI effects other than... reporting telemetry 😅.
Happy to change it if you feel strongly though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just add a click listener on the window (capture) and check if the target is under the toast bar ?
It's something we do in order to hide the secondary toolbar:
https://github.com/mozilla/pdf.js/blob/master/web/app.js#L2750-L2765
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@calixteman about this one, does your comment imply that the toast should be over other UI elements like the toolbar? Or did you mean that we should dismiss the toast if the user clicks another element like in the case of the toolbar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a few additional cases where the undo-bar should also be hidden (which should be possible to implement within the src/display/editor/
-code):
- When toggling editing off (i.e. setting
AnnotationEditorType.NONE
). - When destroying the editor.
48e196f
to
a1f4aac
Compare
Move .messageBar out of .dialog into its own standalone class in order to reuse as much of it for the upcoming feature for an undo message for annotations.
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.
Fix colors in dark and high contrast modes
a1f4aac
to
a3d26c3
Compare
23c6dfa
to
c1cbf9b
Compare
This PR adds a simple popup/snackbar setup and wires it up for annotation removal, so when a user deletes any number of annotations, they get a message about it alongside an undo button that allows them to quickly undo the deletion.