mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-19 22:58:07 +02:00
[Editor] Add a color picker with predefined colors for highlighting text (bug 1866434)
The doorhanger for highlighting has a basic color picker composed of 5 predefined colors to set the default color to use. These colors can be changed thanks to a preference for now but it's something which could be changed in the Firefox settings in the future. Each highlight has in its own toolbar a color picker to just change its color. The different color pickers are so similar (modulo few differences in their styles) that this patch introduces a new class ColorPicker which provides a color picker component which could be reused in future editors. All in all, a large part of this patch is dedicated to color picker itself and its style and the rest is almost a matter of wiring the component.
This commit is contained in:
parent
c0436013a0
commit
ff23d37fa2
22 changed files with 573 additions and 87 deletions
|
@ -904,6 +904,38 @@
|
|||
}
|
||||
}
|
||||
|
||||
.colorPicker {
|
||||
--hover-outline-color: #0250bb;
|
||||
--selected-outline-color: #0060df;
|
||||
--swatch-border-color: #cfcfd8;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--hover-outline-color: #80ebff;
|
||||
--selected-outline-color: #aaf2ff;
|
||||
--swatch-border-color: #52525e;
|
||||
}
|
||||
|
||||
@media screen and (forced-colors: active) {
|
||||
--hover-outline-color: Highlight;
|
||||
--selected-outline-color: var(--hover-outline-color);
|
||||
--swatch-border-color: ButtonText;
|
||||
}
|
||||
|
||||
.swatch {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid var(--swatch-border-color);
|
||||
border-radius: 100%;
|
||||
outline-offset: 2px;
|
||||
box-sizing: border-box;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
button:is(:hover, .selected) > .swatch {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.annotationEditorLayer {
|
||||
&[data-main-rotation="0"] {
|
||||
.highlightEditor > .editToolbar {
|
||||
|
@ -962,7 +994,144 @@
|
|||
}
|
||||
|
||||
.editToolbar {
|
||||
--editor-toolbar-colorpicker-arrow-image: url(images/toolbarButton-menuArrow.svg);
|
||||
|
||||
transform-origin: center !important;
|
||||
|
||||
.buttons {
|
||||
.colorPicker {
|
||||
position: relative;
|
||||
width: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
mask-image: var(--editor-toolbar-colorpicker-arrow-image);
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
display: inline-block;
|
||||
background-color: var(--editor-toolbar-fg-color);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
background-color: var(--editor-toolbar-hover-fg-color);
|
||||
}
|
||||
|
||||
&:has(.dropdown:not(.hidden)) {
|
||||
background-color: var(--editor-toolbar-hover-bg-color);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 11px;
|
||||
padding-block: 8px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--editor-toolbar-bg-color);
|
||||
border: 1px solid var(--editor-toolbar-border-color);
|
||||
box-shadow: var(--editor-toolbar-shadow);
|
||||
inset-block-start: calc(100% + 4px);
|
||||
width: calc(100% + 2 * var(--editor-toolbar-padding));
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: none;
|
||||
|
||||
&:is(:active, :focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
> .swatch {
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[aria-selected="true"] > .swatch {
|
||||
outline: 2px solid var(--selected-outline-color);
|
||||
}
|
||||
|
||||
&:is(:hover, :active, :focus-visible) > .swatch {
|
||||
outline: 2px solid var(--hover-outline-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.editorParamsToolbar:has(#highlightParamsToolbarContainer) {
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
#highlightParamsToolbarContainer {
|
||||
height: auto;
|
||||
padding-inline: 10px;
|
||||
padding-block: 10px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
|
||||
.colorPicker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
#highlightColorPickerLabel {
|
||||
width: fit-content;
|
||||
inset-inline-start: 0;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
height: auto;
|
||||
|
||||
button {
|
||||
width: auto;
|
||||
height: auto;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: none;
|
||||
flex: 0 0 auto;
|
||||
|
||||
.swatch {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&:is(:active, :focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&[aria-selected="true"] > .swatch {
|
||||
outline: 2px solid var(--selected-outline-color);
|
||||
}
|
||||
|
||||
&:is(:hover, :active, :focus-visible) > .swatch {
|
||||
outline: 2px solid var(--hover-outline-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ class AnnotationEditorParams {
|
|||
#bindListeners({
|
||||
editorFreeTextFontSize,
|
||||
editorFreeTextColor,
|
||||
editorHighlightColor,
|
||||
editorHighlightOpacity,
|
||||
editorInkColor,
|
||||
editorInkThickness,
|
||||
editorInkOpacity,
|
||||
|
@ -48,12 +46,6 @@ class AnnotationEditorParams {
|
|||
editorFreeTextColor.addEventListener("input", function () {
|
||||
dispatchEvent("FREETEXT_COLOR", this.value);
|
||||
});
|
||||
editorHighlightColor.addEventListener("input", function () {
|
||||
dispatchEvent("HIGHLIGHT_COLOR", this.value);
|
||||
});
|
||||
editorHighlightOpacity.addEventListener("input", function () {
|
||||
dispatchEvent("HIGHLIGHT_OPACITY", this.valueAsNumber);
|
||||
});
|
||||
editorInkColor.addEventListener("input", function () {
|
||||
dispatchEvent("INK_COLOR", this.value);
|
||||
});
|
||||
|
@ -76,12 +68,6 @@ class AnnotationEditorParams {
|
|||
case AnnotationEditorParamsType.FREETEXT_COLOR:
|
||||
editorFreeTextColor.value = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
|
||||
editorHighlightColor.value = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.HIGHLIGHT_OPACITY:
|
||||
editorHighlightOpacity.value = value;
|
||||
break;
|
||||
case AnnotationEditorParamsType.INK_COLOR:
|
||||
editorInkColor.value = value;
|
||||
break;
|
||||
|
|
|
@ -442,6 +442,7 @@ const PDFViewerApplication = {
|
|||
textLayerMode: AppOptions.get("textLayerMode"),
|
||||
annotationMode: AppOptions.get("annotationMode"),
|
||||
annotationEditorMode,
|
||||
annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
|
||||
imageResourcesPath: AppOptions.get("imageResourcesPath"),
|
||||
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
||||
isOffscreenCanvasSupported,
|
||||
|
|
|
@ -158,6 +158,11 @@ const defaultOptions = {
|
|||
value: 0,
|
||||
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
||||
},
|
||||
highlightEditorColors: {
|
||||
/** @type {string} */
|
||||
value: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F",
|
||||
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
||||
},
|
||||
historyUpdateUrl: {
|
||||
/** @type {boolean} */
|
||||
value: false,
|
||||
|
|
|
@ -36,8 +36,14 @@
|
|||
}
|
||||
|
||||
&.highlight {
|
||||
--blend-mode: multiply;
|
||||
|
||||
@media screen and (forced-colors: active) {
|
||||
--blend-mode: difference;
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
mix-blend-mode: multiply;
|
||||
mix-blend-mode: var(--blend-mode);
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ function isValidAnnotationEditorMode(mode) {
|
|||
* @property {number} [annotationEditorMode] - Enables the creation and editing
|
||||
* of new Annotations. The constants from {@link AnnotationEditorType} should
|
||||
* be used. The default value is `AnnotationEditorType.NONE`.
|
||||
* @property {string} [annotationEditorHighlightColors] - A comma separated list
|
||||
* of colors to propose to highlight some text in the pdf.
|
||||
* @property {string} [imageResourcesPath] - Path for image resources, mainly
|
||||
* mainly for annotation icons. Include trailing slash.
|
||||
* @property {boolean} [enablePrintAutoRotate] - Enables automatic rotation of
|
||||
|
@ -202,6 +204,8 @@ class PDFViewer {
|
|||
|
||||
#altTextManager = null;
|
||||
|
||||
#annotationEditorHighlightColors = null;
|
||||
|
||||
#annotationEditorMode = AnnotationEditorType.NONE;
|
||||
|
||||
#annotationEditorUIManager = null;
|
||||
|
@ -276,6 +280,8 @@ class PDFViewer {
|
|||
options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
|
||||
this.#annotationEditorMode =
|
||||
options.annotationEditorMode ?? AnnotationEditorType.NONE;
|
||||
this.#annotationEditorHighlightColors =
|
||||
options.annotationEditorHighlightColors || null;
|
||||
this.imageResourcesPath = options.imageResourcesPath || "";
|
||||
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||
|
@ -862,8 +868,13 @@ class PDFViewer {
|
|||
this.#altTextManager,
|
||||
this.eventBus,
|
||||
pdfDocument,
|
||||
this.pageColors
|
||||
this.pageColors,
|
||||
this.#annotationEditorHighlightColors
|
||||
);
|
||||
this.eventBus.dispatch("annotationeditoruimanager", {
|
||||
source: this,
|
||||
uiManager: this.#annotationEditorUIManager,
|
||||
});
|
||||
if (mode !== AnnotationEditorType.NONE) {
|
||||
this.#annotationEditorUIManager.updateMode(mode);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ const {
|
|||
AnnotationMode,
|
||||
build,
|
||||
CMapCompressionType,
|
||||
ColorPicker,
|
||||
createValidAbsoluteUrl,
|
||||
DOMSVGFactory,
|
||||
DrawLayer,
|
||||
|
@ -80,6 +81,7 @@ export {
|
|||
AnnotationMode,
|
||||
build,
|
||||
CMapCompressionType,
|
||||
ColorPicker,
|
||||
createValidAbsoluteUrl,
|
||||
DOMSVGFactory,
|
||||
DrawLayer,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AnnotationEditorType, noContextMenu } from "pdfjs-lib";
|
||||
import { AnnotationEditorType, ColorPicker, noContextMenu } from "pdfjs-lib";
|
||||
import {
|
||||
DEFAULT_SCALE,
|
||||
DEFAULT_SCALE_VALUE,
|
||||
|
@ -120,9 +120,24 @@ class Toolbar {
|
|||
// Bind the event listeners for click and various other actions.
|
||||
this.#bindListeners(options);
|
||||
|
||||
if (options.editorHighlightColorPicker) {
|
||||
this.eventBus._on("annotationeditoruimanager", ({ uiManager }) => {
|
||||
this.#setAnnotationEditorUIManager(
|
||||
uiManager,
|
||||
options.editorHighlightColorPicker
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
#setAnnotationEditorUIManager(uiManager, parentContainer) {
|
||||
const colorPicker = new ColorPicker({ uiManager });
|
||||
uiManager.setMainHighlightColorPicker(colorPicker);
|
||||
parentContainer.append(colorPicker.renderMainDropdown());
|
||||
}
|
||||
|
||||
setPageNumber(pageNumber, pageLabel) {
|
||||
this.pageNumber = pageNumber;
|
||||
this.pageLabel = pageLabel;
|
||||
|
|
|
@ -532,6 +532,11 @@ body {
|
|||
.editorParamsToolbarContainer .editorParamsLabel {
|
||||
padding-inline-end: 10px;
|
||||
flex: none;
|
||||
font: menu;
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%;
|
||||
color: var(--main-color);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,14 +172,9 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
</div> <!-- findbar -->
|
||||
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorHighlightParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorHighlightColor" class="editorParamsLabel" data-l10n-id="editor_highlight_color">Color</label>
|
||||
<input type="color" value="#FFFF00" id="editorHighlightColor" class="editorParamsColor" tabindex="100">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorHighlightOpacity" class="editorParamsLabel" data-l10n-id="editor_highlight_opacity">Opacity</label>
|
||||
<input type="range" id="editorHighlightOpacity" class="editorParamsSlider" value="100" min="1" max="100" step="1" tabindex="101">
|
||||
<div id="highlightParamsToolbarContainer" class="editorParamsToolbarContainer">
|
||||
<div id="editorHighlightColorPicker" class="colorPicker">
|
||||
<span id="highlightColorPickerLabel" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-colorpicker-label">Highlight color</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -217,7 +212,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorStampParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="107" data-l10n-id="pdfjs-editor-stamp-add-image-button">
|
||||
<span data-l10n-id="pdfjs-editor-stamp-add-image-button-label">Add image</span>
|
||||
<span class="editorParamsLabel" data-l10n-id="pdfjs-editor-stamp-add-image-button-label">Add image</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -61,6 +61,9 @@ function getViewerConfiguration() {
|
|||
editorHighlightParamsToolbar: document.getElementById(
|
||||
"editorHighlightParamsToolbar"
|
||||
),
|
||||
editorHighlightColorPicker: document.getElementById(
|
||||
"editorHighlightColorPicker"
|
||||
),
|
||||
editorInkButton: document.getElementById("editorInk"),
|
||||
editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"),
|
||||
editorStampButton: document.getElementById("editorStamp"),
|
||||
|
@ -168,8 +171,6 @@ function getViewerConfiguration() {
|
|||
annotationEditorParams: {
|
||||
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
||||
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
||||
editorHighlightColor: document.getElementById("editorHighlightColor"),
|
||||
editorHighlightOpacity: document.getElementById("editorHighlightOpacity"),
|
||||
editorInkColor: document.getElementById("editorInkColor"),
|
||||
editorInkThickness: document.getElementById("editorInkThickness"),
|
||||
editorInkOpacity: document.getElementById("editorInkOpacity"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue