diff --git a/l10n/en-US/viewer.ftl b/l10n/en-US/viewer.ftl index c448db888..e8c32ae45 100644 --- a/l10n/en-US/viewer.ftl +++ b/l10n/en-US/viewer.ftl @@ -597,3 +597,15 @@ pdfjs-editor-add-signature-add-button = Add pdfjs-editor-delete-signature-button = .title = Remove signature pdfjs-editor-delete-signature-button-label = Remove signature + +## Editor toolbar + +pdfjs-editor-add-signature-edit-button-label = Edit description + +## Edit signature description dialog + +pdfjs-editor-edit-signature-dialog-title = Edit description + +## Dialog buttons + +pdfjs-editor-edit-signature-update-button = Update diff --git a/src/display/editor/drawers/signaturedraw.js b/src/display/editor/drawers/signaturedraw.js index 5fa0e864b..1118421da 100644 --- a/src/display/editor/drawers/signaturedraw.js +++ b/src/display/editor/drawers/signaturedraw.js @@ -606,7 +606,8 @@ class SignatureExtractor { [pageWidth, pageHeight] = [pageHeight, pageWidth]; } - const { curves, thickness, width, height } = lines; + const { curves, width, height } = lines; + const thickness = lines.thickness ?? 0; const linesAndPoints = []; const ratio = Math.min(pageWidth / width, pageHeight / height); const xScale = ratio / pageWidth; diff --git a/src/display/editor/signature.js b/src/display/editor/signature.js index fdf894489..bdcbf4523 100644 --- a/src/display/editor/signature.js +++ b/src/display/editor/signature.js @@ -62,10 +62,10 @@ class DrawnSignatureOptions extends InkDrawingOptions { class SignatureEditor extends DrawingEditor { #isExtracted = false; - #signatureData = null; - #description = null; + #signatureData = null; + #signatureUUID = null; static _type = "signature"; @@ -78,6 +78,7 @@ class SignatureEditor extends DrawingEditor { super({ ...params, mustBeCommitted: true, name: "signatureEditor" }); this._willKeepAspectRatio = true; this.#signatureData = params.signatureData || null; + this.#description = null; } /** @inheritdoc */ @@ -155,9 +156,7 @@ class SignatureEditor extends DrawingEditor { mustSmooth, areContours, }); - this.#signatureData = null; - this.#signatureUUID = uuid; - this.addSignature(outline.outline, heightInPage, description); + this.addSignature(outline, heightInPage, description, uuid); } else { this.div.hidden = true; this._uiManager.getSignature(this); @@ -169,14 +168,65 @@ class SignatureEditor extends DrawingEditor { setUuid(uuid) { this.#signatureUUID = uuid; + this.addEditToolbar(); } - setDescription(description) { + getUuid() { + return this.#signatureUUID; + } + + get description() { + return this.#description; + } + + set description(description) { this.#description = description; + super.addEditToolbar().then(toolbar => { + toolbar?.updateEditSignatureButton(description); + }); } - addSignature(outline, heightInPage, description) { + getSignaturePreview() { + const { newCurves, areContours, thickness, width, height } = + this.#signatureData; + const maxDim = Math.max(width, height); + const outlineData = SignatureExtractor.processDrawnLines({ + lines: { + curves: newCurves.map(points => ({ points })), + thickness, + width, + height, + }, + pageWidth: maxDim, + pageHeight: maxDim, + rotation: 0, + innerMargin: 0, + mustSmooth: false, + areContours, + }); + return { areContours, outline: outlineData.outline }; + } + + /** @inheritdoc */ + async addEditToolbar() { + const toolbar = await super.addEditToolbar(); + if (!toolbar) { + return null; + } + if (this._uiManager.signatureManager && this.#description !== null) { + await toolbar.addEditSignatureButton( + this._uiManager.signatureManager, + this.#signatureUUID, + this.#description + ); + toolbar.show(); + } + return toolbar; + } + + addSignature(data, heightInPage, description, uuid) { const { x: savedX, y: savedY } = this; + const { outline } = (this.#signatureData = data); this.#isExtracted = outline instanceof ContourDrawOutline; this.#description = description; let drawingOptions; @@ -208,6 +258,7 @@ class SignatureEditor extends DrawingEditor { this.onScaleChanging(); this.rotate(); this._uiManager.addToAnnotationStorage(this); + this.setUuid(uuid); this.div.hidden = false; } @@ -335,7 +386,7 @@ 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; } diff --git a/src/display/editor/toolbar.js b/src/display/editor/toolbar.js index 24cd47d1b..715a4b820 100644 --- a/src/display/editor/toolbar.js +++ b/src/display/editor/toolbar.js @@ -26,6 +26,8 @@ class EditorToolbar { #altText = null; + #signatureDescriptionButton = null; + static #l10nRemove = null; constructor(editor) { @@ -154,6 +156,19 @@ class EditorToolbar { this.#buttons.prepend(button, this.#divider); } + async addEditSignatureButton(signatureManager) { + const button = (this.#signatureDescriptionButton = + await signatureManager.renderEditButton(this.#editor)); + this.#addListenersToElement(button); + this.#buttons.prepend(button, this.#divider); + } + + updateEditSignatureButton(description) { + if (this.#signatureDescriptionButton) { + this.#signatureDescriptionButton.title = description; + } + } + remove() { this.#toolbar.remove(); this.#colorPicker?.destroy(); diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index cb9310e60..06a501700 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -1012,6 +1012,10 @@ class AnnotationEditorUIManager { this.#signatureManager?.getSignature({ uiManager: this, editor }); } + get signatureManager() { + return this.#signatureManager; + } + switchToMode(mode, callback) { // Switching to a mode can be asynchronous. this._eventBus.on("annotationeditormodechanged", callback, { diff --git a/web/app.js b/web/app.js index 394425a4a..b84251bc4 100644 --- a/web/app.js +++ b/web/app.js @@ -465,11 +465,15 @@ const PDFViewerApplication = { AppOptions.get("enableSignatureEditor") && appConfig.addSignatureDialog ? new SignatureManager( appConfig.addSignatureDialog, + appConfig.editSignatureDialog, appConfig.annotationEditorParams?.editorSignatureAddSignature || null, this.overlayManager, l10n, - externalServices.createSignatureStorage(), + externalServices.createSignatureStorage( + eventBus, + this._globalAbortController.signal + ), eventBus ) : null; diff --git a/web/chromecom.js b/web/chromecom.js index c66734a87..6129fa2dd 100644 --- a/web/chromecom.js +++ b/web/chromecom.js @@ -422,8 +422,8 @@ class ExternalServices extends BaseExternalServices { return new GenericScripting(AppOptions.get("sandboxBundleSrc")); } - createSignatureStorage() { - return new SignatureStorage(); + createSignatureStorage(eventBus, signal) { + return new SignatureStorage(eventBus, signal); } } diff --git a/web/dialog.css b/web/dialog.css index 0170f9cb2..e45b6a846 100644 --- a/web/dialog.css +++ b/web/dialog.css @@ -201,7 +201,7 @@ } } - button:not(:is(.toggle-button, .closeButton)) { + button:not(:is(.toggle-button, .closeButton, .clearInputButton)) { border-radius: 4px; border: 1px solid; font: menu; diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 536172a5c..72f246ac2 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -496,13 +496,33 @@ class MLManager { } class SignatureStorage { + #eventBus = null; + #signatures = null; + #signal = null; + + constructor(eventBus, signal) { + this.#eventBus = eventBus; + this.#signal = signal; + } + #handleSignature(data) { return FirefoxCom.requestAsync("handleSignature", data); } async getAll() { + if (this.#signal) { + window.addEventListener( + "storedSignaturesChanged", + () => { + this.#signatures = null; + this.#eventBus?.dispatch("storedsignatureschanged", { source: this }); + }, + { signal: this.#signal } + ); + this.#signal = null; + } if (!this.#signatures) { this.#signatures = new Map(); const data = await this.#handleSignature({ action: "get" }); @@ -546,19 +566,6 @@ class SignatureStorage { } return false; } - - async update(uuid, data) { - const signatures = await this.getAll(); - const oldData = signatures.get(uuid); - if (!oldData) { - return false; - } - if (await this.#handleSignature({ action: "update", uuid, ...data })) { - Object.assign(oldData, data); - return true; - } - return false; - } } class ExternalServices extends BaseExternalServices { @@ -647,8 +654,8 @@ class ExternalServices extends BaseExternalServices { return FirefoxScripting; } - createSignatureStorage() { - return new SignatureStorage(); + createSignatureStorage(eventBus, signal) { + return new SignatureStorage(eventBus, signal); } dispatchGlobalEvent(event) { diff --git a/web/generic_signature_storage.js b/web/generic_signature_storage.js index bfd11ac0e..da1993346 100644 --- a/web/generic_signature_storage.js +++ b/web/generic_signature_storage.js @@ -15,24 +15,50 @@ import { getUuid } from "pdfjs-lib"; +const KEY_STORAGE = "pdfjs.signature"; + class SignatureStorage { // TODO: Encrypt the data in using a password and add a UI for entering it. // We could use the Web Crypto API for this (see https://bradyjoslin.com/blog/encryption-webcrypto/ // for an example). + #eventBus; + #signatures = null; + #signal = null; + + constructor(eventBus, signal) { + this.#eventBus = eventBus; + this.#signal = signal; + } + #save() { localStorage.setItem( - "pdfjs.signature", + KEY_STORAGE, JSON.stringify(Object.fromEntries(this.#signatures.entries())) ); } async getAll() { + if (this.#signal) { + window.addEventListener( + "storage", + ({ key }) => { + if (key === KEY_STORAGE) { + this.#signatures = null; + this.#eventBus?.dispatch("storedsignatureschanged", { + source: this, + }); + } + }, + { signal: this.#signal } + ); + this.#signal = null; + } if (!this.#signatures) { this.#signatures = new Map(); - const data = localStorage.getItem("pdfjs.signature"); + const data = localStorage.getItem(KEY_STORAGE); if (data) { for (const [key, value] of Object.entries(JSON.parse(data))) { this.#signatures.set(key, value); @@ -68,18 +94,6 @@ class SignatureStorage { return true; } - - async update(uuid, data) { - const signatures = await this.getAll(); - const oldData = signatures.get(uuid); - if (!oldData) { - return false; - } - Object.assign(oldData, data); - this.#save(); - - return true; - } } export { SignatureStorage }; diff --git a/web/genericcom.js b/web/genericcom.js index 9cdf38d23..8e57bfc6c 100644 --- a/web/genericcom.js +++ b/web/genericcom.js @@ -47,8 +47,8 @@ class ExternalServices extends BaseExternalServices { return new GenericScripting(AppOptions.get("sandboxBundleSrc")); } - createSignatureStorage() { - return new SignatureStorage(); + createSignatureStorage(eventBus, signal) { + return new SignatureStorage(eventBus, signal); } } diff --git a/web/images/editor-toolbar-edit.svg b/web/images/editor-toolbar-edit.svg new file mode 100644 index 000000000..692de38d3 --- /dev/null +++ b/web/images/editor-toolbar-edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/signature_manager.css b/web/signature_manager.css index 810e6bc19..b05354609 100644 --- a/web/signature_manager.css +++ b/web/signature_manager.css @@ -46,9 +46,80 @@ } } -#addSignatureDialog { - --border-color: #8f8f9d; +.signatureDialog { --primary-color: var(--text-primary-color); + --description-input-color: var(--primary-color); + --border-color: #8f8f9d; + + @media screen and (forced-colors: active) { + --primary-color: ButtonText; + --border-color: ButtonText; + } + + width: 570px; + max-width: 100%; + min-width: 300px; + padding: 16px 0; + + .mainContainer { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 12px; + + span:not([role="sectionhead"]) { + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: normal; + } + + .title { + margin-inline-start: 16px; + } + } + + .inputWithClearButton { + --button-dimension: 24px; + + --closing-button-icon: url(images/messageBar_closingButton.svg); + --closing-button-color: var(--primary-color); + + width: 100%; + position: relative; + display: flex; + align-items: center; + justify-content: center; + + > input { + width: 100%; + height: 32px; + padding-inline: 8px calc(4px + var(--button-dimension)); + box-sizing: border-box; + background-color: transparent; + border-radius: 4px; + border: 1px solid var(--border-color); + color: var(--description-input-color); + } + + .clearInputButton { + position: absolute; + inset-block-start: 4px; + inset-inline-end: 4px; + display: inline-block; + width: var(--button-dimension); + height: var(--button-dimension); + background-color: var(--closing-button-color); + mask-size: cover; + mask-image: var(--closing-button-icon); + padding: 0; + border: 0; + } + } +} + +#addSignatureDialog { --secondary-color: var(--text-secondary-color); --bg-hover: #e0e0e6; --tab-top-line-active-color: #0060df; @@ -69,9 +140,6 @@ --signature-placeholder-color: var(--secondary-color); --signature-draw-placeholder-color: var(--primary-color); --signature-color: var(--primary-color); - --closing-button-icon: url(images/messageBar_closingButton.svg); - --closing-button-color: var(--primary-color); - --description-input-color: var(--primary-color); --clear-signature-button-border-width: 0; --clear-signature-button-border-style: solid; --clear-signature-button-border-color: transparent; @@ -114,11 +182,9 @@ } @media screen and (forced-colors: active) { - --primary-color: ButtonText; --secondary-color: ButtonText; --bg: HighlightText; --bg-hover: var(--bg); - --border-color: ButtonText; --tab-top-line-active-color: ButtonText; --tab-top-line-active-hover-color: HighlightText; --tab-top-line-hover-color: SelectedItem; @@ -152,11 +218,6 @@ --thickness-slider-color: ButtonText; } - width: 570px; - max-width: 100%; - min-width: 300px; - padding: 16px 0; - #addSignatureDialogLabel { overflow: hidden; position: absolute; @@ -174,26 +235,7 @@ height: 100%; } - span { - font: menu; - font-size: 13px; - font-style: normal; - font-weight: 400; - line-height: normal; - } - .mainContainer { - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - - .title { - margin-inline-start: 16px; - font-weight: 590; - } - [role="tablist"] { width: 100%; display: flex; @@ -465,43 +507,6 @@ gap: 4px; flex: 1 0 0; - > #inputWithClearButton { - --button-dimension: 24px; - - width: 100%; - position: relative; - display: flex; - align-items: center; - justify-content: center; - - > input { - width: 100%; - height: 32px; - padding: 8px 4px 8px 8px; - padding-block: 8px; - padding-inline: 8px calc(4px + var(--button-dimension)); - box-sizing: border-box; - background-color: transparent; - border-radius: 4px; - border: 1px solid var(--border-color); - color: var(--description-input-color); - } - - #addSignatureDescriptionClearButton { - position: absolute; - inset-block-start: 4px; - inset-inline-end: 4px; - display: inline-block; - width: var(--button-dimension); - height: var(--button-dimension); - background-color: var(--closing-button-color); - mask-size: cover; - mask-image: var(--closing-button-icon); - padding: 0; - border: 0; - } - } - > label { width: auto; } @@ -626,6 +631,56 @@ } } +#editSignatureDescriptionDialog { + .mainContainer { + padding-inline: 16px; + box-sizing: border-box; + + .title { + margin-inline-start: 0; + } + + #editSignatureDescriptionAndView { + width: auto; + display: flex; + justify-content: flex-end; + align-items: flex-start; + gap: 12px; + align-self: stretch; + + #editSignatureDescriptionContainer { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + flex: 1 1 auto; + } + + > svg { + width: 210px; + height: 180px; + padding: 8px; + background-color: var(--signature-bg); + + > 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 { + fill: var(--button-signature-color); + stroke-width: 0.5px; + } + } + } + } + } +} + #editorSignatureParamsToolbar { padding: 10px; @@ -716,11 +771,11 @@ stroke-miterlimit: 10; vector-effect: non-scaling-stroke; fill: none; - } - &.contours > path { - fill: var(--button-signature-color); - stroke-width: 0.5px; + &.contours { + fill: var(--button-signature-color); + stroke-width: 0.5px; + } } } @@ -760,3 +815,12 @@ } } } + +.editDescription.altText { + --alt-text-add-image: url(images/editor-toolbar-edit.svg) !important; + + &::before { + width: 16px !important; + height: 16px !important; + } +} diff --git a/web/signature_manager.js b/web/signature_manager.js index 99c2e7136..38cc6bfb3 100644 --- a/web/signature_manager.js +++ b/web/signature_manager.js @@ -92,6 +92,8 @@ class SignatureManager { #overlayManager; + #editDescriptionDialog; + #signatureStorage; #uiManager = null; @@ -114,7 +116,6 @@ class SignatureManager { imagePicker, imagePickerLink, description, - clearDescription, clearButton, cancelButton, addButton, @@ -123,6 +124,7 @@ class SignatureManager { saveCheckbox, saveContainer, }, + editSignatureElements, addSignatureToolbarButton, overlayManager, l10n, @@ -131,8 +133,8 @@ class SignatureManager { ) { this.#addButton = addButton; this.#clearButton = clearButton; - this.#clearDescription = clearDescription; - this.#description = description; + this.#clearDescription = description.lastElementChild; + this.#description = description.firstElementChild; this.#dialog = dialog; this.#drawSVG = drawSVG; this.#drawPlaceholder = drawPlaceholder; @@ -150,6 +152,10 @@ class SignatureManager { this.#l10n = l10n; this.#signatureStorage = signatureStorage; this.#eventBus = eventBus; + this.#editDescriptionDialog = new EditDescriptionDialog( + editSignatureElements, + overlayManager + ); SignatureManager.#l10nDescription ||= Object.freeze({ signature: "pdfjs-editor-add-signature-description-default-when-drawing", @@ -177,15 +183,15 @@ class SignatureManager { description.addEventListener( "input", () => { - clearDescription.disabled = description.value === ""; + this.#clearDescription.disabled = description.value === ""; }, { passive: true } ); - clearDescription.addEventListener( + this.#clearDescription.addEventListener( "click", () => { this.#description.value = ""; - clearDescription.disabled = true; + this.#clearDescription.disabled = true; }, { passive: true } ); @@ -200,6 +206,8 @@ class SignatureManager { this.#initTabButtons(typeButton, drawButton, imageButton, panels); imagePicker.accept = SupportedImageMimeTypes.join(","); + eventBus._on("storedsignatureschanged", this.#signaturesChanged.bind(this)); + overlayManager.register(dialog); } @@ -650,6 +658,7 @@ class SignatureManager { const div = document.createElement("div"); const button = document.createElement("button"); + button.addEventListener("click", () => { this.#eventBus.dispatch("switchannotationeditorparams", { source: this, @@ -690,7 +699,7 @@ class SignatureManager { svg.setAttribute("viewBox", outline.viewBox); svg.setAttribute("preserveAspectRatio", "xMidYMid meet"); if (areContours) { - svg.classList.add("contours"); + path.classList.add("contours"); } path.setAttribute("d", outline.toSVGPath()); @@ -718,14 +727,23 @@ class SignatureManager { this.#addSignatureToolbarButton.before(div); } + async #signaturesChanged() { + const parent = this.#addSignatureToolbarButton.parentElement; + while (parent.firstElementChild !== this.#addSignatureToolbarButton) { + parent.firstElementChild.remove(); + } + this.#loadSignaturesPromise = null; + await this.loadSignatures(/* reload = */ true); + } + getSignature(params) { return this.open(params); } - async loadSignatures() { + async loadSignatures(reload = false) { if ( !this.#addSignatureToolbarButton || - this.#addSignatureToolbarButton.previousElementSibling || + (!reload && this.#addSignatureToolbarButton.previousElementSibling) || !this.#signatureStorage ) { return; @@ -744,7 +762,9 @@ class SignatureManager { ) ), ]); - return; + if (!reload) { + return; + } } const [signatures, signaturesData] = await this.#loadSignaturesPromise; this.#loadSignaturesPromise = null; @@ -761,6 +781,27 @@ class SignatureManager { } } + async renderEditButton(editor) { + const button = document.createElement("button"); + button.classList.add("altText", "editDescription"); + button.tabIndex = 0; + button.title = editor.description; + const span = document.createElement("span"); + button.append(span); + span.setAttribute( + "data-l10n-id", + "pdfjs-editor-add-signature-edit-button-label" + ); + button.addEventListener( + "click", + () => { + this.#editDescriptionDialog.open(editor); + }, + { passive: true } + ); + return button; + } + async open({ uiManager, editor }) { this.#tabsToAltText ||= new Map( this.#tabButtons.keys().map(name => [name, ""]) @@ -822,11 +863,6 @@ class SignatureManager { data = this.#extractedSignatureData; break; } - this.#currentEditor.addSignature( - data.outline, - DEFAULT_HEIGHT_IN_PAGE, - this.#description.value - ); let uuid = null; if (this.#saveCheckbox.checked) { const description = this.#description.value; @@ -858,7 +894,13 @@ class SignatureManager { console.warn("SignatureManager.add: cannot save the signature."); } } - this.#currentEditor.setUuid(uuid); + this.#currentEditor.addSignature( + data, + DEFAULT_HEIGHT_IN_PAGE, + this.#description.value, + uuid + ); + this.#finish(); } @@ -868,4 +910,100 @@ class SignatureManager { } } +class EditDescriptionDialog { + #currentEditor; + + #previousDescription; + + #description; + + #dialog; + + #overlayManager; + + #signatureSVG; + + #uiManager; + + constructor( + { dialog, description, cancelButton, updateButton, editSignatureView }, + overlayManager + ) { + const descriptionInput = (this.#description = + description.firstElementChild); + this.#signatureSVG = editSignatureView; + this.#dialog = dialog; + this.#overlayManager = overlayManager; + + dialog.addEventListener("close", this.#close.bind(this)); + dialog.addEventListener("contextmenu", e => { + if (e.target !== this.#description) { + e.preventDefault(); + } + }); + cancelButton.addEventListener("click", this.#finish.bind(this)); + updateButton.addEventListener("click", this.#update.bind(this)); + + const clearDescription = description.lastElementChild; + clearDescription.addEventListener("click", () => { + descriptionInput.value = ""; + clearDescription.disabled = true; + }); + descriptionInput.addEventListener( + "input", + () => { + const { value } = descriptionInput; + clearDescription.disabled = value === ""; + updateButton.disabled = value === this.#previousDescription; + editSignatureView.setAttribute("aria-label", value); + }, + { passive: true } + ); + + overlayManager.register(dialog); + } + + async open(editor) { + this.#uiManager = editor._uiManager; + this.#currentEditor = editor; + this.#previousDescription = this.#description.value = editor.description; + this.#description.dispatchEvent(new Event("input")); + this.#uiManager.removeEditListeners(); + const { areContours, outline } = editor.getSignaturePreview(); + const svgFactory = new DOMSVGFactory(); + const path = svgFactory.createElement("path"); + this.#signatureSVG.append(path); + this.#signatureSVG.setAttribute("viewBox", outline.viewBox); + path.setAttribute("d", outline.toSVGPath()); + if (areContours) { + path.classList.add("contours"); + } + + await this.#overlayManager.open(this.#dialog); + } + + async #update() { + const description = this.#description.value; + if (this.#previousDescription === description) { + this.#finish(); + return; + } + this.#currentEditor.description = description; + this.#finish(); + } + + #finish() { + if (this.#overlayManager.active === this.#dialog) { + this.#overlayManager.close(this.#dialog); + } + } + + #close() { + this.#uiManager?.addEditListeners(); + this.#uiManager = null; + this.#currentEditor = null; + this.#signatureSVG.firstElementChild.remove(); + } +} + export { SignatureManager }; diff --git a/web/viewer.html b/web/viewer.html index c75766df0..1466e487e 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -684,13 +684,13 @@ See https://github.com/adobe-type-tools/cmap-resources - + This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use. - Add a signature + Add a signature @@ -731,9 +731,9 @@ See https://github.com/adobe-type-tools/cmap-resources Description (alt text) - - - + + + Clear signature @@ -754,7 +754,7 @@ See https://github.com/adobe-type-tools/cmap-resources Close - + Cancel Add @@ -762,6 +762,28 @@ See https://github.com/adobe-type-tools/cmap-resources + + + + Edit description + + + + Description (alt text) + + + + + + + + + Cancel + Update + + + + diff --git a/web/viewer.js b/web/viewer.js index 007edc8c1..d3e99af73 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -229,9 +229,6 @@ function getViewerConfiguration() { imagePicker: document.getElementById("addSignatureFilePicker"), imagePickerLink: document.getElementById("addSignatureImageBrowse"), description: document.getElementById("addSignatureDescription"), - clearDescription: document.getElementById( - "addSignatureDescriptionClearButton" - ), clearButton: document.getElementById("clearSignatureButton"), saveContainer: document.getElementById("addSignatureSaveContainer"), saveCheckbox: document.getElementById("addSignatureSaveCheckbox"), @@ -240,6 +237,13 @@ function getViewerConfiguration() { cancelButton: document.getElementById("addSignatureCancelButton"), addButton: document.getElementById("addSignatureAddButton"), }, + editSignatureDialog: { + dialog: document.getElementById("editSignatureDescriptionDialog"), + description: document.getElementById("editSignatureDescription"), + editSignatureView: document.getElementById("editSignatureView"), + cancelButton: document.getElementById("editSignatureCancelButton"), + updateButton: document.getElementById("editSignatureUpdateButton"), + }, annotationEditorParams: { editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"), editorFreeTextColor: document.getElementById("editorFreeTextColor"),