Skip to content

Commit a5ce712

Browse files
authored
Merge pull request #18900 from ryzokuken/popup-undo-annotation
Annotation deletion popup (bug 1899731)
2 parents f8d11a3 + 41bf874 commit a5ce712

18 files changed

+1249
-92
lines changed

gulpfile.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,7 @@ function buildComponents(defines, dir) {
11481148
"web/images/messageBar_*.svg",
11491149
"web/images/toolbarButton-{editorHighlight,menuArrow}.svg",
11501150
"web/images/cursor-*.svg",
1151+
"web/images/secondaryToolbarButton-documentProperties.svg",
11511152
];
11521153

11531154
return ordered([

l10n/en-US/viewer.ftl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,3 +503,24 @@ pdfjs-editor-alt-text-settings-editor-title = Alt text editor
503503
pdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image
504504
pdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.
505505
pdfjs-editor-alt-text-settings-close-button = Close
506+
507+
## "Annotations removed" bar
508+
509+
pdfjs-editor-undo-bar-message-highlight = Highlight removed
510+
pdfjs-editor-undo-bar-message-freetext = Text removed
511+
pdfjs-editor-undo-bar-message-ink = Drawing removed
512+
pdfjs-editor-undo-bar-message-stamp = Image removed
513+
# Variables:
514+
# $count (Number) - the number of removed annotations.
515+
pdfjs-editor-undo-bar-message-multiple =
516+
{ $count ->
517+
[one] { $count } annotation removed
518+
*[other] { $count } annotations removed
519+
}
520+
521+
pdfjs-editor-undo-bar-undo-button =
522+
.title = Undo
523+
pdfjs-editor-undo-bar-undo-button-label = Undo
524+
pdfjs-editor-undo-bar-close-button =
525+
.title = Close
526+
pdfjs-editor-undo-bar-close-button-label = Close

src/display/editor/draw.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ class DrawingEditor extends AnnotationEditor {
676676
signal,
677677
});
678678
parent.toggleDrawing();
679+
uiManager._editorUndoBar?.hide();
679680

680681
if (this._currentDraw) {
681682
parent.drawLayer.updateProperties(

src/display/editor/editor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,8 @@ class AnnotationEditor {
11421142

11431143
bindEvents(this, this.div, ["pointerdown"]);
11441144

1145+
this._uiManager._editorUndoBar?.hide();
1146+
11451147
return this.div;
11461148
}
11471149

src/display/editor/tools.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,8 @@ class AnnotationEditorUIManager {
620620

621621
#editorsToRescale = new Set();
622622

623+
_editorUndoBar = null;
624+
623625
#enableHighlightFloatingButton = false;
624626

625627
#enableUpdatedAddImage = false;
@@ -829,7 +831,8 @@ class AnnotationEditorUIManager {
829831
enableHighlightFloatingButton,
830832
enableUpdatedAddImage,
831833
enableNewAltTextWhenAddingImage,
832-
mlManager
834+
mlManager,
835+
editorUndoBar
833836
) {
834837
const signal = (this._signal = this.#abortController.signal);
835838
this.#container = container;
@@ -864,6 +867,7 @@ class AnnotationEditorUIManager {
864867
rotation: 0,
865868
};
866869
this.isShiftKeyDown = false;
870+
this._editorUndoBar = editorUndoBar || null;
867871

868872
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
869873
Object.defineProperty(this, "reset", {
@@ -904,6 +908,7 @@ class AnnotationEditorUIManager {
904908
clearTimeout(this.#translationTimeoutId);
905909
this.#translationTimeoutId = null;
906910
}
911+
this._editorUndoBar?.destroy();
907912
}
908913

909914
combinedSignal(ac) {
@@ -1656,6 +1661,8 @@ class AnnotationEditorUIManager {
16561661
this.setEditingState(false);
16571662
this.#disableAll();
16581663

1664+
this._editorUndoBar?.hide();
1665+
16591666
this.#updateModeCapability.resolve();
16601667
return;
16611668
}
@@ -2038,6 +2045,7 @@ class AnnotationEditorUIManager {
20382045
hasSomethingToRedo: true,
20392046
isEmpty: this.#isEmpty(),
20402047
});
2048+
this._editorUndoBar?.hide();
20412049
}
20422050

20432051
/**
@@ -2099,6 +2107,10 @@ class AnnotationEditorUIManager {
20992107
? [drawingEditor]
21002108
: [...this.#selectedEditors];
21012109
const cmd = () => {
2110+
this._editorUndoBar?.show(
2111+
undo,
2112+
editors.length === 1 ? editors[0].editorType : editors.length
2113+
);
21022114
for (const editor of editors) {
21032115
editor.remove();
21042116
}

test/integration/freetext_editor_spec.mjs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,4 +3670,125 @@ describe("FreeText Editor", () => {
36703670
);
36713671
});
36723672
});
3673+
3674+
describe("Undo deletion popup has the expected behaviour", () => {
3675+
let pages;
3676+
const editorSelector = getEditorSelector(0);
3677+
3678+
beforeEach(async () => {
3679+
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
3680+
});
3681+
3682+
afterEach(async () => {
3683+
await closePages(pages);
3684+
});
3685+
3686+
it("must check that deleting a FreeText editor can be undone using the undo button", async () => {
3687+
await Promise.all(
3688+
pages.map(async ([browserName, page]) => {
3689+
await switchToFreeText(page);
3690+
3691+
const rect = await getRect(page, ".annotationEditorLayer");
3692+
const data = "Hello PDF.js World !!";
3693+
await page.mouse.click(rect.x + 100, rect.y + 100);
3694+
await page.waitForSelector(editorSelector, {
3695+
visible: true,
3696+
});
3697+
await page.type(`${editorSelector} .internal`, data);
3698+
3699+
// Commit.
3700+
await page.keyboard.press("Escape");
3701+
await page.waitForSelector(`${editorSelector} .overlay.enabled`);
3702+
await waitForSerialized(page, 1);
3703+
3704+
await page.waitForSelector(`${editorSelector} button.delete`);
3705+
await page.click(`${editorSelector} button.delete`);
3706+
await waitForSerialized(page, 0);
3707+
3708+
await page.waitForSelector("#editorUndoBar:not([hidden])");
3709+
await page.click("#editorUndoBarUndoButton");
3710+
await waitForSerialized(page, 1);
3711+
await page.waitForSelector(editorSelector);
3712+
})
3713+
);
3714+
});
3715+
3716+
it("must check that the undo deletion popup displays the correct message", async () => {
3717+
await Promise.all(
3718+
pages.map(async ([browserName, page]) => {
3719+
await switchToFreeText(page);
3720+
3721+
const rect = await getRect(page, ".annotationEditorLayer");
3722+
const data = "Hello PDF.js World !!";
3723+
await page.mouse.click(rect.x + 100, rect.y + 100);
3724+
await page.waitForSelector(editorSelector, {
3725+
visible: true,
3726+
});
3727+
await page.type(`${editorSelector} .internal`, data);
3728+
3729+
// Commit.
3730+
await page.keyboard.press("Escape");
3731+
await page.waitForSelector(`${editorSelector} .overlay.enabled`);
3732+
await waitForSerialized(page, 1);
3733+
3734+
await page.waitForSelector(`${editorSelector} button.delete`);
3735+
await page.click(`${editorSelector} button.delete`);
3736+
await waitForSerialized(page, 0);
3737+
3738+
await page.waitForFunction(() => {
3739+
const messageElement = document.querySelector(
3740+
"#editorUndoBarMessage"
3741+
);
3742+
return messageElement && messageElement.textContent.trim() !== "";
3743+
});
3744+
const message = await page.waitForSelector("#editorUndoBarMessage");
3745+
const messageText = await page.evaluate(
3746+
el => el.textContent,
3747+
message
3748+
);
3749+
expect(messageText).toContain("Text removed");
3750+
})
3751+
);
3752+
});
3753+
3754+
it("must check that the popup disappears when a new textbox is created", async () => {
3755+
await Promise.all(
3756+
pages.map(async ([browserName, page]) => {
3757+
await switchToFreeText(page);
3758+
3759+
let rect = await getRect(page, ".annotationEditorLayer");
3760+
const data = "Hello PDF.js World !!";
3761+
await page.mouse.click(rect.x + 100, rect.y + 100);
3762+
await page.waitForSelector(editorSelector, {
3763+
visible: true,
3764+
});
3765+
await page.type(`${editorSelector} .internal`, data);
3766+
3767+
await page.keyboard.press("Escape");
3768+
await page.waitForSelector(`${editorSelector} .overlay.enabled`);
3769+
await waitForSerialized(page, 1);
3770+
3771+
await page.waitForSelector(`${editorSelector} button.delete`);
3772+
await page.click(`${editorSelector} button.delete`);
3773+
await waitForSerialized(page, 0);
3774+
3775+
await page.waitForSelector("#editorUndoBar:not([hidden])");
3776+
rect = await getRect(page, ".annotationEditorLayer");
3777+
const newData = "This is a new text box!";
3778+
await page.mouse.click(rect.x + 150, rect.y + 150);
3779+
await page.waitForSelector(getEditorSelector(1), {
3780+
visible: true,
3781+
});
3782+
await page.type(`${getEditorSelector(1)} .internal`, newData);
3783+
3784+
await page.keyboard.press("Escape");
3785+
await page.waitForSelector(
3786+
`${getEditorSelector(1)} .overlay.enabled`
3787+
);
3788+
await waitForSerialized(page, 1);
3789+
await page.waitForSelector("#editorUndoBar", { hidden: true });
3790+
})
3791+
);
3792+
});
3793+
});
36733794
});

0 commit comments

Comments
 (0)