2022-06-01 17:38:08 +09:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2023-10-12 20:16:58 +09:00
|
|
|
import {
|
2023-12-06 23:27:31 +09:00
|
|
|
awaitPromise,
|
2022-07-22 19:13:47 +09:00
|
|
|
closePages,
|
2023-12-06 23:27:31 +09:00
|
|
|
createPromise,
|
2023-08-03 03:08:09 +09:00
|
|
|
dragAndDropAnnotation,
|
2023-06-07 00:18:02 +09:00
|
|
|
getEditors,
|
2022-07-29 00:59:03 +09:00
|
|
|
getEditorSelector,
|
2023-07-26 19:57:59 +09:00
|
|
|
getFirstSerialized,
|
2023-10-12 20:16:58 +09:00
|
|
|
getSelectedEditors,
|
2023-06-07 00:18:02 +09:00
|
|
|
getSerialized,
|
2023-10-27 05:42:41 +09:00
|
|
|
hover,
|
|
|
|
kbBigMoveDown,
|
|
|
|
kbBigMoveLeft,
|
|
|
|
kbBigMoveRight,
|
|
|
|
kbBigMoveUp,
|
|
|
|
kbCopy,
|
|
|
|
kbGoToBegin,
|
|
|
|
kbGoToEnd,
|
|
|
|
kbModifierDown,
|
|
|
|
kbModifierUp,
|
|
|
|
kbPaste,
|
|
|
|
kbRedo,
|
|
|
|
kbSelectAll,
|
|
|
|
kbUndo,
|
2022-07-22 19:13:47 +09:00
|
|
|
loadAndWait,
|
2023-09-28 05:35:57 +09:00
|
|
|
scrollIntoView,
|
2022-10-25 22:28:22 +09:00
|
|
|
waitForEvent,
|
2022-12-07 00:16:24 +09:00
|
|
|
waitForSelectedEditor,
|
2023-09-28 05:35:57 +09:00
|
|
|
waitForSerialized,
|
2022-12-07 00:16:24 +09:00
|
|
|
waitForStorageEntries,
|
2024-02-11 02:21:34 +09:00
|
|
|
waitForTimeout,
|
2023-10-12 20:16:58 +09:00
|
|
|
waitForUnselectedEditor,
|
|
|
|
} from "./test_utils.mjs";
|
|
|
|
import { PNG } from "pngjs";
|
2023-07-06 02:46:21 +09:00
|
|
|
|
2022-10-25 22:28:22 +09:00
|
|
|
const copyPaste = async page => {
|
|
|
|
let promise = waitForEvent(page, "copy");
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbCopy(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
await promise;
|
|
|
|
|
2024-02-11 02:21:34 +09:00
|
|
|
await waitForTimeout(10);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
promise = waitForEvent(page, "paste");
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbPaste(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
await promise;
|
|
|
|
};
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const selectAll = async page => {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbSelectAll(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
() => !document.querySelector(".freeTextEditor:not(.selectedEditor)")
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clearAll = async page => {
|
|
|
|
await selectAll(page);
|
2023-07-27 05:11:55 +09:00
|
|
|
await page.keyboard.down("Control");
|
|
|
|
await page.keyboard.press("Backspace");
|
|
|
|
await page.keyboard.up("Control");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForStorageEntries(page, 0);
|
|
|
|
};
|
|
|
|
|
|
|
|
const switchToFreeText = async page => {
|
|
|
|
await page.click("#editorFreeText");
|
|
|
|
await page.waitForSelector(".annotationEditorLayer.freetextEditing");
|
2023-07-27 05:11:55 +09:00
|
|
|
};
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const getXY = (page, selector) =>
|
|
|
|
page.evaluate(sel => {
|
|
|
|
const bbox = document.querySelector(sel).getBoundingClientRect();
|
|
|
|
return `${bbox.x}::${bbox.y}`;
|
|
|
|
}, selector);
|
|
|
|
const waitForPositionChange = (page, selector, xy) =>
|
|
|
|
page.waitForFunction(
|
|
|
|
(sel, currentXY) => {
|
|
|
|
const bbox = document.querySelector(sel).getBoundingClientRect();
|
|
|
|
return `${bbox.x}::${bbox.y}` !== currentXY;
|
|
|
|
},
|
|
|
|
{},
|
|
|
|
selector,
|
|
|
|
xy
|
|
|
|
);
|
|
|
|
|
2023-10-27 05:44:35 +09:00
|
|
|
const cancelFocusIn = async (page, selector) => {
|
|
|
|
page.evaluate(sel => {
|
|
|
|
const el = document.querySelector(sel);
|
|
|
|
el.addEventListener(
|
|
|
|
"focusin",
|
|
|
|
evt => {
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopPropagation();
|
|
|
|
},
|
|
|
|
{ capture: true, once: true }
|
|
|
|
);
|
|
|
|
}, selector);
|
|
|
|
};
|
|
|
|
|
2023-06-07 00:18:02 +09:00
|
|
|
describe("FreeText Editor", () => {
|
2022-06-01 17:38:08 +09:00
|
|
|
describe("FreeText", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
2022-07-27 21:11:29 +09:00
|
|
|
pages = await loadAndWait("aboutstacks.pdf", ".annotationEditorLayer");
|
2022-06-01 17:38:08 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must write a string in a FreeText editor", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2022-06-01 17:38:08 +09:00
|
|
|
|
|
|
|
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 data = "Hello PDF.js World !!";
|
2022-06-13 18:01:55 +09:00
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-07-29 00:59:03 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
2022-06-01 17:38:08 +09:00
|
|
|
|
2022-07-29 00:59:03 +09:00
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
2022-06-01 17:38:08 +09:00
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2022-06-01 17:38:08 +09:00
|
|
|
|
2022-12-07 00:16:24 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(0));
|
2022-10-25 22:28:22 +09:00
|
|
|
await waitForStorageEntries(page, 1);
|
2022-08-04 19:44:05 +09:00
|
|
|
|
2023-08-09 01:24:03 +09:00
|
|
|
let content = await page.$eval(getEditorSelector(0), el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
|
|
|
|
// Edit again.
|
|
|
|
await page.keyboard.press("Enter");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay:not(.enabled)`
|
|
|
|
);
|
2023-08-09 01:24:03 +09:00
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-08-09 01:24:03 +09:00
|
|
|
|
|
|
|
content = await page.$eval(getEditorSelector(0), el =>
|
2022-06-01 17:38:08 +09:00
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must copy/paste", async () => {
|
2022-10-25 22:28:22 +09:00
|
|
|
// Run sequentially to avoid clipboard issues.
|
|
|
|
for (const [browserName, page] of pages) {
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
// Select the editor created previously.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
|
|
|
);
|
|
|
|
|
2022-12-07 00:16:24 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(0));
|
2022-10-25 22:28:22 +09:00
|
|
|
await copyPaste(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(1), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
await waitForStorageEntries(page, 2);
|
|
|
|
|
|
|
|
const content = await page.$eval(getEditorSelector(0), el =>
|
2023-12-22 06:57:58 +09:00
|
|
|
el.innerText.trimEnd().replaceAll("\xa0", " ")
|
2022-10-25 22:28:22 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
let pastedContent = await page.$eval(getEditorSelector(1), el =>
|
2023-12-22 06:57:58 +09:00
|
|
|
el.innerText.trimEnd().replaceAll("\xa0", " ")
|
2022-10-25 22:28:22 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
expect(pastedContent).withContext(`In ${browserName}`).toEqual(content);
|
|
|
|
|
|
|
|
await copyPaste(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(2), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
await waitForStorageEntries(page, 3);
|
|
|
|
|
|
|
|
pastedContent = await page.$eval(getEditorSelector(2), el =>
|
2023-12-22 06:57:58 +09:00
|
|
|
el.innerText.trimEnd().replaceAll("\xa0", " ")
|
2022-10-25 22:28:22 +09:00
|
|
|
);
|
|
|
|
expect(pastedContent).withContext(`In ${browserName}`).toEqual(content);
|
|
|
|
}
|
2022-06-01 17:38:08 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
it("must clear all", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-07-27 05:11:55 +09:00
|
|
|
await clearAll(page);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
2022-07-18 21:47:09 +09:00
|
|
|
for (const n of [0, 1, 2]) {
|
2024-01-21 18:13:12 +09:00
|
|
|
const hasEditor = await page.evaluate(
|
|
|
|
sel => !!document.querySelector(sel),
|
|
|
|
getEditorSelector(n)
|
|
|
|
);
|
2022-06-01 17:38:08 +09:00
|
|
|
|
|
|
|
expect(hasEditor).withContext(`In ${browserName}`).toEqual(false);
|
|
|
|
}
|
2022-08-04 19:44:05 +09:00
|
|
|
|
2022-10-25 22:28:22 +09:00
|
|
|
await waitForStorageEntries(page, 0);
|
2022-06-01 17:38:08 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that a paste has been undone", async () => {
|
2022-10-25 22:28:22 +09:00
|
|
|
// Run sequentially to avoid clipboard issues.
|
2023-09-28 05:35:57 +09:00
|
|
|
for (const [, page] of pages) {
|
2022-10-25 22:28:22 +09:00
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(3), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
await page.type(`${getEditorSelector(3)} .internal`, data);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(3), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${getEditorSelector(3)} .overlay.enabled`);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
2022-10-25 22:28:22 +09:00
|
|
|
// And select it again.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
|
|
|
);
|
|
|
|
|
2022-12-07 00:16:24 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(3));
|
2022-10-25 22:28:22 +09:00
|
|
|
await copyPaste(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(4), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(4)
|
|
|
|
);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
|
|
|
const promise = waitForEvent(page, "paste");
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbPaste(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
await promise;
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(5 + i));
|
2022-10-25 22:28:22 +09:00
|
|
|
}
|
2022-06-01 17:38:08 +09:00
|
|
|
|
2022-10-25 22:28:22 +09:00
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(6 - i)
|
|
|
|
);
|
2022-10-25 22:28:22 +09:00
|
|
|
}
|
|
|
|
}
|
2022-06-01 17:38:08 +09:00
|
|
|
});
|
2022-06-29 01:21:32 +09:00
|
|
|
|
|
|
|
it("must check that aria-owns is correct", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.$eval(".textLayer", el => {
|
|
|
|
for (const span of el.querySelectorAll(
|
|
|
|
`span[role="presentation"]`
|
|
|
|
)) {
|
|
|
|
if (span.innerText.includes("Stacks are simple to create")) {
|
|
|
|
span.setAttribute("pdfjs", true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await scrollIntoView(page, `span[pdfjs="true"]`);
|
|
|
|
|
2022-07-27 21:11:29 +09:00
|
|
|
const [stacksRect, oldAriaOwns] = await page.$eval(
|
2023-10-27 05:44:35 +09:00
|
|
|
`span[pdfjs="true"]`,
|
2022-06-29 01:21:32 +09:00
|
|
|
el => {
|
2023-10-27 05:44:35 +09:00
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return [{ x, y, width, height }, el.getAttribute("aria-owns")];
|
2022-06-29 01:21:32 +09:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(oldAriaOwns).withContext(`In ${browserName}`).toEqual(null);
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(
|
2022-07-27 21:11:29 +09:00
|
|
|
stacksRect.x + stacksRect.width + 1,
|
|
|
|
stacksRect.y + stacksRect.height / 2
|
2022-06-29 01:21:32 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(7), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-07-29 00:59:03 +09:00
|
|
|
await page.type(`${getEditorSelector(7)} .internal`, data);
|
2022-06-29 01:21:32 +09:00
|
|
|
|
|
|
|
// Commit.
|
2022-07-27 21:11:29 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(7)} .overlay.enabled`
|
|
|
|
);
|
2022-06-29 01:21:32 +09:00
|
|
|
|
|
|
|
const ariaOwns = await page.$eval(".textLayer", el => {
|
|
|
|
const span = el.querySelector(`span[pdfjs="true"]`);
|
|
|
|
return span?.getAttribute("aria-owns") || null;
|
|
|
|
});
|
|
|
|
|
2022-07-29 00:59:03 +09:00
|
|
|
expect(ariaOwns.endsWith("_7-editor"))
|
2022-06-29 01:21:32 +09:00
|
|
|
.withContext(`In ${browserName}`)
|
2022-07-29 00:59:03 +09:00
|
|
|
.toEqual(true);
|
2023-10-27 05:44:35 +09:00
|
|
|
await scrollIntoView(page, ".annotationEditorLayer");
|
2022-06-29 01:21:32 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
2022-07-27 21:11:29 +09:00
|
|
|
|
|
|
|
it("must check that right click doesn't select", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
2023-07-27 05:11:55 +09:00
|
|
|
await clearAll(page);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
2022-07-27 21:11:29 +09:00
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(8), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-07-29 00:59:03 +09:00
|
|
|
await page.type(`${getEditorSelector(8)} .internal`, data);
|
2022-07-27 21:11:29 +09:00
|
|
|
|
2022-07-29 00:59:03 +09:00
|
|
|
const editorRect = await page.$eval(getEditorSelector(8), el => {
|
2022-07-27 21:11:29 +09:00
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(8)} .overlay.enabled`
|
|
|
|
);
|
2022-07-27 21:11:29 +09:00
|
|
|
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
2022-07-28 02:05:44 +09:00
|
|
|
.toEqual([8]);
|
2022-07-27 21:11:29 +09:00
|
|
|
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
() => !document.querySelector(".selectedEditor")
|
|
|
|
);
|
2022-07-27 21:11:29 +09:00
|
|
|
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
|
|
|
);
|
|
|
|
|
2022-12-07 00:16:24 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(8));
|
2022-10-25 22:28:22 +09:00
|
|
|
|
2022-07-27 21:11:29 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
2022-07-28 02:05:44 +09:00
|
|
|
.toEqual([8]);
|
2022-07-27 21:11:29 +09:00
|
|
|
|
|
|
|
// Escape.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
() => !document.querySelector(".selectedEditor")
|
|
|
|
);
|
2022-07-27 21:11:29 +09:00
|
|
|
|
|
|
|
// TODO: uncomment that stuff once we've a way to dismiss
|
|
|
|
// the context menu.
|
|
|
|
/* await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2,
|
|
|
|
{ button: "right" }
|
|
|
|
); */
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
2023-06-06 04:00:56 +09:00
|
|
|
|
|
|
|
it("must check that text change can be undone/redone", async () => {
|
|
|
|
// Run sequentially to avoid clipboard issues.
|
|
|
|
for (const [browserName, page] of pages) {
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
2023-07-27 05:11:55 +09:00
|
|
|
await clearAll(page);
|
2023-06-06 04:00:56 +09:00
|
|
|
|
|
|
|
await page.mouse.click(rect.x + 200, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(9), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-06-06 04:00:56 +09:00
|
|
|
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
|
|
await page.type(`${getEditorSelector(9)} .internal`, "A");
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(9), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
2023-11-12 04:47:05 +09:00
|
|
|
editorRect.x + 1.5 * editorRect.width,
|
|
|
|
editorRect.y
|
2023-06-06 04:00:56 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(9)} .overlay.enabled`
|
|
|
|
);
|
2023-06-06 04:00:56 +09:00
|
|
|
|
|
|
|
if (i < 4) {
|
|
|
|
// And select it again.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2,
|
2023-11-30 17:40:57 +09:00
|
|
|
{ count: 2 }
|
2023-06-06 04:00:56 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(9)} .overlay:not(.enabled)`
|
|
|
|
);
|
2023-06-06 04:00:56 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
let prevText = await page.$eval(
|
|
|
|
`${getEditorSelector(9)} .internal`,
|
|
|
|
el => el.innerText
|
|
|
|
);
|
|
|
|
|
|
|
|
const waitForTextChange = previous =>
|
|
|
|
page.waitForFunction(
|
|
|
|
(prev, sel) => document.querySelector(sel).innerText !== prev,
|
|
|
|
{},
|
|
|
|
previous,
|
|
|
|
`${getEditorSelector(9)} .internal`
|
|
|
|
);
|
|
|
|
const getText = () =>
|
|
|
|
page.$eval(`${getEditorSelector(9)} .internal`, el => el.innerText);
|
|
|
|
|
|
|
|
// We're in the middle of the text.
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForTextChange(prevText);
|
2023-06-06 04:00:56 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
let text = (prevText = await getText());
|
2023-06-06 04:00:56 +09:00
|
|
|
expect(text).withContext(`In ${browserName}`).toEqual("AAAA");
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForTextChange(prevText);
|
2023-06-06 04:00:56 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
text = prevText = await getText();
|
2023-06-06 04:00:56 +09:00
|
|
|
|
|
|
|
expect(text).withContext(`In ${browserName}`).toEqual("AAA");
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbRedo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForTextChange(prevText);
|
2023-06-06 04:00:56 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
text = prevText = await getText();
|
2023-06-06 04:00:56 +09:00
|
|
|
|
|
|
|
expect(text).withContext(`In ${browserName}`).toEqual("AAAA");
|
2023-06-08 19:50:30 +09:00
|
|
|
|
|
|
|
for (let i = 0; i < 4; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
if (i < 3) {
|
|
|
|
await waitForTextChange(prevText);
|
|
|
|
prevText = await getText();
|
|
|
|
}
|
2023-06-08 19:50:30 +09:00
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
() => !document.querySelector(".selectedEditor")
|
|
|
|
);
|
2023-06-08 19:50:30 +09:00
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbRedo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(9), {
|
|
|
|
visible: true,
|
2023-06-08 19:50:30 +09:00
|
|
|
});
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
text = await getText();
|
2023-06-08 19:50:30 +09:00
|
|
|
expect(text).withContext(`In ${browserName}`).toEqual("A");
|
|
|
|
|
|
|
|
// Add a new A.
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(9), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2,
|
2023-11-30 17:40:57 +09:00
|
|
|
{ count: 2 }
|
2023-06-08 19:50:30 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(9)} .overlay:not(.enabled)`
|
|
|
|
);
|
2023-06-08 19:50:30 +09:00
|
|
|
await page.type(`${getEditorSelector(9)} .internal`, "A");
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
2023-11-12 04:47:05 +09:00
|
|
|
editorRect.x + 1.5 * editorRect.width,
|
|
|
|
editorRect.y
|
2023-06-08 19:50:30 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${getEditorSelector(9)} .overlay.enabled`);
|
2023-06-08 19:50:30 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
text = await getText();
|
2023-06-08 19:50:30 +09:00
|
|
|
expect(text).withContext(`In ${browserName}`).toEqual("AA");
|
2023-06-06 04:00:56 +09:00
|
|
|
}
|
|
|
|
});
|
2022-06-01 17:38:08 +09:00
|
|
|
});
|
2022-07-21 17:42:15 +09:00
|
|
|
|
|
|
|
describe("FreeText (multiselection)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
2022-07-27 21:11:29 +09:00
|
|
|
pages = await loadAndWait("aboutstacks.pdf", ".annotationEditorLayer");
|
2022-07-21 17:42:15 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must select/unselect several editors and check copy, paste and delete operations", async () => {
|
2022-10-25 22:28:22 +09:00
|
|
|
// Run sequentially to avoid clipboard issues.
|
|
|
|
for (const [browserName, page] of pages) {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
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.
|
2023-10-27 05:42:41 +09:00
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
2022-10-25 22:28:22 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
const editorCenters = [];
|
2023-11-12 04:47:05 +09:00
|
|
|
let lastX = rect.x + rect.width / 10;
|
2022-10-25 22:28:22 +09:00
|
|
|
for (let i = 0; i < 4; i++) {
|
|
|
|
const data = `FreeText ${i}`;
|
2023-11-12 04:47:05 +09:00
|
|
|
await page.mouse.click(lastX, rect.y + rect.height / 10);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(i), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
await page.type(`${getEditorSelector(i)} .internal`, data);
|
2022-07-21 17:42:15 +09:00
|
|
|
|
2022-10-25 22:28:22 +09:00
|
|
|
const editorRect = await page.$eval(getEditorSelector(i), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
2023-11-12 04:47:05 +09:00
|
|
|
lastX = editorRect.x + editorRect.width + 10;
|
2022-10-25 22:28:22 +09:00
|
|
|
editorCenters.push({
|
|
|
|
x: editorRect.x + editorRect.width / 2,
|
|
|
|
y: editorRect.y + editorRect.height / 2,
|
2022-07-21 17:42:15 +09:00
|
|
|
});
|
|
|
|
|
2022-10-25 22:28:22 +09:00
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
2023-11-12 04:47:05 +09:00
|
|
|
editorRect.x + 1.5 * editorRect.width,
|
|
|
|
editorRect.y
|
2022-10-25 22:28:22 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(i)} .overlay.enabled`
|
|
|
|
);
|
2022-10-25 22:28:22 +09:00
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 1, 2, 3]);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
// Unselect the editor.
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbModifierDown(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
await page.mouse.click(editorCenters[1].x, editorCenters[1].y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForUnselectedEditor(page, getEditorSelector(1));
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 2, 3]);
|
|
|
|
|
|
|
|
await page.mouse.click(editorCenters[2].x, editorCenters[2].y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForUnselectedEditor(page, getEditorSelector(2));
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 3]);
|
|
|
|
|
|
|
|
await page.mouse.click(editorCenters[1].x, editorCenters[1].y);
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbModifierUp(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(1));
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 1, 3]);
|
|
|
|
|
|
|
|
await copyPaste(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(6), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
// 0,1,3 are unselected and new pasted editors are selected.
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([4, 5, 6]);
|
|
|
|
|
|
|
|
// No ctrl here, hence all are unselected and 2 is selected.
|
|
|
|
await page.mouse.click(editorCenters[2].x, editorCenters[2].y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(2));
|
2022-10-25 22:28:22 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([2]);
|
|
|
|
|
|
|
|
await page.mouse.click(editorCenters[1].x, editorCenters[1].y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(1));
|
2022-10-25 22:28:22 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([1]);
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbModifierDown(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
await page.mouse.click(editorCenters[3].x, editorCenters[3].y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(3));
|
2022-10-25 22:28:22 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([1, 3]);
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbModifierUp(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
// Delete 1 and 3.
|
|
|
|
await page.keyboard.press("Backspace");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sels => sels.every(sel => !document.querySelector(sel)),
|
|
|
|
{},
|
|
|
|
[1, 3].map(getEditorSelector)
|
|
|
|
);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 2, 4, 5, 6]);
|
|
|
|
|
|
|
|
// Create an empty editor.
|
2023-10-27 05:42:41 +09:00
|
|
|
await page.mouse.click(
|
|
|
|
rect.x + (rect.width / 10) * 7,
|
|
|
|
rect.y + rect.height / 10
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(7), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([7]);
|
|
|
|
|
|
|
|
// Set the focus to 2 and check that only 2 is selected.
|
|
|
|
await page.mouse.click(editorCenters[2].x, editorCenters[2].y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(2));
|
2022-10-25 22:28:22 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([2]);
|
|
|
|
|
|
|
|
// Create an empty editor.
|
2023-10-27 05:42:41 +09:00
|
|
|
await page.mouse.click(
|
|
|
|
rect.x + (rect.width / 10) * 8,
|
|
|
|
rect.y + rect.height / 10
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(8), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-10-25 22:28:22 +09:00
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([8]);
|
|
|
|
// Dismiss it.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(8)
|
|
|
|
);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
2022-10-25 22:28:22 +09:00
|
|
|
|
|
|
|
// Check that all the editors are correctly selected (and the focus
|
|
|
|
// didn't move to the body when the empty editor was removed).
|
|
|
|
expect(await getSelectedEditors(page))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 2, 4, 5, 6]);
|
|
|
|
}
|
2022-07-21 17:42:15 +09:00
|
|
|
});
|
|
|
|
});
|
2022-12-07 00:16:24 +09:00
|
|
|
|
|
|
|
describe("FreeText (bugs)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must serialize invisible annotations", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2022-12-07 00:16:24 +09:00
|
|
|
let currentId = 0;
|
|
|
|
const expected = [];
|
2023-07-06 23:23:53 +09:00
|
|
|
const oneToFourteen = Array.from(new Array(14).keys(), x => x + 1);
|
2022-12-07 00:16:24 +09:00
|
|
|
|
|
|
|
for (const pageNumber of oneToFourteen) {
|
|
|
|
const pageSelector = `.page[data-page-number = "${pageNumber}"]`;
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await scrollIntoView(page, pageSelector);
|
|
|
|
const annotationLayerSelector = `${pageSelector} > .annotationEditorLayer.freetextEditing`;
|
2022-12-07 00:16:24 +09:00
|
|
|
await page.waitForSelector(annotationLayerSelector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
|
|
|
if (![1, 14].includes(pageNumber)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const rect = await page.$eval(annotationLayerSelector, 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 data = `Hello PDF.js World !! on page ${pageNumber}`;
|
|
|
|
expected.push(data);
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(currentId), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-12-07 00:16:24 +09:00
|
|
|
await page.type(`${getEditorSelector(currentId)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
2022-12-08 02:27:32 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(currentId)} .overlay.enabled`
|
|
|
|
);
|
2022-12-07 00:16:24 +09:00
|
|
|
|
|
|
|
await waitForSelectedEditor(page, getEditorSelector(currentId));
|
|
|
|
await waitForStorageEntries(page, currentId + 1);
|
|
|
|
|
|
|
|
const content = await page.$eval(getEditorSelector(currentId), el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
|
|
|
|
currentId += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const serialize = proprName =>
|
2023-06-29 15:43:02 +09:00
|
|
|
page.evaluate(name => {
|
|
|
|
const { map } =
|
|
|
|
window.PDFViewerApplication.pdfDocument.annotationStorage
|
|
|
|
.serializable;
|
|
|
|
return map ? Array.from(map.values(), x => x[name]) : [];
|
|
|
|
}, proprName);
|
2022-12-07 00:16:24 +09:00
|
|
|
|
|
|
|
expect(await serialize("value"))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(expected);
|
|
|
|
expect(await serialize("fontSize"))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([10, 10]);
|
|
|
|
expect(await serialize("color"))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([
|
|
|
|
[0, 0, 0],
|
|
|
|
[0, 0, 0],
|
|
|
|
]);
|
2022-12-05 20:25:06 +09:00
|
|
|
|
|
|
|
// Increase the font size for all the annotations.
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
|
|
|
|
|
|
|
const [prevFontSize, prevColor] = await page.$eval(
|
|
|
|
".selectedEditor .internal",
|
|
|
|
el => {
|
|
|
|
const style = getComputedStyle(el);
|
|
|
|
return [style.fontSize, style.color];
|
|
|
|
}
|
|
|
|
);
|
2022-12-05 20:25:06 +09:00
|
|
|
|
|
|
|
page.evaluate(() => {
|
|
|
|
window.PDFViewerApplication.eventBus.dispatch(
|
|
|
|
"switchannotationeditorparams",
|
|
|
|
{
|
|
|
|
source: null,
|
2023-07-26 19:57:59 +09:00
|
|
|
type: window.pdfjsLib.AnnotationEditorParamsType.FREETEXT_SIZE,
|
2022-12-05 20:25:06 +09:00
|
|
|
value: 13,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
prev =>
|
|
|
|
getComputedStyle(
|
|
|
|
document.querySelector(".selectedEditor .internal")
|
|
|
|
).fontSize !== prev,
|
|
|
|
{},
|
|
|
|
prevFontSize
|
|
|
|
);
|
2022-12-05 20:25:06 +09:00
|
|
|
|
|
|
|
expect(await serialize("fontSize"))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([13, 13]);
|
|
|
|
|
|
|
|
// Change the colors for all the annotations.
|
2024-01-23 08:00:07 +09:00
|
|
|
await page.evaluate(() => {
|
2022-12-05 20:25:06 +09:00
|
|
|
window.PDFViewerApplication.eventBus.dispatch(
|
|
|
|
"switchannotationeditorparams",
|
|
|
|
{
|
|
|
|
source: null,
|
2023-07-26 19:57:59 +09:00
|
|
|
type: window.pdfjsLib.AnnotationEditorParamsType.FREETEXT_COLOR,
|
2022-12-05 20:25:06 +09:00
|
|
|
value: "#FF0000",
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
prev =>
|
|
|
|
getComputedStyle(
|
|
|
|
document.querySelector(".selectedEditor .internal")
|
|
|
|
).color !== prev,
|
|
|
|
{},
|
|
|
|
prevColor
|
|
|
|
);
|
2022-12-05 20:25:06 +09:00
|
|
|
|
|
|
|
expect(await serialize("color"))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([
|
|
|
|
[255, 0, 0],
|
|
|
|
[255, 0, 0],
|
|
|
|
]);
|
2022-12-07 00:16:24 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2022-12-08 02:27:32 +09:00
|
|
|
|
|
|
|
describe("issue 15789", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("issue15789.pdf", ".annotationEditorLayer");
|
|
|
|
pages = await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await page.select("#scaleSelect", "1");
|
|
|
|
return [browserName, page];
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must take the media box into account", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2022-12-08 02:27:32 +09:00
|
|
|
let currentId = 0;
|
|
|
|
|
|
|
|
for (let step = 0; step < 3; step++) {
|
|
|
|
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, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = `Hello ${step}`;
|
|
|
|
const x = rect.x + 0.1 * rect.width;
|
|
|
|
const y = rect.y + 0.1 * rect.height;
|
|
|
|
await page.mouse.click(x, y);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(currentId), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2022-12-08 02:27:32 +09:00
|
|
|
await page.type(`${getEditorSelector(currentId)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(currentId)} .overlay.enabled`
|
|
|
|
);
|
2022-12-08 02:27:32 +09:00
|
|
|
|
|
|
|
await page.evaluate(() => {
|
|
|
|
document.getElementById("pageRotateCw").click();
|
|
|
|
});
|
|
|
|
currentId += 1;
|
2023-07-27 20:04:14 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
".page[data-page-number='1'] .canvasWrapper",
|
|
|
|
{
|
|
|
|
timeout: 0,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
await page.waitForSelector(
|
|
|
|
".page[data-page-number='1'] .annotationEditorLayer:not([hidden])",
|
|
|
|
{
|
|
|
|
timeout: 0,
|
|
|
|
}
|
|
|
|
);
|
2022-12-08 02:27:32 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
const serialize = proprName =>
|
2023-06-29 15:43:02 +09:00
|
|
|
page.evaluate(name => {
|
|
|
|
const { map } =
|
|
|
|
window.PDFViewerApplication.pdfDocument.annotationStorage
|
|
|
|
.serializable;
|
|
|
|
return map ? Array.from(map.values(), x => x[name]) : [];
|
|
|
|
}, proprName);
|
2022-12-08 02:27:32 +09:00
|
|
|
|
|
|
|
const rects = (await serialize("rect")).map(rect =>
|
|
|
|
rect.slice(0, 2).map(x => Math.floor(x))
|
|
|
|
);
|
|
|
|
const expected = [
|
|
|
|
[-28, 695],
|
|
|
|
[-38, -10],
|
|
|
|
[501, -20],
|
|
|
|
];
|
|
|
|
// Dimensions aren't exactly the same from a platform to an other
|
|
|
|
// so we're a bit tolerant here with the numbers.
|
|
|
|
// Anyway the goal is to check that the bottom left corner of the
|
|
|
|
// media box is taken into account.
|
|
|
|
// The pdf has a media box equals to [-99 -99 612.0 792.0].
|
|
|
|
const diffs = rects.map(
|
|
|
|
(rect, i) =>
|
|
|
|
Math.abs(rect[0] - expected[i][0]) < 10 &&
|
|
|
|
Math.abs(rect[1] - expected[i][1]) < 10
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(diffs)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([true, true, true]);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
describe("FreeText (move existing)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("freetexts.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must move an annotation", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
const editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
|
|
|
|
// All the current annotations should be serialized as null objects
|
|
|
|
// because they haven't been edited yet.
|
2023-09-28 05:35:57 +09:00
|
|
|
const serialized = await getSerialized(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
expect(serialized).withContext(`In ${browserName}`).toEqual([]);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
2023-08-09 18:23:26 +09:00
|
|
|
// Select the annotation we want to move.
|
|
|
|
await page.mouse.click(editorRect.x + 2, editorRect.y + 2);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(0));
|
2023-08-09 18:23:26 +09:00
|
|
|
|
2023-08-03 03:08:09 +09:00
|
|
|
await dragAndDropAnnotation(
|
|
|
|
page,
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2,
|
|
|
|
100,
|
|
|
|
100
|
2023-06-07 00:18:02 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSerialized(page, 1);
|
2023-06-07 00:18:02 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("FreeText (update existing)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("freetexts.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must update an existing annotation", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
let editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2,
|
2023-11-30 17:40:57 +09:00
|
|
|
{ count: 2 }
|
2023-06-07 00:18:02 +09:00
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay:not(.enabled)`
|
|
|
|
);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbGoToEnd(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel =>
|
|
|
|
document.getSelection().anchorOffset ===
|
|
|
|
document.querySelector(sel).innerText.length,
|
|
|
|
{},
|
|
|
|
`${getEditorSelector(0)} .internal`
|
|
|
|
);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
await page.type(
|
|
|
|
`${getEditorSelector(0)} .internal`,
|
|
|
|
" and edited in Firefox"
|
|
|
|
);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const serialized = await getSerialized(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
expect(serialized.length).withContext(`In ${browserName}`).toEqual(1);
|
|
|
|
expect(serialized[0]).toEqual(
|
|
|
|
jasmine.objectContaining({
|
|
|
|
color: [107, 217, 41],
|
|
|
|
fontSize: 14,
|
|
|
|
value: "Hello World from Acrobat and edited in Firefox",
|
|
|
|
id: "26R",
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
// Disable editing mode.
|
|
|
|
await page.click("#editorFreeText");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
|
|
|
|
2023-06-07 00:18:02 +09:00
|
|
|
// We want to check that the editor is displayed but not the original
|
|
|
|
// annotation.
|
|
|
|
editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(1);
|
|
|
|
const hidden = await page.$eval(
|
|
|
|
"[data-annotation-id='26R']",
|
|
|
|
el => el.hidden
|
|
|
|
);
|
|
|
|
expect(hidden).withContext(`In ${browserName}`).toBeTrue();
|
|
|
|
|
|
|
|
// Re-enable editing mode.
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
await page.focus(".annotationEditorLayer");
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSerialized(page, 0);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
|
|
|
|
// Undo again.
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
// Nothing should happen, it's why we can't wait for something
|
|
|
|
// specific!
|
2024-02-11 02:21:34 +09:00
|
|
|
await waitForTimeout(200);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
// We check that the editor hasn't been removed.
|
|
|
|
editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-06-16 01:33:03 +09:00
|
|
|
describe("FreeText (update existing but not empty ones)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("issue14438.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must update an existing annotation but not an empty one", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-16 01:33:03 +09:00
|
|
|
|
|
|
|
const editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(1);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-06-07 00:18:02 +09:00
|
|
|
describe("FreeText (delete existing)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("freetexts.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must delete an existing annotation", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
|
|
|
let editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(3), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(3));
|
2023-06-07 00:18:02 +09:00
|
|
|
await page.keyboard.press("Backspace");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(3)
|
|
|
|
);
|
2023-06-07 00:18:02 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const serialized = await getSerialized(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
expect(serialized).toEqual([
|
|
|
|
{
|
|
|
|
pageIndex: 0,
|
|
|
|
id: "51R",
|
|
|
|
deleted: true,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
// Disable editing mode.
|
2023-06-07 00:18:02 +09:00
|
|
|
await page.click("#editorFreeText");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
|
|
|
|
2023-06-07 00:18:02 +09:00
|
|
|
// We want to check that nothing is displayed.
|
|
|
|
editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(0);
|
|
|
|
const hidden = await page.$eval(
|
|
|
|
"[data-annotation-id='51R']",
|
|
|
|
el => el.hidden
|
|
|
|
);
|
|
|
|
expect(hidden).withContext(`In ${browserName}`).toBeTrue();
|
|
|
|
|
|
|
|
// Re-enable editing mode.
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-07 00:18:02 +09:00
|
|
|
await page.focus(".annotationEditorLayer");
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSerialized(page, 0);
|
2023-06-07 00:18:02 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-06-16 20:00:00 +09:00
|
|
|
|
|
|
|
describe("FreeText (copy/paste existing)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("freetexts.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must copy and paste an existing annotation", async () => {
|
|
|
|
// Run sequentially to avoid clipboard issues.
|
|
|
|
for (const [browserName, page] of pages) {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-16 20:00:00 +09:00
|
|
|
|
|
|
|
const editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(1), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(1));
|
2023-06-16 20:00:00 +09:00
|
|
|
|
|
|
|
await copyPaste(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(6), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-06-16 20:00:00 +09:00
|
|
|
await waitForStorageEntries(page, 7);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2023-06-21 18:07:14 +09:00
|
|
|
|
2023-07-07 22:51:48 +09:00
|
|
|
describe("FreeText (edit existing in double clicking on it)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("freetexts.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must move an annotation", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-11-30 17:40:57 +09:00
|
|
|
await page.click("[data-annotation-id='26R']", { count: 2 });
|
2023-09-18 01:49:11 +09:00
|
|
|
await page.waitForSelector(`${getEditorSelector(0)}-editor`);
|
2023-07-07 22:51:48 +09:00
|
|
|
|
|
|
|
const [focusedId, editable] = await page.evaluate(() => {
|
|
|
|
const el = document.activeElement;
|
|
|
|
return [el.id, el.contentEditable];
|
|
|
|
});
|
|
|
|
expect(focusedId)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual("pdfjs_internal_editor_0-editor");
|
|
|
|
expect(editable).withContext(`In ${browserName}`).toEqual("true");
|
|
|
|
|
|
|
|
const editorIds = await getEditors(page, "freeText");
|
|
|
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-06-21 18:07:14 +09:00
|
|
|
describe("FreeText with popup", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait(
|
|
|
|
"annotation-freetext.pdf",
|
|
|
|
".annotationEditorLayer"
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must not remove an empty annotation", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-10-27 05:42:41 +09:00
|
|
|
await page.waitForSelector("[data-annotation-id='23R']");
|
|
|
|
// Cannot use page.hover with Firefox on Mac because of a bug.
|
|
|
|
// TODO: remove this when we switch to BiDi.
|
|
|
|
await hover(page, "[data-annotation-id='23R']");
|
|
|
|
|
2023-06-21 18:07:14 +09:00
|
|
|
// Wait for the popup to be displayed.
|
|
|
|
await page.waitForFunction(
|
2023-09-28 05:35:57 +09:00
|
|
|
() =>
|
|
|
|
document.querySelector("[data-annotation-id='popup_23R']")
|
|
|
|
.hidden === false
|
2023-06-21 18:07:14 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
// Enter in editing mode.
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
|
|
|
|
2024-02-11 02:21:34 +09:00
|
|
|
await waitForTimeout(200);
|
2023-09-28 05:35:57 +09:00
|
|
|
|
|
|
|
// Disable editing mode.
|
2023-06-21 18:07:14 +09:00
|
|
|
await page.click("#editorFreeText");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
2023-06-21 18:07:14 +09:00
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
// TODO: remove this when we switch to BiDi.
|
|
|
|
await hover(page, "[data-annotation-id='23R']");
|
2023-06-21 18:07:14 +09:00
|
|
|
// Wait for the popup to be displayed.
|
|
|
|
await page.waitForFunction(
|
2023-09-28 05:35:57 +09:00
|
|
|
() =>
|
|
|
|
document.querySelector("[data-annotation-id='popup_23R']")
|
|
|
|
.hidden === false
|
2023-06-21 18:07:14 +09:00
|
|
|
);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
2023-06-21 17:41:19 +09:00
|
|
|
|
|
|
|
it("must hide the popup when editing", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await page.click("[data-annotation-id='20R']");
|
|
|
|
// Wait for the popup to be displayed.
|
|
|
|
await page.waitForFunction(
|
2023-09-28 05:35:57 +09:00
|
|
|
() =>
|
|
|
|
document.querySelector("[data-annotation-id='popup_20R']")
|
|
|
|
.hidden === false
|
2023-06-21 17:41:19 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
// Enter in editing mode.
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-06-21 17:41:19 +09:00
|
|
|
// Wait for the popup to be hidden.
|
|
|
|
await page.waitForFunction(
|
2023-09-28 05:35:57 +09:00
|
|
|
() =>
|
|
|
|
document.querySelector("[data-annotation-id='popup_20R']")
|
|
|
|
.hidden === true
|
2023-06-21 17:41:19 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
// Exit editing mode.
|
|
|
|
await page.click("#editorFreeText");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
|
|
|
|
2023-06-21 17:41:19 +09:00
|
|
|
// Wait for the popup to be visible.
|
|
|
|
await page.waitForFunction(
|
2023-09-28 05:35:57 +09:00
|
|
|
() =>
|
|
|
|
document.querySelector("[data-annotation-id='popup_20R']")
|
|
|
|
.hidden === false
|
2023-06-21 17:41:19 +09:00
|
|
|
);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
2023-06-21 18:07:14 +09:00
|
|
|
});
|
2023-07-05 06:56:24 +09:00
|
|
|
|
|
|
|
describe("FreeText rotation", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that the dimensions of a rotated annotations are correct after a font size change", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.evaluate(() => {
|
|
|
|
window.PDFViewerApplication.rotatePages(90);
|
|
|
|
});
|
|
|
|
await page.waitForSelector(
|
|
|
|
".annotationEditorLayer[data-main-rotation='90']"
|
|
|
|
);
|
|
|
|
await switchToFreeText(page);
|
2023-07-05 06:56:24 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-07-05 06:56:24 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
|
|
|
|
|
|
|
// Make Chrome happy.
|
|
|
|
await page.waitForFunction(() => {
|
|
|
|
const box = [
|
|
|
|
...window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.map.values(),
|
|
|
|
][0].rect;
|
|
|
|
return box[2] !== box[0];
|
|
|
|
}, {});
|
2023-07-05 06:56:24 +09:00
|
|
|
|
|
|
|
let serialized = await getSerialized(page);
|
|
|
|
let bbox = serialized[0].rect;
|
|
|
|
let width = bbox[2] - bbox[0];
|
|
|
|
let height = bbox[3] - bbox[1];
|
|
|
|
expect(width < height)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(true);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.evaluate(() => {
|
|
|
|
window.PDFViewerApplication.rotatePages(270);
|
|
|
|
});
|
|
|
|
await page.waitForSelector(
|
|
|
|
".annotationEditorLayer[data-main-rotation='0']"
|
|
|
|
);
|
2023-07-05 06:56:24 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
|
|
|
|
|
|
|
const prevWidth = await page.$eval(
|
|
|
|
".selectedEditor .internal",
|
|
|
|
el => el.getBoundingClientRect().width
|
|
|
|
);
|
2023-07-05 06:56:24 +09:00
|
|
|
|
|
|
|
page.evaluate(() => {
|
|
|
|
window.PDFViewerApplication.eventBus.dispatch(
|
|
|
|
"switchannotationeditorparams",
|
|
|
|
{
|
|
|
|
source: null,
|
2023-07-26 19:57:59 +09:00
|
|
|
type: window.pdfjsLib.AnnotationEditorParamsType.FREETEXT_SIZE,
|
2023-07-05 06:56:24 +09:00
|
|
|
value: 50,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
2023-09-28 05:35:57 +09:00
|
|
|
|
|
|
|
await page.waitForFunction(
|
|
|
|
prev =>
|
|
|
|
document
|
|
|
|
.querySelector(".selectedEditor .internal")
|
|
|
|
.getBoundingClientRect().width !== prev,
|
|
|
|
{},
|
|
|
|
prevWidth
|
|
|
|
);
|
|
|
|
|
|
|
|
// Make Chrome happy.
|
|
|
|
await page.waitForFunction(() => {
|
|
|
|
const box = [
|
|
|
|
...window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.map.values(),
|
|
|
|
][0].rect;
|
|
|
|
return box[2] !== box[0];
|
|
|
|
}, {});
|
2023-07-05 06:56:24 +09:00
|
|
|
|
|
|
|
serialized = await getSerialized(page);
|
|
|
|
bbox = serialized[0].rect;
|
|
|
|
width = bbox[2] - bbox[0];
|
|
|
|
height = bbox[3] - bbox[1];
|
|
|
|
expect(width < height)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(true);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-07-06 23:23:53 +09:00
|
|
|
|
|
|
|
describe("FreeText (remove)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must delete invisible annotations", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-07-06 23:23:53 +09:00
|
|
|
let currentId = 0;
|
|
|
|
const oneToFourteen = Array.from(new Array(14).keys(), x => x + 1);
|
|
|
|
|
|
|
|
for (const pageNumber of oneToFourteen) {
|
|
|
|
const pageSelector = `.page[data-page-number = "${pageNumber}"]`;
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await scrollIntoView(page, pageSelector);
|
|
|
|
const annotationLayerSelector = `${pageSelector} > .annotationEditorLayer.freetextEditing`;
|
2023-07-06 23:23:53 +09:00
|
|
|
await page.waitForSelector(annotationLayerSelector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
|
|
|
if (![1, 14].includes(pageNumber)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const rect = await page.$eval(annotationLayerSelector, 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 data = `Hello PDF.js World !! on page ${pageNumber}`;
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(currentId), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-07-06 23:23:53 +09:00
|
|
|
await page.type(`${getEditorSelector(currentId)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(currentId)} .overlay.enabled`
|
|
|
|
);
|
2023-07-06 23:23:53 +09:00
|
|
|
|
|
|
|
currentId += 1;
|
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
2023-07-06 23:23:53 +09:00
|
|
|
|
|
|
|
const serialize = () =>
|
|
|
|
page.evaluate(() => {
|
|
|
|
const { map } =
|
|
|
|
window.PDFViewerApplication.pdfDocument.annotationStorage
|
|
|
|
.serializable;
|
|
|
|
return map ? Array.from(map.values(), x => x.pageIndex) : [];
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(await serialize())
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual([0, 13]);
|
|
|
|
|
|
|
|
// Delete
|
|
|
|
await page.keyboard.press("Backspace");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSerialized(page, 0);
|
2023-07-06 23:23:53 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-07-06 02:46:21 +09:00
|
|
|
|
|
|
|
describe("FreeText (open existing)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
2023-10-27 05:42:41 +09:00
|
|
|
pages = await loadAndWait("issue16633.pdf", ".annotationEditorLayer");
|
2023-07-06 02:46:21 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must open an existing annotation and check that the position are good", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-07-06 02:46:21 +09:00
|
|
|
|
|
|
|
await page.evaluate(() => {
|
|
|
|
document.getElementById("editorFreeTextParamsToolbar").remove();
|
|
|
|
});
|
|
|
|
|
|
|
|
const toBinary = buf => {
|
|
|
|
for (let i = 0; i < buf.length; i += 4) {
|
|
|
|
const gray =
|
|
|
|
(0.2126 * buf[i] + 0.7152 * buf[i + 1] + 0.0722 * buf[i + 2]) /
|
|
|
|
255;
|
|
|
|
buf[i] = buf[i + 1] = buf[i + 2] = gray <= 0.5 ? 0 : 255;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// We want to detect the first non-white pixel in the image.
|
|
|
|
// But we can have some antialiasing...
|
|
|
|
// The idea to just try to detect the beginning of the vertical bar
|
|
|
|
// of the "H" letter.
|
|
|
|
// Hence we just take the first non-white pixel in the image which is
|
|
|
|
// the most repeated one.
|
|
|
|
const getFirstPixel = (buf, width, height) => {
|
|
|
|
toBinary(buf);
|
|
|
|
const firsts = [];
|
|
|
|
const stats = {};
|
|
|
|
// Get the position of the first pixels.
|
|
|
|
// The position of char depends on a lot of different parameters,
|
|
|
|
// hence it's possible to not have a pixel where we expect to have
|
|
|
|
// it. So we just collect the positions of the first black pixel and
|
|
|
|
// take the first one where its abscissa is the most frequent.
|
|
|
|
for (let i = height - 1; i >= 0; i--) {
|
|
|
|
for (let j = 0; j < width; j++) {
|
|
|
|
const idx = (width * i + j) << 2;
|
|
|
|
if (buf[idx] === 0) {
|
|
|
|
firsts.push([j, i]);
|
|
|
|
stats[j] = (stats[j] || 0) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let maxValue = -Infinity;
|
|
|
|
let maxJ = 0;
|
|
|
|
for (const [j, count] of Object.entries(stats)) {
|
|
|
|
if (count > maxValue) {
|
|
|
|
maxValue = count;
|
|
|
|
maxJ = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
maxJ = parseInt(maxJ, 10);
|
|
|
|
for (const [j, i] of firsts) {
|
|
|
|
if (j === maxJ) {
|
|
|
|
return [j, i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const n of [0, 1, 2, 3, 4]) {
|
|
|
|
const rect = await page.$eval(getEditorSelector(n), el => {
|
|
|
|
// With Chrome something is wrong when serializing a DomRect,
|
|
|
|
// hence we extract the values and just return them.
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
const editorPng = await page.screenshot({
|
|
|
|
clip: rect,
|
|
|
|
type: "png",
|
|
|
|
});
|
|
|
|
const editorImage = PNG.sync.read(editorPng);
|
|
|
|
const editorFirstPix = getFirstPixel(
|
|
|
|
editorImage.data,
|
|
|
|
editorImage.width,
|
|
|
|
editorImage.height
|
|
|
|
);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const annotationId = await page.evaluate(N => {
|
2023-07-06 02:46:21 +09:00
|
|
|
const editor = document.getElementById(
|
|
|
|
`pdfjs_internal_editor_${N}`
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
const annId = editor.getAttribute("annotation-id");
|
2023-07-06 02:46:21 +09:00
|
|
|
const annotation = document.querySelector(
|
2023-09-28 05:35:57 +09:00
|
|
|
`[data-annotation-id="${annId}"]`
|
2023-07-06 02:46:21 +09:00
|
|
|
);
|
|
|
|
editor.hidden = true;
|
|
|
|
annotation.hidden = false;
|
2023-09-28 05:35:57 +09:00
|
|
|
return annId;
|
2023-07-06 02:46:21 +09:00
|
|
|
}, n);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${getEditorSelector(n)}[hidden]`);
|
|
|
|
await page.waitForSelector(
|
|
|
|
`[data-annotation-id="${annotationId}"]:not([hidden])`
|
|
|
|
);
|
|
|
|
|
2023-07-06 02:46:21 +09:00
|
|
|
const annotationPng = await page.screenshot({
|
|
|
|
clip: rect,
|
|
|
|
type: "png",
|
|
|
|
});
|
|
|
|
const annotationImage = PNG.sync.read(annotationPng);
|
|
|
|
const annotationFirstPix = getFirstPixel(
|
|
|
|
annotationImage.data,
|
|
|
|
annotationImage.width,
|
|
|
|
annotationImage.height
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(
|
|
|
|
Math.abs(editorFirstPix[0] - annotationFirstPix[0]) <= 3 &&
|
|
|
|
Math.abs(editorFirstPix[1] - annotationFirstPix[1]) <= 3
|
|
|
|
)
|
|
|
|
.withContext(
|
|
|
|
`In ${browserName}, first pix coords in editor: ${editorFirstPix} and in annotation: ${annotationFirstPix}`
|
|
|
|
)
|
|
|
|
.toEqual(true);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("FreeText (open existing and rotated)", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait(
|
|
|
|
"rotated_freetexts.pdf",
|
|
|
|
".annotationEditorLayer",
|
|
|
|
100
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must open an existing rotated annotation and check that the position are good", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-07-06 02:46:21 +09:00
|
|
|
|
|
|
|
await page.evaluate(() => {
|
|
|
|
document.getElementById("editorFreeTextParamsToolbar").remove();
|
|
|
|
});
|
|
|
|
|
|
|
|
const toBinary = buf => {
|
|
|
|
for (let i = 0; i < buf.length; i += 4) {
|
|
|
|
const gray =
|
|
|
|
(0.2126 * buf[i] + 0.7152 * buf[i + 1] + 0.0722 * buf[i + 2]) /
|
|
|
|
255;
|
|
|
|
buf[i] = buf[i + 1] = buf[i + 2] = gray >= 0.5 ? 255 : 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const getFirstPixel = (buf, width, height, start) => {
|
|
|
|
toBinary(buf);
|
|
|
|
const firsts = [];
|
|
|
|
const stats = {};
|
|
|
|
switch (start) {
|
|
|
|
case "TL":
|
|
|
|
for (let j = 0; j < width; j++) {
|
|
|
|
for (let i = 0; i < height; i++) {
|
|
|
|
const idx = (width * i + j) << 2;
|
|
|
|
if (buf[idx] === 0) {
|
|
|
|
firsts.push([j, i]);
|
|
|
|
stats[j] = (stats[j] || 0) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "TR":
|
|
|
|
for (let i = 0; i < height; i++) {
|
|
|
|
for (let j = width - 1; j >= 0; j--) {
|
|
|
|
const idx = (width * i + j) << 2;
|
|
|
|
if (buf[idx] === 0) {
|
|
|
|
firsts.push([j, i]);
|
|
|
|
stats[j] = (stats[j] || 0) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "BR":
|
|
|
|
for (let j = width - 1; j >= 0; j--) {
|
|
|
|
for (let i = height - 1; i >= 0; i--) {
|
|
|
|
const idx = (width * i + j) << 2;
|
|
|
|
if (buf[idx] === 0) {
|
|
|
|
firsts.push([j, i]);
|
|
|
|
stats[j] = (stats[j] || 0) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "BL":
|
|
|
|
for (let i = height - 1; i >= 0; i--) {
|
|
|
|
for (let j = 0; j < width; j++) {
|
|
|
|
const idx = (width * i + j) << 2;
|
|
|
|
if (buf[idx] === 0) {
|
|
|
|
firsts.push([j, i]);
|
|
|
|
stats[j] = (stats[j] || 0) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let maxValue = -Infinity;
|
|
|
|
let maxJ = 0;
|
|
|
|
for (const [j, count] of Object.entries(stats)) {
|
|
|
|
if (count > maxValue) {
|
|
|
|
maxValue = count;
|
|
|
|
maxJ = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
maxJ = parseInt(maxJ, 10);
|
|
|
|
for (const [j, i] of firsts) {
|
|
|
|
if (j === maxJ) {
|
|
|
|
return [j, i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const [n, start] of [
|
|
|
|
[0, "BL"],
|
|
|
|
[1, "BR"],
|
|
|
|
[2, "TR"],
|
|
|
|
[3, "TL"],
|
|
|
|
]) {
|
|
|
|
const rect = await page.$eval(getEditorSelector(n), el => {
|
|
|
|
// With Chrome something is wrong when serializing a DomRect,
|
|
|
|
// hence we extract the values and just return them.
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
const editorPng = await page.screenshot({
|
|
|
|
clip: rect,
|
|
|
|
type: "png",
|
|
|
|
});
|
|
|
|
const editorImage = PNG.sync.read(editorPng);
|
|
|
|
const editorFirstPix = getFirstPixel(
|
|
|
|
editorImage.data,
|
|
|
|
editorImage.width,
|
|
|
|
editorImage.height,
|
|
|
|
start
|
|
|
|
);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const annotationId = await page.evaluate(N => {
|
2023-07-06 02:46:21 +09:00
|
|
|
const editor = document.getElementById(
|
|
|
|
`pdfjs_internal_editor_${N}`
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
const annId = editor.getAttribute("annotation-id");
|
2023-07-06 02:46:21 +09:00
|
|
|
const annotation = document.querySelector(
|
2023-09-28 05:35:57 +09:00
|
|
|
`[data-annotation-id="${annId}"]`
|
2023-07-06 02:46:21 +09:00
|
|
|
);
|
|
|
|
editor.hidden = true;
|
|
|
|
annotation.hidden = false;
|
2023-09-28 05:35:57 +09:00
|
|
|
return annId;
|
2023-07-06 02:46:21 +09:00
|
|
|
}, n);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${getEditorSelector(n)}[hidden]`);
|
|
|
|
await page.waitForSelector(
|
|
|
|
`[data-annotation-id="${annotationId}"]:not([hidden])`
|
|
|
|
);
|
|
|
|
|
2023-07-06 02:46:21 +09:00
|
|
|
const annotationPng = await page.screenshot({
|
|
|
|
clip: rect,
|
|
|
|
type: "png",
|
|
|
|
});
|
|
|
|
const annotationImage = PNG.sync.read(annotationPng);
|
|
|
|
const annotationFirstPix = getFirstPixel(
|
|
|
|
annotationImage.data,
|
|
|
|
annotationImage.width,
|
|
|
|
annotationImage.height,
|
|
|
|
start
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(
|
|
|
|
Math.abs(editorFirstPix[0] - annotationFirstPix[0]) <= 3 &&
|
|
|
|
Math.abs(editorFirstPix[1] - annotationFirstPix[1]) <= 3
|
|
|
|
)
|
|
|
|
.withContext(
|
|
|
|
`In ${browserName}, first pix coords in editor: ${editorFirstPix} and in annotation: ${annotationFirstPix}`
|
|
|
|
)
|
|
|
|
.toEqual(true);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-07-25 22:56:43 +09:00
|
|
|
|
|
|
|
describe("Keyboard shortcuts when the editor layer isn't focused", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that the shortcuts are working correctly", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-07-25 22:56:43 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
|
|
|
await page.focus("#editorFreeTextColor");
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(0)
|
|
|
|
);
|
2023-07-25 22:56:43 +09:00
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbRedo(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !!document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(0)
|
|
|
|
);
|
2023-07-25 22:56:43 +09:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-07-26 19:57:59 +09:00
|
|
|
|
|
|
|
describe("Move editor with arrows", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check the position of moved editor", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-07-26 19:57:59 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
2023-09-28 05:35:57 +09:00
|
|
|
const selectorEditor = getEditorSelector(0);
|
2023-07-26 19:57:59 +09:00
|
|
|
await page.mouse.click(rect.x + 200, rect.y + 200);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
2023-07-26 19:57:59 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const editorRect = await page.$eval(selectorEditor, el => {
|
2023-07-26 19:57:59 +09:00
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
2023-07-26 19:57:59 +09:00
|
|
|
|
|
|
|
const [pageX, pageY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
let xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
for (let i = 0; i < 20; i++) {
|
|
|
|
await page.keyboard.press("ArrowRight");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
let [newX, newY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
expect(Math.round(newX))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageX + 20));
|
|
|
|
expect(Math.round(newY))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageY));
|
|
|
|
|
|
|
|
for (let i = 0; i < 20; i++) {
|
|
|
|
await page.keyboard.press("ArrowDown");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
[newX, newY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
expect(Math.round(newX))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageX + 20));
|
|
|
|
expect(Math.round(newY))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageY - 20));
|
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveLeft(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
[newX, newY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
expect(Math.round(newX))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageX));
|
|
|
|
expect(Math.round(newY))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageY - 20));
|
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveUp(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
[newX, newY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
expect(Math.round(newX))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageX));
|
|
|
|
expect(Math.round(newY))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageY));
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check arrow doesn't move an editor when a slider is focused", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
2023-07-26 19:57:59 +09:00
|
|
|
await page.focus("#editorFreeTextFontSize");
|
|
|
|
|
|
|
|
const [page1X, , page2X] = await getFirstSerialized(
|
|
|
|
page,
|
|
|
|
x => x.rect
|
|
|
|
);
|
|
|
|
const pageWidth = page2X - page1X;
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const selectorEditor = getEditorSelector(0);
|
|
|
|
let xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
for (let i = 0; i < 5; i++) {
|
|
|
|
await page.keyboard.press("ArrowRight");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-26 19:57:59 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
const [new1X, , new2X] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
const newWidth = new2X - new1X;
|
|
|
|
expect(Math.round(new1X))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.not.toEqual(Math.round(page1X + 5));
|
|
|
|
expect(newWidth)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.not.toEqual(pageWidth);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
2023-07-27 05:11:55 +09:00
|
|
|
|
|
|
|
it("must check the position of an empty freetext", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await clearAll(page);
|
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
2023-09-28 05:35:57 +09:00
|
|
|
let selectorEditor = getEditorSelector(1);
|
2023-07-27 05:11:55 +09:00
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
2023-07-27 05:11:55 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const editorRect = await page.$eval(selectorEditor, el => {
|
2023-07-27 05:11:55 +09:00
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x,
|
|
|
|
editorRect.y + 2 * editorRect.height
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
2023-07-27 05:11:55 +09:00
|
|
|
|
|
|
|
const [pageX, pageY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
|
|
|
|
await clearAll(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
selectorEditor = getEditorSelector(2);
|
2023-07-27 05:11:55 +09:00
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-07-27 05:11:55 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
let xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
for (let i = 0; i < 20; i++) {
|
|
|
|
await page.keyboard.press("ArrowRight");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveDown(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < 20; i++) {
|
|
|
|
await page.keyboard.press("ArrowLeft");
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveUp(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveRight(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < 2; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveLeft(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-07-27 05:11:55 +09:00
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
2023-07-27 05:11:55 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
2023-07-27 05:11:55 +09:00
|
|
|
|
|
|
|
const [newX, newY] = await getFirstSerialized(page, x => x.rect);
|
|
|
|
expect(Math.round(newX))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageX));
|
|
|
|
expect(Math.round(newY))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(Math.round(pageY));
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
2023-07-26 19:57:59 +09:00
|
|
|
});
|
2023-07-28 03:12:38 +09:00
|
|
|
|
|
|
|
describe("Focus must go on the current page", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait(
|
|
|
|
"tracemonkey.pdf",
|
|
|
|
".annotationEditorLayer",
|
|
|
|
100,
|
|
|
|
async page => {
|
|
|
|
await page.waitForFunction(async () => {
|
|
|
|
await window.PDFViewerApplication.initializedPromise;
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
await page.evaluate(() => {
|
|
|
|
window.visitedPages = [];
|
|
|
|
window.PDFViewerApplication.eventBus.on(
|
|
|
|
"pagechanging",
|
|
|
|
({ pageNumber }) => {
|
|
|
|
window.visitedPages.push(pageNumber);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that the focus is on the right page", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-07-28 03:12:38 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-07-28 03:12:38 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
// Commit.
|
2023-10-27 05:44:35 +09:00
|
|
|
await cancelFocusIn(page, getEditorSelector(0));
|
2023-07-28 03:12:38 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-07-28 03:12:38 +09:00
|
|
|
|
|
|
|
const oneToFourteen = Array.from(new Array(14).keys(), x => x + 1);
|
|
|
|
|
|
|
|
for (const pageNumber of oneToFourteen) {
|
|
|
|
const pageSelector = `.page[data-page-number = "${pageNumber}"]`;
|
2023-09-28 05:35:57 +09:00
|
|
|
await scrollIntoView(page, pageSelector);
|
|
|
|
const annotationLayerSelector = `${pageSelector} > .annotationEditorLayer:not([hidden]).freetextEditing`;
|
2023-07-28 03:12:38 +09:00
|
|
|
await page.waitForSelector(annotationLayerSelector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const visitedPages = await page.evaluate(() => {
|
|
|
|
const p = window.visitedPages;
|
|
|
|
delete window.visitedPages;
|
|
|
|
return p;
|
|
|
|
});
|
|
|
|
const sorted = visitedPages.slice().sort((a, b) => a - b);
|
|
|
|
|
|
|
|
expect(visitedPages.length)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.not.toEqual(0);
|
|
|
|
expect(visitedPages).withContext(`In ${browserName}`).toEqual(sorted);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-08-09 02:47:24 +09:00
|
|
|
|
|
|
|
describe("Freetext must stay focused after having been moved", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must keep the focus", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-08-09 02:47:24 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-08-09 02:47:24 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, "A");
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-08-09 02:47:24 +09:00
|
|
|
|
|
|
|
await page.mouse.click(rect.x + 110, rect.y + 150);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(1), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${getEditorSelector(1)} .internal`, "B");
|
2023-08-09 02:47:24 +09:00
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(1)} .overlay.enabled`
|
|
|
|
);
|
2023-08-09 02:47:24 +09:00
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await page.mouse.click(rect.x + 111, rect.y + 151);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(1));
|
2023-08-09 02:47:24 +09:00
|
|
|
|
|
|
|
const pos = n =>
|
|
|
|
page.evaluate(sel => {
|
|
|
|
const editor = document.querySelector(sel);
|
|
|
|
return Array.prototype.indexOf.call(
|
|
|
|
editor.parentNode.childNodes,
|
|
|
|
editor
|
|
|
|
);
|
|
|
|
}, getEditorSelector(n));
|
|
|
|
|
|
|
|
expect(await pos(0))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(0);
|
|
|
|
expect(await pos(1))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(1);
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
const getY = selector =>
|
|
|
|
page.evaluate(
|
|
|
|
sel => document.querySelector(sel).getBoundingClientRect().y,
|
|
|
|
selector
|
|
|
|
);
|
|
|
|
const height = await page.evaluate(
|
|
|
|
sel => document.querySelector(sel).getBoundingClientRect().height,
|
|
|
|
getEditorSelector(0)
|
|
|
|
);
|
|
|
|
|
|
|
|
const y0 = await getY(getEditorSelector(0));
|
2023-09-28 05:35:57 +09:00
|
|
|
const selectorEditor = getEditorSelector(1);
|
|
|
|
let xy = await getXY(page, selectorEditor);
|
2023-10-27 05:42:41 +09:00
|
|
|
while ((await getY(selectorEditor)) > y0 - height) {
|
|
|
|
await kbBigMoveUp(page);
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
2023-08-09 02:47:24 +09:00
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
// The editor must be moved in the DOM and potentially the focus
|
|
|
|
// will be lost, hence there's a callback will get back the focus.
|
2024-02-11 02:21:34 +09:00
|
|
|
await waitForTimeout(200);
|
2023-09-28 05:35:57 +09:00
|
|
|
|
2023-08-09 02:47:24 +09:00
|
|
|
const focused = await page.evaluate(sel => {
|
|
|
|
const editor = document.querySelector(sel);
|
|
|
|
return editor === document.activeElement;
|
|
|
|
}, getEditorSelector(1));
|
|
|
|
expect(focused).withContext(`In ${browserName}`).toEqual(true);
|
|
|
|
|
|
|
|
expect(await pos(0))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(1);
|
|
|
|
expect(await pos(1))
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(0);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-08-09 18:23:26 +09:00
|
|
|
|
|
|
|
describe("Move several FreeTexts", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must move several annotations", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-08-09 18:23:26 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const allPositions = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
await page.mouse.click(rect.x + 10 + 30 * i, rect.y + 100 + 5 * i);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(i), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-08-09 18:23:26 +09:00
|
|
|
await page.type(
|
|
|
|
`${getEditorSelector(i)} .internal`,
|
|
|
|
String.fromCharCode(65 + i)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(i)} .overlay.enabled`
|
|
|
|
);
|
2023-08-09 18:23:26 +09:00
|
|
|
|
|
|
|
allPositions.push(
|
|
|
|
await page.$eval(getEditorSelector(i), el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await selectAll(page);
|
2023-08-09 18:23:26 +09:00
|
|
|
await dragAndDropAnnotation(page, rect.x + 161, rect.y + 126, 39, 74);
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
const pos = await page.$eval(getEditorSelector(i), el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
const oldPos = allPositions[i];
|
2023-10-27 05:42:41 +09:00
|
|
|
expect(Math.abs(Math.round(pos.x - oldPos.x) - 39))
|
2023-08-09 18:23:26 +09:00
|
|
|
.withContext(`In ${browserName}`)
|
2023-10-27 05:42:41 +09:00
|
|
|
.toBeLessThanOrEqual(1);
|
|
|
|
expect(Math.abs(Math.round(pos.y - oldPos.y) - 74))
|
2023-08-09 18:23:26 +09:00
|
|
|
.withContext(`In ${browserName}`)
|
2023-10-27 05:42:41 +09:00
|
|
|
.toBeLessThanOrEqual(1);
|
2023-08-09 18:23:26 +09:00
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-08-11 01:02:27 +09:00
|
|
|
|
|
|
|
describe("Don't unselect all when scrolling", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait(
|
|
|
|
"tracemonkey.pdf",
|
|
|
|
".annotationEditorLayer",
|
|
|
|
100,
|
|
|
|
async page => {
|
|
|
|
await page.waitForFunction(async () => {
|
|
|
|
await window.PDFViewerApplication.initializedPromise;
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
await page.evaluate(() => {
|
|
|
|
window.PDFViewerApplication.eventBus.on(
|
|
|
|
"annotationeditorstateschanged",
|
|
|
|
({ details }) => {
|
|
|
|
window.editingEvents?.push(details);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that selected editor stay selected", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-08-11 01:02:27 +09:00
|
|
|
|
|
|
|
const rect = await page.$eval(".annotationEditorLayer", el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-08-11 01:02:27 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
2023-10-27 05:42:41 +09:00
|
|
|
|
2023-08-11 01:02:27 +09:00
|
|
|
// Commit.
|
2023-10-27 05:44:35 +09:00
|
|
|
await cancelFocusIn(page, getEditorSelector(0));
|
2023-08-11 01:02:27 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-08-11 01:02:27 +09:00
|
|
|
|
|
|
|
await page.evaluate(() => {
|
|
|
|
window.editingEvents = [];
|
|
|
|
});
|
|
|
|
|
|
|
|
for (let pageNumber = 1; pageNumber <= 4; pageNumber++) {
|
|
|
|
const pageSelector = `.page[data-page-number = "${pageNumber}"]`;
|
2023-09-28 05:35:57 +09:00
|
|
|
await scrollIntoView(page, pageSelector);
|
|
|
|
const annotationLayerSelector = `${pageSelector} > .annotationEditorLayer.freetextEditing`;
|
2023-08-11 01:02:27 +09:00
|
|
|
await page.waitForSelector(annotationLayerSelector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const editingEvents = await page.evaluate(() => {
|
|
|
|
const e = window.editingEvents;
|
|
|
|
delete window.editingEvents;
|
|
|
|
return e;
|
|
|
|
});
|
|
|
|
expect(editingEvents.length)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(0);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-09-07 19:30:29 +09:00
|
|
|
|
|
|
|
describe("FreeText on several pages", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that first annotation is selected without errors", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-09-07 19:30:29 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const page1Selector = `.page[data-page-number = "1"] > .annotationEditorLayer.freetextEditing`;
|
2023-09-07 19:30:29 +09:00
|
|
|
let rect = await page.$eval(page1Selector, el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
2023-10-27 05:44:35 +09:00
|
|
|
const selectorEditor = getEditorSelector(0);
|
2023-09-07 19:30:29 +09:00
|
|
|
await page.mouse.click(rect.x + 10, rect.y + 10);
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.waitForSelector(selectorEditor, {
|
2023-09-28 05:35:57 +09:00
|
|
|
visible: true,
|
|
|
|
});
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.type(`${selectorEditor} .internal`, "Hello");
|
2023-09-07 19:30:29 +09:00
|
|
|
|
|
|
|
// Commit.
|
2023-10-27 05:44:35 +09:00
|
|
|
await cancelFocusIn(page, selectorEditor);
|
2023-09-07 19:30:29 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
|
|
|
|
|
|
|
// Unselect.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await waitForUnselectedEditor(page, selectorEditor);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(selectorEditor, el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
// Select the editor created previously.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
2023-09-28 05:35:57 +09:00
|
|
|
);
|
2023-09-07 19:30:29 +09:00
|
|
|
|
|
|
|
// Go to the last page.
|
2023-10-27 05:44:35 +09:00
|
|
|
await scrollIntoView(page, `.page[data-page-number = "14"]`);
|
2023-09-07 19:30:29 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
const page14Selector = `.page[data-page-number = "14"] > .annotationEditorLayer.freetextEditing`;
|
2023-09-07 19:30:29 +09:00
|
|
|
await page.waitForSelector(page14Selector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
|
|
|
|
|
|
|
rect = await page.$eval(page14Selector, el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
|
|
|
await page.mouse.click(rect.x + 10, rect.y + 10);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(1), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${getEditorSelector(1)} .internal`, "World");
|
2023-09-07 19:30:29 +09:00
|
|
|
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-09-07 19:30:29 +09:00
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
for (let i = 0; i < 13; i++) {
|
2023-09-07 19:30:29 +09:00
|
|
|
await page.keyboard.press("P");
|
2023-09-28 05:35:57 +09:00
|
|
|
const pageSelector = `.page[data-page-number = "${
|
|
|
|
13 - i
|
|
|
|
}"] > .annotationEditorLayer.freetextEditing`;
|
|
|
|
await page.waitForSelector(pageSelector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
2023-09-07 19:30:29 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
rect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return {
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
await page.mouse.click(
|
|
|
|
rect.x + rect.width / 2,
|
|
|
|
rect.y + rect.height / 2
|
|
|
|
);
|
|
|
|
|
2023-09-28 05:35:57 +09:00
|
|
|
await waitForSelectedEditor(page, getEditorSelector(0));
|
|
|
|
|
2023-09-07 19:30:29 +09:00
|
|
|
const content = await page.$eval(getEditorSelector(0), el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual("Hello");
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-09-08 01:02:55 +09:00
|
|
|
|
2023-09-29 23:19:02 +09:00
|
|
|
describe("Deleted FreeText", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that a deleted freetext can be restored", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
|
|
|
|
const page1Selector = `.page[data-page-number = "1"] > .annotationEditorLayer.freetextEditing`;
|
|
|
|
const rect = await page.$eval(page1Selector, el => {
|
|
|
|
const { x, y } = el.getBoundingClientRect();
|
|
|
|
return { x, y };
|
|
|
|
});
|
2023-10-27 05:44:35 +09:00
|
|
|
const selectorEditor = getEditorSelector(0);
|
2023-09-29 23:19:02 +09:00
|
|
|
await page.mouse.click(rect.x + 10, rect.y + 10);
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.waitForSelector(selectorEditor, {
|
2023-09-29 23:19:02 +09:00
|
|
|
visible: true,
|
|
|
|
});
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.type(`${selectorEditor} .internal`, "Hello");
|
2023-09-29 23:19:02 +09:00
|
|
|
|
|
|
|
// Commit.
|
2023-10-27 05:44:35 +09:00
|
|
|
await cancelFocusIn(page, selectorEditor);
|
2023-09-29 23:19:02 +09:00
|
|
|
await page.keyboard.press("Escape");
|
2023-10-27 05:44:35 +09:00
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
|
|
|
|
|
|
|
// Unselect.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await waitForUnselectedEditor(page, selectorEditor);
|
|
|
|
|
|
|
|
const editorRect = await page.$eval(selectorEditor, el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
|
|
|
|
// Select the editor created previously.
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
2023-09-29 23:19:02 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
// Go to the last page.
|
2023-10-27 05:44:35 +09:00
|
|
|
await scrollIntoView(page, `.page[data-page-number = "14"]`);
|
2023-09-29 23:19:02 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`.page[data-page-number = "14"] > .annotationEditorLayer.freetextEditing`,
|
|
|
|
{
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
await clearAll(page);
|
|
|
|
|
|
|
|
// Go to the first page.
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbGoToBegin(page);
|
2023-09-29 23:19:02 +09:00
|
|
|
await page.waitForSelector(page1Selector, {
|
|
|
|
visible: true,
|
|
|
|
timeout: 0,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Make sure that nothing has be added.
|
|
|
|
await waitForStorageEntries(page, 0);
|
|
|
|
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbUndo(page);
|
2023-09-29 23:19:02 +09:00
|
|
|
await waitForSerialized(page, 1);
|
|
|
|
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-09-08 01:02:55 +09:00
|
|
|
describe("FreeText accessibility", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("bug1823296.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that the parent structTree id is correct", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-09-08 01:02:55 +09:00
|
|
|
|
|
|
|
const parentId = "p3R_mc8";
|
|
|
|
const rect = await page.evaluate(id => {
|
|
|
|
const parent = document.getElementById(id);
|
|
|
|
let span = null;
|
|
|
|
for (const child of parent.childNodes) {
|
|
|
|
if (child.innerText === "000.[5]") {
|
|
|
|
span = child;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const { x, y, width, height } = span.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
}, parentId);
|
|
|
|
await page.mouse.click(
|
|
|
|
rect.x + rect.width + 5,
|
|
|
|
rect.y + rect.height / 2
|
|
|
|
);
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
2023-09-08 01:02:55 +09:00
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, "Hello Wolrd");
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
2023-09-28 05:35:57 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-09-08 01:02:55 +09:00
|
|
|
|
|
|
|
await waitForStorageEntries(page, 1);
|
|
|
|
|
|
|
|
const id = await getFirstSerialized(page, x => x.structTreeParentId);
|
|
|
|
expect(id).withContext(`In ${browserName}`).toEqual(parentId);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-09-24 06:53:19 +09:00
|
|
|
|
|
|
|
describe("Bug 1854818: mouse events in a selected FreeText editor", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check the text can be selected with the mouse", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
2023-09-28 05:35:57 +09:00
|
|
|
await switchToFreeText(page);
|
2023-09-24 06:53:19 +09:00
|
|
|
|
|
|
|
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 data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
const internalEditorSelector = `${getEditorSelector(0)} .internal`;
|
|
|
|
await page.type(internalEditorSelector, data);
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
2023-11-30 17:40:57 +09:00
|
|
|
await page.click(getEditorSelector(0), { count: 2 });
|
2023-09-24 06:53:19 +09:00
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay:not(.enabled)`
|
|
|
|
);
|
|
|
|
await page.click(internalEditorSelector, {
|
2023-11-30 17:40:57 +09:00
|
|
|
count: 3,
|
2023-09-24 06:53:19 +09:00
|
|
|
});
|
|
|
|
const selection = await page.evaluate(() =>
|
|
|
|
window.getSelection().toString()
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(selection).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-10-06 02:25:36 +09:00
|
|
|
|
|
|
|
describe("Create editor with keyboard", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must create an editor from the toolbar", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await page.focus("#editorFreeText");
|
|
|
|
await page.keyboard.press("Enter");
|
|
|
|
|
|
|
|
let selectorEditor = getEditorSelector(0);
|
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
let xy = await getXY(page, selectorEditor);
|
|
|
|
for (let i = 0; i < 5; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveUp(page);
|
2023-10-06 02:25:36 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
|
|
|
}
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
|
|
|
|
|
|
|
let content = await page.$eval(selectorEditor, el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
|
|
|
|
// Disable editing mode.
|
|
|
|
await page.click("#editorFreeText");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
|
|
|
|
|
|
|
await page.focus("#editorFreeText");
|
|
|
|
await page.keyboard.press(" ");
|
|
|
|
selectorEditor = getEditorSelector(1);
|
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
xy = await getXY(page, selectorEditor);
|
|
|
|
for (let i = 0; i < 5; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveDown(page);
|
2023-10-06 02:25:36 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
|
|
|
}
|
|
|
|
|
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
|
|
|
|
|
|
|
// Unselect.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await waitForUnselectedEditor(page, selectorEditor);
|
|
|
|
|
|
|
|
content = await page.$eval(getEditorSelector(1), el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must create an editor with keyboard", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await page.keyboard.press("Enter");
|
|
|
|
let selectorEditor = getEditorSelector(2);
|
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
let xy = await getXY(page, selectorEditor);
|
|
|
|
for (let i = 0; i < 10; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveLeft(page);
|
2023-10-06 02:25:36 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
|
|
|
}
|
|
|
|
|
|
|
|
const data = "Hello PDF.js World !!";
|
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
|
|
|
|
|
|
|
// Unselect.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await waitForUnselectedEditor(page, selectorEditor);
|
|
|
|
|
|
|
|
let content = await page.$eval(getEditorSelector(2), el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
|
|
|
|
await page.keyboard.press(" ");
|
|
|
|
selectorEditor = getEditorSelector(3);
|
|
|
|
await page.waitForSelector(selectorEditor, {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
xy = await getXY(page, selectorEditor);
|
|
|
|
for (let i = 0; i < 10; i++) {
|
2023-10-27 05:42:41 +09:00
|
|
|
await kbBigMoveRight(page);
|
2023-10-06 02:25:36 +09:00
|
|
|
await waitForPositionChange(page, selectorEditor, xy);
|
|
|
|
xy = await getXY(page, selectorEditor);
|
|
|
|
}
|
|
|
|
|
|
|
|
await page.type(`${selectorEditor} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(`${selectorEditor} .overlay.enabled`);
|
|
|
|
|
|
|
|
// Unselect.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await waitForUnselectedEditor(page, selectorEditor);
|
|
|
|
|
|
|
|
content = await page.$eval(selectorEditor, el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-10-30 01:23:31 +09:00
|
|
|
|
|
|
|
describe("Avoid to steal keyboard events", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check the keyboard event is limited to the input", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
|
|
|
|
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 data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
|
|
|
|
2023-12-06 23:27:31 +09:00
|
|
|
let handle = await createPromise(page, resolve => {
|
|
|
|
document.addEventListener("selectionchange", resolve, {
|
|
|
|
once: true,
|
|
|
|
});
|
|
|
|
});
|
2023-10-30 01:23:31 +09:00
|
|
|
await page.click("#pageNumber");
|
2023-12-06 23:27:31 +09:00
|
|
|
await awaitPromise(handle);
|
2023-10-30 01:23:31 +09:00
|
|
|
|
2023-12-06 23:27:31 +09:00
|
|
|
handle = await createPromise(page, resolve => {
|
|
|
|
document
|
|
|
|
.getElementById("pageNumber")
|
|
|
|
.addEventListener("keyup", resolve, { once: true });
|
|
|
|
});
|
2023-10-30 01:23:31 +09:00
|
|
|
await page.keyboard.press("Backspace");
|
2023-12-06 23:27:31 +09:00
|
|
|
await awaitPromise(handle);
|
2023-10-30 01:23:31 +09:00
|
|
|
|
|
|
|
let content = await page.$eval("#pageNumber", el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual("");
|
|
|
|
|
|
|
|
content = await page.$eval(getEditorSelector(0), el =>
|
|
|
|
el.innerText.trimEnd()
|
|
|
|
);
|
|
|
|
expect(content).withContext(`In ${browserName}`).toEqual(data);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-11-09 02:13:15 +09:00
|
|
|
|
|
|
|
describe("Delete a freetext in using the delete button", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that a freetext is deleted", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
|
|
|
|
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 data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
|
|
|
|
|
|
|
// Delete it in using the button.
|
|
|
|
await page.click(`${getEditorSelector(0)} button.delete`);
|
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(0)
|
|
|
|
);
|
|
|
|
await waitForStorageEntries(page, 0);
|
|
|
|
|
|
|
|
// Undo.
|
|
|
|
await kbUndo(page);
|
|
|
|
await waitForSerialized(page, 1);
|
|
|
|
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("Delete two freetexts in using the delete button and the keyboard", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that freetexts are deleted", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
|
|
|
|
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 data = "Hello PDF.js World !!";
|
|
|
|
|
|
|
|
for (let i = 1; i <= 2; i++) {
|
|
|
|
const editorSelector = getEditorSelector(i - 1);
|
|
|
|
await page.mouse.click(rect.x + i * 100, rect.y + i * 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`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select the editor created previously.
|
|
|
|
const editorRect = await page.$eval(getEditorSelector(0), el => {
|
|
|
|
const { x, y, width, height } = el.getBoundingClientRect();
|
|
|
|
return { x, y, width, height };
|
|
|
|
});
|
|
|
|
await page.mouse.click(
|
|
|
|
editorRect.x + editorRect.width / 2,
|
|
|
|
editorRect.y + editorRect.height / 2
|
|
|
|
);
|
|
|
|
await waitForSelectedEditor(page, getEditorSelector(0));
|
|
|
|
|
|
|
|
await selectAll(page);
|
|
|
|
|
|
|
|
// Delete it in using the button.
|
|
|
|
await page.focus(`${getEditorSelector(0)} button.delete`);
|
|
|
|
await page.keyboard.press("Enter");
|
|
|
|
await page.waitForFunction(
|
|
|
|
sel => !document.querySelector(sel),
|
|
|
|
{},
|
|
|
|
getEditorSelector(0)
|
|
|
|
);
|
|
|
|
await waitForStorageEntries(page, 0);
|
|
|
|
|
|
|
|
// Undo.
|
|
|
|
await kbUndo(page);
|
|
|
|
await waitForSerialized(page, 2);
|
|
|
|
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
await page.waitForSelector(getEditorSelector(1), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2023-12-22 06:57:58 +09:00
|
|
|
|
|
|
|
describe("Consecutive white spaces in Freetext without appearance", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("bug1871353.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that consecutive white spaces are preserved when a freetext is edited", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
await page.click(getEditorSelector(0), { count: 2 });
|
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, "C");
|
|
|
|
|
|
|
|
await page.click("#editorFreeText");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
|
|
|
|
|
|
|
const [value] = await getSerialized(page, x => x.value);
|
|
|
|
expect(value)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual("CA B");
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("Consecutive white spaces in Freetext with appearance", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("bug1871353.1.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that consecutive white spaces are preserved when a freetext is edited", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
await page.click(getEditorSelector(0), { count: 2 });
|
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, "Z");
|
|
|
|
|
|
|
|
await page.click("#editorFreeText");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`.annotationEditorLayer:not(.freetextEditing)`
|
|
|
|
);
|
|
|
|
|
|
|
|
const [value] = await getSerialized(page, x => x.value);
|
|
|
|
expect(value)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual("ZX Y");
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2024-01-15 03:06:06 +09:00
|
|
|
|
|
|
|
describe("Freetext with several lines", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that all lines are correctly exported", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
|
|
|
|
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 data = "Hello\nPDF.js\nWorld\n!!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
|
|
|
|
|
|
|
await waitForSerialized(page, 1);
|
|
|
|
const serialized = (await getSerialized(page))[0];
|
|
|
|
expect(serialized.value)
|
|
|
|
.withContext(`In ${browserName}`)
|
|
|
|
.toEqual(data);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2024-01-23 08:00:07 +09:00
|
|
|
|
|
|
|
describe("Freetext UI when undoing/redoing", () => {
|
|
|
|
let pages;
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
await closePages(pages);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("must check that the parameters are updated when undoing/redoing", async () => {
|
|
|
|
await Promise.all(
|
|
|
|
pages.map(async ([browserName, page]) => {
|
|
|
|
await switchToFreeText(page);
|
|
|
|
|
|
|
|
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 data = "Hello PDF.js World !!";
|
|
|
|
await page.mouse.click(rect.x + 100, rect.y + 100);
|
|
|
|
await page.waitForSelector(getEditorSelector(0), {
|
|
|
|
visible: true,
|
|
|
|
});
|
|
|
|
await page.type(`${getEditorSelector(0)} .internal`, data);
|
|
|
|
|
|
|
|
// Commit.
|
|
|
|
await page.keyboard.press("Escape");
|
|
|
|
await page.waitForSelector(
|
|
|
|
`${getEditorSelector(0)} .overlay.enabled`
|
|
|
|
);
|
|
|
|
|
|
|
|
await page.evaluate(() => {
|
|
|
|
window.PDFViewerApplication.eventBus.dispatch(
|
|
|
|
"switchannotationeditorparams",
|
|
|
|
{
|
|
|
|
source: null,
|
|
|
|
type: window.pdfjsLib.AnnotationEditorParamsType.FREETEXT_COLOR,
|
|
|
|
value: "#FF0000",
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
await page.waitForFunction(
|
|
|
|
() =>
|
|
|
|
getComputedStyle(
|
|
|
|
document.querySelector(".selectedEditor .internal")
|
|
|
|
).color === "rgb(255, 0, 0)"
|
|
|
|
);
|
|
|
|
await kbUndo(page);
|
|
|
|
await page.waitForFunction(
|
|
|
|
() =>
|
|
|
|
getComputedStyle(
|
|
|
|
document.querySelector(".selectedEditor .internal")
|
|
|
|
).color === "rgb(0, 0, 0)"
|
|
|
|
);
|
|
|
|
await page.waitForFunction(
|
|
|
|
() =>
|
|
|
|
document.getElementById("editorFreeTextColor").value === "#000000"
|
|
|
|
);
|
|
|
|
await kbRedo(page);
|
|
|
|
await page.waitForFunction(
|
|
|
|
() =>
|
|
|
|
getComputedStyle(
|
|
|
|
document.querySelector(".selectedEditor .internal")
|
|
|
|
).color === "rgb(255, 0, 0)"
|
|
|
|
);
|
|
|
|
await page.waitForFunction(
|
|
|
|
() =>
|
|
|
|
document.getElementById("editorFreeTextColor").value === "#ff0000"
|
|
|
|
);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2022-06-01 17:38:08 +09:00
|
|
|
});
|