[editor] Add some UI elements in order to set font size & color, and ink thickness & color
This commit is contained in:
parent
4e025e1f08
commit
1a3ef2a0aa
@ -259,3 +259,9 @@ editor_ink.title=Add Ink Annotation
|
||||
editor_ink_label=Ink Annotation
|
||||
|
||||
freetext_default_content=Enter some text…
|
||||
|
||||
# Editor Parameters
|
||||
editor_free_text_font_color=Font Color
|
||||
editor_free_text_font_size=Font Size
|
||||
editor_ink_line_color=Line Color
|
||||
editor_ink_line_thickness=Line Thickness
|
||||
|
@ -3767,7 +3767,7 @@ class InkAnnotation extends MarkupAnnotation {
|
||||
}
|
||||
|
||||
const appearanceBuffer = [
|
||||
`${thickness} w`,
|
||||
`${thickness} w 1 J 1 j`,
|
||||
`${getPdfColor(color, /* isFill */ false)}`,
|
||||
];
|
||||
const buffer = [];
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
Util,
|
||||
warn,
|
||||
} from "../shared/util.js";
|
||||
import { getRGB, PixelsPerInch } from "./display_utils.js";
|
||||
import {
|
||||
getShadingPattern,
|
||||
PathType,
|
||||
@ -33,7 +34,6 @@ import {
|
||||
} from "./pattern_helper.js";
|
||||
import { applyMaskImageData } from "../shared/image_utils.js";
|
||||
import { isNodeJS } from "../shared/is_node.js";
|
||||
import { PixelsPerInch } from "./display_utils.js";
|
||||
|
||||
// <canvas> contexts store most of the state we need natively.
|
||||
// However, PDF needs a bit more state, which we store here.
|
||||
@ -1326,10 +1326,7 @@ class CanvasGraphics {
|
||||
// Then for every color in the pdf, if its rounded luminance is the
|
||||
// same as the background one then it's replaced by the new
|
||||
// background color else by the foreground one.
|
||||
const cB = parseInt(defaultBg.slice(1), 16);
|
||||
const rB = (cB && 0xff0000) >> 16;
|
||||
const gB = (cB && 0x00ff00) >> 8;
|
||||
const bB = cB && 0x0000ff;
|
||||
const [rB, gB, bB] = getRGB(defaultBg);
|
||||
const newComp = x => {
|
||||
x /= 255;
|
||||
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
||||
|
@ -567,6 +567,28 @@ function getXfaPageViewport(xfaPage, { scale = 1, rotation = 0 }) {
|
||||
});
|
||||
}
|
||||
|
||||
function getRGB(color) {
|
||||
if (color.startsWith("#")) {
|
||||
const colorRGB = parseInt(color.slice(1), 16);
|
||||
return [
|
||||
(colorRGB & 0xff0000) >> 16,
|
||||
(colorRGB & 0x00ff00) >> 8,
|
||||
colorRGB & 0x0000ff,
|
||||
];
|
||||
}
|
||||
|
||||
if (color.startsWith("rgb(")) {
|
||||
// getComputedStyle(...).color returns a `rgb(R, G, B)` color.
|
||||
return color
|
||||
.slice(/* "rgb(".length */ 4, -1) // Strip out "rgb(" and ")".
|
||||
.split(",")
|
||||
.map(x => parseInt(x));
|
||||
}
|
||||
|
||||
warn(`Not a valid color format: "${color}"`);
|
||||
return [0, 0, 0];
|
||||
}
|
||||
|
||||
export {
|
||||
deprecated,
|
||||
DOMCanvasFactory,
|
||||
@ -575,6 +597,7 @@ export {
|
||||
DOMSVGFactory,
|
||||
getFilenameFromUrl,
|
||||
getPdfFilenameFromUrl,
|
||||
getRGB,
|
||||
getXfaPageViewport,
|
||||
isDataScheme,
|
||||
isPdfFile,
|
||||
|
@ -78,6 +78,8 @@ class AnnotationEditorLayer {
|
||||
if (!AnnotationEditorLayer._initialized) {
|
||||
AnnotationEditorLayer._initialized = true;
|
||||
FreeTextEditor.initialize(options.l10n);
|
||||
|
||||
options.uiManager.registerEditorTypes([FreeTextEditor, InkEditor]);
|
||||
}
|
||||
this.#uiManager = options.uiManager;
|
||||
this.annotationStorage = options.annotationStorage;
|
||||
@ -98,14 +100,22 @@ class AnnotationEditorLayer {
|
||||
* @param {number} mode
|
||||
*/
|
||||
updateMode(mode) {
|
||||
if (mode === AnnotationEditorType.INK) {
|
||||
// We want to have the ink editor covering all of the page without having
|
||||
// to click to create it: it must be here when we start to draw.
|
||||
this.div.addEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
} else {
|
||||
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
||||
switch (mode) {
|
||||
case AnnotationEditorType.INK:
|
||||
// We want to have the ink editor covering all of the page without
|
||||
// having to click to create it: it must be here when we start to draw.
|
||||
this.div.addEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
break;
|
||||
case AnnotationEditorType.FREETEXT:
|
||||
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.addEventListener("click", this.#boundClick);
|
||||
break;
|
||||
default:
|
||||
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
}
|
||||
|
||||
this.setActiveEditor(null);
|
||||
}
|
||||
|
||||
@ -130,13 +140,10 @@ class AnnotationEditorLayer {
|
||||
|
||||
/**
|
||||
* Add some commands into the CommandManager (undo/redo stuff).
|
||||
* @param {function} cmd
|
||||
* @param {function} undo
|
||||
* @param {boolean} mustExec - If true the command is executed after having
|
||||
* been added.
|
||||
* @param {Object} params
|
||||
*/
|
||||
addCommands(cmd, undo, mustExec) {
|
||||
this.#uiManager.addCommands(cmd, undo, mustExec);
|
||||
addCommands(params) {
|
||||
this.#uiManager.addCommands(params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,7 +239,10 @@ class AnnotationEditorLayer {
|
||||
this.unselectAll();
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
} else {
|
||||
this.#uiManager.allowClick = false;
|
||||
// When in Ink mode, setting the editor to null allows the
|
||||
// user to have to make one click in order to start drawing.
|
||||
this.#uiManager.allowClick =
|
||||
this.#uiManager.getMode() === AnnotationEditorType.INK;
|
||||
this.div.addEventListener("click", this.#boundClick);
|
||||
}
|
||||
}
|
||||
@ -332,7 +342,7 @@ class AnnotationEditorLayer {
|
||||
editor.remove();
|
||||
};
|
||||
|
||||
this.addCommands(cmd, undo, true);
|
||||
this.addCommands({ cmd, undo, mustExec: true });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,7 +357,7 @@ class AnnotationEditorLayer {
|
||||
editor.remove();
|
||||
};
|
||||
|
||||
this.addCommands(cmd, undo, false);
|
||||
this.addCommands({ cmd, undo, mustExec: false });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -372,6 +372,21 @@ class AnnotationEditor {
|
||||
this.div.classList.remove("selectedEditor");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update some parameters which have been changed through the UI.
|
||||
* @param {number} type
|
||||
* @param {*} value
|
||||
*/
|
||||
updateParams(type, value) {}
|
||||
|
||||
/**
|
||||
* Get some properties to update in the UI.
|
||||
* @returns {Object}
|
||||
*/
|
||||
get propertiesToUpdate() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export { AnnotationEditor };
|
||||
|
@ -14,12 +14,14 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AnnotationEditorParamsType,
|
||||
AnnotationEditorType,
|
||||
assert,
|
||||
LINE_FACTOR,
|
||||
} from "../../shared/util.js";
|
||||
import { AnnotationEditor } from "./editor.js";
|
||||
import { bindEvents } from "./tools.js";
|
||||
import { getRGB } from "../display_utils.js";
|
||||
|
||||
/**
|
||||
* Basic text editor in order to create a FreeTex annotation.
|
||||
@ -41,10 +43,14 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
|
||||
static _internalPadding = 0;
|
||||
|
||||
static _defaultFontSize = 10;
|
||||
|
||||
static _defaultColor = "CanvasText";
|
||||
|
||||
constructor(params) {
|
||||
super({ ...params, name: "freeTextEditor" });
|
||||
this.#color = params.color || "CanvasText";
|
||||
this.#fontSize = params.fontSize || 10;
|
||||
this.#color = params.color || FreeTextEditor._defaultColor;
|
||||
this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize;
|
||||
}
|
||||
|
||||
static initialize(l10n) {
|
||||
@ -89,6 +95,94 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
return editor;
|
||||
}
|
||||
|
||||
static updateDefaultParams(type, value) {
|
||||
switch (type) {
|
||||
case AnnotationEditorParamsType.FREETEXT_SIZE:
|
||||
FreeTextEditor._defaultFontSize = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.FREETEXT_COLOR:
|
||||
FreeTextEditor._defaultColor = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
updateParams(type, value) {
|
||||
switch (type) {
|
||||
case AnnotationEditorParamsType.FREETEXT_SIZE:
|
||||
this.#updateFontSize(value);
|
||||
break;
|
||||
case AnnotationEditorParamsType.FREETEXT_COLOR:
|
||||
this.#updateColor(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static get defaultPropertiesToUpdate() {
|
||||
return [
|
||||
[
|
||||
AnnotationEditorParamsType.FREETEXT_SIZE,
|
||||
FreeTextEditor._defaultFontSize,
|
||||
],
|
||||
[AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor],
|
||||
];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
get propertiesToUpdate() {
|
||||
return [
|
||||
[AnnotationEditorParamsType.FREETEXT_SIZE, this.#fontSize],
|
||||
[AnnotationEditorParamsType.FREETEXT_COLOR, this.#color],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the font size and make this action as undoable.
|
||||
* @param {number} fontSize
|
||||
*/
|
||||
#updateFontSize(fontSize) {
|
||||
const setFontsize = size => {
|
||||
this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`;
|
||||
this.translate(0, -(size - this.#fontSize) * this.parent.scaleFactor);
|
||||
this.#fontSize = size;
|
||||
};
|
||||
const savedFontsize = this.#fontSize;
|
||||
this.parent.addCommands({
|
||||
cmd: () => {
|
||||
setFontsize(fontSize);
|
||||
},
|
||||
undo: () => {
|
||||
setFontsize(savedFontsize);
|
||||
},
|
||||
mustExec: true,
|
||||
type: AnnotationEditorParamsType.FREETEXT_SIZE,
|
||||
overwriteIfSameType: true,
|
||||
keepUndo: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the color and make this action undoable.
|
||||
* @param {string} color
|
||||
*/
|
||||
#updateColor(color) {
|
||||
const savedColor = this.#color;
|
||||
this.parent.addCommands({
|
||||
cmd: () => {
|
||||
this.#color = color;
|
||||
this.editorDiv.style.color = color;
|
||||
},
|
||||
undo: () => {
|
||||
this.#color = savedColor;
|
||||
this.editorDiv.style.color = savedColor;
|
||||
},
|
||||
mustExec: true,
|
||||
type: AnnotationEditorParamsType.FREETEXT_COLOR,
|
||||
overwriteIfSameType: true,
|
||||
keepUndo: true,
|
||||
});
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
getInitialTranslation() {
|
||||
// The start of the base line is where the user clicked.
|
||||
@ -116,6 +210,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
enableEditMode() {
|
||||
super.enableEditMode();
|
||||
this.overlayDiv.classList.remove("enabled");
|
||||
this.editorDiv.contentEditable = true;
|
||||
this.div.draggable = false;
|
||||
}
|
||||
|
||||
@ -123,6 +218,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
disableEditMode() {
|
||||
super.disableEditMode();
|
||||
this.overlayDiv.classList.add("enabled");
|
||||
this.editorDiv.contentEditable = false;
|
||||
this.div.draggable = true;
|
||||
}
|
||||
|
||||
@ -223,7 +319,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
this.editorDiv.contentEditable = true;
|
||||
|
||||
const { style } = this.editorDiv;
|
||||
style.fontSize = `${this.#fontSize}%`;
|
||||
style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
|
||||
style.color = this.#color;
|
||||
|
||||
this.div.append(this.editorDiv);
|
||||
@ -248,6 +344,7 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
this.editorDiv.innerHTML = this.#contentHTML;
|
||||
this.div.draggable = true;
|
||||
}
|
||||
|
||||
return this.div;
|
||||
@ -258,9 +355,12 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor;
|
||||
const rect = this.getRect(padding, padding);
|
||||
|
||||
// We don't use this.#color directly because it can be CanvasText.
|
||||
const color = getRGB(getComputedStyle(this.editorDiv).color);
|
||||
|
||||
return {
|
||||
annotationType: AnnotationEditorType.FREETEXT,
|
||||
color: [0, 0, 0],
|
||||
color,
|
||||
fontSize: this.#fontSize,
|
||||
value: this.#content,
|
||||
pageIndex: this.parent.pageIndex,
|
||||
|
@ -13,9 +13,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AnnotationEditorType, Util } from "../../shared/util.js";
|
||||
import {
|
||||
AnnotationEditorParamsType,
|
||||
AnnotationEditorType,
|
||||
Util,
|
||||
} from "../../shared/util.js";
|
||||
import { AnnotationEditor } from "./editor.js";
|
||||
import { fitCurve } from "./fit_curve/fit_curve.js";
|
||||
import { getRGB } from "../display_utils.js";
|
||||
|
||||
/**
|
||||
* Basic draw editor in order to generate an Ink annotation.
|
||||
@ -43,10 +48,14 @@ class InkEditor extends AnnotationEditor {
|
||||
|
||||
#realHeight = 0;
|
||||
|
||||
static _defaultThickness = 1;
|
||||
|
||||
static _defaultColor = "CanvasText";
|
||||
|
||||
constructor(params) {
|
||||
super({ ...params, name: "inkEditor" });
|
||||
this.color = params.color || "CanvasText";
|
||||
this.thickness = params.thickness || 1;
|
||||
this.color = params.color || InkEditor._defaultColor;
|
||||
this.thickness = params.thickness || InkEditor._defaultThickness;
|
||||
this.paths = [];
|
||||
this.bezierPath2D = [];
|
||||
this.currentPath = [];
|
||||
@ -89,6 +98,88 @@ class InkEditor extends AnnotationEditor {
|
||||
return editor;
|
||||
}
|
||||
|
||||
static updateDefaultParams(type, value) {
|
||||
switch (type) {
|
||||
case AnnotationEditorParamsType.INK_THICKNESS:
|
||||
InkEditor._defaultThickness = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.INK_COLOR:
|
||||
InkEditor._defaultColor = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
updateParams(type, value) {
|
||||
switch (type) {
|
||||
case AnnotationEditorParamsType.INK_THICKNESS:
|
||||
this.#updateThickness(value);
|
||||
break;
|
||||
case AnnotationEditorParamsType.INK_COLOR:
|
||||
this.#updateColor(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static get defaultPropertiesToUpdate() {
|
||||
return [
|
||||
[AnnotationEditorParamsType.INK_THICKNESS, InkEditor._defaultThickness],
|
||||
[AnnotationEditorParamsType.INK_COLOR, InkEditor._defaultColor],
|
||||
];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
get propertiesToUpdate() {
|
||||
return [
|
||||
[AnnotationEditorParamsType.INK_THICKNESS, this.thickness],
|
||||
[AnnotationEditorParamsType.INK_COLOR, this.color],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the thickness and make this action undoable.
|
||||
* @param {number} thickness
|
||||
*/
|
||||
#updateThickness(thickness) {
|
||||
const savedThickness = this.thickness;
|
||||
this.parent.addCommands({
|
||||
cmd: () => {
|
||||
this.thickness = thickness;
|
||||
this.#fitToContent();
|
||||
},
|
||||
undo: () => {
|
||||
this.thickness = savedThickness;
|
||||
this.#fitToContent();
|
||||
},
|
||||
mustExec: true,
|
||||
type: AnnotationEditorParamsType.INK_THICKNESS,
|
||||
overwriteIfSameType: true,
|
||||
keepUndo: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the color and make this action undoable.
|
||||
* @param {string} color
|
||||
*/
|
||||
#updateColor(color) {
|
||||
const savedColor = this.color;
|
||||
this.parent.addCommands({
|
||||
cmd: () => {
|
||||
this.color = color;
|
||||
this.#redraw();
|
||||
},
|
||||
undo: () => {
|
||||
this.color = savedColor;
|
||||
this.#redraw();
|
||||
},
|
||||
mustExec: true,
|
||||
type: AnnotationEditorParamsType.INK_COLOR,
|
||||
overwriteIfSameType: true,
|
||||
keepUndo: true,
|
||||
});
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
rebuild() {
|
||||
if (this.div === null) {
|
||||
@ -186,7 +277,7 @@ class InkEditor extends AnnotationEditor {
|
||||
this.ctx.lineWidth =
|
||||
(this.thickness * this.parent.scaleFactor) / this.scaleFactor;
|
||||
this.ctx.lineCap = "round";
|
||||
this.ctx.lineJoin = "miter";
|
||||
this.ctx.lineJoin = "round";
|
||||
this.ctx.miterLimit = 10;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
}
|
||||
@ -263,7 +354,7 @@ class InkEditor extends AnnotationEditor {
|
||||
}
|
||||
};
|
||||
|
||||
this.parent.addCommands(cmd, undo, true);
|
||||
this.parent.addCommands({ cmd, undo, mustExec: true });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -755,9 +846,12 @@ class InkEditor extends AnnotationEditor {
|
||||
const height =
|
||||
this.rotation % 180 === 0 ? rect[3] - rect[1] : rect[2] - rect[0];
|
||||
|
||||
// We don't use this.color directly because it can be CanvasText.
|
||||
const color = getRGB(this.ctx.strokeStyle);
|
||||
|
||||
return {
|
||||
annotationType: AnnotationEditorType.INK,
|
||||
color: [0, 0, 0],
|
||||
color,
|
||||
thickness: this.thickness,
|
||||
paths: this.#serializePaths(
|
||||
this.scaleFactor / this.parent.scaleFactor,
|
||||
|
@ -64,9 +64,36 @@ class CommandManager {
|
||||
* @param {function} cmd
|
||||
* @param {function} undo
|
||||
* @param {boolean} mustExec
|
||||
* @param {number} type
|
||||
* @param {boolean} overwriteIfSameType
|
||||
* @param {boolean} keepUndo
|
||||
*/
|
||||
add(cmd, undo, mustExec) {
|
||||
const save = [cmd, undo];
|
||||
add({
|
||||
cmd,
|
||||
undo,
|
||||
mustExec,
|
||||
type = NaN,
|
||||
overwriteIfSameType = false,
|
||||
keepUndo = false,
|
||||
}) {
|
||||
const save = { cmd, undo, type };
|
||||
if (
|
||||
overwriteIfSameType &&
|
||||
!isNaN(this.#position) &&
|
||||
this.#commands[this.#position].type === type
|
||||
) {
|
||||
// For example when we change a color we don't want to
|
||||
// be able to undo all the steps, hence we only want to
|
||||
// keep the last undoable action in this sequence of actions.
|
||||
if (keepUndo) {
|
||||
save.undo = this.#commands[this.#position].undo;
|
||||
}
|
||||
this.#commands[this.#position] = save;
|
||||
if (mustExec) {
|
||||
cmd();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const next = (this.#position + 1) % this.#maxSize;
|
||||
if (next !== this.#start) {
|
||||
if (this.#start < next) {
|
||||
@ -94,7 +121,7 @@ class CommandManager {
|
||||
// Nothing to undo.
|
||||
return;
|
||||
}
|
||||
this.#commands[this.#position][1]();
|
||||
this.#commands[this.#position].undo();
|
||||
if (this.#position === this.#start) {
|
||||
this.#position = NaN;
|
||||
} else {
|
||||
@ -108,7 +135,7 @@ class CommandManager {
|
||||
redo() {
|
||||
if (isNaN(this.#position)) {
|
||||
if (this.#start < this.#commands.length) {
|
||||
this.#commands[this.#start][0]();
|
||||
this.#commands[this.#start].cmd();
|
||||
this.#position = this.#start;
|
||||
}
|
||||
return;
|
||||
@ -116,7 +143,7 @@ class CommandManager {
|
||||
|
||||
const next = (this.#position + 1) % this.#maxSize;
|
||||
if (next !== this.#start && next < this.#commands.length) {
|
||||
this.#commands[next][0]();
|
||||
this.#commands[next].cmd();
|
||||
this.#position = next;
|
||||
}
|
||||
}
|
||||
@ -273,6 +300,10 @@ class AnnotationEditorUIManager {
|
||||
|
||||
#commandManager = new CommandManager();
|
||||
|
||||
#editorTypes = null;
|
||||
|
||||
#eventBus = null;
|
||||
|
||||
#idManager = new IdManager();
|
||||
|
||||
#isAllSelected = false;
|
||||
@ -281,6 +312,26 @@ class AnnotationEditorUIManager {
|
||||
|
||||
#mode = AnnotationEditorType.NONE;
|
||||
|
||||
#previousActiveEditor = null;
|
||||
|
||||
constructor(eventBus) {
|
||||
this.#eventBus = eventBus;
|
||||
}
|
||||
|
||||
#dispatchUpdateUI(details) {
|
||||
this.#eventBus?.dispatch("annotationeditorparamschanged", {
|
||||
source: this,
|
||||
details,
|
||||
});
|
||||
}
|
||||
|
||||
registerEditorTypes(types) {
|
||||
this.#editorTypes = types;
|
||||
for (const editorType of this.#editorTypes) {
|
||||
this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an id.
|
||||
* @returns {string}
|
||||
@ -326,6 +377,21 @@ class AnnotationEditorUIManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a parameter in the current editor or globally.
|
||||
* @param {number} type
|
||||
* @param {*} value
|
||||
*/
|
||||
updateParams(type, value) {
|
||||
(this.#activeEditor || this.#previousActiveEditor)?.updateParams(
|
||||
type,
|
||||
value
|
||||
);
|
||||
for (const editorType of this.#editorTypes) {
|
||||
editorType.updateDefaultParams(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable all the layers.
|
||||
*/
|
||||
@ -395,7 +461,24 @@ class AnnotationEditorUIManager {
|
||||
* @param {AnnotationEditor} editor
|
||||
*/
|
||||
setActiveEditor(editor) {
|
||||
if (this.#activeEditor === editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#previousActiveEditor = this.#activeEditor;
|
||||
|
||||
this.#activeEditor = editor;
|
||||
if (editor) {
|
||||
this.#dispatchUpdateUI(editor.propertiesToUpdate);
|
||||
} else {
|
||||
if (this.#previousActiveEditor) {
|
||||
this.#dispatchUpdateUI(this.#previousActiveEditor.propertiesToUpdate);
|
||||
} else {
|
||||
for (const editorType of this.#editorTypes) {
|
||||
this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -414,12 +497,10 @@ class AnnotationEditorUIManager {
|
||||
|
||||
/**
|
||||
* Add a command to execute (cmd) and another one to undo it.
|
||||
* @param {function} cmd
|
||||
* @param {function} undo
|
||||
* @param {boolean} mustExec
|
||||
* @param {Object} params
|
||||
*/
|
||||
addCommands(cmd, undo, mustExec) {
|
||||
this.#commandManager.add(cmd, undo, mustExec);
|
||||
addCommands(params) {
|
||||
this.#commandManager.add(params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -468,7 +549,7 @@ class AnnotationEditorUIManager {
|
||||
}
|
||||
};
|
||||
|
||||
this.addCommands(cmd, undo, true);
|
||||
this.addCommands({ cmd, undo, mustExec: true });
|
||||
} else {
|
||||
if (!this.#activeEditor) {
|
||||
return;
|
||||
@ -482,7 +563,7 @@ class AnnotationEditorUIManager {
|
||||
};
|
||||
}
|
||||
|
||||
this.addCommands(cmd, undo, true);
|
||||
this.addCommands({ cmd, undo, mustExec: true });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -509,7 +590,7 @@ class AnnotationEditorUIManager {
|
||||
layer.addOrRebuild(editor);
|
||||
};
|
||||
|
||||
this.addCommands(cmd, undo, true);
|
||||
this.addCommands({ cmd, undo, mustExec: true });
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,7 +611,7 @@ class AnnotationEditorUIManager {
|
||||
editor.remove();
|
||||
};
|
||||
|
||||
this.addCommands(cmd, undo, true);
|
||||
this.addCommands({ cmd, undo, mustExec: true });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@
|
||||
/** @typedef {import("./display/text_layer").TextLayerRenderTask} TextLayerRenderTask */
|
||||
|
||||
import {
|
||||
AnnotationEditorParamsType,
|
||||
AnnotationEditorType,
|
||||
AnnotationMode,
|
||||
CMapCompressionType,
|
||||
@ -110,6 +111,7 @@ if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) {
|
||||
|
||||
export {
|
||||
AnnotationEditorLayer,
|
||||
AnnotationEditorParamsType,
|
||||
AnnotationEditorType,
|
||||
AnnotationEditorUIManager,
|
||||
AnnotationLayer,
|
||||
|
@ -60,6 +60,13 @@ const AnnotationEditorType = {
|
||||
INK: 15,
|
||||
};
|
||||
|
||||
const AnnotationEditorParamsType = {
|
||||
FREETEXT_SIZE: 0,
|
||||
FREETEXT_COLOR: 1,
|
||||
INK_COLOR: 2,
|
||||
INK_THICKNESS: 3,
|
||||
};
|
||||
|
||||
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
|
||||
const PermissionFlag = {
|
||||
PRINT: 0x04,
|
||||
@ -1146,6 +1153,7 @@ export {
|
||||
AbortException,
|
||||
AnnotationActionEventType,
|
||||
AnnotationBorderStyleType,
|
||||
AnnotationEditorParamsType,
|
||||
AnnotationEditorPrefix,
|
||||
AnnotationEditorType,
|
||||
AnnotationFieldFlag,
|
||||
|
@ -94,6 +94,7 @@ describe("Editor", () => {
|
||||
const content = await page.$eval(`${editorPrefix}0`, el =>
|
||||
el.innerText.trimEnd()
|
||||
);
|
||||
|
||||
let pastedContent = await page.$eval(`${editorPrefix}2`, el =>
|
||||
el.innerText.trimEnd()
|
||||
);
|
||||
|
@ -4217,8 +4217,8 @@ describe("annotation", function () {
|
||||
const appearance = data.dependencies[0].data;
|
||||
expect(appearance).toEqual(
|
||||
"2 0 obj\n" +
|
||||
"<< /FormType 1 /Subtype /Form /Type /XObject /BBox [0 0 44 44] /Length 121>> stream\n" +
|
||||
"1 w\n" +
|
||||
"<< /FormType 1 /Subtype /Form /Type /XObject /BBox [0 0 44 44] /Length 129>> stream\n" +
|
||||
"1 w 1 J 1 j\n" +
|
||||
"0 G\n" +
|
||||
"10 11 m\n" +
|
||||
"12 13 14 15 16 17 c\n" +
|
||||
@ -4243,8 +4243,8 @@ describe("annotation", function () {
|
||||
annotationType: AnnotationEditorType.INK,
|
||||
rect: [12, 34, 56, 78],
|
||||
rotation: 0,
|
||||
thickness: 1,
|
||||
color: [0, 0, 0],
|
||||
thickness: 3,
|
||||
color: [0, 255, 0],
|
||||
paths: [
|
||||
{
|
||||
bezier: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||
@ -4264,10 +4264,12 @@ describe("annotation", function () {
|
||||
null
|
||||
);
|
||||
|
||||
expect(operatorList.argsArray.length).toEqual(6);
|
||||
expect(operatorList.argsArray.length).toEqual(8);
|
||||
expect(operatorList.fnArray).toEqual([
|
||||
OPS.beginAnnotation,
|
||||
OPS.setLineWidth,
|
||||
OPS.setLineCap,
|
||||
OPS.setLineJoin,
|
||||
OPS.setStrokeRGBColor,
|
||||
OPS.constructPath,
|
||||
OPS.stroke,
|
||||
@ -4275,16 +4277,20 @@ describe("annotation", function () {
|
||||
]);
|
||||
|
||||
// Linewidth.
|
||||
expect(operatorList.argsArray[1]).toEqual([1]);
|
||||
expect(operatorList.argsArray[1]).toEqual([3]);
|
||||
// LineCap.
|
||||
expect(operatorList.argsArray[2]).toEqual([1]);
|
||||
// LineJoin.
|
||||
expect(operatorList.argsArray[3]).toEqual([1]);
|
||||
// Color.
|
||||
expect(operatorList.argsArray[2]).toEqual(
|
||||
new Uint8ClampedArray([0, 0, 0])
|
||||
expect(operatorList.argsArray[4]).toEqual(
|
||||
new Uint8ClampedArray([0, 255, 0])
|
||||
);
|
||||
// Path.
|
||||
expect(operatorList.argsArray[3][0]).toEqual([OPS.moveTo, OPS.curveTo]);
|
||||
expect(operatorList.argsArray[3][1]).toEqual([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
expect(operatorList.argsArray[5][0]).toEqual([OPS.moveTo, OPS.curveTo]);
|
||||
expect(operatorList.argsArray[5][1]).toEqual([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
// Min-max.
|
||||
expect(operatorList.argsArray[3][2]).toEqual([1, 1, 2, 2]);
|
||||
expect(operatorList.argsArray[5][2]).toEqual([1, 1, 2, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
|
84
web/annotation_editor_params.js
Normal file
84
web/annotation_editor_params.js
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
import { AnnotationEditorParamsType } from "pdfjs-lib";
|
||||
|
||||
class AnnotationEditorParams {
|
||||
/**
|
||||
* @param {AnnotationEditorParamsOptions} options
|
||||
* @param {EventBus} eventBus
|
||||
*/
|
||||
constructor(options, eventBus) {
|
||||
this.eventBus = eventBus;
|
||||
this.#bindListeners(options);
|
||||
}
|
||||
|
||||
#bindListeners({
|
||||
editorFreeTextFontSize,
|
||||
editorFreeTextColor,
|
||||
editorInkColor,
|
||||
editorInkThickness,
|
||||
}) {
|
||||
editorFreeTextFontSize.addEventListener("input", evt => {
|
||||
this.eventBus.dispatch("switchannotationeditorparams", {
|
||||
source: this,
|
||||
type: AnnotationEditorParamsType.FREETEXT_SIZE,
|
||||
value: editorFreeTextFontSize.valueAsNumber,
|
||||
});
|
||||
});
|
||||
editorFreeTextColor.addEventListener("input", evt => {
|
||||
this.eventBus.dispatch("switchannotationeditorparams", {
|
||||
source: this,
|
||||
type: AnnotationEditorParamsType.FREETEXT_COLOR,
|
||||
value: editorFreeTextColor.value,
|
||||
});
|
||||
});
|
||||
editorInkColor.addEventListener("input", evt => {
|
||||
this.eventBus.dispatch("switchannotationeditorparams", {
|
||||
source: this,
|
||||
type: AnnotationEditorParamsType.INK_COLOR,
|
||||
value: editorInkColor.value,
|
||||
});
|
||||
});
|
||||
editorInkThickness.addEventListener("input", evt => {
|
||||
this.eventBus.dispatch("switchannotationeditorparams", {
|
||||
source: this,
|
||||
type: AnnotationEditorParamsType.INK_THICKNESS,
|
||||
value: editorInkThickness.valueAsNumber,
|
||||
});
|
||||
});
|
||||
|
||||
this.eventBus._on("annotationeditorparamschanged", evt => {
|
||||
for (const [type, value] of evt.details) {
|
||||
switch (type) {
|
||||
case AnnotationEditorParamsType.FREETEXT_SIZE:
|
||||
editorFreeTextFontSize.value = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.FREETEXT_COLOR:
|
||||
editorFreeTextColor.value = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.INK_COLOR:
|
||||
editorInkColor.value = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.INK_THICKNESS:
|
||||
editorInkThickness.value = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { AnnotationEditorParams };
|
14
web/app.js
14
web/app.js
@ -56,6 +56,7 @@ import {
|
||||
} from "pdfjs-lib";
|
||||
import { CursorTool, PDFCursorTools } from "./pdf_cursor_tools.js";
|
||||
import { LinkTarget, PDFLinkService } from "./pdf_link_service.js";
|
||||
import { AnnotationEditorParams } from "./annotation_editor_params.js";
|
||||
import { OverlayManager } from "./overlay_manager.js";
|
||||
import { PasswordPrompt } from "./password_prompt.js";
|
||||
import { PDFAttachmentViewer } from "./pdf_attachment_viewer.js";
|
||||
@ -237,6 +238,8 @@ const PDFViewerApplication = {
|
||||
eventBus: null,
|
||||
/** @type {IL10n} */
|
||||
l10n: null,
|
||||
/** @type {AnnotationEditorParams} */
|
||||
annotationEditorParams: null,
|
||||
isInitialViewSet: false,
|
||||
downloadComplete: false,
|
||||
isViewerEmbedded: window.parent !== window,
|
||||
@ -568,6 +571,10 @@ const PDFViewerApplication = {
|
||||
}
|
||||
|
||||
if (annotationEditorEnabled) {
|
||||
this.annotationEditorParams = new AnnotationEditorParams(
|
||||
appConfig.annotationEditorParams,
|
||||
eventBus
|
||||
);
|
||||
for (const element of [
|
||||
document.getElementById("editorModeButtons"),
|
||||
document.getElementById("editorModeSeparator"),
|
||||
@ -1907,6 +1914,10 @@ const PDFViewerApplication = {
|
||||
"switchannotationeditormode",
|
||||
webViewerSwitchAnnotationEditorMode
|
||||
);
|
||||
eventBus._on(
|
||||
"switchannotationeditorparams",
|
||||
webViewerSwitchAnnotationEditorParams
|
||||
);
|
||||
eventBus._on("print", webViewerPrint);
|
||||
eventBus._on("download", webViewerDownload);
|
||||
eventBus._on("firstpage", webViewerFirstPage);
|
||||
@ -2491,6 +2502,9 @@ function webViewerPresentationMode() {
|
||||
function webViewerSwitchAnnotationEditorMode(evt) {
|
||||
PDFViewerApplication.pdfViewer.annotationEditorMode = evt.mode;
|
||||
}
|
||||
function webViewerSwitchAnnotationEditorParams(evt) {
|
||||
PDFViewerApplication.pdfViewer.annotationEditorParams = evt;
|
||||
}
|
||||
function webViewerPrint() {
|
||||
PDFViewerApplication.triggerPrinting();
|
||||
}
|
||||
|
@ -720,7 +720,9 @@ class BaseViewer {
|
||||
mode: annotationEditorMode,
|
||||
});
|
||||
|
||||
this.#annotationEditorUIManager = new AnnotationEditorUIManager();
|
||||
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
|
||||
this.eventBus
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2170,6 +2172,14 @@ class BaseViewer {
|
||||
|
||||
this.#annotationEditorUIManager.updateMode(mode);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line accessor-pairs
|
||||
set annotationEditorParams({ type, value }) {
|
||||
if (!this.#annotationEditorUIManager) {
|
||||
throw new Error(`The AnnotationEditor is not enabled.`);
|
||||
}
|
||||
this.#annotationEditorUIManager.updateParams(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
export { BaseViewer, PagesCountLimit, PDFPageViewBuffer };
|
||||
|
@ -104,7 +104,9 @@ class Toolbar {
|
||||
zoomOut: options.zoomOut,
|
||||
editorNoneButton: options.editorNoneButton,
|
||||
editorFreeTextButton: options.editorFreeTextButton,
|
||||
editorFreeTextParamsToolbar: options.editorFreeTextParamsToolbar,
|
||||
editorInkButton: options.editorInkButton,
|
||||
editorInkParamsToolbar: options.editorInkParamsToolbar,
|
||||
};
|
||||
|
||||
this._wasLocalized = false;
|
||||
@ -212,20 +214,33 @@ class Toolbar {
|
||||
#bindEditorToolsListener({
|
||||
editorNoneButton,
|
||||
editorFreeTextButton,
|
||||
editorFreeTextParamsToolbar,
|
||||
editorInkButton,
|
||||
editorInkParamsToolbar,
|
||||
}) {
|
||||
const editorModeChanged = (evt, disableButtons = false) => {
|
||||
const editorButtons = [
|
||||
[AnnotationEditorType.NONE, editorNoneButton],
|
||||
[AnnotationEditorType.FREETEXT, editorFreeTextButton],
|
||||
[AnnotationEditorType.INK, editorInkButton],
|
||||
{ mode: AnnotationEditorType.NONE, button: editorNoneButton },
|
||||
{
|
||||
mode: AnnotationEditorType.FREETEXT,
|
||||
button: editorFreeTextButton,
|
||||
toolbar: editorFreeTextParamsToolbar,
|
||||
},
|
||||
{
|
||||
mode: AnnotationEditorType.INK,
|
||||
button: editorInkButton,
|
||||
toolbar: editorInkParamsToolbar,
|
||||
},
|
||||
];
|
||||
|
||||
for (const [mode, button] of editorButtons) {
|
||||
for (const { mode, button, toolbar } of editorButtons) {
|
||||
const checked = mode === evt.mode;
|
||||
button.classList.toggle("toggled", checked);
|
||||
button.setAttribute("aria-checked", checked);
|
||||
button.disabled = disableButtons;
|
||||
if (toolbar) {
|
||||
toolbar.classList.toggle("hidden", !checked);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.eventBus._on("annotationeditormodechanged", editorModeChanged);
|
||||
|
@ -335,7 +335,8 @@ select {
|
||||
|
||||
#toolbarContainer,
|
||||
.findbar,
|
||||
.secondaryToolbar {
|
||||
.secondaryToolbar,
|
||||
.editorParamsToolbar {
|
||||
position: relative;
|
||||
height: 32px;
|
||||
background-color: var(--toolbar-bg-color);
|
||||
@ -415,7 +416,8 @@ select {
|
||||
}
|
||||
|
||||
.findbar,
|
||||
.secondaryToolbar {
|
||||
.secondaryToolbar,
|
||||
.editorParamsToolbar {
|
||||
top: 32px;
|
||||
position: absolute;
|
||||
z-index: 10000;
|
||||
@ -487,7 +489,8 @@ select {
|
||||
background-color: rgba(255, 102, 102, 1);
|
||||
}
|
||||
|
||||
.secondaryToolbar {
|
||||
.secondaryToolbar,
|
||||
.editorParamsToolbar {
|
||||
padding: 6px 0 10px;
|
||||
inset-inline-end: 4px;
|
||||
height: auto;
|
||||
@ -495,6 +498,50 @@ select {
|
||||
background-color: var(--doorhanger-bg-color);
|
||||
}
|
||||
|
||||
.editorParamsToolbarContainer {
|
||||
width: 220px;
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
|
||||
.editorParamsToolbarContainer > .editorParamsSetter {
|
||||
min-height: 26px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-inline: 10px;
|
||||
}
|
||||
|
||||
.editorParamsToolbarContainer .editorParamsLabel {
|
||||
padding-inline-end: 10px;
|
||||
flex: none;
|
||||
color: var(--main-color);
|
||||
}
|
||||
|
||||
.editorParamsToolbarContainer .editorParamsColor {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.editorParamsToolbarContainer .editorParamsSlider {
|
||||
background-color: transparent;
|
||||
width: 90px;
|
||||
flex: 0 1 0;
|
||||
}
|
||||
|
||||
.editorParamsToolbarContainer .editorParamsSlider::-moz-range-progress {
|
||||
background-color: black;
|
||||
}
|
||||
.editorParamsToolbarContainer .editorParamsSlider::-moz-range-track,
|
||||
.editorParamsToolbarContainer
|
||||
.editorParamsSlider::-webkit-slider-runnable-track {
|
||||
background-color: black;
|
||||
}
|
||||
.editorParamsToolbarContainer .editorParamsSlider::-moz-range-thumb,
|
||||
.editorParamsToolbarContainer .editorParamsSlider::-webkit-slider-thumb {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#secondaryToolbarButtonContainer {
|
||||
max-width: 220px;
|
||||
min-height: 26px;
|
||||
@ -503,6 +550,16 @@ select {
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
|
||||
#editorInkParamsToolbar {
|
||||
inset-inline-end: 40px;
|
||||
background-color: var(--toolbar-bg-color);
|
||||
}
|
||||
|
||||
#editorFreeTextParamsToolbar {
|
||||
inset-inline-end: 68px;
|
||||
background-color: var(--toolbar-bg-color);
|
||||
}
|
||||
|
||||
.doorHanger,
|
||||
.doorHangerRight {
|
||||
border-radius: 2px;
|
||||
|
@ -147,6 +147,32 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
</div>
|
||||
</div> <!-- findbar -->
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorFreeTextParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="editor_free_text_font_color">Font Color</label>
|
||||
<input type="color" id="editorFreeTextColor" name="fontColor" class="editorParamsColor" tabindex="100">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="editor_free_text_font_size">Font Size</label>
|
||||
<input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" name="fontSize" value="10" min="5" max="100" step="1" tabindex="101">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorInkParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkColor" class="editorParamsLabel" data-l10n-id="editor_ink_line_color">Line Color</label>
|
||||
<input type="color" id="editorInkColor" name="inkColor" class="editorParamsColor" tabindex="102">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="editor_ink_line_thickness">Line Thickness</label>
|
||||
<input type="range" id="editorInkThickness" class="editorParamsSlider" name="lineThickness" value="1" min="1" max="20" step="1" tabindex="103">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
|
||||
<div id="secondaryToolbarButtonContainer">
|
||||
<button id="secondaryPresentationMode" class="secondaryToolbarButton visibleLargeView" title="Switch to Presentation Mode" tabindex="51" data-l10n-id="presentation_mode">
|
||||
|
@ -95,7 +95,11 @@ function getViewerConfiguration() {
|
||||
print: document.getElementById("print"),
|
||||
editorNoneButton: document.getElementById("editorNone"),
|
||||
editorFreeTextButton: document.getElementById("editorFreeText"),
|
||||
editorFreeTextParamsToolbar: document.getElementById(
|
||||
"editorFreeTextParamsToolbar"
|
||||
),
|
||||
editorInkButton: document.getElementById("editorInk"),
|
||||
editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"),
|
||||
presentationModeButton: document.getElementById("presentationMode"),
|
||||
download: document.getElementById("download"),
|
||||
viewBookmark: document.getElementById("viewBookmark"),
|
||||
@ -193,6 +197,12 @@ function getViewerConfiguration() {
|
||||
linearized: document.getElementById("linearizedField"),
|
||||
},
|
||||
},
|
||||
annotationEditorParams: {
|
||||
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
||||
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
||||
editorInkColor: document.getElementById("editorInkColor"),
|
||||
editorInkThickness: document.getElementById("editorInkThickness"),
|
||||
},
|
||||
errorWrapper,
|
||||
printContainer: document.getElementById("printContainer"),
|
||||
openFileInput:
|
||||
|
Loading…
Reference in New Issue
Block a user