Skip to content
Open
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
26 changes: 19 additions & 7 deletions src/display/editor/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ function bindEvents(obj, element, names) {
}
}

// The `type` values of the `<input>` elements which don't hold editable text.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change looks good now, but please amend the commit message so that the intent of the change is clear from the Git logs too before landing this.

// The keyboard events must only be handled by the editor when the focused
// element isn't a text input, hence any type not listed here (text, number,
// password, email, ...) is treated as a text input.
const NON_TEXT_INPUT_TYPES = new Set([
"button",
"checkbox",
"color",
"file",
"hidden",
"image",
"radio",
"range",
"reset",
"submit",
]);

/**
* Class to store current pointers used by the editor to be able to handle
* multiple pointers (e.g. two fingers, a pen, a mouse, ...).
Expand Down Expand Up @@ -861,13 +878,8 @@ class AnnotationEditorUIManager {
document.activeElement.tagName !== "BUTTON" &&
self.hasSomethingToControl();

const textInputChecker = (_self, { target: el }) => {
if (el instanceof HTMLInputElement) {
const { type } = el;
return type !== "text" && type !== "number";
}
return true;
};
const textInputChecker = (_self, { target: el }) =>
!(el instanceof HTMLInputElement) || NON_TEXT_INPUT_TYPES.has(el.type);

const small = this.TRANSLATE_SMALL;
const big = this.TRANSLATE_BIG;
Expand Down
78 changes: 78 additions & 0 deletions test/integration/freetext_editor_spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2750,6 +2750,84 @@ describe("FreeText Editor", () => {
})
);
});

it("must check that the shortcuts depend on the focused input type", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await switchToFreeText(page);

const rect = await getRect(page, ".annotationEditorLayer");

// Add two editors so that the "select all" shortcut has something to
// select.
await createFreeTextEditor({
page,
x: rect.x + 100,
y: rect.y + 100,
data: "Hello",
});
await createFreeTextEditor({
page,
x: rect.x + 100,
y: rect.y + 200,
data: "PDF.js World",
});

// Nothing must be selected before triggering the shortcut.
await page.keyboard.press("Escape");
await page.waitForFunction(
() => !document.querySelector(".freeTextEditor.selectedEditor")
);

const addInput = type =>
page.evaluate(inputType => {
const input = document.createElement("input");
input.type = inputType;
input.id = "testInputForShortcuts";
input.value = "abc";
document.body.append(input);
input.focus();
}, type);
const removeInput = () =>
page.evaluate(() => {
document.getElementById("testInputForShortcuts").remove();
});
const countSelectedEditors = () =>
page.$$eval(".freeTextEditor.selectedEditor", els => els.length);

// When the focus is in a text input, the editor mustn't handle the
// "select all" shortcut, hence no editor must be selected.
for (const type of ["text", "number", "password", "email"]) {
await addInput(type);
await page.waitForSelector("#testInputForShortcuts:focus");
await kbSelectAll(page);
expect(await countSelectedEditors())
.withContext(`In ${browserName} for type=${type}`)
.toEqual(0);
await removeInput();
}

// When the focus is in a non-text input, the editor must handle the
// "select all" shortcut, hence all the editors must be selected.
for (const type of ["checkbox", "button"]) {
await addInput(type);
await page.waitForSelector("#testInputForShortcuts:focus");
await kbSelectAll(page);
await page.waitForFunction(
() =>
!document.querySelector(".freeTextEditor:not(.selectedEditor)")
);
await removeInput();

// Reset the selection for the next iteration.
await page.keyboard.press("Escape");
await page.waitForFunction(
() => !document.querySelector(".freeTextEditor.selectedEditor")
);
}
})
);
});
});

describe("Delete a freetext in using the delete button", () => {
Expand Down
Loading