[Editor] Make highlight annotations editable (bug 1883884)
The goal of this patch is to be able to edit existing highlight annotations.
This commit is contained in:
parent
0676ea19cf
commit
a62ceedb69
@ -705,6 +705,11 @@ class Annotation {
|
|||||||
this.data.pageIndex = params.pageIndex;
|
this.data.pageIndex = params.pageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const it = dict.get("IT");
|
||||||
|
if (it instanceof Name) {
|
||||||
|
this.data.it = it.name;
|
||||||
|
}
|
||||||
|
|
||||||
this._isOffscreenCanvasSupported =
|
this._isOffscreenCanvasSupported =
|
||||||
params.evaluatorOptions.isOffscreenCanvasSupported;
|
params.evaluatorOptions.isOffscreenCanvasSupported;
|
||||||
this._fallbackFontDict = null;
|
this._fallbackFontDict = null;
|
||||||
@ -1377,6 +1382,7 @@ class Annotation {
|
|||||||
class AnnotationBorderStyle {
|
class AnnotationBorderStyle {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.width = 1;
|
this.width = 1;
|
||||||
|
this.rawWidth = 1;
|
||||||
this.style = AnnotationBorderStyleType.SOLID;
|
this.style = AnnotationBorderStyleType.SOLID;
|
||||||
this.dashArray = [3];
|
this.dashArray = [3];
|
||||||
this.horizontalCornerRadius = 0;
|
this.horizontalCornerRadius = 0;
|
||||||
@ -1407,6 +1413,7 @@ class AnnotationBorderStyle {
|
|||||||
}
|
}
|
||||||
if (typeof width === "number") {
|
if (typeof width === "number") {
|
||||||
if (width > 0) {
|
if (width > 0) {
|
||||||
|
this.rawWidth = width;
|
||||||
const maxWidth = (rect[2] - rect[0]) / 2;
|
const maxWidth = (rect[2] - rect[0]) / 2;
|
||||||
const maxHeight = (rect[3] - rect[1]) / 2;
|
const maxHeight = (rect[3] - rect[1]) / 2;
|
||||||
|
|
||||||
@ -4283,6 +4290,10 @@ class InkAnnotation extends MarkupAnnotation {
|
|||||||
const { dict, xref } = params;
|
const { dict, xref } = params;
|
||||||
this.data.annotationType = AnnotationType.INK;
|
this.data.annotationType = AnnotationType.INK;
|
||||||
this.data.inkLists = [];
|
this.data.inkLists = [];
|
||||||
|
this.data.isEditable = !this.data.noHTML && this.data.it === "InkHighlight";
|
||||||
|
// We want to be able to add mouse listeners to the annotation.
|
||||||
|
this.data.noHTML = false;
|
||||||
|
this.data.opacity = dict.get("CA") || 1;
|
||||||
|
|
||||||
const rawInkLists = dict.getArray("InkList");
|
const rawInkLists = dict.getArray("InkList");
|
||||||
if (!Array.isArray(rawInkLists)) {
|
if (!Array.isArray(rawInkLists)) {
|
||||||
@ -4534,6 +4545,10 @@ class HighlightAnnotation extends MarkupAnnotation {
|
|||||||
|
|
||||||
const { dict, xref } = params;
|
const { dict, xref } = params;
|
||||||
this.data.annotationType = AnnotationType.HIGHLIGHT;
|
this.data.annotationType = AnnotationType.HIGHLIGHT;
|
||||||
|
this.data.isEditable = !this.data.noHTML;
|
||||||
|
// We want to be able to add mouse listeners to the annotation.
|
||||||
|
this.data.noHTML = false;
|
||||||
|
this.data.opacity = dict.get("CA") || 1;
|
||||||
|
|
||||||
const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
|
const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
|
||||||
if (quadPoints) {
|
if (quadPoints) {
|
||||||
@ -4573,11 +4588,15 @@ class HighlightAnnotation extends MarkupAnnotation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static createNewDict(annotation, xref, { apRef, ap }) {
|
static createNewDict(annotation, xref, { apRef, ap, oldAnnotation }) {
|
||||||
const { color, opacity, rect, rotation, user, quadPoints } = annotation;
|
const { color, opacity, rect, rotation, user, quadPoints } = annotation;
|
||||||
const highlight = new Dict(xref);
|
const highlight = oldAnnotation || new Dict(xref);
|
||||||
highlight.set("Type", Name.get("Annot"));
|
highlight.set("Type", Name.get("Annot"));
|
||||||
highlight.set("Subtype", Name.get("Highlight"));
|
highlight.set("Subtype", Name.get("Highlight"));
|
||||||
|
highlight.set(
|
||||||
|
oldAnnotation ? "M" : "CreationDate",
|
||||||
|
`D:${getModificationDate()}`
|
||||||
|
);
|
||||||
highlight.set("CreationDate", `D:${getModificationDate()}`);
|
highlight.set("CreationDate", `D:${getModificationDate()}`);
|
||||||
highlight.set("Rect", rect);
|
highlight.set("Rect", rect);
|
||||||
highlight.set("F", 4);
|
highlight.set("F", 4);
|
||||||
|
|||||||
@ -2807,7 +2807,11 @@ class InkAnnotationElement extends AnnotationElement {
|
|||||||
// Use the polyline SVG element since it allows us to use coordinates
|
// Use the polyline SVG element since it allows us to use coordinates
|
||||||
// directly and to draw both straight lines and curves.
|
// directly and to draw both straight lines and curves.
|
||||||
this.svgElementName = "svg:polyline";
|
this.svgElementName = "svg:polyline";
|
||||||
this.annotationEditorType = AnnotationEditorType.INK;
|
|
||||||
|
this.annotationEditorType =
|
||||||
|
this.data.it === "InkHighlight"
|
||||||
|
? AnnotationEditorType.HIGHLIGHT
|
||||||
|
: AnnotationEditorType.INK;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -2857,6 +2861,10 @@ class InkAnnotationElement extends AnnotationElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.container.append(svg);
|
this.container.append(svg);
|
||||||
|
|
||||||
|
if (this._isEditable) {
|
||||||
|
this._editOnDoubleClick();
|
||||||
|
}
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2876,6 +2884,7 @@ class HighlightAnnotationElement extends AnnotationElement {
|
|||||||
ignoreBorder: true,
|
ignoreBorder: true,
|
||||||
createQuadrilaterals: true,
|
createQuadrilaterals: true,
|
||||||
});
|
});
|
||||||
|
this.annotationEditorType = AnnotationEditorType.HIGHLIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -2884,6 +2893,8 @@ class HighlightAnnotationElement extends AnnotationElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.container.classList.add("highlightAnnotation");
|
this.container.classList.add("highlightAnnotation");
|
||||||
|
this._editOnDoubleClick();
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3247,6 +3258,7 @@ class AnnotationLayer {
|
|||||||
export {
|
export {
|
||||||
AnnotationLayer,
|
AnnotationLayer,
|
||||||
FreeTextAnnotationElement,
|
FreeTextAnnotationElement,
|
||||||
|
HighlightAnnotationElement,
|
||||||
InkAnnotationElement,
|
InkAnnotationElement,
|
||||||
StampAnnotationElement,
|
StampAnnotationElement,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -225,6 +225,10 @@ class DrawLayer {
|
|||||||
this.#mapping.get(id).classList.remove(className);
|
this.#mapping.get(id).classList.remove(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSVGRoot(id) {
|
||||||
|
return this.#mapping.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
remove(id) {
|
remove(id) {
|
||||||
if (this.#parent === null) {
|
if (this.#parent === null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -323,8 +323,10 @@ class AnnotationEditorLayer {
|
|||||||
editor = changedAnnotations.get(id);
|
editor = changedAnnotations.get(id);
|
||||||
if (editor) {
|
if (editor) {
|
||||||
this.#uiManager.addChangedExistingAnnotation(editor);
|
this.#uiManager.addChangedExistingAnnotation(editor);
|
||||||
editor.renderAnnotationElement(editable);
|
if (editor.renderAnnotationElement(editable)) {
|
||||||
editor.show(false);
|
// Content has changed, so we need to hide the editor.
|
||||||
|
editor.show(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
editable.show();
|
editable.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1367,6 +1367,7 @@ class AnnotationEditor {
|
|||||||
data.rect,
|
data.rect,
|
||||||
pageHeight
|
pageHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
editor.x = x / pageWidth;
|
editor.x = x / pageWidth;
|
||||||
editor.y = y / pageHeight;
|
editor.y = y / pageHeight;
|
||||||
editor.width = width / pageWidth;
|
editor.width = width / pageWidth;
|
||||||
@ -1765,7 +1766,7 @@ class AnnotationEditor {
|
|||||||
/**
|
/**
|
||||||
* Render an annotation in the annotation layer.
|
* Render an annotation in the annotation layer.
|
||||||
* @param {Object} annotation
|
* @param {Object} annotation
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement|null}
|
||||||
*/
|
*/
|
||||||
renderAnnotationElement(annotation) {
|
renderAnnotationElement(annotation) {
|
||||||
let content = annotation.container.querySelector(".annotationContent");
|
let content = annotation.container.querySelector(".annotationContent");
|
||||||
|
|||||||
@ -21,6 +21,10 @@ import {
|
|||||||
} from "../../shared/util.js";
|
} from "../../shared/util.js";
|
||||||
import { bindEvents, KeyboardManager } from "./tools.js";
|
import { bindEvents, KeyboardManager } from "./tools.js";
|
||||||
import { FreeOutliner, Outliner } from "./outliner.js";
|
import { FreeOutliner, Outliner } from "./outliner.js";
|
||||||
|
import {
|
||||||
|
HighlightAnnotationElement,
|
||||||
|
InkAnnotationElement,
|
||||||
|
} from "../annotation_layer.js";
|
||||||
import { AnnotationEditor } from "./editor.js";
|
import { AnnotationEditor } from "./editor.js";
|
||||||
import { ColorPicker } from "./color_picker.js";
|
import { ColorPicker } from "./color_picker.js";
|
||||||
import { noContextMenu } from "../display_utils.js";
|
import { noContextMenu } from "../display_utils.js";
|
||||||
@ -51,6 +55,8 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
#id = null;
|
#id = null;
|
||||||
|
|
||||||
|
#initialData = null;
|
||||||
|
|
||||||
#isFreeHighlight = false;
|
#isFreeHighlight = false;
|
||||||
|
|
||||||
#lastPoint = null;
|
#lastPoint = null;
|
||||||
@ -111,7 +117,7 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
this.#isFreeHighlight = true;
|
this.#isFreeHighlight = true;
|
||||||
this.#createFreeOutlines(params);
|
this.#createFreeOutlines(params);
|
||||||
this.#addToDrawLayer();
|
this.#addToDrawLayer();
|
||||||
} else {
|
} else if (this.#boxes) {
|
||||||
this.#anchorNode = params.anchorNode;
|
this.#anchorNode = params.anchorNode;
|
||||||
this.#anchorOffset = params.anchorOffset;
|
this.#anchorOffset = params.anchorOffset;
|
||||||
this.#focusNode = params.focusNode;
|
this.#focusNode = params.focusNode;
|
||||||
@ -316,15 +322,22 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
* @param {string} color
|
* @param {string} color
|
||||||
*/
|
*/
|
||||||
#updateColor(color) {
|
#updateColor(color) {
|
||||||
const setColor = col => {
|
const setColorAndOpacity = (col, opa) => {
|
||||||
this.color = col;
|
this.color = col;
|
||||||
this.parent?.drawLayer.changeColor(this.#id, col);
|
this.parent?.drawLayer.changeColor(this.#id, col);
|
||||||
this.#colorPicker?.updateColor(col);
|
this.#colorPicker?.updateColor(col);
|
||||||
|
this.#opacity = opa;
|
||||||
|
this.parent?.drawLayer.changeOpacity(this.#id, opa);
|
||||||
};
|
};
|
||||||
const savedColor = this.color;
|
const savedColor = this.color;
|
||||||
|
const savedOpacity = this.#opacity;
|
||||||
this.addCommands({
|
this.addCommands({
|
||||||
cmd: setColor.bind(this, color),
|
cmd: setColorAndOpacity.bind(
|
||||||
undo: setColor.bind(this, savedColor),
|
this,
|
||||||
|
color,
|
||||||
|
HighlightEditor._defaultOpacity
|
||||||
|
),
|
||||||
|
undo: setColorAndOpacity.bind(this, savedColor, savedOpacity),
|
||||||
post: this._uiManager.updateUI.bind(this._uiManager, this),
|
post: this._uiManager.updateUI.bind(this._uiManager, this),
|
||||||
mustExec: true,
|
mustExec: true,
|
||||||
type: AnnotationEditorParamsType.HIGHLIGHT_COLOR,
|
type: AnnotationEditorParamsType.HIGHLIGHT_COLOR,
|
||||||
@ -410,7 +423,9 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
onceAdded() {
|
onceAdded() {
|
||||||
this.parent.addUndoableEditor(this);
|
if (!this.annotationElementId) {
|
||||||
|
this.parent.addUndoableEditor(this);
|
||||||
|
}
|
||||||
this.div.focus();
|
this.div.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,29 +784,114 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
static deserialize(data, parent, uiManager) {
|
static deserialize(data, parent, uiManager) {
|
||||||
|
let initialData = null;
|
||||||
|
if (data instanceof HighlightAnnotationElement) {
|
||||||
|
const {
|
||||||
|
data: { quadPoints, rect, rotation, id, color, opacity },
|
||||||
|
parent: {
|
||||||
|
page: { pageNumber },
|
||||||
|
},
|
||||||
|
} = data;
|
||||||
|
initialData = data = {
|
||||||
|
annotationType: AnnotationEditorType.HIGHLIGHT,
|
||||||
|
color: Array.from(color),
|
||||||
|
opacity,
|
||||||
|
quadPoints,
|
||||||
|
boxes: null,
|
||||||
|
pageIndex: pageNumber - 1,
|
||||||
|
rect: rect.slice(0),
|
||||||
|
rotation,
|
||||||
|
id,
|
||||||
|
deleted: false,
|
||||||
|
};
|
||||||
|
} else if (data instanceof InkAnnotationElement) {
|
||||||
|
const {
|
||||||
|
data: {
|
||||||
|
inkLists,
|
||||||
|
rect,
|
||||||
|
rotation,
|
||||||
|
id,
|
||||||
|
color,
|
||||||
|
borderStyle: { rawWidth: thickness },
|
||||||
|
},
|
||||||
|
parent: {
|
||||||
|
page: { pageNumber },
|
||||||
|
},
|
||||||
|
} = data;
|
||||||
|
initialData = data = {
|
||||||
|
annotationType: AnnotationEditorType.HIGHLIGHT,
|
||||||
|
color: Array.from(color),
|
||||||
|
thickness,
|
||||||
|
inkLists,
|
||||||
|
boxes: null,
|
||||||
|
pageIndex: pageNumber - 1,
|
||||||
|
rect: rect.slice(0),
|
||||||
|
rotation,
|
||||||
|
id,
|
||||||
|
deleted: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { color, quadPoints, inkLists, opacity } = data;
|
||||||
const editor = super.deserialize(data, parent, uiManager);
|
const editor = super.deserialize(data, parent, uiManager);
|
||||||
|
|
||||||
const {
|
|
||||||
rect: [blX, blY, trX, trY],
|
|
||||||
color,
|
|
||||||
quadPoints,
|
|
||||||
} = data;
|
|
||||||
editor.color = Util.makeHexColor(...color);
|
editor.color = Util.makeHexColor(...color);
|
||||||
editor.#opacity = data.opacity;
|
editor.#opacity = opacity || 1;
|
||||||
|
if (inkLists) {
|
||||||
|
editor.#thickness = data.thickness;
|
||||||
|
}
|
||||||
|
editor.annotationElementId = data.id || null;
|
||||||
|
editor.#initialData = initialData;
|
||||||
|
|
||||||
const [pageWidth, pageHeight] = editor.pageDimensions;
|
const [pageWidth, pageHeight] = editor.pageDimensions;
|
||||||
editor.width = (trX - blX) / pageWidth;
|
const [pageX, pageY] = editor.pageTranslation;
|
||||||
editor.height = (trY - blY) / pageHeight;
|
|
||||||
const boxes = (editor.#boxes = []);
|
if (quadPoints) {
|
||||||
for (let i = 0; i < quadPoints.length; i += 8) {
|
const boxes = (editor.#boxes = []);
|
||||||
boxes.push({
|
for (let i = 0; i < quadPoints.length; i += 8) {
|
||||||
x: (quadPoints[4] - trX) / pageWidth,
|
boxes.push({
|
||||||
y: (trY - (1 - quadPoints[i + 5])) / pageHeight,
|
x: (quadPoints[i] - pageX) / pageWidth,
|
||||||
width: (quadPoints[i + 2] - quadPoints[i]) / pageWidth,
|
y: 1 - (quadPoints[i + 1] - pageY) / pageHeight,
|
||||||
height: (quadPoints[i + 5] - quadPoints[i + 1]) / pageHeight,
|
width: (quadPoints[i + 2] - quadPoints[i]) / pageWidth,
|
||||||
|
height: (quadPoints[i + 1] - quadPoints[i + 5]) / pageHeight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
editor.#createOutlines();
|
||||||
|
editor.#addToDrawLayer();
|
||||||
|
editor.rotate(editor.rotation);
|
||||||
|
} else if (inkLists) {
|
||||||
|
editor.#isFreeHighlight = true;
|
||||||
|
const points = inkLists[0];
|
||||||
|
const point = {
|
||||||
|
x: points[0] - pageX,
|
||||||
|
y: pageHeight - (points[1] - pageY),
|
||||||
|
};
|
||||||
|
const outliner = new FreeOutliner(
|
||||||
|
point,
|
||||||
|
[0, 0, pageWidth, pageHeight],
|
||||||
|
1,
|
||||||
|
editor.#thickness / 2,
|
||||||
|
true,
|
||||||
|
0.001
|
||||||
|
);
|
||||||
|
for (let i = 0, ii = points.length; i < ii; i += 2) {
|
||||||
|
point.x = points[i] - pageX;
|
||||||
|
point.y = pageHeight - (points[i + 1] - pageY);
|
||||||
|
outliner.add(point);
|
||||||
|
}
|
||||||
|
const { id, clipPathId } = parent.drawLayer.highlight(
|
||||||
|
outliner,
|
||||||
|
editor.color,
|
||||||
|
editor._defaultOpacity,
|
||||||
|
/* isPathUpdatable = */ true
|
||||||
|
);
|
||||||
|
editor.#createFreeOutlines({
|
||||||
|
highlightOutlines: outliner.getOutlines(),
|
||||||
|
highlightId: id,
|
||||||
|
clipPathId,
|
||||||
});
|
});
|
||||||
|
editor.#addToDrawLayer();
|
||||||
}
|
}
|
||||||
editor.#createOutlines();
|
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
@ -803,10 +903,18 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.deleted) {
|
||||||
|
return {
|
||||||
|
pageIndex: this.pageIndex,
|
||||||
|
id: this.annotationElementId,
|
||||||
|
deleted: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const rect = this.getRect(0, 0);
|
const rect = this.getRect(0, 0);
|
||||||
const color = AnnotationEditor._colorManager.convert(this.color);
|
const color = AnnotationEditor._colorManager.convert(this.color);
|
||||||
|
|
||||||
return {
|
const serialized = {
|
||||||
annotationType: AnnotationEditorType.HIGHLIGHT,
|
annotationType: AnnotationEditorType.HIGHLIGHT,
|
||||||
color,
|
color,
|
||||||
opacity: this.#opacity,
|
opacity: this.#opacity,
|
||||||
@ -818,6 +926,27 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
rotation: this.#getRotation(),
|
rotation: this.#getRotation(),
|
||||||
structTreeParentId: this._structTreeParentId,
|
structTreeParentId: this._structTreeParentId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialized.id = this.annotationElementId;
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hasElementChanged(serialized) {
|
||||||
|
const { color } = this.#initialData;
|
||||||
|
return serialized.color.some((c, i) => c !== color[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
renderAnnotationElement(annotation) {
|
||||||
|
annotation.updateEdited({
|
||||||
|
rect: this.getRect(0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static canCreateNewEmptyEditor() {
|
static canCreateNewEmptyEditor() {
|
||||||
|
|||||||
@ -32,6 +32,9 @@ import {
|
|||||||
scrollIntoView,
|
scrollIntoView,
|
||||||
setCaretAt,
|
setCaretAt,
|
||||||
switchToEditor,
|
switchToEditor,
|
||||||
|
waitAndClick,
|
||||||
|
waitForAnnotationModeChanged,
|
||||||
|
waitForSelectedEditor,
|
||||||
waitForSerialized,
|
waitForSerialized,
|
||||||
} from "./test_utils.mjs";
|
} from "./test_utils.mjs";
|
||||||
|
|
||||||
@ -1921,4 +1924,100 @@ describe("Highlight Editor", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Highlight (edit existing in double clicking on it)", () => {
|
||||||
|
let pages;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
pages = await loadAndWait(
|
||||||
|
"highlights.pdf",
|
||||||
|
".annotationEditorLayer",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
highlightEditorColors:
|
||||||
|
"yellow=#FFFF00,green=#00FF00,blue=#0000FF,pink=#FF00FF,red=#FF0102",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await closePages(pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must change the color of an highlight", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
const modeChangedHandle = await waitForAnnotationModeChanged(page);
|
||||||
|
await waitAndClick(page, "[data-annotation-id='687R']", { count: 2 });
|
||||||
|
await awaitPromise(modeChangedHandle);
|
||||||
|
await page.waitForSelector("#highlightParamsToolbarContainer");
|
||||||
|
|
||||||
|
const editorSelector = getEditorSelector(5);
|
||||||
|
await page.waitForSelector(editorSelector);
|
||||||
|
|
||||||
|
await waitAndClick(
|
||||||
|
page,
|
||||||
|
`${editorSelector} .editToolbar button.colorPicker`
|
||||||
|
);
|
||||||
|
await waitAndClick(
|
||||||
|
page,
|
||||||
|
`${editorSelector} .editToolbar button[title = "Red"]`
|
||||||
|
);
|
||||||
|
await page.waitForSelector(
|
||||||
|
`.page[data-page-number = "1"] svg.highlight[fill = "#FF0102"]`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Free Highlight (edit existing in double clicking on it)", () => {
|
||||||
|
let pages;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
pages = await loadAndWait(
|
||||||
|
"highlights.pdf",
|
||||||
|
".annotationEditorLayer",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
highlightEditorColors:
|
||||||
|
"yellow=#FFFF00,green=#00FF00,blue=#0000FF,pink=#FF00FF,red=#FF0102",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await closePages(pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must change the color of a free highlight", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
const modeChangedHandle = await waitForAnnotationModeChanged(page);
|
||||||
|
await page.click("[data-annotation-id='693R']", { count: 2 });
|
||||||
|
await awaitPromise(modeChangedHandle);
|
||||||
|
await page.waitForSelector("#highlightParamsToolbarContainer");
|
||||||
|
|
||||||
|
const editorSelector = getEditorSelector(6);
|
||||||
|
await page.waitForSelector(editorSelector);
|
||||||
|
await page.focus(editorSelector);
|
||||||
|
await waitForSelectedEditor(page, editorSelector);
|
||||||
|
|
||||||
|
await waitAndClick(
|
||||||
|
page,
|
||||||
|
`${editorSelector} .editToolbar button.colorPicker`
|
||||||
|
);
|
||||||
|
await waitAndClick(
|
||||||
|
page,
|
||||||
|
`${editorSelector} .editToolbar button[title = "Red"]`
|
||||||
|
);
|
||||||
|
await page.waitForSelector(
|
||||||
|
`.page[data-page-number = "1"] svg.highlight[fill = "#FF0102"]`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -194,6 +194,11 @@ async function clearInput(page, selector, waitForInputEvent = false) {
|
|||||||
: action();
|
: action();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function waitAndClick(page, selector, clickOptions = {}) {
|
||||||
|
await page.waitForSelector(selector, { visible: true });
|
||||||
|
await page.click(selector, clickOptions);
|
||||||
|
}
|
||||||
|
|
||||||
function getSelector(id) {
|
function getSelector(id) {
|
||||||
return `[data-element-id="${id}"]`;
|
return `[data-element-id="${id}"]`;
|
||||||
}
|
}
|
||||||
@ -800,6 +805,7 @@ export {
|
|||||||
serializeBitmapDimensions,
|
serializeBitmapDimensions,
|
||||||
setCaretAt,
|
setCaretAt,
|
||||||
switchToEditor,
|
switchToEditor,
|
||||||
|
waitAndClick,
|
||||||
waitForAnnotationEditorLayer,
|
waitForAnnotationEditorLayer,
|
||||||
waitForAnnotationModeChanged,
|
waitForAnnotationModeChanged,
|
||||||
waitForEntryInStorage,
|
waitForEntryInStorage,
|
||||||
|
|||||||
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
@ -662,3 +662,5 @@
|
|||||||
!file_pdfjs_test.pdf
|
!file_pdfjs_test.pdf
|
||||||
!issue18536.pdf
|
!issue18536.pdf
|
||||||
!issue18561.pdf
|
!issue18561.pdf
|
||||||
|
!highlights.pdf
|
||||||
|
!highlight.pdf
|
||||||
|
|||||||
BIN
test/pdfs/highlight.pdf
Executable file
BIN
test/pdfs/highlight.pdf
Executable file
Binary file not shown.
BIN
test/pdfs/highlights.pdf
Executable file
BIN
test/pdfs/highlights.pdf
Executable file
Binary file not shown.
@ -10202,5 +10202,277 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"link": true,
|
"link": true,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "highlight-update-print",
|
||||||
|
"file": "pdfs/highlight.pdf",
|
||||||
|
"md5": "74671e2d9541931a606e886114bf3efa",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"print": true,
|
||||||
|
"annotationStorage": {
|
||||||
|
"pdfjs_internal_editor_0": {
|
||||||
|
"annotationType": 9,
|
||||||
|
"color": [83, 255, 188],
|
||||||
|
"opacity": 1,
|
||||||
|
"thickness": 12,
|
||||||
|
"quadPoints": [
|
||||||
|
224.95899963378906, 649.6790161132812, 257.0950012207031,
|
||||||
|
649.6790161132812, 224.95899963378906, 665.8670043945312,
|
||||||
|
257.0950012207031, 665.8670043945312
|
||||||
|
],
|
||||||
|
"outlines": [
|
||||||
|
[
|
||||||
|
224.62632386, 649.4661241, 224.62632386, 666.0718055, 257.44364369,
|
||||||
|
666.0718055, 257.44364369, 649.4661241
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [224.62632386, 649.4661241, 257.44364369, 666.0718055],
|
||||||
|
"rotation": 0,
|
||||||
|
"structTreeParentId": null,
|
||||||
|
"id": "24R"
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_1": {
|
||||||
|
"annotationType": 9,
|
||||||
|
"color": [128, 235, 255],
|
||||||
|
"opacity": 1,
|
||||||
|
"thickness": 12,
|
||||||
|
"quadPoints": null,
|
||||||
|
"outlines": {
|
||||||
|
"outline": [
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
231.02000427246094,
|
||||||
|
575.9500122070312,
|
||||||
|
234.9244860593802,
|
||||||
|
575.8426675799172,
|
||||||
|
235.67976763594078,
|
||||||
|
575.8027971554493,
|
||||||
|
236.50453905085675,
|
||||||
|
575.765994157359,
|
||||||
|
237.32931046577278,
|
||||||
|
575.7291911592689,
|
||||||
|
238.15139102232476,
|
||||||
|
575.6967454939373,
|
||||||
|
238.97078072051278,
|
||||||
|
575.6686571613642,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
240.19986526779482,
|
||||||
|
575.6265246625046,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
248.19520403340397,
|
||||||
|
575.3534715117306,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
248.6047837595648,
|
||||||
|
587.3464796601443,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
240.60944499395563,
|
||||||
|
587.6195328109183,
|
||||||
|
238.6632878655088,
|
||||||
|
587.6857348021831,
|
||||||
|
237.88825461323634,
|
||||||
|
587.7160188758909,
|
||||||
|
237.11665096007022,
|
||||||
|
587.7501062268005,
|
||||||
|
236.3450473069041,
|
||||||
|
587.7841935777101,
|
||||||
|
235.50103901924535,
|
||||||
|
587.8260330788092,
|
||||||
|
234.5846260970941,
|
||||||
|
587.875624730098,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
231.02000427246094,
|
||||||
|
587.9500122070312
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
231.02000427246094, 581.9500122070312, 241.21000671386722,
|
||||||
|
581.9500122070312, 243.60000610351562, 581.3499755859375, 246,
|
||||||
|
581.3499755859375, 248.39999389648438, 581.3499755859375,
|
||||||
|
248.39999389648438, 581.3499755859375
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
230.69150427246095, 575.1494715117307, 248.9332837595648,
|
||||||
|
588.1540122070312
|
||||||
|
],
|
||||||
|
"rotation": 0,
|
||||||
|
"structTreeParentId": null,
|
||||||
|
"id": "41R"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "highlight-update-save-print",
|
||||||
|
"file": "pdfs/highlight.pdf",
|
||||||
|
"md5": "74671e2d9541931a606e886114bf3efa",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"save": true,
|
||||||
|
"print": true,
|
||||||
|
"annotationStorage": {
|
||||||
|
"pdfjs_internal_editor_0": {
|
||||||
|
"annotationType": 9,
|
||||||
|
"color": [83, 255, 188],
|
||||||
|
"opacity": 1,
|
||||||
|
"thickness": 12,
|
||||||
|
"quadPoints": [
|
||||||
|
224.95899963378906, 649.6790161132812, 257.0950012207031,
|
||||||
|
649.6790161132812, 224.95899963378906, 665.8670043945312,
|
||||||
|
257.0950012207031, 665.8670043945312
|
||||||
|
],
|
||||||
|
"outlines": [
|
||||||
|
[
|
||||||
|
224.62632386, 649.4661241, 224.62632386, 666.0718055, 257.44364369,
|
||||||
|
666.0718055, 257.44364369, 649.4661241
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [224.62632386, 649.4661241, 257.44364369, 666.0718055],
|
||||||
|
"rotation": 0,
|
||||||
|
"structTreeParentId": null,
|
||||||
|
"id": "24R"
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_1": {
|
||||||
|
"annotationType": 9,
|
||||||
|
"color": [128, 235, 255],
|
||||||
|
"opacity": 1,
|
||||||
|
"thickness": 12,
|
||||||
|
"quadPoints": null,
|
||||||
|
"outlines": {
|
||||||
|
"outline": [
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
231.02000427246094,
|
||||||
|
575.9500122070312,
|
||||||
|
234.9244860593802,
|
||||||
|
575.8426675799172,
|
||||||
|
235.67976763594078,
|
||||||
|
575.8027971554493,
|
||||||
|
236.50453905085675,
|
||||||
|
575.765994157359,
|
||||||
|
237.32931046577278,
|
||||||
|
575.7291911592689,
|
||||||
|
238.15139102232476,
|
||||||
|
575.6967454939373,
|
||||||
|
238.97078072051278,
|
||||||
|
575.6686571613642,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
240.19986526779482,
|
||||||
|
575.6265246625046,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
248.19520403340397,
|
||||||
|
575.3534715117306,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
248.6047837595648,
|
||||||
|
587.3464796601443,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
240.60944499395563,
|
||||||
|
587.6195328109183,
|
||||||
|
238.6632878655088,
|
||||||
|
587.6857348021831,
|
||||||
|
237.88825461323634,
|
||||||
|
587.7160188758909,
|
||||||
|
237.11665096007022,
|
||||||
|
587.7501062268005,
|
||||||
|
236.3450473069041,
|
||||||
|
587.7841935777101,
|
||||||
|
235.50103901924535,
|
||||||
|
587.8260330788092,
|
||||||
|
234.5846260970941,
|
||||||
|
587.875624730098,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
231.02000427246094,
|
||||||
|
587.9500122070312
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
231.02000427246094, 581.9500122070312, 241.21000671386722,
|
||||||
|
581.9500122070312, 243.60000610351562, 581.3499755859375, 246,
|
||||||
|
581.3499755859375, 248.39999389648438, 581.3499755859375,
|
||||||
|
248.39999389648438, 581.3499755859375
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
230.69150427246095, 575.1494715117307, 248.9332837595648,
|
||||||
|
588.1540122070312
|
||||||
|
],
|
||||||
|
"rotation": 0,
|
||||||
|
"structTreeParentId": null,
|
||||||
|
"id": "41R"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "highlight-delete-print",
|
||||||
|
"file": "pdfs/highlight.pdf",
|
||||||
|
"md5": "74671e2d9541931a606e886114bf3efa",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"print": true,
|
||||||
|
"annotationStorage": {
|
||||||
|
"pdfjs_internal_editor_0": {
|
||||||
|
"annotationType": 9,
|
||||||
|
"id": "24R",
|
||||||
|
"deleted": true,
|
||||||
|
"pageIndex": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "highlight-delete-save-print",
|
||||||
|
"file": "pdfs/highlight.pdf",
|
||||||
|
"md5": "74671e2d9541931a606e886114bf3efa",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"print": true,
|
||||||
|
"save": true,
|
||||||
|
"annotationStorage": {
|
||||||
|
"pdfjs_internal_editor_1": {
|
||||||
|
"annotationType": 9,
|
||||||
|
"id": "41R",
|
||||||
|
"deleted": true,
|
||||||
|
"pageIndex": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user