[Editor] Add a floating button close to the selected text to highlight it (bug 1867742)
For now keep this feature behind a pref in order to make some experiments before deciding to enable it.
This commit is contained in:
parent
eb160726ee
commit
b4267cd294
@ -72,6 +72,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"enableHighlightFloatingButton": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"highlightEditorColors": {
|
"highlightEditorColors": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
|
"default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
|
||||||
|
@ -318,6 +318,8 @@ pdfjs-editor-stamp-button-label = Add or edit images
|
|||||||
pdfjs-editor-highlight-button =
|
pdfjs-editor-highlight-button =
|
||||||
.title = Highlight
|
.title = Highlight
|
||||||
pdfjs-editor-highlight-button-label = Highlight
|
pdfjs-editor-highlight-button-label = Highlight
|
||||||
|
pdfjs-highlight-floating-button =
|
||||||
|
.title = Highlight
|
||||||
|
|
||||||
## Remove button for the various kind of editor.
|
## Remove button for the various kind of editor.
|
||||||
|
|
||||||
|
@ -135,4 +135,80 @@ class EditorToolbar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { EditorToolbar };
|
class HighlightToolbar {
|
||||||
|
#buttons = null;
|
||||||
|
|
||||||
|
#toolbar = null;
|
||||||
|
|
||||||
|
#uiManager;
|
||||||
|
|
||||||
|
constructor(uiManager) {
|
||||||
|
this.#uiManager = uiManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
#render() {
|
||||||
|
const editToolbar = (this.#toolbar = document.createElement("div"));
|
||||||
|
editToolbar.className = "editToolbar";
|
||||||
|
editToolbar.setAttribute("role", "toolbar");
|
||||||
|
editToolbar.addEventListener("contextmenu", noContextMenu);
|
||||||
|
|
||||||
|
const buttons = (this.#buttons = document.createElement("div"));
|
||||||
|
buttons.className = "buttons";
|
||||||
|
editToolbar.append(buttons);
|
||||||
|
|
||||||
|
this.#addHighlightButton();
|
||||||
|
|
||||||
|
return editToolbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
#getLastPoint(boxes, isLTR) {
|
||||||
|
let lastY = 0;
|
||||||
|
let lastX = 0;
|
||||||
|
for (const box of boxes) {
|
||||||
|
const y = box.y + box.height;
|
||||||
|
if (y < lastY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const x = box.x + (isLTR ? box.width : 0);
|
||||||
|
if (y > lastY) {
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isLTR) {
|
||||||
|
if (x > lastX) {
|
||||||
|
lastX = x;
|
||||||
|
}
|
||||||
|
} else if (x < lastX) {
|
||||||
|
lastX = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [isLTR ? 1 - lastX : lastX, lastY];
|
||||||
|
}
|
||||||
|
|
||||||
|
show(parent, boxes, isLTR) {
|
||||||
|
const [x, y] = this.#getLastPoint(boxes, isLTR);
|
||||||
|
const { style } = (this.#toolbar ||= this.#render());
|
||||||
|
parent.append(this.#toolbar);
|
||||||
|
style.insetInlineEnd = `${100 * x}%`;
|
||||||
|
style.top = `calc(${100 * y}% + var(--editor-toolbar-vert-offset))`;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.#toolbar.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
#addHighlightButton() {
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.className = "highlightButton";
|
||||||
|
button.tabIndex = 0;
|
||||||
|
button.setAttribute("data-l10n-id", `pdfjs-highlight-floating-button`);
|
||||||
|
button.addEventListener("contextmenu", noContextMenu);
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
this.#uiManager.highlightSelection("floating_button");
|
||||||
|
});
|
||||||
|
this.#buttons.append(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { EditorToolbar, HighlightToolbar };
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
getRGB,
|
getRGB,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
} from "../display_utils.js";
|
} from "../display_utils.js";
|
||||||
|
import { HighlightToolbar } from "./toolbar.js";
|
||||||
|
|
||||||
function bindEvents(obj, element, names) {
|
function bindEvents(obj, element, names) {
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
@ -555,6 +556,8 @@ class AnnotationEditorUIManager {
|
|||||||
|
|
||||||
#editorsToRescale = new Set();
|
#editorsToRescale = new Set();
|
||||||
|
|
||||||
|
#enableHighlightFloatingButton = false;
|
||||||
|
|
||||||
#filterFactory = null;
|
#filterFactory = null;
|
||||||
|
|
||||||
#focusMainContainerTimeoutId = null;
|
#focusMainContainerTimeoutId = null;
|
||||||
@ -563,6 +566,8 @@ class AnnotationEditorUIManager {
|
|||||||
|
|
||||||
#highlightWhenShiftUp = false;
|
#highlightWhenShiftUp = false;
|
||||||
|
|
||||||
|
#highlightToolbar = null;
|
||||||
|
|
||||||
#idManager = new IdManager();
|
#idManager = new IdManager();
|
||||||
|
|
||||||
#isEnabled = false;
|
#isEnabled = false;
|
||||||
@ -771,6 +776,7 @@ class AnnotationEditorUIManager {
|
|||||||
pdfDocument,
|
pdfDocument,
|
||||||
pageColors,
|
pageColors,
|
||||||
highlightColors,
|
highlightColors,
|
||||||
|
enableHighlightFloatingButton,
|
||||||
mlManager
|
mlManager
|
||||||
) {
|
) {
|
||||||
this.#container = container;
|
this.#container = container;
|
||||||
@ -782,10 +788,12 @@ class AnnotationEditorUIManager {
|
|||||||
this._eventBus._on("scalechanging", this.#boundOnScaleChanging);
|
this._eventBus._on("scalechanging", this.#boundOnScaleChanging);
|
||||||
this._eventBus._on("rotationchanging", this.#boundOnRotationChanging);
|
this._eventBus._on("rotationchanging", this.#boundOnRotationChanging);
|
||||||
this.#addSelectionListener();
|
this.#addSelectionListener();
|
||||||
|
this.#addKeyboardManager();
|
||||||
this.#annotationStorage = pdfDocument.annotationStorage;
|
this.#annotationStorage = pdfDocument.annotationStorage;
|
||||||
this.#filterFactory = pdfDocument.filterFactory;
|
this.#filterFactory = pdfDocument.filterFactory;
|
||||||
this.#pageColors = pageColors;
|
this.#pageColors = pageColors;
|
||||||
this.#highlightColors = highlightColors || null;
|
this.#highlightColors = highlightColors || null;
|
||||||
|
this.#enableHighlightFloatingButton = enableHighlightFloatingButton;
|
||||||
this.#mlManager = mlManager || null;
|
this.#mlManager = mlManager || null;
|
||||||
this.viewParameters = {
|
this.viewParameters = {
|
||||||
realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
|
realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
|
||||||
@ -821,6 +829,8 @@ class AnnotationEditorUIManager {
|
|||||||
this.#selectedEditors.clear();
|
this.#selectedEditors.clear();
|
||||||
this.#commandManager.destroy();
|
this.#commandManager.destroy();
|
||||||
this.#altTextManager?.destroy();
|
this.#altTextManager?.destroy();
|
||||||
|
this.#highlightToolbar?.hide();
|
||||||
|
this.#highlightToolbar = null;
|
||||||
if (this.#focusMainContainerTimeoutId) {
|
if (this.#focusMainContainerTimeoutId) {
|
||||||
clearTimeout(this.#focusMainContainerTimeoutId);
|
clearTimeout(this.#focusMainContainerTimeoutId);
|
||||||
this.#focusMainContainerTimeoutId = null;
|
this.#focusMainContainerTimeoutId = null;
|
||||||
@ -946,6 +956,12 @@ class AnnotationEditorUIManager {
|
|||||||
this.viewParameters.rotation = pagesRotation;
|
this.viewParameters.rotation = pagesRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getAnchorElementForSelection({ anchorNode }) {
|
||||||
|
return anchorNode.nodeType === Node.TEXT_NODE
|
||||||
|
? anchorNode.parentElement
|
||||||
|
: anchorNode;
|
||||||
|
}
|
||||||
|
|
||||||
highlightSelection(methodOfCreation = "") {
|
highlightSelection(methodOfCreation = "") {
|
||||||
const selection = document.getSelection();
|
const selection = document.getSelection();
|
||||||
if (!selection || selection.isCollapsed) {
|
if (!selection || selection.isCollapsed) {
|
||||||
@ -953,18 +969,19 @@ class AnnotationEditorUIManager {
|
|||||||
}
|
}
|
||||||
const { anchorNode, anchorOffset, focusNode, focusOffset } = selection;
|
const { anchorNode, anchorOffset, focusNode, focusOffset } = selection;
|
||||||
const text = selection.toString();
|
const text = selection.toString();
|
||||||
const anchorElement =
|
const anchorElement = this.#getAnchorElementForSelection(selection);
|
||||||
anchorNode.nodeType === Node.TEXT_NODE
|
|
||||||
? anchorNode.parentElement
|
|
||||||
: anchorNode;
|
|
||||||
const textLayer = anchorElement.closest(".textLayer");
|
const textLayer = anchorElement.closest(".textLayer");
|
||||||
const boxes = this.getSelectionBoxes(textLayer);
|
const boxes = this.getSelectionBoxes(textLayer);
|
||||||
|
if (!boxes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
selection.empty();
|
selection.empty();
|
||||||
if (this.#mode === AnnotationEditorType.NONE) {
|
if (this.#mode === AnnotationEditorType.NONE) {
|
||||||
this._eventBus.dispatch("showannotationeditorui", {
|
this._eventBus.dispatch("showannotationeditorui", {
|
||||||
source: this,
|
source: this,
|
||||||
mode: AnnotationEditorType.HIGHLIGHT,
|
mode: AnnotationEditorType.HIGHLIGHT,
|
||||||
});
|
});
|
||||||
|
this.showAllEditors("highlight", true, /* updateButton = */ true);
|
||||||
}
|
}
|
||||||
for (const layer of this.#allLayers.values()) {
|
for (const layer of this.#allLayers.values()) {
|
||||||
if (layer.hasTextLayer(textLayer)) {
|
if (layer.hasTextLayer(textLayer)) {
|
||||||
@ -982,6 +999,21 @@ class AnnotationEditorUIManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#displayHighlightToolbar() {
|
||||||
|
const selection = document.getSelection();
|
||||||
|
if (!selection || selection.isCollapsed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const anchorElement = this.#getAnchorElementForSelection(selection);
|
||||||
|
const textLayer = anchorElement.closest(".textLayer");
|
||||||
|
const boxes = this.getSelectionBoxes(textLayer);
|
||||||
|
if (!boxes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#highlightToolbar ||= new HighlightToolbar(this);
|
||||||
|
this.#highlightToolbar.show(textLayer, boxes, this.direction === "ltr");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an editor in the annotation storage.
|
* Add an editor in the annotation storage.
|
||||||
* @param {AnnotationEditor} editor
|
* @param {AnnotationEditor} editor
|
||||||
@ -1000,6 +1032,7 @@ class AnnotationEditorUIManager {
|
|||||||
const selection = document.getSelection();
|
const selection = document.getSelection();
|
||||||
if (!selection || selection.isCollapsed) {
|
if (!selection || selection.isCollapsed) {
|
||||||
if (this.#selectedTextNode) {
|
if (this.#selectedTextNode) {
|
||||||
|
this.#highlightToolbar?.hide();
|
||||||
this.#selectedTextNode = null;
|
this.#selectedTextNode = null;
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
hasSelectedText: false,
|
hasSelectedText: false,
|
||||||
@ -1012,12 +1045,11 @@ class AnnotationEditorUIManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const anchorElement =
|
const anchorElement = this.#getAnchorElementForSelection(selection);
|
||||||
anchorNode.nodeType === Node.TEXT_NODE
|
const textLayer = anchorElement.closest(".textLayer");
|
||||||
? anchorNode.parentElement
|
if (!textLayer) {
|
||||||
: anchorNode;
|
|
||||||
if (!anchorElement.closest(".textLayer")) {
|
|
||||||
if (this.#selectedTextNode) {
|
if (this.#selectedTextNode) {
|
||||||
|
this.#highlightToolbar?.hide();
|
||||||
this.#selectedTextNode = null;
|
this.#selectedTextNode = null;
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
hasSelectedText: false,
|
hasSelectedText: false,
|
||||||
@ -1025,16 +1057,22 @@ class AnnotationEditorUIManager {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.#highlightToolbar?.hide();
|
||||||
this.#selectedTextNode = anchorNode;
|
this.#selectedTextNode = anchorNode;
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
hasSelectedText: true,
|
hasSelectedText: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.#mode !== AnnotationEditorType.HIGHLIGHT) {
|
if (
|
||||||
|
this.#mode !== AnnotationEditorType.HIGHLIGHT &&
|
||||||
|
this.#mode !== AnnotationEditorType.NONE
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showAllEditors("highlight", true, /* updateButton = */ true);
|
if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
|
||||||
|
this.showAllEditors("highlight", true, /* updateButton = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
this.#highlightWhenShiftUp = this.isShiftKeyDown;
|
this.#highlightWhenShiftUp = this.isShiftKeyDown;
|
||||||
if (!this.isShiftKeyDown) {
|
if (!this.isShiftKeyDown) {
|
||||||
@ -1046,7 +1084,7 @@ class AnnotationEditorUIManager {
|
|||||||
window.removeEventListener("pointerup", pointerup);
|
window.removeEventListener("pointerup", pointerup);
|
||||||
window.removeEventListener("blur", pointerup);
|
window.removeEventListener("blur", pointerup);
|
||||||
if (e.type === "pointerup") {
|
if (e.type === "pointerup") {
|
||||||
this.highlightSelection("main_toolbar");
|
this.#onSelectEnd("main_toolbar");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener("pointerup", pointerup);
|
window.addEventListener("pointerup", pointerup);
|
||||||
@ -1054,6 +1092,14 @@ class AnnotationEditorUIManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#onSelectEnd(methodOfCreation = "") {
|
||||||
|
if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
|
||||||
|
this.highlightSelection(methodOfCreation);
|
||||||
|
} else if (this.#enableHighlightFloatingButton) {
|
||||||
|
this.#displayHighlightToolbar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#addSelectionListener() {
|
#addSelectionListener() {
|
||||||
document.addEventListener("selectionchange", this.#boundSelectionChange);
|
document.addEventListener("selectionchange", this.#boundSelectionChange);
|
||||||
}
|
}
|
||||||
@ -1076,7 +1122,7 @@ class AnnotationEditorUIManager {
|
|||||||
this.isShiftKeyDown = false;
|
this.isShiftKeyDown = false;
|
||||||
if (this.#highlightWhenShiftUp) {
|
if (this.#highlightWhenShiftUp) {
|
||||||
this.#highlightWhenShiftUp = false;
|
this.#highlightWhenShiftUp = false;
|
||||||
this.highlightSelection("main_toolbar");
|
this.#onSelectEnd("main_toolbar");
|
||||||
}
|
}
|
||||||
if (!this.hasSelection) {
|
if (!this.hasSelection) {
|
||||||
return;
|
return;
|
||||||
@ -1252,7 +1298,10 @@ class AnnotationEditorUIManager {
|
|||||||
if (!this.isShiftKeyDown && event.key === "Shift") {
|
if (!this.isShiftKeyDown && event.key === "Shift") {
|
||||||
this.isShiftKeyDown = true;
|
this.isShiftKeyDown = true;
|
||||||
}
|
}
|
||||||
if (!this.isEditorHandlingKeyboard) {
|
if (
|
||||||
|
this.#mode !== AnnotationEditorType.NONE &&
|
||||||
|
!this.isEditorHandlingKeyboard
|
||||||
|
) {
|
||||||
AnnotationEditorUIManager._keyboardManager.exec(this, event);
|
AnnotationEditorUIManager._keyboardManager.exec(this, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1266,7 +1315,7 @@ class AnnotationEditorUIManager {
|
|||||||
this.isShiftKeyDown = false;
|
this.isShiftKeyDown = false;
|
||||||
if (this.#highlightWhenShiftUp) {
|
if (this.#highlightWhenShiftUp) {
|
||||||
this.#highlightWhenShiftUp = false;
|
this.#highlightWhenShiftUp = false;
|
||||||
this.highlightSelection("main_toolbar");
|
this.#onSelectEnd("main_toolbar");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1335,7 +1384,6 @@ class AnnotationEditorUIManager {
|
|||||||
setEditingState(isEditing) {
|
setEditingState(isEditing) {
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
this.#addFocusManager();
|
this.#addFocusManager();
|
||||||
this.#addKeyboardManager();
|
|
||||||
this.#addCopyPasteListeners();
|
this.#addCopyPasteListeners();
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
isEditing: this.#mode !== AnnotationEditorType.NONE,
|
isEditing: this.#mode !== AnnotationEditorType.NONE,
|
||||||
@ -1346,7 +1394,6 @@ class AnnotationEditorUIManager {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.#removeFocusManager();
|
this.#removeFocusManager();
|
||||||
this.#removeKeyboardManager();
|
|
||||||
this.#removeCopyPasteListeners();
|
this.#removeCopyPasteListeners();
|
||||||
this.#dispatchUpdateStates({
|
this.#dispatchUpdateStates({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
|
@ -46,8 +46,11 @@ const getXY = (page, selector) =>
|
|||||||
return `${bbox.x}::${bbox.y}`;
|
return `${bbox.x}::${bbox.y}`;
|
||||||
}, selector);
|
}, selector);
|
||||||
|
|
||||||
const getSpanRectFromText = (page, pageNumber, text) =>
|
const getSpanRectFromText = async (page, pageNumber, text) => {
|
||||||
page.evaluate(
|
await page.waitForSelector(
|
||||||
|
`.page[data-page-number="${pageNumber}"] > .textLayer .endOfContent`
|
||||||
|
);
|
||||||
|
return page.evaluate(
|
||||||
(number, content) => {
|
(number, content) => {
|
||||||
for (const el of document.querySelectorAll(
|
for (const el of document.querySelectorAll(
|
||||||
`.page[data-page-number="${number}"] > .textLayer > span`
|
`.page[data-page-number="${number}"] > .textLayer > span`
|
||||||
@ -62,6 +65,7 @@ const getSpanRectFromText = (page, pageNumber, text) =>
|
|||||||
pageNumber,
|
pageNumber,
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
describe("Highlight Editor", () => {
|
describe("Highlight Editor", () => {
|
||||||
describe("Editor must be removed without exception", () => {
|
describe("Editor must be removed without exception", () => {
|
||||||
@ -1510,4 +1514,46 @@ describe("Highlight Editor", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Highlight from floating highlight button", () => {
|
||||||
|
let pages;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
pages = await loadAndWait(
|
||||||
|
"tracemonkey.pdf",
|
||||||
|
".annotationEditorLayer",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{ highlightEditorColors: "red=#AB0000" }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await closePages(pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must check that clicking on the highlight floating button triggers an highlight", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
const rect = await getSpanRectFromText(page, 1, "Abstract");
|
||||||
|
const x = rect.x + rect.width / 2;
|
||||||
|
const y = rect.y + rect.height / 2;
|
||||||
|
await page.mouse.click(x, y, { count: 2, delay: 100 });
|
||||||
|
|
||||||
|
await page.waitForSelector(".textLayer .highlightButton");
|
||||||
|
await page.click(".textLayer .highlightButton");
|
||||||
|
|
||||||
|
await page.waitForSelector(getEditorSelector(0));
|
||||||
|
const usedColor = await page.evaluate(() => {
|
||||||
|
const highlight = document.querySelector(
|
||||||
|
`.page[data-page-number = "1"] .canvasWrapper > svg.highlight`
|
||||||
|
);
|
||||||
|
return highlight.getAttribute("fill");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(usedColor).withContext(`In ${browserName}`).toEqual("#AB0000");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -195,10 +195,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.annotationEditorLayer
|
.annotationEditorLayer
|
||||||
:is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor) {
|
:is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor),
|
||||||
|
.textLayer {
|
||||||
.editToolbar {
|
.editToolbar {
|
||||||
--editor-toolbar-delete-image: url(images/editor-toolbar-delete.svg);
|
--editor-toolbar-delete-image: url(images/editor-toolbar-delete.svg);
|
||||||
--editor-toolbar-bg-color: #f0f0f4;
|
--editor-toolbar-bg-color: #f0f0f4;
|
||||||
|
--editor-toolbar-highlight-image: url(images/toolbarButton-editorHighlight.svg);
|
||||||
--editor-toolbar-fg-color: #2e2e56;
|
--editor-toolbar-fg-color: #2e2e56;
|
||||||
--editor-toolbar-border-color: #8f8f9d;
|
--editor-toolbar-border-color: #8f8f9d;
|
||||||
--editor-toolbar-hover-border-color: var(--editor-toolbar-border-color);
|
--editor-toolbar-hover-border-color: var(--editor-toolbar-border-color);
|
||||||
@ -284,6 +286,25 @@
|
|||||||
margin-inline: 2px;
|
margin-inline: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.highlightButton {
|
||||||
|
width: var(--editor-toolbar-height);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
mask-image: var(--editor-toolbar-highlight-image);
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: var(--editor-toolbar-fg-color);
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover::before {
|
||||||
|
background-color: var(--editor-toolbar-hover-fg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.delete {
|
.delete {
|
||||||
width: var(--editor-toolbar-height);
|
width: var(--editor-toolbar-height);
|
||||||
|
|
||||||
|
@ -424,6 +424,9 @@ const PDFViewerApplication = {
|
|||||||
annotationMode: AppOptions.get("annotationMode"),
|
annotationMode: AppOptions.get("annotationMode"),
|
||||||
annotationEditorMode,
|
annotationEditorMode,
|
||||||
annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
|
annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
|
||||||
|
enableHighlightFloatingButton: AppOptions.get(
|
||||||
|
"enableHighlightFloatingButton"
|
||||||
|
),
|
||||||
imageResourcesPath: AppOptions.get("imageResourcesPath"),
|
imageResourcesPath: AppOptions.get("imageResourcesPath"),
|
||||||
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
||||||
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
||||||
|
@ -143,6 +143,14 @@ const defaultOptions = {
|
|||||||
value: typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING"),
|
value: typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING"),
|
||||||
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
||||||
},
|
},
|
||||||
|
enableHighlightFloatingButton: {
|
||||||
|
// We'll probably want to make some experiments before enabling this
|
||||||
|
// in Firefox release, but it has to be temporary.
|
||||||
|
// TODO: remove it when unnecessary.
|
||||||
|
/** @type {boolean} */
|
||||||
|
value: typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING"),
|
||||||
|
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
|
||||||
|
},
|
||||||
enableML: {
|
enableML: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -214,6 +214,8 @@ class PDFViewer {
|
|||||||
|
|
||||||
#copyCallbackBound = null;
|
#copyCallbackBound = null;
|
||||||
|
|
||||||
|
#enableHighlightFloatingButton = false;
|
||||||
|
|
||||||
#enablePermissions = false;
|
#enablePermissions = false;
|
||||||
|
|
||||||
#mlManager = null;
|
#mlManager = null;
|
||||||
@ -282,6 +284,8 @@ class PDFViewer {
|
|||||||
options.annotationEditorMode ?? AnnotationEditorType.NONE;
|
options.annotationEditorMode ?? AnnotationEditorType.NONE;
|
||||||
this.#annotationEditorHighlightColors =
|
this.#annotationEditorHighlightColors =
|
||||||
options.annotationEditorHighlightColors || null;
|
options.annotationEditorHighlightColors || null;
|
||||||
|
this.#enableHighlightFloatingButton =
|
||||||
|
options.enableHighlightFloatingButton === true;
|
||||||
this.imageResourcesPath = options.imageResourcesPath || "";
|
this.imageResourcesPath = options.imageResourcesPath || "";
|
||||||
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
|
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||||
@ -863,6 +867,7 @@ class PDFViewer {
|
|||||||
pdfDocument,
|
pdfDocument,
|
||||||
this.pageColors,
|
this.pageColors,
|
||||||
this.#annotationEditorHighlightColors,
|
this.#annotationEditorHighlightColors,
|
||||||
|
this.#enableHighlightFloatingButton,
|
||||||
this.#mlManager
|
this.#mlManager
|
||||||
);
|
);
|
||||||
this.eventBus.dispatch("annotationeditoruimanager", {
|
this.eventBus.dispatch("annotationeditoruimanager", {
|
||||||
|
Loading…
Reference in New Issue
Block a user