[Editor] Add the possibility to paste an image from the clipboard (bug 1848317)

This commit is contained in:
Calixte Denizet 2023-08-11 17:27:26 +02:00
parent 4b2eebf32e
commit 2dd6f07b57
4 changed files with 111 additions and 11 deletions

View File

@ -464,6 +464,31 @@ class AnnotationEditorLayer {
return null;
}
/**
* Paste some content into a new editor.
* @param {number} mode
* @param {Object} params
*/
pasteEditor(mode, params) {
this.#uiManager.updateToolbar(mode);
this.#uiManager.updateMode(mode);
const { offsetX, offsetY } = this.#getCenterPoint();
const id = this.getNextId();
const editor = this.#createNewEditor({
parent: this,
id,
x: offsetX,
y: offsetY,
uiManager: this.#uiManager,
isCentered: true,
...params,
});
if (editor) {
this.add(editor);
}
}
/**
* Create a new editor
* @param {Object} data
@ -504,10 +529,7 @@ class AnnotationEditorLayer {
return editor;
}
/**
* Create and add a new editor.
*/
addNewEditor() {
#getCenterPoint() {
const { x, y, width, height } = this.div.getBoundingClientRect();
const tlX = Math.max(0, x);
const tlY = Math.max(0, y);
@ -520,11 +542,15 @@ class AnnotationEditorLayer {
? [centerX, centerY]
: [centerY, centerX];
return { offsetX, offsetY };
}
/**
* Create and add a new editor.
*/
addNewEditor() {
this.#createAndAddNewEditor(
{
offsetX,
offsetY,
},
this.#getCenterPoint(),
/* isCentered = */ true
);
}

View File

@ -140,6 +140,26 @@ class AnnotationEditor {
return [];
}
/**
* Check if this kind of editor is able to handle the given mime type for
* pasting.
* @param {string} mime
* @returns {boolean}
*/
static isHandlingMimeForPasting(_mime) {
return false;
}
/**
* Extract the data from the clipboard item and delegate the creation of the
* editor to the parent.
* @param {DataTransferItem} item
* @param {AnnotationEditorLayer} parent
*/
static paste(item, parent) {
unreachable("Not implemented");
}
/**
* Get the properties to update in the UI for this editor.
* @returns {Array}

View File

@ -30,6 +30,8 @@ class StampEditor extends AnnotationEditor {
#bitmapUrl = null;
#bitmapFile = null;
#canvas = null;
#observer = null;
@ -45,6 +47,7 @@ class StampEditor extends AnnotationEditor {
constructor(params) {
super({ ...params, name: "stampEditor" });
this.#bitmapUrl = params.bitmapUrl;
this.#bitmapFile = params.bitmapFile;
}
static get supportedTypes() {
@ -64,10 +67,26 @@ class StampEditor extends AnnotationEditor {
return shadow(
this,
"supportedTypes",
types.map(type => `image/${type}`).join(",")
types.map(type => `image/${type}`)
);
}
static get supportedTypesStr() {
return shadow(this, "supportedTypesStr", this.supportedTypes.join(","));
}
/** @inheritdoc */
static isHandlingMimeForPasting(mime) {
return this.supportedTypes.includes(mime);
}
/** @inheritdoc */
static paste(item, parent) {
parent.pasteEditor(AnnotationEditorType.STAMP, {
bitmapFile: item.getAsFile(),
});
}
#getBitmapDone() {
this._uiManager.enableWaiting(false);
if (this.#canvas) {
@ -115,6 +134,29 @@ class StampEditor extends AnnotationEditor {
return;
}
if (this.#bitmapFile) {
const file = this.#bitmapFile;
this.#bitmapFile = null;
this._uiManager.enableWaiting(true);
this.#bitmapPromise = this._uiManager.imageManager
.getFromFile(file)
.then(data => {
this.#bitmapPromise = null;
if (!data) {
this.remove();
return;
}
({
bitmap: this.#bitmap,
id: this.#bitmapId,
isSvg: this.#isSvg,
} = data);
this.#createCanvas();
})
.finally(() => this.#getBitmapDone());
return;
}
const input = document.createElement("input");
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
input.hidden = true;
@ -122,7 +164,7 @@ class StampEditor extends AnnotationEditor {
document.body.append(input);
}
input.type = "file";
input.accept = StampEditor.supportedTypes;
input.accept = StampEditor.supportedTypesStr;
this.#bitmapPromise = new Promise(resolve => {
input.addEventListener("change", async () => {
this.#bitmapPromise = null;

View File

@ -919,8 +919,17 @@ class AnnotationEditorUIManager {
*/
paste(event) {
event.preventDefault();
const { clipboardData } = event;
for (const item of clipboardData.items) {
for (const editorType of this.#editorTypes) {
if (editorType.isHandlingMimeForPasting(item.type)) {
editorType.paste(item, this.currentLayer);
return;
}
}
}
let data = event.clipboardData.getData("application/pdfjs");
let data = clipboardData.getData("application/pdfjs");
if (!data) {
return;
}
@ -1099,6 +1108,9 @@ class AnnotationEditorUIManager {
* @param {string|null} editId
*/
updateMode(mode, editId = null) {
if (this.#mode === mode) {
return;
}
this.#mode = mode;
if (mode === AnnotationEditorType.NONE) {
this.setEditingState(false);