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

[Editor] Populate the 'Add signature' menu with the saved signatures (bug 1947828)

This commit is contained in:
Calixte Denizet 2025-02-12 19:29:16 +01:00
parent d6f63d0e4b
commit 68451fe17e
15 changed files with 474 additions and 67 deletions

View file

@ -320,6 +320,9 @@ pdfjs-highlight-floating-button1 =
.title = Highlight
.aria-label = Highlight
pdfjs-highlight-floating-button-label = Highlight
pdfjs-editor-signature-button =
.title = Add signature
pdfjs-editor-signature-button-label = Add signature
## Remove button for the various kind of editor.
@ -349,6 +352,9 @@ pdfjs-editor-stamp-add-image-button-label = Add image
pdfjs-editor-free-highlight-thickness-input = Thickness
pdfjs-editor-free-highlight-thickness-title =
.title = Change thickness when highlighting items other than text
pdfjs-editor-signature-add-signature-button =
.title = Add new signature
pdfjs-editor-signature-add-signature-button-label = Add new signature
# .default-content is used as a placeholder in an empty text editor.
pdfjs-free-text2 =
@ -585,3 +591,9 @@ pdfjs-editor-add-signature-error-close-button = Close
pdfjs-editor-add-signature-cancel-button = Cancel
pdfjs-editor-add-signature-add-button = Add
## Main menu for adding/removing signatures
pdfjs-editor-delete-signature-button =
.title = Remove signature
pdfjs-editor-delete-signature-button-label = Remove signature

View file

@ -698,8 +698,12 @@ class AnnotationEditorLayer {
/**
* Create and add a new editor.
*/
addNewEditor() {
this.createAndAddNewEditor(this.#getCenterPoint(), /* isCentered = */ true);
addNewEditor(data = {}) {
this.createAndAddNewEditor(
this.#getCenterPoint(),
/* isCentered = */ true,
data
);
}
/**

View file

@ -784,7 +784,7 @@ class SignatureExtractor {
let data = null;
let offset = 0;
for await (const chunk of readable) {
data ||= new Uint8Array(new Uint32Array(chunk.buffer)[0]);
data ||= new Uint8Array(new Uint32Array(chunk.buffer, 0, 4)[0]);
data.set(chunk, offset);
offset += chunk.length;
}

View file

@ -26,7 +26,7 @@ class SignatureOptions extends DrawingOptions {
super();
super.updateProperties({
fill: "black",
fill: "CanvasText",
"stroke-width": 0,
});
}
@ -43,7 +43,7 @@ class DrawnSignatureOptions extends InkDrawingOptions {
super(viewerParameters);
super.updateProperties({
stroke: "black",
stroke: "CanvasText",
"stroke-width": 1,
});
}
@ -62,6 +62,12 @@ class DrawnSignatureOptions extends InkDrawingOptions {
class SignatureEditor extends DrawingEditor {
#isExtracted = false;
#signatureData = null;
#description = null;
#signatureUUID = null;
static _type = "signature";
static _editorType = AnnotationEditorType.SIGNATURE;
@ -71,8 +77,7 @@ class SignatureEditor extends DrawingEditor {
constructor(params) {
super({ ...params, mustBeCommitted: true, name: "signatureEditor" });
this._willKeepAspectRatio = true;
this._description = "";
this._signatureUUID = null;
this.#signatureData = params.signatureData || null;
}
/** @inheritdoc */
@ -128,17 +133,52 @@ class SignatureEditor extends DrawingEditor {
this.div.setAttribute("role", "figure");
if (this._drawId === null) {
this.div.hidden = true;
this._uiManager.getSignature(this);
if (this.#signatureData) {
const {
lines,
mustSmooth,
areContours,
description,
uuid,
heightInPage,
} = this.#signatureData;
const {
rawDims: { pageWidth, pageHeight },
rotation,
} = this.parent.viewport;
const outline = SignatureExtractor.processDrawnLines({
lines,
pageWidth,
pageHeight,
rotation,
innerMargin: SignatureEditor._INNER_MARGIN,
mustSmooth,
areContours,
});
this.#signatureData = null;
this.#signatureUUID = uuid;
this.addSignature(outline.outline, heightInPage, description);
} else {
this.div.hidden = true;
this._uiManager.getSignature(this);
}
}
return this.div;
}
setUuid(uuid) {
this.#signatureUUID = uuid;
}
setDescription(description) {
this.#description = description;
}
addSignature(outline, heightInPage, description) {
const { x: savedX, y: savedY } = this;
this.#isExtracted = outline instanceof ContourDrawOutline;
this._description = description;
this.#description = description;
let drawingOptions;
if (this.#isExtracted) {
drawingOptions = SignatureEditor.getDefaultDrawingOptions();
@ -251,11 +291,12 @@ class SignatureEditor extends DrawingEditor {
};
if (isForCopying) {
serialized.paths = { lines, points };
serialized.uuid = this.#signatureUUID;
} else {
serialized.lines = lines;
}
if (this._description) {
serialized.accessibilityData = { type: "Figure", alt: this._description };
if (this.#description) {
serialized.accessibilityData = { type: "Figure", alt: this.#description };
}
return serialized;
}
@ -294,7 +335,8 @@ class SignatureEditor extends DrawingEditor {
static async deserialize(data, parent, uiManager) {
const editor = await super.deserialize(data, parent, uiManager);
editor.#isExtracted = data.areContours;
editor._description = data.accessibilityData?.alt || "";
editor.#description = data.accessibilityData?.alt || "";
editor.#signatureUUID = data.uuid;
return editor;
}
}

View file

@ -1698,6 +1698,9 @@ class AnnotationEditorUIManager {
this.#updateModeCapability.resolve();
return;
}
if (mode === AnnotationEditorType.SIGNATURE) {
await this.#signatureManager?.loadSignatures();
}
this.setEditingState(true);
await this.#enableAll();
this.unselectAll();
@ -1758,7 +1761,7 @@ class AnnotationEditorUIManager {
switch (type) {
case AnnotationEditorParamsType.CREATE:
this.currentLayer.addNewEditor();
this.currentLayer.addNewEditor(value);
return;
case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
this.#mainHighlightColorPicker?.updateColor(value);

View file

@ -465,9 +465,12 @@ const PDFViewerApplication = {
AppOptions.get("enableSignatureEditor") && appConfig.addSignatureDialog
? new SignatureManager(
appConfig.addSignatureDialog,
appConfig.annotationEditorParams?.editorSignatureAddSignature ||
null,
this.overlayManager,
this.l10n,
externalServices.createSignatureStorage()
l10n,
externalServices.createSignatureStorage(),
eventBus
)
: null;

View file

@ -20,8 +20,6 @@
--text-primary-color: #15141a;
--text-secondary-color: #5b5b66;
--hover-filter: brightness(0.9);
--focus-ring-color: #0060df;
--focus-ring-outline: 2px solid var(--focus-ring-color);
--link-fg-color: #0060df;
--link-hover-fg-color: #0250bb;
--separator-color: #f0f0f4;
@ -58,7 +56,6 @@
--dialog-shadow: 0 2px 14px 0 #15141a;
--text-primary-color: #fbfbfe;
--text-secondary-color: #cfcfd8;
--focus-ring-color: #0df;
--hover-filter: brightness(1.4);
--link-fg-color: #0df;
--link-hover-fg-color: #80ebff;
@ -82,7 +79,6 @@
--text-primary-color: CanvasText;
--text-secondary-color: CanvasText;
--hover-filter: none;
--focus-ring-color: ButtonBorder;
--link-fg-color: LinkText;
--link-hover-fg-color: LinkText;
--separator-color: CanvasText;

View file

@ -504,11 +504,11 @@ class SignatureStorage {
async getAll() {
if (!this.#signatures) {
this.#signatures = Object.create(null);
this.#signatures = new Map();
const data = await this.#handleSignature({ action: "get" });
if (data) {
for (const { uuid, description, signatureData } of data) {
this.#signatures[uuid] = { description, signatureData };
this.#signatures.set(uuid, { description, signatureData });
}
}
}
@ -517,7 +517,7 @@ class SignatureStorage {
async isFull() {
// We want to store at most 5 signatures.
return Object.keys(await this.getAll()).length === 5;
return (await this.getAll()).size === 5;
}
async create(data) {
@ -531,17 +531,17 @@ class SignatureStorage {
if (!uuid) {
return null;
}
this.#signatures[uuid] = data;
this.#signatures.set(uuid, data);
return uuid;
}
async delete(uuid) {
const signatures = await this.getAll();
if (!signatures[uuid]) {
if (!signatures.has(uuid)) {
return false;
}
if (await this.#handleSignature({ action: "delete", uuid })) {
delete signatures[uuid];
signatures.delete(uuid);
return true;
}
return false;
@ -549,7 +549,7 @@ class SignatureStorage {
async update(uuid, data) {
const signatures = await this.getAll();
const oldData = signatures[uuid];
const oldData = signatures.get(uuid);
if (!oldData) {
return false;
}

View file

@ -23,19 +23,28 @@ class SignatureStorage {
#signatures = null;
#save() {
localStorage.setItem("pdfjs.signature", JSON.stringify(this.#signatures));
localStorage.setItem(
"pdfjs.signature",
JSON.stringify(Object.fromEntries(this.#signatures.entries()))
);
}
async getAll() {
if (!this.#signatures) {
this.#signatures = new Map();
const data = localStorage.getItem("pdfjs.signature");
this.#signatures = data ? JSON.parse(data) : Object.create(null);
if (data) {
for (const [key, value] of Object.entries(JSON.parse(data))) {
this.#signatures.set(key, value);
}
}
}
return this.#signatures;
}
async isFull() {
return Object.keys(await this.getAll()).length === 5;
// Only allow 5 signatures to be saved.
return (await this.getAll()).size === 5;
}
async create(data) {
@ -43,7 +52,7 @@ class SignatureStorage {
return null;
}
const uuid = getUuid();
this.#signatures[uuid] = data;
this.#signatures.set(uuid, data);
this.#save();
return uuid;
@ -51,10 +60,10 @@ class SignatureStorage {
async delete(uuid) {
const signatures = await this.getAll();
if (!signatures[uuid]) {
if (!signatures.has(uuid)) {
return false;
}
delete signatures[uuid];
signatures.delete(uuid);
this.#save();
return true;
@ -62,7 +71,7 @@ class SignatureStorage {
async update(uuid, data) {
const signatures = await this.getAll();
const oldData = signatures[uuid];
const oldData = signatures.get(uuid);
if (!oldData) {
return false;
}

View file

@ -143,9 +143,6 @@
--undo-button-fg-color-hover: var(--undo-button-fg-color);
--undo-button-fg-color-active: var(--undo-button-fg-color);
--focus-ring-color: #0060df;
--focus-ring-outline: 2px solid var(--focus-ring-color);
@media (prefers-color-scheme: dark) {
--text-primary-color: #fbfbfe;
@ -172,8 +169,6 @@
--undo-button-fg-color: ButtonFace;
--undo-button-fg-color-hover: SelectedItemText;
--undo-button-fg-color-active: SelectedItemText;
--focus-ring-color: CanvasText;
}
position: fixed;

View file

@ -27,14 +27,19 @@
--page-border: 9px solid transparent;
--spreadHorizontalWrapped-margin-LR: -3.5px;
--loading-icon-delay: 400ms;
}
--focus-ring-color: #0060df;
--focus-ring-outline: 2px solid var(--focus-ring-color);
@media screen and (forced-colors: active) {
:root {
@media (prefers-color-scheme: dark) {
--focus-ring-color: #0df;
}
@media screen and (forced-colors: active) {
--pdfViewer-padding-bottom: 9px;
--page-margin: 8px auto -1px;
--page-border: 1px solid CanvasText;
--spreadHorizontalWrapped-margin-LR: 3.5px;
--focus-ring-color: CanvasText;
}
}

View file

@ -933,9 +933,7 @@ class PDFViewer {
uiManager: this.#annotationEditorUIManager,
});
if (mode !== AnnotationEditorType.NONE) {
if (mode === AnnotationEditorType.STAMP) {
this.#mlManager?.loadModel("altText");
}
this.#preloadEditingData(mode);
this.#annotationEditorUIManager.updateMode(mode);
}
} else {
@ -2315,6 +2313,18 @@ class PDFViewer {
}
}
#preloadEditingData(mode) {
switch (mode) {
case AnnotationEditorType.STAMP:
this.#mlManager?.loadModel("altText");
break;
case AnnotationEditorType.SIGNATURE:
// Start to load the signature data.
this.#signatureManager?.loadSignatures();
break;
}
}
get annotationEditorMode() {
return this.#annotationEditorUIManager
? this.#annotationEditorMode
@ -2345,9 +2355,7 @@ class PDFViewer {
if (!this.pdfDocument) {
return;
}
if (mode === AnnotationEditorType.STAMP) {
this.#mlManager?.loadModel("altText");
}
this.#preloadEditingData(mode);
const { eventBus, pdfDocument } = this;
const updater = async () => {

View file

@ -13,6 +13,39 @@
* limitations under the License.
*/
:root {
--clear-signature-button-icon: url(images/editor-toolbar-delete.svg);
--signature-bg: #f9f9fb;
--signature-hover-bg: #f0f0f4;
--button-signature-bg: transparent;
--button-signature-color: var(--main-color);
--button-signature-active-bg: #cfcfd8;
--button-signature-active-border: none;
--button-signature-active-color: var(--button-signature-color);
--button-signature-border: none;
--button-signature-hover-bg: #e0e0e6;
--button-signature-hover-color: var(--button-signature-color);
@media (prefers-color-scheme: dark) {
--signature-bg: #2b2a33;
--signature-hover-bg: var(--signature-bg);
--button-signature-active-bg: #5b5b66;
--button-signature-hover-bg: #52525e;
}
@media screen and (forced-colors: active) {
--signature-bg: HighlightText;
--signature-hover-bg: var(--signature-bg);
--button-signature-bg: HighlightText;
--button-signature-color: ButtonText;
--button-signature-active-bg: ButtonText;
--button-signature-active-color: HighlightText;
--button-signature-border: 1px solid ButtonText;
--button-signature-hover-bg: Highlight;
--button-signature-hover-color: HighlightText;
}
}
#addSignatureDialog {
--border-color: #8f8f9d;
--primary-color: var(--text-primary-color);
@ -31,8 +64,8 @@
--tab-bg-hover: var(--bg-hover);
--tab-text-color: var(--primary-color);
--tab-text-active-color: var(--tab-top-line-active-color);
--tab-text-active-hover-color: var(--tab-text-hover-color);
--tab-text-hover-color: var(--tab-text-color);
--signature-bg: #f9f9fb;
--signature-placeholder-color: var(--secondary-color);
--signature-draw-placeholder-color: var(--primary-color);
--signature-color: var(--primary-color);
@ -43,7 +76,6 @@
--clear-signature-button-border-style: solid;
--clear-signature-button-border-color: transparent;
--clear-signature-button-border-disabled-color: transparent;
--clear-signature-button-icon: url(images/editor-toolbar-delete.svg);
--clear-signature-button-color: var(--primary-color);
--clear-signature-button-hover-color: var(--clear-signature-button-color);
--clear-signature-button-active-color: var(--clear-signature-button-color);
@ -72,7 +104,6 @@
--secondary-color: #cfcfd8;
--tab-top-line-active-color: #0df;
--tab-top-line-inactive-color: #8f8f9d;
--signature-bg: #2b2a33;
--clear-signature-button-bg-active: #5b5b66;
--clear-signature-button-bg-focus: #2b2a33;
--clear-signature-button-bg-disabled: color-mix(
@ -99,8 +130,8 @@
--tab-bg-active-hover-color: SelectedItem;
--tab-text-color: ButtonText;
--tab-text-active-color: HighlightText;
--tab-text-active-hover-color: HighlightText;
--tab-text-hover-color: SelectedItem;
--signature-bg: var(--bg);
--signature-color: ButtonText;
--clear-signature-button-border-width: 1px;
--clear-signature-button-border-style: solid;
@ -214,7 +245,7 @@
&:hover {
border-block-start-color: var(--tab-top-line-active-hover-color);
background-color: var(--tab-bg-active-hover-color);
color: var(--tab-text-hover-color);
color: var(--tab-text-active-hover-color);
}
}
}
@ -594,3 +625,138 @@
}
}
}
#editorSignatureParamsToolbar {
padding: 10px;
#addSignatureDoorHanger {
gap: 8px;
overflow-y: unset;
.toolbarAddSignatureButtonContainer {
height: 32px;
display: flex;
justify-content: space-between;
align-items: center;
align-self: stretch;
gap: 8px;
button {
border: var(--button-signature-border);
border-radius: 4px;
background-color: var(--button-signature-bg);
color: var(--button-signature-color);
&:hover {
background-color: var(--button-signature-hover-bg);
}
&:active {
border: var(--button-signature-active-border);
background-color: var(--button-signature-active-bg);
color: var(--button-signature-active-color);
&::before {
background-color: var(--button-signature-active-color);
}
}
&:focus-visible {
outline: var(--focus-ring-outline);
&::before {
background-color: var(--button-signature-color);
}
}
}
.deleteButton {
&::before {
mask-image: var(--clear-signature-button-icon);
}
}
.toolbarAddSignatureButton {
width: auto;
height: 100%;
min-height: var(--menuitem-height);
aspect-ratio: unset;
display: flex;
align-items: center;
justify-content: flex-start;
outline: none;
border-radius: 4px;
box-sizing: border-box;
font: message-box;
position: relative;
flex: 1 1 auto;
padding: 0;
gap: 8px;
text-align: start;
white-space: normal;
cursor: default;
overflow: hidden;
> svg {
display: inline-block;
height: 100%;
aspect-ratio: 1;
background-color: var(--signature-bg);
flex: none;
padding: 4px;
box-sizing: border-box;
border: none;
border-radius: 4px;
> path {
stroke: var(--button-signature-color);
stroke-width: 1px;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 10;
vector-effect: non-scaling-stroke;
fill: none;
}
&.contours > path {
fill: var(--button-signature-color);
stroke-width: 0.5px;
}
}
&:is(:hover, :active) > svg {
border-radius: 4px 0 0 4px;
background-color: var(--signature-hover-bg);
}
&:hover {
> span {
color: var(--button-signature-hover-color);
}
}
&:active {
background-color: var(--button-signature-active-bg);
}
&:is([disabled="disabled"], [disabled]) {
opacity: 0.5;
pointer-events: none;
}
> span {
height: auto;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
font: menu;
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: normal;
overflow: hidden;
}
}
}
}
}

View file

@ -14,6 +14,7 @@
*/
import {
AnnotationEditorParamsType,
DOMSVGFactory,
noContextMenu,
SignatureExtractor,
@ -21,6 +22,9 @@ import {
SupportedImageMimeTypes,
} from "pdfjs-lib";
// Default height of the added signature in page coordinates.
const DEFAULT_HEIGHT_IN_PAGE = 40;
class SignatureManager {
#addButton;
@ -70,6 +74,10 @@ class SignatureManager {
#tabButtons;
#addSignatureToolbarButton;
#loadSignaturesPromise = null;
#typeInput;
#currentTab = null;
@ -78,6 +86,8 @@ class SignatureManager {
#hasDescriptionChanged = false;
#eventBus;
#l10n;
#overlayManager;
@ -113,9 +123,11 @@ class SignatureManager {
saveCheckbox,
saveContainer,
},
addSignatureToolbarButton,
overlayManager,
l10n,
signatureStorage
signatureStorage,
eventBus
) {
this.#addButton = addButton;
this.#clearButton = clearButton;
@ -133,9 +145,11 @@ class SignatureManager {
this.#overlayManager = overlayManager;
this.#saveCheckbox = saveCheckbox;
this.#saveContainer = saveContainer;
this.#addSignatureToolbarButton = addSignatureToolbarButton;
this.#typeInput = typeInput;
this.#l10n = l10n;
this.#signatureStorage = signatureStorage;
this.#eventBus = eventBus;
SignatureManager.#l10nDescription ||= Object.freeze({
signature: "pdfjs-editor-add-signature-description-default-when-drawing",
@ -360,7 +374,7 @@ class SignatureManager {
this.#drawCurves = {
width: drawWidth,
height: drawHeight,
thickness: this.#drawThickness.value,
thickness: parseInt(this.#drawThickness.value),
curves: [],
};
this.#disableButtons(true);
@ -610,10 +624,147 @@ class SignatureManager {
);
}
#addToolbarButton(signatureData, uuid, description) {
const { curves, areContours, thickness, width, height } = signatureData;
const maxDim = Math.max(width, height);
const outlineData = SignatureExtractor.processDrawnLines({
lines: {
curves,
thickness,
width,
height,
},
pageWidth: maxDim,
pageHeight: maxDim,
rotation: 0,
innerMargin: 0,
mustSmooth: false,
areContours,
});
if (!outlineData) {
return;
}
const { outline } = outlineData;
const svgFactory = new DOMSVGFactory();
const div = document.createElement("div");
const button = document.createElement("button");
button.addEventListener("click", () => {
this.#eventBus.dispatch("switchannotationeditorparams", {
source: this,
type: AnnotationEditorParamsType.CREATE,
value: {
signatureData: {
lines: {
curves,
thickness,
width,
height,
},
mustSmooth: false,
areContours,
description,
uuid,
heightInPage: DEFAULT_HEIGHT_IN_PAGE,
},
},
});
});
div.append(button);
div.classList.add("toolbarAddSignatureButtonContainer");
const svg = svgFactory.create(1, 1, true);
button.append(svg);
const span = document.createElement("span");
button.append(span);
button.classList.add("toolbarAddSignatureButton");
button.type = "button";
button.title = span.textContent = description;
button.tabIndex = 0;
const path = svgFactory.createElement("path");
svg.append(path);
svg.setAttribute("viewBox", outline.viewBox);
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
if (areContours) {
svg.classList.add("contours");
}
path.setAttribute("d", outline.toSVGPath());
const deleteButton = document.createElement("button");
div.append(deleteButton);
deleteButton.classList.add("toolbarButton", "deleteButton");
deleteButton.setAttribute(
"data-l10n-id",
"pdfjs-editor-delete-signature-button"
);
deleteButton.type = "button";
deleteButton.tabIndex = 0;
deleteButton.addEventListener("click", async () => {
if (await this.#signatureStorage.delete(uuid)) {
div.remove();
}
});
const deleteSpan = document.createElement("span");
deleteButton.append(deleteSpan);
deleteSpan.setAttribute(
"data-l10n-id",
"pdfjs-editor-delete-signature-button-label"
);
this.#addSignatureToolbarButton.before(div);
}
getSignature(params) {
return this.open(params);
}
async loadSignatures() {
if (
!this.#addSignatureToolbarButton ||
this.#addSignatureToolbarButton.previousElementSibling ||
!this.#signatureStorage
) {
return;
}
if (!this.#loadSignaturesPromise) {
// The first call of loadSignatures() starts loading the signatures.
// The second one will wait until the signatures are loaded in the DOM.
this.#loadSignaturesPromise = this.#signatureStorage
.getAll()
.then(async signatures => [
signatures,
await Promise.all(
Array.from(
signatures
.values()
.map(({ signatureData }) =>
SignatureExtractor.decompressSignature(signatureData)
)
)
),
]);
return;
}
const [signatures, signaturesData] = await this.#loadSignaturesPromise;
this.#loadSignaturesPromise = null;
let i = 0;
for (const [uuid, { description }] of signatures) {
const data = signaturesData[i++];
if (!data) {
continue;
}
data.curves = data.outlines.map(points => ({ points }));
delete data.outlines;
this.#addToolbarButton(data, uuid, description);
}
}
async open({ uiManager, editor }) {
this.#tabsToAltText ||= new Map(
this.#tabButtons.keys().map(name => [name, ""])
@ -677,9 +828,10 @@ class SignatureManager {
}
this.#currentEditor.addSignature(
data.outline,
/* heightInPage */ 40,
DEFAULT_HEIGHT_IN_PAGE,
this.#description.value
);
let uuid = null;
if (this.#saveCheckbox.checked) {
const description = this.#description.value;
const { newCurves, areContours, thickness, width, height } = data;
@ -690,15 +842,27 @@ class SignatureManager {
width,
height,
});
const uuid = (this.#currentEditor._signatureUUID =
await this.#signatureStorage.create({
description,
signatureData,
}));
if (!uuid) {
uuid = await this.#signatureStorage.create({
description,
signatureData,
});
if (uuid) {
this.#addToolbarButton(
{
curves: newCurves.map(points => ({ points })),
areContours,
thickness,
width,
height,
},
uuid,
description
);
} else {
console.warn("SignatureManager.add: cannot save the signature.");
}
}
this.#currentEditor.setUuid(uuid);
this.#finish();
}

View file

@ -245,13 +245,13 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="toolbarViewerRight" class="toolbarHorizontalGroup">
<div id="editorModeButtons" class="toolbarHorizontalGroup" role="radiogroup">
<div id="editorSignature" class="toolbarButtonWithContainer" hidden="true">
<button id="editorSignatureButton" class="toolbarButton" type="button" disabled="disabled" title="Add or edit signatures" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorSignatureParamsToolbar" tabindex="0">
<span>Add or edit signatures</span>
<button id="editorSignatureButton" class="toolbarButton" type="button" disabled="disabled" title="Add signature" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorSignatureParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-signature-button">
<span data-l10n-id="pdfjs-editor-signature-button-label">Add signature</span>
</button>
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorSignatureParamsToolbar">
<div class="menuContainer">
<button id="editorSignatureAddSignature" class="toolbarButton labeled" type="button" title="Add signature" tabindex="0">
<span class="editorParamsLabel">Add signature</span>
<div id="addSignatureDoorHanger" class="menuContainer">
<button id="editorSignatureAddSignature" class="toolbarButton labeled" type="button" title="Add new signature" tabindex="0" data-l10n-id="pdfjs-editor-signature-add-signature-button">
<span data-l10n-id="pdfjs-editor-signature-add-signature-button-label" class="editorParamsLabel">Add new signature</span>
</button>
</div>
</div>