bb19cf9b64
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.
1097 lines
35 KiB
JavaScript
1097 lines
35 KiB
JavaScript
/* Copyright 2022 Mozilla Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {
|
|
awaitPromise,
|
|
closePages,
|
|
createPromise,
|
|
getEditorSelector,
|
|
getSerialized,
|
|
kbBigMoveLeft,
|
|
kbBigMoveUp,
|
|
kbSelectAll,
|
|
loadAndWait,
|
|
scrollIntoView,
|
|
waitForSerialized,
|
|
} from "./test_utils.mjs";
|
|
|
|
const selectAll = async page => {
|
|
await kbSelectAll(page);
|
|
await page.waitForFunction(
|
|
() => !document.querySelector(".highlightEditor:not(.selectedEditor)")
|
|
);
|
|
};
|
|
|
|
const waitForPointerUp = page =>
|
|
createPromise(page, resolve => {
|
|
window.addEventListener("pointerup", resolve, { once: true });
|
|
});
|
|
|
|
const getXY = (page, selector) =>
|
|
page.evaluate(sel => {
|
|
const bbox = document.querySelector(sel).getBoundingClientRect();
|
|
return `${bbox.x}::${bbox.y}`;
|
|
}, selector);
|
|
|
|
const getSpanRectFromText = (page, pageNumber, text) =>
|
|
page.evaluate(
|
|
(number, content) => {
|
|
for (const el of document.querySelectorAll(
|
|
`.page[data-page-number="${number}"] > .textLayer > span`
|
|
)) {
|
|
if (el.textContent === content) {
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
return { x, y, width, height };
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
pageNumber,
|
|
text
|
|
);
|
|
|
|
describe("Highlight Editor", () => {
|
|
describe("Editor must be removed without exception", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must scroll and check that the draw layer is there", 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)}`);
|
|
|
|
const oneToOne = Array.from(new Array(13).keys(), n => n + 2).concat(
|
|
Array.from(new Array(13).keys(), n => 13 - n)
|
|
);
|
|
for (const pageNumber of oneToOne) {
|
|
await scrollIntoView(
|
|
page,
|
|
`.page[data-page-number = "${pageNumber}"]`
|
|
);
|
|
}
|
|
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight`,
|
|
{
|
|
visible: true,
|
|
}
|
|
);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Editor must keep selected", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must scroll and check that the highlight is selected", 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.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
const oneToOne = Array.from(new Array(13).keys(), n => n + 2).concat(
|
|
Array.from(new Array(13).keys(), n => 13 - n)
|
|
);
|
|
for (const pageNumber of oneToOne) {
|
|
await scrollIntoView(
|
|
page,
|
|
`.page[data-page-number = "${pageNumber}"]`
|
|
);
|
|
}
|
|
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("The default color must have the correct value", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"tracemonkey.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "red=#AB0000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must highlight with red color", 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.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
const usedColor = await page.evaluate(() => {
|
|
const highlight = document.querySelector(
|
|
`.page[data-page-number = "1"] .canvasWrapper > svg.highlight`
|
|
);
|
|
return highlight.getAttribute("fill");
|
|
});
|
|
|
|
expect(usedColor).withContext(`In ${browserName}`).toEqual("#AB0000");
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Invisible editor must change its color", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"tracemonkey.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "yellow=#FFFF98,green=#53FFBC" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must scroll and change the color without exceptions", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
|
|
let rect = await getSpanRectFromText(page, 1, "Abstract");
|
|
let x = rect.x + rect.width / 2;
|
|
let y = rect.y + rect.height / 2;
|
|
await page.mouse.click(x, y, { count: 2 });
|
|
|
|
await page.waitForSelector(`${getEditorSelector(0)}`);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
for (const pageNumber of Array.from(
|
|
new Array(13).keys(),
|
|
n => n + 2
|
|
)) {
|
|
await scrollIntoView(
|
|
page,
|
|
`.page[data-page-number = "${pageNumber}"]`
|
|
);
|
|
}
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "14"] .textLayer .endOfContent`
|
|
);
|
|
|
|
rect = await getSpanRectFromText(page, 14, "References");
|
|
x = rect.x + rect.width / 2;
|
|
y = rect.y + rect.height / 2;
|
|
await page.mouse.click(x, y, { count: 2 });
|
|
await page.waitForSelector(`${getEditorSelector(1)}`);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "14"] svg.highlightOutline.selected`
|
|
);
|
|
await selectAll(page);
|
|
await page.waitForSelector(
|
|
`${getEditorSelector(1)} .editToolbar button.colorPicker`
|
|
);
|
|
await page.click(
|
|
`${getEditorSelector(1)} .editToolbar button.colorPicker`
|
|
);
|
|
await page.waitForSelector(
|
|
`${getEditorSelector(1)} .editToolbar button[title = "Green"]`
|
|
);
|
|
await page.click(
|
|
`${getEditorSelector(1)} .editToolbar button[title = "Green"]`
|
|
);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "14"] svg.highlight[fill = "#53FFBC"]`
|
|
);
|
|
|
|
for (const pageNumber of Array.from(
|
|
new Array(13).keys(),
|
|
n => 13 - n
|
|
)) {
|
|
await scrollIntoView(
|
|
page,
|
|
`.page[data-page-number = "${pageNumber}"]`
|
|
);
|
|
}
|
|
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#53FFBC"]`
|
|
);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Highlight data serialization", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"tracemonkey.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "red=#AB0000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must be correctly serialized", 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.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
await waitForSerialized(page, 1);
|
|
const serialized = (await getSerialized(page))[0];
|
|
expect(serialized.annotationType)
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual(9);
|
|
expect(serialized.color)
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual([0xab, 0, 0]);
|
|
|
|
// We don't check the quadPoints and outlines values because they're
|
|
// dependent on the font used in the text layer.
|
|
expect(serialized.quadPoints.length)
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual(8);
|
|
expect(serialized.outlines.length)
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual(1);
|
|
expect(serialized.outlines[0].length)
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual(8);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Color picker and keyboard", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"tracemonkey.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{
|
|
highlightEditorColors:
|
|
"yellow=#FFFF00,green=#00FF00,blue=#0000FF,pink=#FF00FF,red=#FF0000",
|
|
}
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that we can use the keyboard to select a color", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
const sel = getEditorSelector(0);
|
|
|
|
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(sel);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
await page.waitForSelector(`${sel} .editToolbar button.colorPicker`);
|
|
await page.click(`${sel} .editToolbar button.colorPicker`);
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Red"]`
|
|
);
|
|
await page.click(`${sel} .editToolbar button[title = "Red"]`);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#FF0000"]`
|
|
);
|
|
|
|
await page.keyboard.press("ArrowUp");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Pink"]:focus`
|
|
);
|
|
await page.keyboard.press("Enter");
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#FF00FF"]`
|
|
);
|
|
|
|
await page.keyboard.press("ArrowUp");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Blue"]:focus`
|
|
);
|
|
await page.keyboard.press(" ");
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#0000FF"]`
|
|
);
|
|
|
|
await page.keyboard.press("ArrowLeft");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Green"]:focus`
|
|
);
|
|
await page.keyboard.press("Enter");
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#00FF00"]`
|
|
);
|
|
|
|
await page.keyboard.press("ArrowRight");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Blue"]:focus`
|
|
);
|
|
await page.keyboard.press("Enter");
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#0000FF"]`
|
|
);
|
|
|
|
await page.keyboard.press("ArrowDown");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Pink"]:focus`
|
|
);
|
|
await page.keyboard.press(" ");
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlight[fill = "#FF00FF"]`
|
|
);
|
|
|
|
for (let i = 0; i < 4; i++) {
|
|
await page.keyboard.press("ArrowUp");
|
|
}
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button.colorPicker .dropdown.hidden`
|
|
);
|
|
await page.keyboard.press("ArrowDown");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button.colorPicker .dropdown:not(.hidden)`
|
|
);
|
|
await page.keyboard.press("ArrowUp");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button.colorPicker .dropdown.hidden`
|
|
);
|
|
await page.keyboard.press(" ");
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button.colorPicker .dropdown:not(.hidden)`
|
|
);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Text highlights aren't draggable", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"tracemonkey.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "red=#AB0000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that a text highlight don't move when arrows are pressed", 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.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
await page.focus(getEditorSelector(0));
|
|
|
|
const xy = await getXY(page, getEditorSelector(0));
|
|
for (let i = 0; i < 5; i++) {
|
|
await kbBigMoveLeft(page);
|
|
}
|
|
expect(await getXY(page, getEditorSelector(0)))
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual(xy);
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
await kbBigMoveUp(page);
|
|
}
|
|
expect(await getXY(page, getEditorSelector(0)))
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual(xy);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Color picker and click outside", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that the dropdown is hidden", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
const sel = getEditorSelector(0);
|
|
|
|
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(sel);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
await page.waitForSelector(`${sel} .editToolbar button.colorPicker`);
|
|
await page.click(`${sel} .editToolbar button.colorPicker`);
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button[title = "Red"]`
|
|
);
|
|
await page.mouse.click(x, y - rect.height);
|
|
await page.waitForSelector(
|
|
`${sel} .editToolbar button.colorPicker .dropdown.hidden`
|
|
);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Color picker can annoy the user when selecting some text", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that editor is unselected when the mouse is down on the text layer", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
const sel = getEditorSelector(0);
|
|
|
|
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(sel);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline.selected`
|
|
);
|
|
|
|
await page.waitForSelector(`${sel} .editToolbar button.colorPicker`);
|
|
await page.mouse.click(x, y - rect.height);
|
|
await page.waitForSelector(
|
|
`.page[data-page-number = "1"] svg.highlightOutline:not(.selected)`
|
|
);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Free highlight thickness can be changed", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"empty.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "yellow=#000000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that the thickness is correctly updated", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
// With Chrome something is wrong when serializing a DomRect,
|
|
// hence we extract the values and just return them.
|
|
const { x, y } = el.getBoundingClientRect();
|
|
return { x, y };
|
|
});
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
const x = rect.x + 120 + i * 120;
|
|
const y = rect.y + 120 + i * 120;
|
|
const clickHandle = await waitForPointerUp(page);
|
|
await page.mouse.move(x, y);
|
|
await page.mouse.down();
|
|
await page.mouse.move(x + 100, y + 100);
|
|
await page.mouse.up();
|
|
await awaitPromise(clickHandle);
|
|
|
|
await page.waitForSelector(getEditorSelector(i));
|
|
}
|
|
|
|
let value = 12;
|
|
await waitForSerialized(page, 3);
|
|
let serialized = await getSerialized(page);
|
|
expect(serialized.map(x => x.thickness))
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual([value, value, value]);
|
|
|
|
await selectAll(page);
|
|
|
|
const prevWidth = await page.evaluate(
|
|
sel => document.querySelector(sel).getBoundingClientRect().width,
|
|
getEditorSelector(0)
|
|
);
|
|
|
|
value = 24;
|
|
page.evaluate(val => {
|
|
window.PDFViewerApplication.eventBus.dispatch(
|
|
"switchannotationeditorparams",
|
|
{
|
|
source: null,
|
|
type: window.pdfjsLib.AnnotationEditorParamsType
|
|
.HIGHLIGHT_THICKNESS,
|
|
value: val,
|
|
}
|
|
);
|
|
}, value);
|
|
|
|
await page.waitForFunction(
|
|
(w, sel) =>
|
|
document.querySelector(sel).getBoundingClientRect().width !== w,
|
|
{},
|
|
prevWidth,
|
|
getEditorSelector(0)
|
|
);
|
|
|
|
await waitForSerialized(page, 3);
|
|
serialized = await getSerialized(page);
|
|
expect(serialized.map(x => x.thickness))
|
|
.withContext(`In ${browserName}`)
|
|
.toEqual([value, value, value]);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Highlight with the keyboard", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that some text has been highlighted", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
const sel = getEditorSelector(0);
|
|
|
|
const spanRect = await page.evaluate(() => {
|
|
const span = document.querySelector(
|
|
`.page[data-page-number="1"] > .textLayer > span`
|
|
);
|
|
const { x, y, width, height } = span.getBoundingClientRect();
|
|
return { x, y, width, height };
|
|
});
|
|
await page.keyboard.down("Shift");
|
|
await page.mouse.click(
|
|
spanRect.x + 1,
|
|
spanRect.y + spanRect.height / 2,
|
|
{ count: 2 }
|
|
);
|
|
for (let i = 0; i < 6; i++) {
|
|
await page.keyboard.press("ArrowRight");
|
|
}
|
|
await page.keyboard.press("ArrowDown");
|
|
await page.keyboard.press("ArrowDown");
|
|
await page.keyboard.up("Shift");
|
|
|
|
const [w, h] = await page.evaluate(s => {
|
|
const {
|
|
style: { width, height },
|
|
} = document.querySelector(s);
|
|
return [parseFloat(width), parseFloat(height)];
|
|
}, sel);
|
|
|
|
// w & h are the width and height of the highlight in percent.
|
|
// We expect the highlight to be around 73% wide and 9% high.
|
|
// We allow a 2% margin of error because of the font used in the text
|
|
// layer we can't be sure of the dimensions.
|
|
expect(Math.abs(w - 73) <= 2)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
expect(Math.abs(h - 9) <= 2)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Free highlight is drawn at the right place after having been rotated (bug 1879108)", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"empty.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "yellow=#000000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that highlight is at the correct position", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
// With Chrome something is wrong when serializing a DomRect,
|
|
// hence we extract the values and just return them.
|
|
const { x, y } = el.getBoundingClientRect();
|
|
return { x, y };
|
|
});
|
|
|
|
const clickHandle = await waitForPointerUp(page);
|
|
await page.mouse.move(rect.x + 120, rect.y + 120);
|
|
await page.mouse.down();
|
|
await page.mouse.move(rect.x + 220, rect.y + 220);
|
|
await page.mouse.up();
|
|
await awaitPromise(clickHandle);
|
|
|
|
await page.waitForSelector(getEditorSelector(0));
|
|
|
|
await page.evaluate(() => {
|
|
window.PDFViewerApplication.rotatePages(90);
|
|
});
|
|
await page.waitForSelector(
|
|
".annotationEditorLayer[data-main-rotation='90']"
|
|
);
|
|
await selectAll(page);
|
|
|
|
const prevWidth = await page.evaluate(
|
|
sel => document.querySelector(sel).getBoundingClientRect().width,
|
|
getEditorSelector(0)
|
|
);
|
|
|
|
page.evaluate(val => {
|
|
window.PDFViewerApplication.eventBus.dispatch(
|
|
"switchannotationeditorparams",
|
|
{
|
|
source: null,
|
|
type: window.pdfjsLib.AnnotationEditorParamsType
|
|
.HIGHLIGHT_THICKNESS,
|
|
value: val,
|
|
}
|
|
);
|
|
}, 24);
|
|
|
|
await page.waitForFunction(
|
|
(w, sel) =>
|
|
document.querySelector(sel).getBoundingClientRect().width !== w,
|
|
{},
|
|
prevWidth,
|
|
getEditorSelector(0)
|
|
);
|
|
|
|
const rectDiv = await page.$eval(getEditorSelector(0), el => {
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
return { x, y, width, height };
|
|
});
|
|
|
|
const rectSVG = await page.$eval("svg.highlight.free", el => {
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
return { x, y, width, height };
|
|
});
|
|
|
|
expect(Math.abs(rectDiv.x - rectSVG.x) <= 2)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
expect(Math.abs(rectDiv.y - rectSVG.y) <= 2)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
expect(Math.abs(rectDiv.height - rectSVG.height) <= 2)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
expect(Math.abs(rectDiv.width - rectSVG.width) <= 2)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Highlight links", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"bug1868759.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "red=#AB0000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that it's possible to highlight a part of a link", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
|
|
const rect = await getSpanRectFromText(
|
|
page,
|
|
1,
|
|
"Questions courantes"
|
|
);
|
|
const x = rect.x + 0.75 * rect.width;
|
|
const y = rect.y + rect.height / 2;
|
|
await page.mouse.click(x, y, { count: 2 });
|
|
|
|
await page.waitForSelector(`${getEditorSelector(0)}`);
|
|
const usedColor = await page.evaluate(() => {
|
|
const highlight = document.querySelector(
|
|
`.page[data-page-number = "1"] .canvasWrapper > svg.highlight`
|
|
);
|
|
return highlight.getAttribute("fill");
|
|
});
|
|
|
|
expect(usedColor).withContext(`In ${browserName}`).toEqual("#AB0000");
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Highlight forms", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"issue12233.pdf",
|
|
".annotationEditorLayer",
|
|
null,
|
|
null,
|
|
{ highlightEditorColors: "red=#AB0000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that it's possible to highlight a part of a form", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
await page.click("#editorHighlight");
|
|
await page.waitForSelector(".annotationEditorLayer.highlightEditing");
|
|
|
|
const rect1 = await page.$eval("#pdfjs_internal_id_5R", el => {
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
return { x, y, width, height };
|
|
});
|
|
const rect2 = await page.$eval("#pdfjs_internal_id_16R", el => {
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
return { x, y, width, height };
|
|
});
|
|
|
|
const x1 = rect1.x + rect1.width / 2;
|
|
const y1 = rect1.y + rect1.height / 2;
|
|
const x2 = rect2.x + rect2.width / 2;
|
|
const y2 = rect2.y + rect2.height / 2;
|
|
const clickHandle = await waitForPointerUp(page);
|
|
await page.mouse.move(x1, y1);
|
|
await page.mouse.down();
|
|
await page.mouse.move(x2, y2);
|
|
await page.mouse.up();
|
|
await awaitPromise(clickHandle);
|
|
|
|
await page.waitForSelector(getEditorSelector(0));
|
|
const usedColor = await page.evaluate(() => {
|
|
const highlight = document.querySelector(
|
|
`.page[data-page-number = "1"] .canvasWrapper > svg.highlight`
|
|
);
|
|
return highlight.getAttribute("fill");
|
|
});
|
|
|
|
expect(usedColor).withContext(`In ${browserName}`).toEqual("#AB0000");
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Send a message when some text is selected", () => {
|
|
let pages;
|
|
|
|
beforeAll(async () => {
|
|
pages = await loadAndWait(
|
|
"tracemonkey.pdf",
|
|
`.page[data-page-number = "1"] .endOfContent`,
|
|
null,
|
|
async page => {
|
|
await page.waitForFunction(async () => {
|
|
await window.PDFViewerApplication.initializedPromise;
|
|
return true;
|
|
});
|
|
await page.evaluate(() => {
|
|
window.editingEvents = [];
|
|
window.PDFViewerApplication.eventBus.on(
|
|
"annotationeditorstateschanged",
|
|
({ details }) => {
|
|
window.editingEvents.push(details);
|
|
}
|
|
);
|
|
});
|
|
},
|
|
{ highlightEditorColors: "red=#AB0000" }
|
|
);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await closePages(pages);
|
|
});
|
|
|
|
it("must check that a message is sent on selection", async () => {
|
|
await Promise.all(
|
|
pages.map(async ([browserName, page]) => {
|
|
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.waitForFunction(() => window.editingEvents.length > 0);
|
|
|
|
let editingEvent = await page.evaluate(() => {
|
|
const e = window.editingEvents[0];
|
|
window.editingEvents.length = 0;
|
|
return e;
|
|
});
|
|
expect(editingEvent.isEditing)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(false);
|
|
expect(editingEvent.hasSelectedText)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(true);
|
|
|
|
// Click somewhere to unselect the current selection.
|
|
await page.mouse.click(rect.x + rect.width + 10, y, { count: 1 });
|
|
await page.waitForFunction(() => window.editingEvents.length > 0);
|
|
editingEvent = await page.evaluate(() => {
|
|
const e = window.editingEvents[0];
|
|
window.editingEvents.length = 0;
|
|
return e;
|
|
});
|
|
expect(editingEvent.hasSelectedText)
|
|
.withContext(`In ${browserName}`)
|
|
.toBe(false);
|
|
|
|
await page.mouse.click(x, y, { count: 2 });
|
|
await page.waitForFunction(() => window.editingEvents.length > 0);
|
|
|
|
await page.evaluate(() => {
|
|
window.PDFViewerApplication.eventBus.dispatch("editingaction", {
|
|
name: "highlightSelection",
|
|
});
|
|
});
|
|
|
|
await page.waitForSelector(getEditorSelector(0));
|
|
const usedColor = await page.evaluate(() => {
|
|
const highlight = document.querySelector(
|
|
`.page[data-page-number = "1"] .canvasWrapper > svg.highlight`
|
|
);
|
|
return highlight.getAttribute("fill");
|
|
});
|
|
|
|
expect(usedColor).withContext(`In ${browserName}`).toEqual("#AB0000");
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
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);
|
|
})
|
|
);
|
|
});
|
|
});
|
|
});
|