mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-19 22:58:07 +02:00
Merge pull request #19486 from calixteman/signature_edit_desc
[Editor] Add the possibility to change a signature description (bug 1948116)
This commit is contained in:
commit
6258a77bd7
16 changed files with 480 additions and 141 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
3
web/images/editor-toolbar-edit.svg
Normal file
3
web/images/editor-toolbar-edit.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.9815 14.3461L14.3875 11.1451C14.3125 10.7361 14.1155 10.3621 13.8195 10.0641L5.0185 1.26214C4.2445 0.489141 2.9855 0.487141 2.2085 1.26214L0.5805 2.89014C-0.1935 3.66514 -0.1935 4.92514 0.5805 5.70014L9.3845 14.5031C9.6805 14.7981 10.0545 14.9941 10.4625 15.0691L13.6645 15.6631C13.7345 15.6751 13.8025 15.6821 13.8705 15.6821C14.1675 15.6821 14.4555 15.5651 14.6695 15.3511C14.9325 15.0871 15.0495 14.7121 14.9815 14.3461ZM2.5285 5.87814L1.3685 4.71814L1.3695 3.87014L3.1895 2.04914L4.0375 2.05014L5.1975 3.21014L2.5285 5.87814ZM10.6895 13.8401C10.5295 13.8101 10.3825 13.7331 10.2665 13.6161L3.4135 6.76314L6.0815 4.09514L12.9345 10.9471C13.0515 11.0651 13.1285 11.2121 13.1595 11.3731L13.6335 13.9301L13.2485 14.3151L10.6895 13.8401Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 869 B |
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -684,13 +684,13 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog" id="addSignatureDialog" aria-labelledby="addSignatureDialogLabel">
|
||||
<dialog class="dialog signatureDialog" id="addSignatureDialog" aria-labelledby="addSignatureDialogLabel">
|
||||
<span id="addSignatureDialogLabel" data-l10n-id="pdfjs-editor-add-signature-dialog-label">
|
||||
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.
|
||||
</span>
|
||||
<div id="addSignatureContainer" class="mainContainer">
|
||||
<div class="title">
|
||||
<span id="addSignatureTitle" role="sectionhead" data-l10n-id="pdfjs-editor-add-signature-dialog-title" tabindex="0" class="title">Add a signature</span>
|
||||
<span role="sectionhead" data-l10n-id="pdfjs-editor-add-signature-dialog-title" tabindex="0">Add a signature</span>
|
||||
</div>
|
||||
<div role="tablist" id="addSignatureOptions">
|
||||
<button id="addSignatureTypeButton" type="button" role="tab" aria-selected="true" aria-controls="addSignatureTypeContainer" data-l10n-id="pdfjs-editor-add-signature-type-button" tabindex="0">
|
||||
|
@ -731,9 +731,9 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
<div id="horizontalContainer">
|
||||
<div id="addSignatureDescriptionContainer">
|
||||
<label for="addSignatureDescription" data-l10n-id="pdfjs-editor-add-signature-description-label">Description (alt text)</span></label>
|
||||
<span id="inputWithClearButton">
|
||||
<input type="text" id="addSignatureDescription" data-l10n-id="pdfjs-editor-add-signature-description-input" data-l10n-args='{ "default": "", "useDefault": true }' tabindex="0"></input>
|
||||
<button id="addSignatureDescriptionClearButton" type="button" tabindex="0" aria-hidden="true"></button>
|
||||
<span id="addSignatureDescription" class="inputWithClearButton">
|
||||
<input type="text" data-l10n-id="pdfjs-editor-add-signature-description-input" tabindex="0"></input>
|
||||
<button class="clearInputButton" type="button" tabindex="0" aria-hidden="true"></button>
|
||||
</span>
|
||||
</div>
|
||||
<button id="clearSignatureButton" type="button" data-l10n-id="pdfjs-editor-add-signature-clear-button" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-clear-button-label">Clear signature</span></button>
|
||||
|
@ -754,7 +754,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
<button id="addSignatureErrorCloseButton" class="closeButton" type="button" tabindex="0" title="Close"><span data-l10n-id="pdfjs-editor-add-signature-error-close-button">Close</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons" class="dialogButtonsGroup">
|
||||
<div class="dialogButtonsGroup">
|
||||
<button id="addSignatureCancelButton" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-cancel-button">Cancel</span></button>
|
||||
<button id="addSignatureAddButton" type="button" class="primaryButton" disabled tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-add-button">Add</span></button>
|
||||
</div>
|
||||
|
@ -762,6 +762,28 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog signatureDialog" id="editSignatureDescriptionDialog" aria-labelledby="editSignatureDescriptionTitle">
|
||||
<div id="editSignatureDescriptionContainer" class="mainContainer">
|
||||
<div class="title">
|
||||
<span id="editSignatureDescriptionTitle" role="sectionhead" data-l10n-id="pdfjs-editor-edit-signature-dialog-title" tabindex="0">Edit description</span>
|
||||
</div>
|
||||
<div id="editSignatureDescriptionAndView">
|
||||
<div id="editSignatureDescriptionContainer">
|
||||
<label for="editSignatureDescription" data-l10n-id="pdfjs-editor-add-signature-description-label">Description (alt text)</span></label>
|
||||
<span id="editSignatureDescription" class="inputWithClearButton">
|
||||
<input type="text" data-l10n-id="pdfjs-editor-add-signature-description-input" tabindex="0"></input>
|
||||
<button class="clearInputButton" type="button" tabindex="0" aria-hidden="true"></button>
|
||||
</span>
|
||||
</div>
|
||||
<svg id="editSignatureView" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
</div>
|
||||
<div class="dialogButtonsGroup">
|
||||
<button id="editSignatureCancelButton" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-cancel-button">Cancel</span></button>
|
||||
<button id="editSignatureUpdateButton" type="button" class="primaryButton" disabled tabindex="0"><span data-l10n-id="pdfjs-editor-edit-signature-update-button">Update</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!--#if !MOZCENTRAL-->
|
||||
<dialog id="printServiceDialog" style="min-width: 200px;">
|
||||
<div class="row">
|
||||
|
|
|
@ -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"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue