[Editor] In caret browsing mode, get the caret position in the text layer (bug 1881692)

The function caretPositionFromPoint return the position within the last visible element
and sometimes there are some elements on top of the ones in the text layer.
So the idea is to hide the visible elements which aren't in the text layer in order
to get the right caret position.
This commit is contained in:
Calixte Denizet 2024-02-23 14:55:54 +01:00
parent 101e8efad7
commit bb19cf9b64
3 changed files with 92 additions and 5 deletions

View File

@ -1030,4 +1030,67 @@ describe("Highlight Editor", () => {
);
});
});
describe("Highlight and caret browsing", () => {
let pages;
beforeAll(async () => {
pages = await loadAndWait(
"tracemonkey.pdf",
".annotationEditorLayer",
null,
null,
{
highlightEditorColors: "red=#AB0000",
supportsCaretBrowsingMode: true,
}
);
});
afterAll(async () => {
await closePages(pages);
});
it("must check that the caret can move a highlighted text", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.click("#editorHighlight");
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
const rect = await getSpanRectFromText(page, 1, "Abstract");
const x = rect.x + rect.width / 2;
const y = rect.y + rect.height / 2;
await page.mouse.click(x, y, { count: 2 });
await page.waitForSelector(`${getEditorSelector(0)}`);
await page.keyboard.press("Escape");
await page.waitForSelector(
`${getEditorSelector(0)}:not(.selectedEditor)`
);
await page.evaluate(() => {
const text =
"Dynamic languages such as JavaScript are more difficult to com-";
for (const el of document.querySelectorAll(
`.page[data-page-number="${1}"] > .textLayer > span`
)) {
if (el.textContent === text) {
window.getSelection().setPosition(el.firstChild, 1);
break;
}
}
});
await page.keyboard.press("ArrowUp");
const [text, offset] = await page.evaluate(() => {
const selection = window.getSelection();
return [selection.anchorNode.textContent, selection.anchorOffset];
});
expect(text).withContext(`In ${browserName}`).toEqual("Abstract");
expect(offset).withContext(`In ${browserName}`).toEqual(1);
})
);
});
});
});

View File

@ -329,6 +329,12 @@ const PDFViewerApplication = {
params.get("highlighteditorcolors")
);
}
if (params.has("supportscaretbrowsingmode")) {
AppOptions.set(
"supportsCaretBrowsingMode",
params.get("supportscaretbrowsingmode") === "true"
);
}
}
},

View File

@ -130,11 +130,29 @@ class CaretBrowsingMode {
}
const midY = rect.y + rect.height / 2;
const caretPosition = CaretBrowsingMode.#caretPositionFromPoint(
caretX,
midY
);
if (caretPosition.offsetNode?.parentElement !== element) {
let caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
let parentElement = caretPosition.offsetNode?.parentElement;
if (parentElement && parentElement !== element) {
// There is an element on top of the one in the text layer, so we
// need to hide all the elements (except the one in the text layer)
// at this position in order to get the correct caret position.
const elementsAtPoint = document.elementsFromPoint(caretX, midY);
const savedVisibilities = [];
for (const el of elementsAtPoint) {
if (el === element) {
break;
}
const { style } = el;
savedVisibilities.push([el, style.visibility]);
style.visibility = "hidden";
}
caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
parentElement = caretPosition.offsetNode?.parentElement;
for (const [el, visibility] of savedVisibilities) {
el.style.visibility = visibility;
}
}
if (parentElement !== element) {
// The element targeted by caretPositionFromPoint isn't in the text
// layer.
if (select) {