[Editor] Change mode when double clicking on an editor
It was only possible to double click on a FreeText editor while being in ink mode (or any other).
This commit is contained in:
parent
a8e05d82e2
commit
47e69e93a3
@ -148,10 +148,10 @@ class AnnotationEditorLayer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the toolbar if it's required to reflect the tool currently used.
|
* Update the toolbar if it's required to reflect the tool currently used.
|
||||||
* @param {number} mode
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
updateToolbar(mode) {
|
updateToolbar(options) {
|
||||||
this.#uiManager.updateToolbar(mode);
|
this.#uiManager.updateToolbar(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -618,12 +618,12 @@ class AnnotationEditorLayer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Paste some content into a new editor.
|
* Paste some content into a new editor.
|
||||||
* @param {number} mode
|
* @param {Object} options
|
||||||
* @param {Object} params
|
* @param {Object} params
|
||||||
*/
|
*/
|
||||||
async pasteEditor(mode, params) {
|
async pasteEditor(options, params) {
|
||||||
this.#uiManager.updateToolbar(mode);
|
this.updateToolbar(options);
|
||||||
await this.#uiManager.updateMode(mode);
|
await this.#uiManager.updateMode(options.mode);
|
||||||
|
|
||||||
const { offsetX, offsetY } = this.#getCenterPoint();
|
const { offsetX, offsetY } = this.#getCenterPoint();
|
||||||
const id = this.getNextId();
|
const id = this.getNextId();
|
||||||
|
|||||||
@ -90,6 +90,8 @@ class AnnotationEditor {
|
|||||||
|
|
||||||
#touchManager = null;
|
#touchManager = null;
|
||||||
|
|
||||||
|
isSelected = false;
|
||||||
|
|
||||||
_isCopy = false;
|
_isCopy = false;
|
||||||
|
|
||||||
_editToolbar = null;
|
_editToolbar = null;
|
||||||
@ -1170,7 +1172,7 @@ class AnnotationEditor {
|
|||||||
const [tx, ty] = this.getInitialTranslation();
|
const [tx, ty] = this.getInitialTranslation();
|
||||||
this.translate(tx, ty);
|
this.translate(tx, ty);
|
||||||
|
|
||||||
bindEvents(this, div, ["keydown", "pointerdown"]);
|
bindEvents(this, div, ["keydown", "pointerdown", "dblclick"]);
|
||||||
|
|
||||||
if (this.isResizable && this._uiManager._supportsPinchToZoom) {
|
if (this.isResizable && this._uiManager._supportsPinchToZoom) {
|
||||||
this.#touchManager ||= new TouchManager({
|
this.#touchManager ||= new TouchManager({
|
||||||
@ -1279,10 +1281,6 @@ class AnnotationEditor {
|
|||||||
this.#selectOnPointerEvent(event);
|
this.#selectOnPointerEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSelected() {
|
|
||||||
return this._uiManager.isSelected(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#selectOnPointerEvent(event) {
|
#selectOnPointerEvent(event) {
|
||||||
const { isMac } = FeatureTest.platform;
|
const { isMac } = FeatureTest.platform;
|
||||||
if (
|
if (
|
||||||
@ -1499,16 +1497,30 @@ class AnnotationEditor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable edit mode.
|
* Enable edit mode.
|
||||||
|
* @returns {boolean} - true if the edit mode has been enabled.
|
||||||
*/
|
*/
|
||||||
enableEditMode() {
|
enableEditMode() {
|
||||||
|
if (this.isInEditMode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parent.setEditingState(false);
|
||||||
this.#isInEditMode = true;
|
this.#isInEditMode = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable edit mode.
|
* Disable edit mode.
|
||||||
|
* @returns {boolean} - true if the edit mode has been disabled.
|
||||||
*/
|
*/
|
||||||
disableEditMode() {
|
disableEditMode() {
|
||||||
|
if (!this.isInEditMode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.parent.setEditingState(true);
|
||||||
this.#isInEditMode = false;
|
this.#isInEditMode = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1832,6 +1844,10 @@ class AnnotationEditor {
|
|||||||
* Select this editor.
|
* Select this editor.
|
||||||
*/
|
*/
|
||||||
select() {
|
select() {
|
||||||
|
if (this.isSelected && this._editToolbar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.isSelected = true;
|
||||||
this.makeResizable();
|
this.makeResizable();
|
||||||
this.div?.classList.add("selectedEditor");
|
this.div?.classList.add("selectedEditor");
|
||||||
if (!this._editToolbar) {
|
if (!this._editToolbar) {
|
||||||
@ -1853,6 +1869,10 @@ class AnnotationEditor {
|
|||||||
* Unselect this editor.
|
* Unselect this editor.
|
||||||
*/
|
*/
|
||||||
unselect() {
|
unselect() {
|
||||||
|
if (!this.isSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.isSelected = false;
|
||||||
this.#resizersDiv?.classList.add("hidden");
|
this.#resizersDiv?.classList.add("hidden");
|
||||||
this.div?.classList.remove("selectedEditor");
|
this.div?.classList.remove("selectedEditor");
|
||||||
if (this.div?.contains(document.activeElement)) {
|
if (this.div?.contains(document.activeElement)) {
|
||||||
@ -1885,10 +1905,38 @@ class AnnotationEditor {
|
|||||||
*/
|
*/
|
||||||
enableEditing() {}
|
enableEditing() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the content of this editor can be changed.
|
||||||
|
* For example, a FreeText editor can be changed (the user can change the
|
||||||
|
* text), but a Stamp editor cannot.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
get canChangeContent() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The editor is about to be edited.
|
* The editor is about to be edited.
|
||||||
*/
|
*/
|
||||||
enterInEditMode() {}
|
enterInEditMode() {
|
||||||
|
if (!this.canChangeContent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.enableEditMode();
|
||||||
|
this.div.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ondblclick callback.
|
||||||
|
* @param {MouseEvent} event
|
||||||
|
*/
|
||||||
|
dblclick(event) {
|
||||||
|
this.enterInEditMode();
|
||||||
|
this.parent.updateToolbar({
|
||||||
|
mode: this.constructor._editorType,
|
||||||
|
editId: this.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {HTMLElement | null} the element requiring an alt text.
|
* @returns {HTMLElement | null} the element requiring an alt text.
|
||||||
|
|||||||
@ -24,11 +24,7 @@ import {
|
|||||||
shadow,
|
shadow,
|
||||||
Util,
|
Util,
|
||||||
} from "../../shared/util.js";
|
} from "../../shared/util.js";
|
||||||
import {
|
import { AnnotationEditorUIManager, KeyboardManager } from "./tools.js";
|
||||||
AnnotationEditorUIManager,
|
|
||||||
bindEvents,
|
|
||||||
KeyboardManager,
|
|
||||||
} from "./tools.js";
|
|
||||||
import { AnnotationEditor } from "./editor.js";
|
import { AnnotationEditor } from "./editor.js";
|
||||||
import { FreeTextAnnotationElement } from "../annotation_layer.js";
|
import { FreeTextAnnotationElement } from "../annotation_layer.js";
|
||||||
|
|
||||||
@ -284,13 +280,10 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
enableEditMode() {
|
enableEditMode() {
|
||||||
if (this.isInEditMode()) {
|
if (!super.enableEditMode()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent.setEditingState(false);
|
|
||||||
this.parent.updateToolbar(AnnotationEditorType.FREETEXT);
|
|
||||||
super.enableEditMode();
|
|
||||||
this.overlayDiv.classList.remove("enabled");
|
this.overlayDiv.classList.remove("enabled");
|
||||||
this.editorDiv.contentEditable = true;
|
this.editorDiv.contentEditable = true;
|
||||||
this._isDraggable = false;
|
this._isDraggable = false;
|
||||||
@ -322,16 +315,16 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
this.editorDiv.addEventListener("paste", this.editorDivPaste.bind(this), {
|
this.editorDiv.addEventListener("paste", this.editorDivPaste.bind(this), {
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
disableEditMode() {
|
disableEditMode() {
|
||||||
if (!this.isInEditMode()) {
|
if (!super.disableEditMode()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent.setEditingState(true);
|
|
||||||
super.disableEditMode();
|
|
||||||
this.overlayDiv.classList.add("enabled");
|
this.overlayDiv.classList.add("enabled");
|
||||||
this.editorDiv.contentEditable = false;
|
this.editorDiv.contentEditable = false;
|
||||||
this.div.setAttribute("aria-activedescendant", this.#editorDivId);
|
this.div.setAttribute("aria-activedescendant", this.#editorDivId);
|
||||||
@ -349,6 +342,8 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
// In case the blur callback hasn't been called.
|
// In case the blur callback hasn't been called.
|
||||||
this.isEditing = false;
|
this.isEditing = false;
|
||||||
this.parent.div.classList.add("freetextEditing");
|
this.parent.div.classList.add("freetextEditing");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
@ -498,18 +493,7 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
this.editorDiv.focus();
|
this.editorDiv.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @inheritdoc */
|
||||||
* ondblclick callback.
|
|
||||||
* @param {MouseEvent} event
|
|
||||||
*/
|
|
||||||
dblclick(event) {
|
|
||||||
this.enterInEditMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* onkeydown callback.
|
|
||||||
* @param {KeyboardEvent} event
|
|
||||||
*/
|
|
||||||
keydown(event) {
|
keydown(event) {
|
||||||
if (event.target === this.div && event.key === "Enter") {
|
if (event.target === this.div && event.key === "Enter") {
|
||||||
this.enterInEditMode();
|
this.enterInEditMode();
|
||||||
@ -546,6 +530,11 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
this.editorDiv.setAttribute("aria-multiline", true);
|
this.editorDiv.setAttribute("aria-multiline", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
get canChangeContent() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
render() {
|
render() {
|
||||||
if (this.div) {
|
if (this.div) {
|
||||||
@ -579,8 +568,6 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
this.overlayDiv.classList.add("overlay", "enabled");
|
this.overlayDiv.classList.add("overlay", "enabled");
|
||||||
this.div.append(this.overlayDiv);
|
this.div.append(this.overlayDiv);
|
||||||
|
|
||||||
bindEvents(this, this.div, ["dblclick", "keydown"]);
|
|
||||||
|
|
||||||
if (this._isCopy || this.annotationElementId) {
|
if (this._isCopy || this.annotationElementId) {
|
||||||
// This editor was created in using copy (ctrl+c).
|
// This editor was created in using copy (ctrl+c).
|
||||||
const [parentWidth, parentHeight] = this.parentDimensions;
|
const [parentWidth, parentHeight] = this.parentDimensions;
|
||||||
|
|||||||
@ -71,9 +71,10 @@ class StampEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
static paste(item, parent) {
|
static paste(item, parent) {
|
||||||
parent.pasteEditor(AnnotationEditorType.STAMP, {
|
parent.pasteEditor(
|
||||||
bitmapFile: item.getAsFile(),
|
{ mode: AnnotationEditorType.STAMP },
|
||||||
});
|
{ bitmapFile: item.getAsFile() }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
|
|||||||
@ -1711,7 +1711,7 @@ class AnnotationEditorUIManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const editor of this.#allEditors.values()) {
|
for (const editor of this.#allEditors.values()) {
|
||||||
if (editor.annotationElementId === editId) {
|
if (editor.annotationElementId === editId || editor.id === editId) {
|
||||||
this.setSelected(editor);
|
this.setSelected(editor);
|
||||||
editor.enterInEditMode();
|
editor.enterInEditMode();
|
||||||
} else {
|
} else {
|
||||||
@ -1730,16 +1730,17 @@ class AnnotationEditorUIManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the toolbar if it's required to reflect the tool currently used.
|
* Update the toolbar if it's required to reflect the tool currently used.
|
||||||
|
* @param {Object} options
|
||||||
* @param {number} mode
|
* @param {number} mode
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
updateToolbar(mode) {
|
updateToolbar(options) {
|
||||||
if (mode === this.#mode) {
|
if (options.mode === this.#mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._eventBus.dispatch("switchannotationeditormode", {
|
this._eventBus.dispatch("switchannotationeditormode", {
|
||||||
source: this,
|
source: this,
|
||||||
mode,
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1229,3 +1229,65 @@ describe("The pen-drawn shape must maintain correct curvature regardless of the
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Should switch from an editor and mode to others by double clicking", () => {
|
||||||
|
let pages;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
pages = await loadAndWait("empty.pdf", ".annotationEditorLayer");
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await closePages(pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must check that the editor an the mode are correct", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
await switchToInk(page);
|
||||||
|
|
||||||
|
const editorLayerRect = await getRect(page, ".annotationEditorLayer");
|
||||||
|
const drawStartX = editorLayerRect.x + 100;
|
||||||
|
const drawStartY = editorLayerRect.y + 100;
|
||||||
|
|
||||||
|
const inkSelector = getEditorSelector(0);
|
||||||
|
const clickHandle = await waitForPointerUp(page);
|
||||||
|
await page.mouse.move(drawStartX, drawStartY);
|
||||||
|
await page.mouse.down();
|
||||||
|
await page.mouse.move(drawStartX + 50, drawStartY + 50);
|
||||||
|
await page.mouse.up();
|
||||||
|
await awaitPromise(clickHandle);
|
||||||
|
await commit(page);
|
||||||
|
|
||||||
|
await switchToEditor("FreeText", page);
|
||||||
|
|
||||||
|
const freeTextSelector = getEditorSelector(1);
|
||||||
|
const data = "Hello PDF.js World !!";
|
||||||
|
await page.mouse.click(
|
||||||
|
editorLayerRect.x + 200,
|
||||||
|
editorLayerRect.y + 200
|
||||||
|
);
|
||||||
|
await page.waitForSelector(freeTextSelector, { visible: true });
|
||||||
|
await page.type(`${freeTextSelector} .internal`, data);
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
await page.waitForSelector(
|
||||||
|
".freeTextEditor.selectedEditor .overlay.enabled"
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.waitForSelector("#editorInkButton:not(.toggled)");
|
||||||
|
let modeChangedHandle = await waitForAnnotationModeChanged(page);
|
||||||
|
await selectEditor(page, inkSelector, 2);
|
||||||
|
await awaitPromise(modeChangedHandle);
|
||||||
|
await page.waitForSelector("#editorInkButton.toggled");
|
||||||
|
await waitForSelectedEditor(page, inkSelector);
|
||||||
|
|
||||||
|
await page.waitForSelector("#editorFreeTextButton:not(.toggled)");
|
||||||
|
modeChangedHandle = await waitForAnnotationModeChanged(page);
|
||||||
|
await selectEditor(page, freeTextSelector, 2);
|
||||||
|
await awaitPromise(modeChangedHandle);
|
||||||
|
await page.waitForSelector("#editorFreeTextButton.toggled");
|
||||||
|
await waitForSelectedEditor(page, freeTextSelector);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -147,6 +147,11 @@
|
|||||||
|
|
||||||
.annotationEditorLayer.disabled {
|
.annotationEditorLayer.disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.highlightEditing
|
||||||
|
:is(.freeTextEditor, .inkEditor, .stampEditor, .signatureEditor) {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotationEditorLayer.freetextEditing {
|
.annotationEditorLayer.freetextEditing {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user