pdfjs-dist
Version:
Generic build of Mozilla's PDF.js library.
377 lines (376 loc) • 10.7 kB
JavaScript
/**
* @licstart The following is the entire license notice for the
* JavaScript code in this page
*
* Copyright 2022 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @licend The above is the entire license notice for the
* JavaScript code in this page
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AnnotationEditorLayer = void 0;
var _tools = require("./tools.js");
var _util = require("../../shared/util.js");
var _freetext = require("./freetext.js");
var _ink = require("./ink.js");
class AnnotationEditorLayer {
#accessibilityManager;
#allowClick = false;
#boundPointerup = this.pointerup.bind(this);
#boundPointerdown = this.pointerdown.bind(this);
#editors = new Map();
#hadPointerDown = false;
#isCleaningUp = false;
#uiManager;
static _initialized = false;
constructor(options) {
if (!AnnotationEditorLayer._initialized) {
AnnotationEditorLayer._initialized = true;
_freetext.FreeTextEditor.initialize(options.l10n);
_ink.InkEditor.initialize(options.l10n);
}
options.uiManager.registerEditorTypes([_freetext.FreeTextEditor, _ink.InkEditor]);
this.#uiManager = options.uiManager;
this.annotationStorage = options.annotationStorage;
this.pageIndex = options.pageIndex;
this.div = options.div;
this.#accessibilityManager = options.accessibilityManager;
this.#uiManager.addLayer(this);
}
updateToolbar(mode) {
this.#uiManager.updateToolbar(mode);
}
updateMode(mode = this.#uiManager.getMode()) {
this.#cleanup();
if (mode === _util.AnnotationEditorType.INK) {
this.addInkEditorIfNeeded(false);
this.disableClick();
} else {
this.enableClick();
}
this.#uiManager.unselectAll();
this.div.classList.toggle("freeTextEditing", mode === _util.AnnotationEditorType.FREETEXT);
this.div.classList.toggle("inkEditing", mode === _util.AnnotationEditorType.INK);
}
addInkEditorIfNeeded(isCommitting) {
if (!isCommitting && this.#uiManager.getMode() !== _util.AnnotationEditorType.INK) {
return;
}
if (!isCommitting) {
for (const editor of this.#editors.values()) {
if (editor.isEmpty()) {
editor.setInBackground();
return;
}
}
}
const editor = this.#createAndAddNewEditor({
offsetX: 0,
offsetY: 0
});
editor.setInBackground();
}
setEditingState(isEditing) {
this.#uiManager.setEditingState(isEditing);
}
addCommands(params) {
this.#uiManager.addCommands(params);
}
enable() {
this.div.style.pointerEvents = "auto";
for (const editor of this.#editors.values()) {
editor.enableEditing();
}
}
disable() {
this.div.style.pointerEvents = "none";
for (const editor of this.#editors.values()) {
editor.disableEditing();
}
}
setActiveEditor(editor) {
const currentActive = this.#uiManager.getActive();
if (currentActive === editor) {
return;
}
this.#uiManager.setActiveEditor(editor);
}
enableClick() {
this.div.addEventListener("pointerdown", this.#boundPointerdown);
this.div.addEventListener("pointerup", this.#boundPointerup);
}
disableClick() {
this.div.removeEventListener("pointerdown", this.#boundPointerdown);
this.div.removeEventListener("pointerup", this.#boundPointerup);
}
attach(editor) {
this.#editors.set(editor.id, editor);
}
detach(editor) {
this.#editors.delete(editor.id);
this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
}
remove(editor) {
this.#uiManager.removeEditor(editor);
this.detach(editor);
this.annotationStorage.remove(editor.id);
editor.div.style.display = "none";
setTimeout(() => {
editor.div.style.display = "";
editor.div.remove();
editor.isAttachedToDOM = false;
if (document.activeElement === document.body) {
this.#uiManager.focusMainContainer();
}
}, 0);
if (!this.#isCleaningUp) {
this.addInkEditorIfNeeded(false);
}
}
#changeParent(editor) {
if (editor.parent === this) {
return;
}
this.attach(editor);
editor.pageIndex = this.pageIndex;
editor.parent?.detach(editor);
editor.parent = this;
if (editor.div && editor.isAttachedToDOM) {
editor.div.remove();
this.div.append(editor.div);
}
}
add(editor) {
this.#changeParent(editor);
this.#uiManager.addEditor(editor);
this.attach(editor);
if (!editor.isAttachedToDOM) {
const div = editor.render();
this.div.append(div);
editor.isAttachedToDOM = true;
}
this.moveEditorInDOM(editor);
editor.onceAdded();
this.addToAnnotationStorage(editor);
}
moveEditorInDOM(editor) {
this.#accessibilityManager?.moveElementInDOM(this.div, editor.div, editor.contentDiv, true);
}
addToAnnotationStorage(editor) {
if (!editor.isEmpty() && !this.annotationStorage.has(editor.id)) {
this.annotationStorage.setValue(editor.id, editor);
}
}
addOrRebuild(editor) {
if (editor.needsToBeRebuilt()) {
editor.rebuild();
} else {
this.add(editor);
}
}
addANewEditor(editor) {
const cmd = () => {
this.addOrRebuild(editor);
};
const undo = () => {
editor.remove();
};
this.addCommands({
cmd,
undo,
mustExec: true
});
}
addUndoableEditor(editor) {
const cmd = () => {
this.addOrRebuild(editor);
};
const undo = () => {
editor.remove();
};
this.addCommands({
cmd,
undo,
mustExec: false
});
}
getNextId() {
return this.#uiManager.getId();
}
#createNewEditor(params) {
switch (this.#uiManager.getMode()) {
case _util.AnnotationEditorType.FREETEXT:
return new _freetext.FreeTextEditor(params);
case _util.AnnotationEditorType.INK:
return new _ink.InkEditor(params);
}
return null;
}
deserialize(data) {
switch (data.annotationType) {
case _util.AnnotationEditorType.FREETEXT:
return _freetext.FreeTextEditor.deserialize(data, this);
case _util.AnnotationEditorType.INK:
return _ink.InkEditor.deserialize(data, this);
}
return null;
}
#createAndAddNewEditor(event) {
const id = this.getNextId();
const editor = this.#createNewEditor({
parent: this,
id,
x: event.offsetX,
y: event.offsetY
});
if (editor) {
this.add(editor);
}
return editor;
}
setSelected(editor) {
this.#uiManager.setSelected(editor);
}
toggleSelected(editor) {
this.#uiManager.toggleSelected(editor);
}
isSelected(editor) {
return this.#uiManager.isSelected(editor);
}
unselect(editor) {
this.#uiManager.unselect(editor);
}
pointerup(event) {
const isMac = _tools.KeyboardManager.platform.isMac;
if (event.button !== 0 || event.ctrlKey && isMac) {
return;
}
if (event.target !== this.div) {
return;
}
if (!this.#hadPointerDown) {
return;
}
this.#hadPointerDown = false;
if (!this.#allowClick) {
this.#allowClick = true;
return;
}
this.#createAndAddNewEditor(event);
}
pointerdown(event) {
const isMac = _tools.KeyboardManager.platform.isMac;
if (event.button !== 0 || event.ctrlKey && isMac) {
return;
}
if (event.target !== this.div) {
return;
}
this.#hadPointerDown = true;
const editor = this.#uiManager.getActive();
this.#allowClick = !editor || editor.isEmpty();
}
drop(event) {
const id = event.dataTransfer.getData("text/plain");
const editor = this.#uiManager.getEditor(id);
if (!editor) {
return;
}
event.preventDefault();
event.dataTransfer.dropEffect = "move";
this.#changeParent(editor);
const rect = this.div.getBoundingClientRect();
const endX = event.clientX - rect.x;
const endY = event.clientY - rect.y;
editor.translate(endX - editor.startX, endY - editor.startY);
this.moveEditorInDOM(editor);
editor.div.focus();
}
dragover(event) {
event.preventDefault();
}
destroy() {
if (this.#uiManager.getActive()?.parent === this) {
this.#uiManager.setActiveEditor(null);
}
for (const editor of this.#editors.values()) {
this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
editor.isAttachedToDOM = false;
editor.div.remove();
editor.parent = null;
}
this.div = null;
this.#editors.clear();
this.#uiManager.removeLayer(this);
}
#cleanup() {
this.#isCleaningUp = true;
for (const editor of this.#editors.values()) {
if (editor.isEmpty()) {
editor.remove();
}
}
this.#isCleaningUp = false;
}
render(parameters) {
this.viewport = parameters.viewport;
(0, _tools.bindEvents)(this, this.div, ["dragover", "drop"]);
this.setDimensions();
for (const editor of this.#uiManager.getEditors(this.pageIndex)) {
this.add(editor);
}
this.updateMode();
}
update(parameters) {
this.#uiManager.commitOrRemove();
this.viewport = parameters.viewport;
this.setDimensions();
this.updateMode();
}
get scaleFactor() {
return this.viewport.scale;
}
get pageDimensions() {
const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox;
const width = pageURx - pageLLx;
const height = pageURy - pageLLy;
return [width, height];
}
get viewportBaseDimensions() {
const {
width,
height,
rotation
} = this.viewport;
return rotation % 180 === 0 ? [width, height] : [height, width];
}
setDimensions() {
const {
width,
height,
rotation
} = this.viewport;
const flipOrientation = rotation % 180 !== 0,
widthStr = Math.floor(width) + "px",
heightStr = Math.floor(height) + "px";
this.div.style.width = flipOrientation ? heightStr : widthStr;
this.div.style.height = flipOrientation ? widthStr : heightStr;
this.div.setAttribute("data-main-rotation", rotation);
}
}
exports.AnnotationEditorLayer = AnnotationEditorLayer;