[Editor] Support resizing editors with the keyboard (bug 1854340)
This commit is contained in:
parent
426209c6e6
commit
05ca3fd99b
@ -280,3 +280,21 @@ editor_alt_text_save_button=Save
|
||||
editor_alt_text_decorative_tooltip=Marked as decorative
|
||||
# This is a placeholder for the alt text input area
|
||||
editor_alt_text_textarea.placeholder=For example, “A young man sits down at a table to eat a meal”
|
||||
|
||||
# Editor resizers
|
||||
# LOCALIZATION NOTE (editor_resizer_label_topLeft): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_topLeft=Top left corner — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_topMiddle): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_topMiddle=Top middle — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_topRight): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_topRight=Top right corner — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_middleRight): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_middleRight=Middle right — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_bottomRight): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_bottomRight=Bottom right corner — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_bottomMiddle): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_bottomMiddle=Bottom middle — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_bottomLeft): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_bottomLeft=Bottom left corner — resize
|
||||
# LOCALIZATION NOTE (editor_resizer_label_middleLeft): This is used in an aria label to help to understand the role of the resizer.
|
||||
editor_resizer_label_middleLeft=Middle left — resize
|
||||
|
@ -15,10 +15,13 @@
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
|
||||
// eslint-disable-next-line max-len
|
||||
/** @typedef {import("./tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
|
||||
|
||||
import { bindEvents, ColorManager } from "./tools.js";
|
||||
import {
|
||||
AnnotationEditorUIManager,
|
||||
bindEvents,
|
||||
ColorManager,
|
||||
KeyboardManager,
|
||||
} from "./tools.js";
|
||||
import { FeatureTest, shadow, unreachable } from "../../shared/util.js";
|
||||
import { noContextMenu } from "../display_utils.js";
|
||||
|
||||
@ -35,6 +38,8 @@ import { noContextMenu } from "../display_utils.js";
|
||||
* Base class for editors.
|
||||
*/
|
||||
class AnnotationEditor {
|
||||
#allResizerDivs = null;
|
||||
|
||||
#altText = "";
|
||||
|
||||
#altTextDecorative = false;
|
||||
@ -51,16 +56,22 @@ class AnnotationEditor {
|
||||
|
||||
#resizersDiv = null;
|
||||
|
||||
#savedDimensions = null;
|
||||
|
||||
#boundFocusin = this.focusin.bind(this);
|
||||
|
||||
#boundFocusout = this.focusout.bind(this);
|
||||
|
||||
#focusedResizerName = "";
|
||||
|
||||
#hasBeenClicked = false;
|
||||
|
||||
#isEditing = false;
|
||||
|
||||
#isInEditMode = false;
|
||||
|
||||
#isResizerEnabledForKeyboard = false;
|
||||
|
||||
#moveInDOMTimeout = null;
|
||||
|
||||
_initialOptions = Object.create(null);
|
||||
@ -85,6 +96,39 @@ class AnnotationEditor {
|
||||
// button to edit the alt text is visually moved outside of the editor.
|
||||
static SMALL_EDITOR_SIZE = 0;
|
||||
|
||||
static get _resizerKeyboardManager() {
|
||||
const resize = AnnotationEditor.prototype._resizeWithKeyboard;
|
||||
const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
|
||||
const big = AnnotationEditorUIManager.TRANSLATE_BIG;
|
||||
|
||||
return shadow(
|
||||
this,
|
||||
"_resizerKeyboardManager",
|
||||
new KeyboardManager([
|
||||
[["ArrowLeft", "mac+ArrowLeft"], resize, { args: [-small, 0] }],
|
||||
[
|
||||
["ctrl+ArrowLeft", "mac+shift+ArrowLeft"],
|
||||
resize,
|
||||
{ args: [-big, 0] },
|
||||
],
|
||||
[["ArrowRight", "mac+ArrowRight"], resize, { args: [small, 0] }],
|
||||
[
|
||||
["ctrl+ArrowRight", "mac+shift+ArrowRight"],
|
||||
resize,
|
||||
{ args: [big, 0] },
|
||||
],
|
||||
[["ArrowUp", "mac+ArrowUp"], resize, { args: [0, -small] }],
|
||||
[["ctrl+ArrowUp", "mac+shift+ArrowUp"], resize, { args: [0, -big] }],
|
||||
[["ArrowDown", "mac+ArrowDown"], resize, { args: [0, small] }],
|
||||
[["ctrl+ArrowDown", "mac+shift+ArrowDown"], resize, { args: [0, big] }],
|
||||
[
|
||||
["Escape", "mac+Escape"],
|
||||
AnnotationEditor.prototype._stopResizingWithKeyboard,
|
||||
],
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AnnotationEditorParameters} parameters
|
||||
*/
|
||||
@ -157,6 +201,14 @@ class AnnotationEditor {
|
||||
"editor_alt_text_button_label",
|
||||
"editor_alt_text_edit_button_label",
|
||||
"editor_alt_text_decorative_tooltip",
|
||||
"editor_resizer_label_topLeft",
|
||||
"editor_resizer_label_topMiddle",
|
||||
"editor_resizer_label_topRight",
|
||||
"editor_resizer_label_middleRight",
|
||||
"editor_resizer_label_bottomRight",
|
||||
"editor_resizer_label_bottomMiddle",
|
||||
"editor_resizer_label_bottomLeft",
|
||||
"editor_resizer_label_middleLeft",
|
||||
].map(str => [str, l10n.get(str)])
|
||||
);
|
||||
if (options?.strings) {
|
||||
@ -277,6 +329,9 @@ class AnnotationEditor {
|
||||
if (parent !== null) {
|
||||
this.pageIndex = parent.pageIndex;
|
||||
this.pageDimensions = parent.pageDimensions;
|
||||
} else {
|
||||
// The editor is being removed from the DOM, so we need to stop resizing.
|
||||
this.#stopResizing();
|
||||
}
|
||||
this.parent = parent;
|
||||
}
|
||||
@ -600,19 +655,32 @@ class AnnotationEditor {
|
||||
}
|
||||
this.#resizersDiv = document.createElement("div");
|
||||
this.#resizersDiv.classList.add("resizers");
|
||||
const classes = ["topLeft", "topRight", "bottomRight", "bottomLeft"];
|
||||
if (!this._willKeepAspectRatio) {
|
||||
classes.push("topMiddle", "middleRight", "bottomMiddle", "middleLeft");
|
||||
}
|
||||
// When the resizers are used with the keyboard, they're focusable, hence
|
||||
// we want to have them in this order (top left, top middle, top right, ...)
|
||||
// in the DOM to have the focus order correct.
|
||||
const classes = this._willKeepAspectRatio
|
||||
? ["topLeft", "topRight", "bottomRight", "bottomLeft"]
|
||||
: [
|
||||
"topLeft",
|
||||
"topMiddle",
|
||||
"topRight",
|
||||
"middleRight",
|
||||
"bottomRight",
|
||||
"bottomMiddle",
|
||||
"bottomLeft",
|
||||
"middleLeft",
|
||||
];
|
||||
for (const name of classes) {
|
||||
const div = document.createElement("div");
|
||||
this.#resizersDiv.append(div);
|
||||
div.classList.add("resizer", name);
|
||||
div.setAttribute("data-resizer-name", name);
|
||||
div.addEventListener(
|
||||
"pointerdown",
|
||||
this.#resizerPointerdown.bind(this, name)
|
||||
);
|
||||
div.addEventListener("contextmenu", noContextMenu);
|
||||
div.tabIndex = -1;
|
||||
}
|
||||
this.div.prepend(this.#resizersDiv);
|
||||
}
|
||||
@ -659,6 +727,15 @@ class AnnotationEditor {
|
||||
this.parent.div.style.cursor = savedParentCursor;
|
||||
this.div.style.cursor = savedCursor;
|
||||
|
||||
this.#addResizeToUndoStack(savedX, savedY, savedWidth, savedHeight);
|
||||
};
|
||||
window.addEventListener("pointerup", pointerUpCallback);
|
||||
// If the user switches to another window (with alt+tab), then we end the
|
||||
// resize session.
|
||||
window.addEventListener("blur", pointerUpCallback);
|
||||
}
|
||||
|
||||
#addResizeToUndoStack(savedX, savedY, savedWidth, savedHeight) {
|
||||
const newX = this.x;
|
||||
const newY = this.y;
|
||||
const newWidth = this.width;
|
||||
@ -693,11 +770,6 @@ class AnnotationEditor {
|
||||
},
|
||||
mustExec: true,
|
||||
});
|
||||
};
|
||||
window.addEventListener("pointerup", pointerUpCallback);
|
||||
// If the user switches to another window (with alt+tab), then we end the
|
||||
// resize session.
|
||||
window.addEventListener("blur", pointerUpCallback);
|
||||
}
|
||||
|
||||
#resizerPointermove(name, event) {
|
||||
@ -1205,12 +1277,12 @@ class AnnotationEditor {
|
||||
}
|
||||
|
||||
/**
|
||||
* If it returns true, then this editor handle the keyboard
|
||||
* If it returns true, then this editor handles the keyboard
|
||||
* events itself.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
shouldGetKeyboardEvents() {
|
||||
return false;
|
||||
return this.#isResizerEnabledForKeyboard;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1303,6 +1375,7 @@ class AnnotationEditor {
|
||||
clearTimeout(this.#moveInDOMTimeout);
|
||||
this.#moveInDOMTimeout = null;
|
||||
}
|
||||
this.#stopResizing();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1319,9 +1392,140 @@ class AnnotationEditor {
|
||||
if (this.isResizable) {
|
||||
this.#createResizers();
|
||||
this.#resizersDiv.classList.remove("hidden");
|
||||
bindEvents(this, this.div, ["keydown"]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* onkeydown callback.
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
keydown(event) {
|
||||
if (
|
||||
!this.isResizable ||
|
||||
event.target !== this.div ||
|
||||
event.key !== "Enter"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this._uiManager.setSelected(this);
|
||||
this.#savedDimensions = {
|
||||
savedX: this.x,
|
||||
savedY: this.y,
|
||||
savedWidth: this.width,
|
||||
savedHeight: this.height,
|
||||
};
|
||||
const children = this.#resizersDiv.children;
|
||||
if (!this.#allResizerDivs) {
|
||||
this.#allResizerDivs = Array.from(children);
|
||||
const boundResizerKeydown = this.#resizerKeydown.bind(this);
|
||||
const boundResizerBlur = this.#resizerBlur.bind(this);
|
||||
for (const div of this.#allResizerDivs) {
|
||||
const name = div.getAttribute("data-resizer-name");
|
||||
div.addEventListener("keydown", boundResizerKeydown);
|
||||
div.addEventListener("blur", boundResizerBlur);
|
||||
div.addEventListener("focus", this.#resizerFocus.bind(this, name));
|
||||
AnnotationEditor._l10nPromise
|
||||
.get(`editor_resizer_label_${name}`)
|
||||
.then(msg => div.setAttribute("aria-label", msg));
|
||||
}
|
||||
}
|
||||
|
||||
// We want to have the resizers in the visual order, so we move the first
|
||||
// (top-left) to the right place.
|
||||
const first = this.#allResizerDivs[0];
|
||||
let firstPosition = 0;
|
||||
for (const div of children) {
|
||||
if (div === first) {
|
||||
break;
|
||||
}
|
||||
firstPosition++;
|
||||
}
|
||||
const nextFirstPosition =
|
||||
(((360 - this.rotation + this.parentRotation) % 360) / 90) *
|
||||
(this.#allResizerDivs.length / 4);
|
||||
|
||||
if (nextFirstPosition !== firstPosition) {
|
||||
// We need to reorder the resizers in the DOM in order to have the focus
|
||||
// on the top-left one.
|
||||
if (nextFirstPosition < firstPosition) {
|
||||
for (let i = 0; i < firstPosition - nextFirstPosition; i++) {
|
||||
this.#resizersDiv.append(this.#resizersDiv.firstChild);
|
||||
}
|
||||
} else if (nextFirstPosition > firstPosition) {
|
||||
for (let i = 0; i < nextFirstPosition - firstPosition; i++) {
|
||||
this.#resizersDiv.firstChild.before(this.#resizersDiv.lastChild);
|
||||
}
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
for (const child of children) {
|
||||
const div = this.#allResizerDivs[i++];
|
||||
const name = div.getAttribute("data-resizer-name");
|
||||
AnnotationEditor._l10nPromise
|
||||
.get(`editor_resizer_label_${name}`)
|
||||
.then(msg => child.setAttribute("aria-label", msg));
|
||||
}
|
||||
}
|
||||
|
||||
this.#setResizerTabIndex(0);
|
||||
this.#isResizerEnabledForKeyboard = true;
|
||||
this.#resizersDiv.firstChild.focus({ focusVisible: true });
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
#resizerKeydown(event) {
|
||||
AnnotationEditor._resizerKeyboardManager.exec(this, event);
|
||||
}
|
||||
|
||||
#resizerBlur(event) {
|
||||
if (
|
||||
this.#isResizerEnabledForKeyboard &&
|
||||
event.relatedTarget?.parentNode !== this.#resizersDiv
|
||||
) {
|
||||
this.#stopResizing();
|
||||
}
|
||||
}
|
||||
|
||||
#resizerFocus(name) {
|
||||
this.#focusedResizerName = this.#isResizerEnabledForKeyboard ? name : "";
|
||||
}
|
||||
|
||||
#setResizerTabIndex(value) {
|
||||
if (!this.#allResizerDivs) {
|
||||
return;
|
||||
}
|
||||
for (const div of this.#allResizerDivs) {
|
||||
div.tabIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
_resizeWithKeyboard(x, y) {
|
||||
if (!this.#isResizerEnabledForKeyboard) {
|
||||
return;
|
||||
}
|
||||
this.#resizerPointermove(this.#focusedResizerName, {
|
||||
movementX: x,
|
||||
movementY: y,
|
||||
});
|
||||
}
|
||||
|
||||
#stopResizing() {
|
||||
this.#isResizerEnabledForKeyboard = false;
|
||||
this.#setResizerTabIndex(-1);
|
||||
if (this.#savedDimensions) {
|
||||
const { savedX, savedY, savedWidth, savedHeight } = this.#savedDimensions;
|
||||
this.#addResizeToUndoStack(savedX, savedY, savedWidth, savedHeight);
|
||||
this.#savedDimensions = null;
|
||||
}
|
||||
}
|
||||
|
||||
_stopResizingWithKeyboard() {
|
||||
this.#stopResizing();
|
||||
this.div.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select this editor.
|
||||
*/
|
||||
|
@ -1021,7 +1021,7 @@ class AnnotationEditorUIManager {
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
keydown(event) {
|
||||
if (!this.getActive()?.shouldGetKeyboardEvents()) {
|
||||
if (!this.isEditorHandlingKeyboard) {
|
||||
AnnotationEditorUIManager._keyboardManager.exec(this, event);
|
||||
}
|
||||
}
|
||||
@ -1732,6 +1732,14 @@ class AnnotationEditorUIManager {
|
||||
}
|
||||
}
|
||||
|
||||
get isEditorHandlingKeyboard() {
|
||||
return (
|
||||
this.getActive()?.shouldGetKeyboardEvents() ||
|
||||
(this.#selectedEditors.size === 1 &&
|
||||
this.#selectedEditors.values().next().value.shouldGetKeyboardEvents())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the current editor the one passed as argument?
|
||||
* @param {AnnotationEditor} editor
|
||||
|
@ -17,6 +17,7 @@ const {
|
||||
closePages,
|
||||
getEditorDimensions,
|
||||
getEditorSelector,
|
||||
getFirstSerialized,
|
||||
loadAndWait,
|
||||
serializeBitmapDimensions,
|
||||
waitForAnnotationEditorLayer,
|
||||
@ -59,6 +60,53 @@ const waitForImage = async (page, selector) => {
|
||||
await page.waitForSelector(`${selector} .altText`);
|
||||
};
|
||||
|
||||
const copyImage = async (page, imagePath, number) => {
|
||||
const data = fs
|
||||
.readFileSync(path.join(__dirname, imagePath))
|
||||
.toString("base64");
|
||||
await page.evaluate(async imageData => {
|
||||
const resp = await fetch(`data:image/png;base64,${imageData}`);
|
||||
const blob = await resp.blob();
|
||||
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
[blob.type]: blob,
|
||||
}),
|
||||
]);
|
||||
}, data);
|
||||
|
||||
let hasPasteEvent = false;
|
||||
while (!hasPasteEvent) {
|
||||
// We retry to paste if nothing has been pasted before 500ms.
|
||||
const promise = Promise.race([
|
||||
page.evaluate(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
document.addEventListener(
|
||||
"paste",
|
||||
e => resolve(e.clipboardData.items.length !== 0),
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
);
|
||||
})
|
||||
),
|
||||
page.evaluate(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve(false), 500);
|
||||
})
|
||||
),
|
||||
]);
|
||||
await page.keyboard.down("Control");
|
||||
await page.keyboard.press("v");
|
||||
await page.keyboard.up("Control");
|
||||
hasPasteEvent = await promise;
|
||||
}
|
||||
|
||||
await waitForImage(page, getEditorSelector(number));
|
||||
};
|
||||
|
||||
describe("Stamp Editor", () => {
|
||||
describe("Basic operations", () => {
|
||||
let pages;
|
||||
@ -235,50 +283,7 @@ describe("Stamp Editor", () => {
|
||||
pages.map(async ([browserName, page]) => {
|
||||
await page.click("#editorStamp");
|
||||
|
||||
const data = fs
|
||||
.readFileSync(path.join(__dirname, "../images/firefox_logo.png"))
|
||||
.toString("base64");
|
||||
await page.evaluate(async imageData => {
|
||||
const resp = await fetch(`data:image/png;base64,${imageData}`);
|
||||
const blob = await resp.blob();
|
||||
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
[blob.type]: blob,
|
||||
}),
|
||||
]);
|
||||
}, data);
|
||||
|
||||
let hasPasteEvent = false;
|
||||
while (!hasPasteEvent) {
|
||||
// We retry to paste if nothing has been pasted before 500ms.
|
||||
const promise = Promise.race([
|
||||
page.evaluate(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
document.addEventListener(
|
||||
"paste",
|
||||
e => resolve(e.clipboardData.items.length !== 0),
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
);
|
||||
})
|
||||
),
|
||||
page.evaluate(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve(false), 500);
|
||||
})
|
||||
),
|
||||
]);
|
||||
await page.keyboard.down("Control");
|
||||
await page.keyboard.press("v");
|
||||
await page.keyboard.up("Control");
|
||||
hasPasteEvent = await promise;
|
||||
}
|
||||
|
||||
await waitForImage(page, getEditorSelector(0));
|
||||
await copyImage(page, "../images/firefox_logo.png", 0);
|
||||
|
||||
// Wait for the alt-text button to be visible.
|
||||
const buttonSelector = `${getEditorSelector(0)} button.altText`;
|
||||
@ -432,4 +437,142 @@ describe("Stamp Editor", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Resize an image with the keyboard", () => {
|
||||
let pages;
|
||||
|
||||
beforeAll(async () => {
|
||||
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer", 50);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
it("must check that the dimensions change", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
await page.click("#editorStamp");
|
||||
|
||||
await copyImage(page, "../images/firefox_logo.png", 0);
|
||||
|
||||
const editorSelector = getEditorSelector(0);
|
||||
|
||||
await page.click(editorSelector);
|
||||
await waitForSelectedEditor(page, editorSelector);
|
||||
|
||||
await page.waitForSelector(
|
||||
`${editorSelector} .resizer.topLeft[tabindex="-1"]`
|
||||
);
|
||||
|
||||
const getDims = async () => {
|
||||
const [blX, blY, trX, trY] = await getFirstSerialized(
|
||||
page,
|
||||
x => x.rect
|
||||
);
|
||||
return [trX - blX, trY - blY];
|
||||
};
|
||||
|
||||
const [width, height] = await getDims();
|
||||
|
||||
// Press Enter to enter in resize-with-keyboard mode.
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
// The resizer must become keyboard focusable.
|
||||
await page.waitForSelector(
|
||||
`${editorSelector} .resizer.topLeft[tabindex="0"]`
|
||||
);
|
||||
|
||||
let prevWidth = width;
|
||||
let prevHeight = height;
|
||||
|
||||
const waitForDimsChange = async (w, h) => {
|
||||
await page.waitForFunction(
|
||||
(prevW, prevH) => {
|
||||
const [x1, y1, x2, y2] =
|
||||
window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.map
|
||||
.values()
|
||||
.next().value.rect;
|
||||
const newWidth = x2 - x1;
|
||||
const newHeight = y2 - y1;
|
||||
return newWidth !== prevW || newHeight !== prevH;
|
||||
},
|
||||
{},
|
||||
w,
|
||||
h
|
||||
);
|
||||
};
|
||||
|
||||
for (let i = 0; i < 40; i++) {
|
||||
await page.keyboard.press("ArrowLeft");
|
||||
await waitForDimsChange(prevWidth, prevHeight);
|
||||
[prevWidth, prevHeight] = await getDims();
|
||||
}
|
||||
|
||||
let [newWidth, newHeight] = await getDims();
|
||||
expect(newWidth > width + 30)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
expect(newHeight > height + 30)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
await page.keyboard.down("Control");
|
||||
await page.keyboard.press("ArrowRight");
|
||||
await page.keyboard.up("Control");
|
||||
await waitForDimsChange(prevWidth, prevHeight);
|
||||
[prevWidth, prevHeight] = await getDims();
|
||||
}
|
||||
|
||||
[newWidth, newHeight] = await getDims();
|
||||
expect(Math.abs(newWidth - width) < 2)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
expect(Math.abs(newHeight - height) < 2)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
|
||||
// Move the focus to the next resizer.
|
||||
await page.keyboard.press("Tab");
|
||||
await page.waitForFunction(
|
||||
() => !!document.activeElement?.classList.contains("topMiddle")
|
||||
);
|
||||
|
||||
for (let i = 0; i < 40; i++) {
|
||||
await page.keyboard.press("ArrowUp");
|
||||
await waitForDimsChange(prevWidth, prevHeight);
|
||||
[prevWidth, prevHeight] = await getDims();
|
||||
}
|
||||
|
||||
[, newHeight] = await getDims();
|
||||
expect(newHeight > height + 50)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
await page.keyboard.down("Control");
|
||||
await page.keyboard.press("ArrowDown");
|
||||
await page.keyboard.up("Control");
|
||||
await waitForDimsChange(prevWidth, prevHeight);
|
||||
[prevWidth, prevHeight] = await getDims();
|
||||
}
|
||||
|
||||
[, newHeight] = await getDims();
|
||||
expect(Math.abs(newHeight - height) < 2)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(true);
|
||||
|
||||
// Escape should remove the focus from the resizer.
|
||||
await page.keyboard.press("Escape");
|
||||
await page.waitForSelector(
|
||||
`${editorSelector} .resizer.topLeft[tabindex="-1"]`
|
||||
);
|
||||
await page.waitForFunction(
|
||||
() => !document.activeElement?.classList.contains("resizer")
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -85,6 +85,14 @@ const DEFAULT_L10N_STRINGS = {
|
||||
editor_alt_text_button_label: "Alt text",
|
||||
editor_alt_text_edit_button_label: "Edit alt text",
|
||||
editor_alt_text_decorative_tooltip: "Marked as decorative",
|
||||
editor_resizer_label_topLeft: "Top left corner — resize",
|
||||
editor_resizer_label_topMiddle: "Top middle — resize",
|
||||
editor_resizer_label_topRight: "Top right corner — resize",
|
||||
editor_resizer_label_middleRight: "Middle right — resize",
|
||||
editor_resizer_label_bottomRight: "Bottom right corner — resize",
|
||||
editor_resizer_label_bottomMiddle: "Bottom middle — resize",
|
||||
editor_resizer_label_bottomLeft: "Bottom left corner — resize",
|
||||
editor_resizer_label_middleLeft: "Middle left — resize",
|
||||
};
|
||||
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
|
||||
DEFAULT_L10N_STRINGS.print_progress_percent = "{{progress}}%";
|
||||
|
Loading…
Reference in New Issue
Block a user