mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-20 15:18:08 +02:00
[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
20 changed files with 624 additions and 65 deletions
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…
Add table
Add a link
Reference in a new issue