1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 14:48:08 +02:00

Merge pull request #16819 from calixteman/editor_stamp_button

[Editor] Add a button to explicitly add an image (bug 1848108)
This commit is contained in:
calixteman 2023-08-11 15:32:47 +02:00 committed by GitHub
commit 4eca3ca199
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 140 additions and 34 deletions

View file

@ -245,8 +245,8 @@ editor_free_text2.title=Text
editor_free_text2_label=Text
editor_ink2.title=Draw
editor_ink2_label=Draw
editor_stamp.title=Add an image
editor_stamp_label=Add an image
editor_stamp1.title=Add or edit images
editor_stamp1_label=Add or edit images
free_text2_default_content=Start typing…
@ -256,6 +256,8 @@ editor_free_text_size=Size
editor_ink_color=Color
editor_ink_thickness=Thickness
editor_ink_opacity=Opacity
editor_stamp_add_image_label=Add image
editor_stamp_add_image.title=Add image
# Editor aria
editor_free_text2_aria_label=Text Editor

View file

@ -166,7 +166,10 @@ class AnnotationEditorLayer {
}
}
const editor = this.#createAndAddNewEditor({ offsetX: 0, offsetY: 0 });
const editor = this.#createAndAddNewEditor(
{ offsetX: 0, offsetY: 0 },
/* isCentered = */ false
);
editor.setInBackground();
}
@ -481,9 +484,10 @@ class AnnotationEditorLayer {
/**
* Create and add a new editor.
* @param {PointerEvent} event
* @param {boolean} isCentered
* @returns {AnnotationEditor}
*/
#createAndAddNewEditor(event) {
#createAndAddNewEditor(event, isCentered) {
const id = this.getNextId();
const editor = this.#createNewEditor({
parent: this,
@ -491,6 +495,7 @@ class AnnotationEditorLayer {
x: event.offsetX,
y: event.offsetY,
uiManager: this.#uiManager,
isCentered,
});
if (editor) {
this.add(editor);
@ -499,6 +504,31 @@ class AnnotationEditorLayer {
return editor;
}
/**
* Create and add a new editor.
*/
addNewEditor() {
const { x, y, width, height } = this.div.getBoundingClientRect();
const tlX = Math.max(0, x);
const tlY = Math.max(0, y);
const brX = Math.min(window.innerWidth, x + width);
const brY = Math.min(window.innerHeight, y + height);
const centerX = (tlX + brX) / 2 - x;
const centerY = (tlY + brY) / 2 - y;
const [offsetX, offsetY] =
this.viewport.rotation % 180 === 0
? [centerX, centerY]
: [centerY, centerX];
this.#createAndAddNewEditor(
{
offsetX,
offsetY,
},
/* isCentered = */ true
);
}
/**
* Set the last selected editor.
* @param {AnnotationEditor} editor
@ -560,7 +590,12 @@ class AnnotationEditorLayer {
return;
}
this.#createAndAddNewEditor(event);
if (this.#uiManager.getMode() === AnnotationEditorType.STAMP) {
this.#uiManager.unselectAll();
return;
}
this.#createAndAddNewEditor(event, /* isCentered = */ false);
}
/**

View file

@ -48,6 +48,8 @@ class AnnotationEditor {
#isInEditMode = false;
_initialOptions = Object.create(null);
_uiManager = null;
_focusEventsAllowed = true;
@ -77,6 +79,7 @@ class AnnotationEditor {
this._uiManager = parameters.uiManager;
this.annotationElementId = null;
this._willKeepAspectRatio = false;
this._initialOptions.isCentered = parameters.isCentered;
const {
rotation,
@ -154,6 +157,29 @@ class AnnotationEditor {
this.div?.classList.toggle("draggable", value);
}
center() {
const [pageWidth, pageHeight] = this.pageDimensions;
switch (this.parentRotation) {
case 90:
this.x -= (this.height * pageHeight) / (pageWidth * 2);
this.y += (this.width * pageWidth) / (pageHeight * 2);
break;
case 180:
this.x += this.width / 2;
this.y += this.height / 2;
break;
case 270:
this.x += (this.height * pageHeight) / (pageWidth * 2);
this.y -= (this.width * pageWidth) / (pageHeight * 2);
break;
default:
this.x -= this.width / 2;
this.y -= this.height / 2;
break;
}
this.fixAndSetPosition();
}
/**
* Add some commands into the CommandManager (undo/redo stuff).
* @param {Object} params

View file

@ -363,6 +363,10 @@ class FreeTextEditor extends AnnotationEditor {
}
this.enableEditMode();
this.editorDiv.focus();
if (this._initialOptions?.isCentered) {
this.center();
}
this._initialOptions = null;
}
/** @inheritdoc */

View file

@ -290,7 +290,12 @@ class StampEditor extends AnnotationEditor {
this.width = width / parentWidth;
this.height = height / parentHeight;
this.setDims(width, height);
this.fixAndSetPosition();
if (this._initialOptions?.isCentered) {
this.center();
} else {
this.fixAndSetPosition();
}
this._initialOptions = null;
if (this.#resizeTimeoutId !== null) {
clearTimeout(this.#resizeTimeoutId);
}

View file

@ -18,6 +18,7 @@
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
import {
AnnotationEditorParamsType,
AnnotationEditorPrefix,
AnnotationEditorType,
FeatureTest,
@ -1144,6 +1145,10 @@ class AnnotationEditorUIManager {
if (!this.#editorTypes) {
return;
}
if (type === AnnotationEditorParamsType.CREATE) {
this.currentLayer.addNewEditor(type);
return;
}
for (const editor of this.#selectedEditors) {
editor.updateParams(type, value);

View file

@ -78,6 +78,7 @@ const AnnotationEditorType = {
const AnnotationEditorParamsType = {
RESIZE: 1,
CREATE: 2,
FREETEXT_SIZE: 11,
FREETEXT_COLOR: 12,
FREETEXT_OPACITY: 13,

View file

@ -15,7 +15,9 @@
const {
closePages,
dragAndDropAnnotation,
getEditorDimensions,
getEditorSelector,
loadAndWait,
serializeBitmapDimensions,
waitForAnnotationEditorLayer,
@ -43,15 +45,8 @@ describe("Stamp Editor", () => {
}
await page.click("#editorStamp");
await page.click("#editorStampAddImage");
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 };
});
await page.mouse.click(rect.x + 100, rect.y + 100);
const input = await page.$("#stampEditorFileInput");
await input.uploadFile(
`${path.join(__dirname, "../images/firefox_logo.png")}`
@ -87,14 +82,7 @@ describe("Stamp Editor", () => {
return;
}
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 };
});
await page.mouse.click(rect.x + 100, rect.y + 100);
await page.click("#editorStampAddImage");
const input = await page.$("#stampEditorFileInput");
await input.uploadFile(
`${path.join(__dirname, "../images/firefox_logo.svg")}`
@ -146,6 +134,7 @@ describe("Stamp Editor", () => {
}
await page.click("#editorStamp");
await page.click("#editorStampAddImage");
const rect = await page.$eval(".annotationEditorLayer", el => {
// With Chrome something is wrong when serializing a DomRect,
@ -154,7 +143,13 @@ describe("Stamp Editor", () => {
return { x: right, y: bottom };
});
await page.mouse.click(rect.x - 10, rect.y - 10);
const editorRect = await page.$eval(getEditorSelector(0), 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 input = await page.$("#stampEditorFileInput");
await input.uploadFile(
`${path.join(__dirname, "../images/firefox_logo.png")}`
@ -162,6 +157,15 @@ describe("Stamp Editor", () => {
await page.waitForTimeout(300);
await dragAndDropAnnotation(
page,
editorRect.x + 10,
editorRect.y + 10,
rect.x - 10,
rect.y - 10
);
await page.waitForTimeout(10);
const { left } = await getEditorDimensions(page, 0);
// The image is bigger than the page, so it has been scaled down to
@ -204,14 +208,7 @@ describe("Stamp Editor", () => {
await page.waitForTimeout(10);
}
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 };
});
await page.mouse.click(rect.x + 10, rect.y + 10);
await page.click("#editorStampAddImage");
await page.waitForTimeout(10);
const input = await page.$("#stampEditorFileInput");
await input.uploadFile(

View file

@ -31,6 +31,7 @@ class AnnotationEditorParams {
editorInkColor,
editorInkThickness,
editorInkOpacity,
editorStampAddImage,
}) {
const dispatchEvent = (typeStr, value) => {
this.eventBus.dispatch("switchannotationeditorparams", {
@ -54,6 +55,9 @@ class AnnotationEditorParams {
editorInkOpacity.addEventListener("input", function () {
dispatchEvent("INK_OPACITY", this.valueAsNumber);
});
editorStampAddImage.addEventListener("click", () => {
dispatchEvent("CREATE");
});
this.eventBus._on("annotationeditorparamschanged", evt => {
for (const [type, value] of evt.details) {

View file

@ -218,6 +218,7 @@ class Toolbar {
editorInkButton,
editorInkParamsToolbar,
editorStampButton,
editorStampParamsToolbar,
}) {
const editorModeChanged = ({ mode }) => {
toggleCheckedBtn(
@ -230,7 +231,11 @@ class Toolbar {
mode === AnnotationEditorType.INK,
editorInkParamsToolbar
);
toggleCheckedBtn(editorStampButton, mode === AnnotationEditorType.STAMP);
toggleCheckedBtn(
editorStampButton,
mode === AnnotationEditorType.STAMP,
editorStampParamsToolbar
);
const isDisable = mode === AnnotationEditorType.DISABLE;
editorFreeTextButton.disabled = isDisable;

View file

@ -118,6 +118,7 @@
--secondaryToolbarButton-spreadOdd-icon: url(images/secondaryToolbarButton-spreadOdd.svg);
--secondaryToolbarButton-spreadEven-icon: url(images/secondaryToolbarButton-spreadEven.svg);
--secondaryToolbarButton-documentProperties-icon: url(images/secondaryToolbarButton-documentProperties.svg);
--editorParams-stampAddImage-icon: url(images/toolbarButton-zoomIn.svg);
}
:root:dir(rtl) {
@ -576,6 +577,11 @@ body {
margin-bottom: -4px;
}
#editorStampParamsToolbar {
inset-inline-end: 40px;
background-color: var(--toolbar-bg-color);
}
#editorInkParamsToolbar {
inset-inline-end: 68px;
background-color: var(--toolbar-bg-color);
@ -586,6 +592,10 @@ body {
background-color: var(--toolbar-bg-color);
}
#editorStampAddImage::before {
mask-image: var(--editorParams-stampAddImage-icon);
}
.doorHanger,
.doorHangerRight {
border-radius: 2px;

View file

@ -198,6 +198,14 @@ See https://github.com/adobe-type-tools/cmap-resources
</div>
</div>
<div class="editorParamsToolbar hidden doorHangerRight" id="editorStampParamsToolbar">
<div class="editorParamsToolbarContainer">
<button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="105" data-l10n-id="editor_stamp_add_image">
<span data-l10n-id="editor_stamp_add_image_label">Add image</span>
</button>
</div>
</div>
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
<div id="secondaryToolbarButtonContainer">
<!--#if GENERIC-->
@ -343,8 +351,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<button id="editorInk" class="toolbarButton" disabled="disabled" title="Draw" role="radio" aria-checked="false" aria-controls="editorInkParamsToolbar" tabindex="35" data-l10n-id="editor_ink2">
<span data-l10n-id="editor_ink2_label">Draw</span>
</button>
<button id="editorStamp" class="toolbarButton hidden" disabled="disabled" title="Image" role="radio" aria-checked="false" tabindex="36" data-l10n-id="editor_stamp">
<span data-l10n-id="editor_stamp_label">Image</span>
<button id="editorStamp" class="toolbarButton hidden" disabled="disabled" title="Add or edit images" role="radio" aria-checked="false" tabindex="36" data-l10n-id="editor_stamp1">
<span data-l10n-id="editor_stamp1_label">Add or edit images</span>
</button>
</div>

View file

@ -64,6 +64,9 @@ function getViewerConfiguration() {
editorInkButton: document.getElementById("editorInk"),
editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"),
editorStampButton: document.getElementById("editorStamp"),
editorStampParamsToolbar: document.getElementById(
"editorStampParamsToolbar"
),
download: document.getElementById("download"),
},
secondaryToolbar: {
@ -160,6 +163,7 @@ function getViewerConfiguration() {
editorInkColor: document.getElementById("editorInkColor"),
editorInkThickness: document.getElementById("editorInkThickness"),
editorInkOpacity: document.getElementById("editorInkOpacity"),
editorStampAddImage: document.getElementById("editorStampAddImage"),
},
printContainer: document.getElementById("printContainer"),
openFileInput: