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:
commit
4eca3ca199
13 changed files with 140 additions and 34 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -363,6 +363,10 @@ class FreeTextEditor extends AnnotationEditor {
|
|||
}
|
||||
this.enableEditMode();
|
||||
this.editorDiv.focus();
|
||||
if (this._initialOptions?.isCentered) {
|
||||
this.center();
|
||||
}
|
||||
this._initialOptions = null;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -78,6 +78,7 @@ const AnnotationEditorType = {
|
|||
|
||||
const AnnotationEditorParamsType = {
|
||||
RESIZE: 1,
|
||||
CREATE: 2,
|
||||
FREETEXT_SIZE: 11,
|
||||
FREETEXT_COLOR: 12,
|
||||
FREETEXT_OPACITY: 13,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue