Skip to content
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

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
21 changes: 21 additions & 0 deletions l10n/en-US/viewer.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions src/display/editor/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@ class DrawingEditor extends AnnotationEditor {
signal,
});
parent.toggleDrawing();
uiManager._editorUndoBar?.hide();

if (this._currentDraw) {
parent.drawLayer.updateProperties(
Expand Down
2 changes: 2 additions & 0 deletions src/display/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,8 @@ class AnnotationEditor {

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

this._uiManager._editorUndoBar?.hide();

return this.div;
}

Expand Down
14 changes: 13 additions & 1 deletion src/display/editor/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,8 @@ class AnnotationEditorUIManager {

#editorsToRescale = new Set();

_editorUndoBar = null;

#enableHighlightFloatingButton = false;

#enableUpdatedAddImage = false;
Expand Down Expand Up @@ -829,7 +831,8 @@ class AnnotationEditorUIManager {
enableHighlightFloatingButton,
enableUpdatedAddImage,
enableNewAltTextWhenAddingImage,
mlManager
mlManager,
editorUndoBar
) {
const signal = (this._signal = this.#abortController.signal);
this.#container = container;
Expand Down Expand Up @@ -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", {
Expand Down Expand Up @@ -904,6 +908,7 @@ class AnnotationEditorUIManager {
clearTimeout(this.#translationTimeoutId);
this.#translationTimeoutId = null;
}
this._editorUndoBar?.destroy();
}

combinedSignal(ac) {
Expand Down Expand Up @@ -1656,6 +1661,8 @@ class AnnotationEditorUIManager {
this.setEditingState(false);
this.#disableAll();

this._editorUndoBar?.hide();

this.#updateModeCapability.resolve();
return;
}
Expand Down Expand Up @@ -2038,6 +2045,7 @@ class AnnotationEditorUIManager {
hasSomethingToRedo: true,
isEmpty: this.#isEmpty(),
});
this._editorUndoBar?.hide();
}

/**
Expand Down Expand Up @@ -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();
}
Expand Down
121 changes: 121 additions & 0 deletions test/integration/freetext_editor_spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3670,4 +3670,125 @@ describe("FreeText Editor", () => {
);
});
});

describe("Undo deletion popup has the expected behaviour", () => {
let pages;
const editorSelector = getEditorSelector(0);

beforeEach(async () => {
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
});

afterEach(async () => {
await closePages(pages);
});

it("must check that deleting a FreeText editor can be undone using the undo button", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await switchToFreeText(page);

const rect = await getRect(page, ".annotationEditorLayer");
const data = "Hello PDF.js World !!";
await page.mouse.click(rect.x + 100, rect.y + 100);
await page.waitForSelector(editorSelector, {
visible: true,
});
await page.type(`${editorSelector} .internal`, data);

// Commit.
await page.keyboard.press("Escape");
await page.waitForSelector(`${editorSelector} .overlay.enabled`);
await waitForSerialized(page, 1);

await page.waitForSelector(`${editorSelector} button.delete`);
await page.click(`${editorSelector} button.delete`);
await waitForSerialized(page, 0);

await page.waitForSelector("#editorUndoBar:not([hidden])");
await page.click("#editorUndoBarUndoButton");
await waitForSerialized(page, 1);
await page.waitForSelector(editorSelector);
})
);
});

it("must check that the undo deletion popup displays the correct message", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await switchToFreeText(page);

const rect = await getRect(page, ".annotationEditorLayer");
const data = "Hello PDF.js World !!";
await page.mouse.click(rect.x + 100, rect.y + 100);
await page.waitForSelector(editorSelector, {
visible: true,
});
await page.type(`${editorSelector} .internal`, data);

// Commit.
await page.keyboard.press("Escape");
await page.waitForSelector(`${editorSelector} .overlay.enabled`);
await waitForSerialized(page, 1);

await page.waitForSelector(`${editorSelector} button.delete`);
await page.click(`${editorSelector} button.delete`);
await waitForSerialized(page, 0);

await page.waitForFunction(() => {
const messageElement = document.querySelector(
"#editorUndoBarMessage"
);
return messageElement && messageElement.textContent.trim() !== "";
});
const message = await page.waitForSelector("#editorUndoBarMessage");
const messageText = await page.evaluate(
el => el.textContent,
message
);
expect(messageText).toContain("Text removed");
})
);
});

it("must check that the popup disappears when a new textbox is created", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await switchToFreeText(page);

let rect = await getRect(page, ".annotationEditorLayer");
const data = "Hello PDF.js World !!";
await page.mouse.click(rect.x + 100, rect.y + 100);
await page.waitForSelector(editorSelector, {
visible: true,
});
await page.type(`${editorSelector} .internal`, data);

await page.keyboard.press("Escape");
await page.waitForSelector(`${editorSelector} .overlay.enabled`);
await waitForSerialized(page, 1);

await page.waitForSelector(`${editorSelector} button.delete`);
await page.click(`${editorSelector} button.delete`);
await waitForSerialized(page, 0);

await page.waitForSelector("#editorUndoBar:not([hidden])");
rect = await getRect(page, ".annotationEditorLayer");
const newData = "This is a new text box!";
await page.mouse.click(rect.x + 150, rect.y + 150);
await page.waitForSelector(getEditorSelector(1), {
visible: true,
});
await page.type(`${getEditorSelector(1)} .internal`, newData);

await page.keyboard.press("Escape");
await page.waitForSelector(
`${getEditorSelector(1)} .overlay.enabled`
);
await waitForSerialized(page, 1);
await page.waitForSelector("#editorUndoBar", { hidden: true });
})
);
});
});
});
Loading
Loading