r2-navigator-js
Version:
Readium 2 'navigator' for NodeJS (TypeScript)
1,070 lines • 105 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.recreateAllHighlightsDebounced = exports.setDrawMargin = exports.HIGHLIGHT_GROUP_PAGEBREAK = exports.HIGHLIGHT_GROUP_TTS = exports.ENABLE_PAGEBREAK_MARGIN_TEXT_EXPERIMENT = exports.ENABLE_CSS_HIGHLIGHTS = exports.ENABLE_FLOATING_UI = void 0;
exports.getBoundingClientRectOfDocumentBody = getBoundingClientRectOfDocumentBody;
exports.hideAllhighlights = hideAllhighlights;
exports.destroyAllhighlights = destroyAllhighlights;
exports.destroyHighlight = destroyHighlight;
exports.destroyHighlightsGroup = destroyHighlightsGroup;
exports.recreateAllHighlightsRaw = recreateAllHighlightsRaw;
exports.recreateAllHighlights = recreateAllHighlights;
exports.createHighlights = createHighlights;
exports.createHighlight = createHighlight;
const crypto = require("crypto");
const debounce = require("debounce");
const electron_1 = require("electron");
const events_1 = require("../../common/events");
const highlight_1 = require("../../common/highlight");
const readium_css_inject_1 = require("../../common/readium-css-inject");
const rect_utils_1 = require("../common/rect-utils");
const readium_css_1 = require("./readium-css");
const selection_1 = require("./selection");
const styles_1 = require("../../common/styles");
const readium_css_2 = require("./readium-css");
const core_1 = require("@flatten-js/core");
const { unify, subtract } = core_1.BooleanOperations;
const dom_1 = require("@floating-ui/dom");
const IS_DEV = (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "dev");
window.DEBUG_RECTS = IS_DEV && rect_utils_1.VERBOSE;
exports.ENABLE_FLOATING_UI = true;
exports.ENABLE_CSS_HIGHLIGHTS = true && !!CSS.highlights;
exports.ENABLE_PAGEBREAK_MARGIN_TEXT_EXPERIMENT = false;
let lastMouseDownX = -1;
let lastMouseDownY = -1;
let bodyEventListenersSet = false;
let _highlightsContainer;
let _timeoutMouseMove;
const TIMEOUT_MOUSE_MS = 200;
const cleanupPolygon = (polygonAccumulator, off) => {
const DEBUG_RECTS = window.DEBUG_RECTS;
const minLength = Math.abs(off) + 1;
let nSegments = 0;
let nArcs = 0;
let total = 0;
if (DEBUG_RECTS) {
console.log("--====}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
}
for (const e of polygonAccumulator.edges) {
const edge = e;
if (edge.isSegment) {
nSegments++;
const segment = edge.shape;
const l = segment.length;
if (core_1.Utils.LE(l, minLength)) {
total++;
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT small LENGTH: " + l + "(" + off + ")");
}
}
else {
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT ok LENGTH: " + l + "(" + off + ")");
}
}
}
else if (edge.isArc) {
nArcs++;
if (DEBUG_RECTS) {
console.log("--POLYGON ARC");
}
}
}
if (DEBUG_RECTS) {
console.log("--====");
console.log("--==== POLYGON SEGMENT small TOTAL 1: " + total);
console.log("--==== POLYGON SEGMENT small SEGMENTS 1: " + nSegments);
console.log("--==== POLYGON SEGMENT small ARCS 1: " + nArcs);
}
total = 0;
nSegments = 0;
nArcs = 0;
if (DEBUG_RECTS) {
console.log("--====}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
}
for (const f of polygonAccumulator.faces) {
const face = f;
for (const e of face.edges) {
const edge = e;
if (edge.isSegment) {
nSegments++;
const segment = edge.shape;
const l = segment.length;
if (core_1.Utils.LE(l, minLength)) {
total++;
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT small LENGTH: " + l + "(" + off + ")");
}
}
else {
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT ok LENGTH: " + l + "(" + off + ")");
}
}
}
else if (edge.isArc) {
nArcs++;
if (DEBUG_RECTS) {
console.log("--POLYGON ARC");
}
}
}
}
if (DEBUG_RECTS) {
console.log("--====");
console.log("--==== POLYGON SEGMENT small TOTAL 2: " + total);
console.log("--==== POLYGON SEGMENT small SEGMENTS 2: " + nSegments);
console.log("--==== POLYGON SEGMENT small ARCS 2: " + nArcs);
}
total = 0;
nSegments = 0;
nArcs = 0;
if (DEBUG_RECTS) {
console.log("--====}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
}
for (const f of polygonAccumulator.faces) {
const face = f;
let edge = face.first;
while (edge) {
if (edge.isSegment) {
nSegments++;
const segment = edge.shape;
const l = segment.length;
if (core_1.Utils.LE(l, minLength)) {
total++;
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT small LENGTH: " + l + "(" + off + ")");
}
}
else {
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT ok LENGTH: " + l + "(" + off + ")");
}
}
}
else if (edge.isArc) {
nArcs++;
if (DEBUG_RECTS) {
console.log("--POLYGON ARC");
}
}
if (edge == face.last) {
break;
}
edge = edge.next;
}
}
if (DEBUG_RECTS) {
console.log("--====");
console.log("--==== POLYGON SEGMENT small TOTAL 3: " + total);
console.log("--==== POLYGON SEGMENT small SEGMENTS 3: " + nSegments);
console.log("--==== POLYGON SEGMENT small ARCS 3: " + nArcs);
console.log("--====}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
}
const faces = Array.from(polygonAccumulator.faces);
for (const f of faces) {
const face = f;
if (DEBUG_RECTS) {
console.log("~~~~ POLY FACE");
}
const edges = Array.from(face.edges);
const edgeShapes = edges.map((edge) => edge.shape);
let chainedEdgeShapes = [];
while (edgeShapes.length) {
if (DEBUG_RECTS) {
console.log("~~~~ POLY EDGE SHAPE");
}
if (!chainedEdgeShapes.length) {
const last = edgeShapes.pop();
chainedEdgeShapes.push(last);
continue;
}
const lastInChain = chainedEdgeShapes[chainedEdgeShapes.length - 1];
const lastInChainStartPoint = lastInChain.breakToFunctional ? lastInChain.start : lastInChain.start;
const lastInChainEndPoint = lastInChain.breakToFunctional ? lastInChain.end : lastInChain.end;
const shapesBefore = [];
const shapesAfter = [];
for (const edgeShape of edgeShapes) {
const edgeShapeStartPoint = edgeShape.breakToFunctional ? edgeShape.start : edgeShape.start;
const edgeShapeEndPoint = edgeShape.breakToFunctional ? edgeShape.end : edgeShape.end;
if (core_1.Utils.EQ(lastInChainStartPoint.x, edgeShapeEndPoint.x) && core_1.Utils.EQ(lastInChainStartPoint.y, edgeShapeEndPoint.y)) {
shapesBefore.push(edgeShape);
}
if (core_1.Utils.EQ(lastInChainEndPoint.x, edgeShapeStartPoint.x) && core_1.Utils.EQ(lastInChainEndPoint.y, edgeShapeStartPoint.y)) {
shapesAfter.push(edgeShape);
}
}
if (shapesBefore.length > 1 || shapesAfter.length > 1 || shapesAfter.length === 0) {
if (DEBUG_RECTS) {
console.log("~~~~ POLY SHAPES BEFORE/AFTER ABORT: " + shapesBefore.length + " ... " + shapesAfter.length);
}
chainedEdgeShapes = [];
break;
}
const startPoint = shapesAfter[0].breakToFunctional ? shapesAfter[0].start : shapesAfter[0].start;
const endPoint = shapesAfter[0].breakToFunctional ? shapesAfter[0].end : shapesAfter[0].end;
if (DEBUG_RECTS) {
console.log("*** SEGMENT/ARC --- START: (" + startPoint.x + ", " + startPoint.y + ") END: (" + endPoint.x + ", " + endPoint.y + ")");
}
edgeShapes.splice(edgeShapes.indexOf(shapesAfter[0]), 1);
chainedEdgeShapes.push(shapesAfter[0]);
if (chainedEdgeShapes.length === edges.length) {
const edgeShapeEndPoint = shapesAfter[0].breakToFunctional ? shapesAfter[0].end : shapesAfter[0].end;
const firstInChainStartPoint = chainedEdgeShapes[0].breakToFunctional ? chainedEdgeShapes[0].start : chainedEdgeShapes[0].start;
if (!core_1.Utils.EQ(firstInChainStartPoint.x, edgeShapeEndPoint.x) || !core_1.Utils.EQ(firstInChainStartPoint.y, edgeShapeEndPoint.y)) {
if (DEBUG_RECTS) {
console.log("~~~~ POLY SHAPES TAIL/HEAD ABORT");
}
chainedEdgeShapes = [];
break;
}
}
}
let previousSegment;
let previousSmallSegment;
const newEdgeShapes = [];
let hasChanged = false;
for (const edgeShape of chainedEdgeShapes) {
if (!edgeShape.breakToFunctional) {
const segment = edgeShape;
const l = segment.length;
if (DEBUG_RECTS) {
console.log("--POLYGON SLOPES: " + (previousSegment === null || previousSegment === void 0 ? void 0 : previousSegment.slope) + " vs. " + segment.slope);
}
if (previousSegment && core_1.Utils.EQ(previousSegment.slope, segment.slope)) {
if (DEBUG_RECTS) {
console.log("--POLYGON SLOPE EQUAL ... merge :)");
}
hasChanged = true;
newEdgeShapes.pop();
const seg = new core_1.Segment(new core_1.Point(previousSegment.start.x, previousSegment.start.y), new core_1.Point(segment.end.x, segment.end.y));
newEdgeShapes.push(seg);
previousSmallSegment = undefined;
previousSegment = seg;
if (chainedEdgeShapes.indexOf(edgeShape) === chainedEdgeShapes.length - 1 && !newEdgeShapes[0].breakToFunctional && core_1.Utils.EQ(newEdgeShapes[0].slope, seg.slope)) {
if (DEBUG_RECTS) {
console.log("--POLYGON SLOPE EQUAL (tail/head link) 1... merge :)");
}
hasChanged = true;
newEdgeShapes.splice(0, 1);
const seg2 = new core_1.Segment(new core_1.Point(newEdgeShapes[0].start.x, newEdgeShapes[0].start.y), new core_1.Point(seg.end.x, seg.end.y));
newEdgeShapes.push(seg2);
previousSmallSegment = undefined;
previousSegment = seg2;
}
}
else if (newEdgeShapes.length && chainedEdgeShapes.indexOf(edgeShape) === chainedEdgeShapes.length - 1 && !newEdgeShapes[0].breakToFunctional && core_1.Utils.EQ(newEdgeShapes[0].slope, segment.slope)) {
if (DEBUG_RECTS) {
console.log("--POLYGON SLOPE EQUAL (tail/head link) 2... merge :)");
}
hasChanged = true;
newEdgeShapes.splice(0, 1);
const seg = new core_1.Segment(new core_1.Point(newEdgeShapes[0].start.x, newEdgeShapes[0].start.y), new core_1.Point(segment.end.x, segment.end.y));
newEdgeShapes.push(seg);
previousSmallSegment = undefined;
previousSegment = seg;
}
else if (core_1.Utils.LE(l, minLength)) {
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT small LENGTH: " + l + "(" + off + ")");
}
if (previousSmallSegment) {
if (DEBUG_RECTS) {
console.log("-->>>> POLYGON SEGMENT small will merge :) ...");
}
hasChanged = true;
newEdgeShapes.pop();
const seg = new core_1.Segment(new core_1.Point(previousSmallSegment.start.x, previousSmallSegment.start.y), new core_1.Point(segment.end.x, segment.end.y));
newEdgeShapes.push(seg);
previousSmallSegment = undefined;
previousSegment = seg;
}
else if (newEdgeShapes.length && chainedEdgeShapes.indexOf(edgeShape) === chainedEdgeShapes.length - 1 && !newEdgeShapes[0].breakToFunctional && core_1.Utils.LE(newEdgeShapes[0].length, minLength)) {
if (DEBUG_RECTS) {
console.log("-->>>> POLYGON SEGMENT small (tail/head link) will merge :) ...");
}
hasChanged = true;
newEdgeShapes.splice(0, 1);
const seg = new core_1.Segment(new core_1.Point(newEdgeShapes[0].start.x, newEdgeShapes[0].start.y), new core_1.Point(segment.end.x, segment.end.y));
;
newEdgeShapes.push(seg);
previousSmallSegment = undefined;
previousSegment = seg;
}
else {
newEdgeShapes.push(segment);
previousSmallSegment = segment;
previousSegment = segment;
}
}
else {
if (DEBUG_RECTS) {
console.log("--POLYGON SEGMENT ok LENGTH: " + l + "(" + off + ")");
}
previousSmallSegment = undefined;
newEdgeShapes.push(segment);
previousSegment = segment;
}
}
else {
if (DEBUG_RECTS) {
console.log("--POLYGON ARC");
}
previousSmallSegment = undefined;
previousSegment = undefined;
newEdgeShapes.push(edgeShape);
}
}
if (hasChanged) {
if (DEBUG_RECTS) {
console.log("-->>>> POLYGON face changed :)");
}
polygonAccumulator.deleteFace(face);
polygonAccumulator.addFace(newEdgeShapes);
}
}
};
const addEdgePoints = (polygon, offset) => {
const boxes = [];
for (const f of polygon.faces) {
const face = f;
for (const edge of face.edges) {
if (edge.isSegment) {
const segment = edge.shape;
const bStart = new core_1.Box(segment.start.x - offset, segment.start.y - offset, segment.start.x + offset * 2, segment.start.y + offset * 2);
boxes.push(bStart);
const bEnd = new core_1.Box(segment.end.x - offset, segment.end.y - offset, segment.end.x + offset * 2, segment.end.y + offset * 2);
boxes.push(bEnd);
}
else {
const arc = edge.shape;
const bStart = new core_1.Box(arc.start.x - offset, arc.start.y - offset, arc.start.x + offset * 2, arc.start.y + offset * 2);
boxes.push(bStart);
const bEnd = new core_1.Box(arc.end.x - offset, arc.end.y - offset, arc.end.x + offset * 2, arc.end.y + offset * 2);
boxes.push(bEnd);
}
}
}
for (const box of boxes) {
polygon.addFace(box);
}
};
const BASE_ORIENTATION = core_1.ORIENTATION.CCW;
const USE_SEGMENT_JOINS_NOT_ARCS = false;
function arcSE(center, start, end, counterClockwise) {
const DEBUG_RECTS = window.DEBUG_RECTS;
const startAngle = Number((new core_1.Vector(center, start).slope).toPrecision(12));
let endAngle = Number((new core_1.Vector(center, end).slope).toPrecision(12));
if (core_1.Utils.EQ(startAngle, endAngle)) {
if (DEBUG_RECTS) {
console.log("--POLYGON ARC ORIENTATION CCW/CW inverse");
}
endAngle += 2 * Math.PI;
counterClockwise = !counterClockwise;
}
const r = Number((new core_1.Vector(center, start).length).toPrecision(12));
;
return new core_1.Arc(center, r, startAngle, endAngle, counterClockwise);
}
function offset_(polygon, off, useSegmentJoinsNotArcs) {
const DEBUG_RECTS = window.DEBUG_RECTS;
const postponeFinalUnify = off > 0;
let polygonAccumulator = postponeFinalUnify ? undefined : polygon.clone();
for (const f of polygon.faces) {
const face = f;
for (const edge of face.edges) {
if (edge.isSegment) {
const polygonEdge = new core_1.Polygon();
const segment = edge.shape;
const v_seg = new core_1.Vector(segment.end.x - segment.start.x, segment.end.y - segment.start.y);
const v_seg_unit = v_seg.normalize();
const absOffset = Math.abs(off);
const v_left = v_seg_unit.rotate90CCW().multiply(absOffset);
const v_right = v_seg_unit.rotate90CW().multiply(absOffset);
const seg_left = segment.translate(v_left).reverse();
const seg_right = segment.translate(v_right);
const seg_left_ = new core_1.Segment(new core_1.Point(Number((seg_left.start.x).toPrecision(12)), Number((seg_left.start.y).toPrecision(12))), new core_1.Point(Number((seg_left.end.x).toPrecision(12)), Number((seg_left.end.y).toPrecision(12))));
const seg_right_ = new core_1.Segment(new core_1.Point(Number((seg_right.start.x).toPrecision(12)), Number((seg_right.start.y).toPrecision(12))), new core_1.Point(Number((seg_right.end.x).toPrecision(12)), Number((seg_right.end.y).toPrecision(12))));
const orientation = BASE_ORIENTATION === core_1.ORIENTATION.CCW ? core_1.CCW : core_1.CW;
const cap1 = arcSE(segment.start, seg_left_.end, seg_right_.start, orientation);
const cap2 = arcSE(segment.end, seg_right_.end, seg_left_.start, orientation);
const cap1_ = useSegmentJoinsNotArcs
?
new core_1.Segment(seg_left_.end, seg_right_.start)
:
cap1;
const cap2_ = useSegmentJoinsNotArcs
?
new core_1.Segment(seg_right_.end, seg_left_.start)
:
cap2;
const face = polygonEdge.addFace([
seg_left_,
cap1_,
seg_right_,
cap2_,
]);
if (face.orientation() !== BASE_ORIENTATION) {
if (DEBUG_RECTS) {
console.log("--POLYGON FACE ORIENTATION CCW/CW reverse() 1");
}
face.reverse();
}
if (!(polygonAccumulator || polygonEdge).faces.size) {
if (DEBUG_RECTS) {
console.log("--################# POLYGON BEFORE unify/substract HAS NO FACES!! " + (polygonAccumulator || polygonEdge).faces.size);
}
}
if (off > 0) {
polygonAccumulator = polygonAccumulator ? unify(polygonAccumulator, polygonEdge) : polygonEdge;
}
else {
polygonAccumulator = polygonAccumulator ? subtract(polygonAccumulator, polygonEdge) : polygonEdge;
}
if (!(polygonAccumulator || polygonEdge).faces.size) {
if (DEBUG_RECTS) {
console.log("--################# POLYGON AFTER unify/substract HAS NO FACES!! " + (polygonAccumulator || polygonEdge).faces.size);
}
if (!useSegmentJoinsNotArcs) {
if (DEBUG_RECTS) {
console.log("--##### POLYGON AFTER unify/substract try again without arc, only segment joiners ...");
}
return offset_(polygon, off, true);
}
}
else {
if (DEBUG_RECTS) {
console.log("--################# POLYGON AFTER unify/substract FACES: " + (polygonAccumulator || polygonEdge).edges.size + " /// " + (polygonAccumulator || polygonEdge).faces.size);
}
}
for (const f of polygonAccumulator.faces) {
const face = f;
if (face.edges.length < 4) {
if (DEBUG_RECTS) {
console.log("-------- POLYGON FACE EDGES not at least 4??!");
}
if (!useSegmentJoinsNotArcs) {
if (DEBUG_RECTS) {
console.log("--##### POLYGON AFTER unify/substract try again without arc, only segment joiners ...");
}
return offset_(polygon, off, true);
}
}
if (face.orientation() !== BASE_ORIENTATION) {
if (DEBUG_RECTS) {
console.log("-------- POLYGON FACE ORIENTATION");
}
}
}
}
else {
console.log("!!!!!!!! POLYGON ARC??!");
return polygon;
}
}
}
Array.from((polygonAccumulator ? polygonAccumulator : polygon).faces).forEach((face) => {
if (face.orientation() !== BASE_ORIENTATION) {
if (DEBUG_RECTS) {
console.log("--HIGH WEBVIEW-- removing polygon orientation face / inner hole (offset poly 1))");
}
if (polygonAccumulator) {
polygonAccumulator.deleteFace(face);
}
}
});
if (polygonAccumulator && postponeFinalUnify) {
polygonAccumulator = unify(polygonAccumulator, polygon);
}
Array.from((polygonAccumulator ? polygonAccumulator : polygon).faces).forEach((face) => {
if (face.orientation() !== BASE_ORIENTATION) {
if (DEBUG_RECTS) {
console.log("--HIGH WEBVIEW-- removing polygon orientation face / inner hole (offset poly 2))");
}
if (polygonAccumulator) {
polygonAccumulator.deleteFace(face);
}
}
});
if (polygonAccumulator) {
if (!polygonAccumulator.faces.size) {
if (DEBUG_RECTS) {
console.log("--################# POLYGON INTERMEDIARY HAS NO FACES!! " + polygonAccumulator.faces.size);
}
}
cleanupPolygon(polygonAccumulator, off);
}
let resPoly = polygonAccumulator ? polygonAccumulator : polygon;
if (!resPoly.faces.size) {
if (DEBUG_RECTS) {
console.log("--################# POLYGON INTERMEDIARY HAS NO FACES!! " + resPoly.faces.size);
}
if (polygonAccumulator) {
if (DEBUG_RECTS) {
console.log("--################# FALLBACK TO SINGLE FACE POLY (BEFORE SUBSTRACT/UNIFY): " + polygon.faces.size);
}
resPoly = polygon;
}
}
return resPoly;
}
function offset(originaPolygon, off, useSegmentJoinsNotArcs = USE_SEGMENT_JOINS_NOT_ARCS) {
const DEBUG_RECTS = window.DEBUG_RECTS;
off = Number((off).toPrecision(12));
if (core_1.Utils.EQ_0(off)) {
return originaPolygon;
}
const singleFacePolygons = [];
for (const f of originaPolygon.faces) {
const face = f;
const poly = new core_1.Polygon();
poly.addFace(face.edges.map((edge) => edge.shape));
singleFacePolygons.push(poly);
}
const singlePolygon = new core_1.Polygon();
for (const polygon of singleFacePolygons) {
const resPoly = offset_(polygon, off, useSegmentJoinsNotArcs);
for (const f of resPoly.faces) {
const face = f;
singlePolygon.addFace(face.edges.map(((edge) => edge.shape)));
}
}
if (!singlePolygon.faces.size) {
if (DEBUG_RECTS) {
console.log("--##### POLYGON OFFSET HAS NO FACES!! " + singlePolygon.faces.size);
}
if (!useSegmentJoinsNotArcs) {
if (DEBUG_RECTS) {
console.log("--##### POLYGON OFFSET try again without arc, only segment joiners ...");
}
return offset(originaPolygon, off, true);
}
}
return singlePolygon;
}
const DEFAULT_BACKGROUND_COLOR = {
blue: 0,
green: 0,
red: 255,
};
const _highlights = [];
exports.HIGHLIGHT_GROUP_TTS = "tts";
exports.HIGHLIGHT_GROUP_PAGEBREAK = "pagebreak";
let _drawMargin = false;
const drawMargin = (h) => {
if (h.group === exports.HIGHLIGHT_GROUP_TTS) {
return false;
}
if (h.drawType === highlight_1.HighlightDrawTypeOpacityMask || h.drawType === highlight_1.HighlightDrawTypeOpacityMaskRuler || h.drawType === highlight_1.HighlightDrawTypeMarginBookmark) {
return true;
}
if (h.group === exports.HIGHLIGHT_GROUP_PAGEBREAK) {
return true;
}
if (Array.isArray(_drawMargin)) {
if (h.group) {
return _drawMargin.includes(h.group);
}
return false;
}
return _drawMargin;
};
const setDrawMargin = (win, drawMargin) => {
_drawMargin = drawMargin;
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- _drawMargin: " + JSON.stringify(_drawMargin, null, 4));
}
recreateAllHighlightsRaw(win);
};
exports.setDrawMargin = setDrawMargin;
const SVG_XML_NAMESPACE = "http://www.w3.org/2000/svg";
function getBoundingClientRectOfDocumentBody(win) {
return win.document.body.getBoundingClientRect();
}
function processMouseEvent(win, ev) {
var _a;
if (_timeoutMouseMove) {
clearTimeout(_timeoutMouseMove);
_timeoutMouseMove = undefined;
}
if (!_highlightsContainer) {
return;
}
const isMouseMove = ev.type === "mousemove";
if (isMouseMove) {
if (ev.buttons > 0) {
return;
}
if (!_highlights.length) {
return;
}
}
const documant = win.document;
const scrollElement = (0, readium_css_1.getScrollingElement)(documant);
const x = ev.clientX;
const y = ev.clientY;
const paginated = (0, readium_css_inject_1.isPaginated)(documant);
const bodyRect = getBoundingClientRectOfDocumentBody(win);
const xOffset = paginated ? (-scrollElement.scrollLeft) : bodyRect.left;
const yOffset = paginated ? (-scrollElement.scrollTop) : bodyRect.top;
const scale = 1 / ((win.READIUM2 && win.READIUM2.isFixedLayout) ? win.READIUM2.fxlViewportScale : 1);
let hit = false;
let foundHighlight;
let foundElement;
for (let i = _highlights.length - 1; i >= 0; i--) {
const highlight = _highlights[i];
const doDrawMargin = drawMargin(highlight);
let highlightParent = documant.getElementById(`${highlight.id}`);
if (!highlightParent) {
highlightParent = _highlightsContainer.querySelector(`#${highlight.id}`);
}
if (!highlightParent) {
continue;
}
let highlightFragment = highlightParent.firstElementChild;
while (highlightFragment) {
if (highlightFragment.namespaceURI === SVG_XML_NAMESPACE) {
const svg = highlightFragment;
hit = (!doDrawMargin || svg.classList.contains(styles_1.CLASS_HIGHLIGHT_CONTOUR_MARGIN)) && svg.polygon.contains(new core_1.Point((x - xOffset) * scale, (y - yOffset) * scale));
if (hit) {
break;
}
}
highlightFragment = highlightFragment.nextElementSibling;
}
if (hit) {
foundHighlight = highlight;
foundElement = highlightParent;
break;
}
}
let highlightContainer = _highlightsContainer.firstElementChild;
while (highlightContainer) {
if (!foundElement || foundElement !== highlightContainer) {
highlightContainer.classList.remove(styles_1.CLASS_HIGHLIGHT_HOVER);
}
highlightContainer = highlightContainer.nextElementSibling;
}
if (!hit) {
const _highlightsFloatingUI = win.document.getElementById(styles_1.ID_HIGHLIGHTS_FLOATING);
if (_highlightsFloatingUI && _highlightsFloatingUI.style.display !== "none") {
_highlightsFloatingUI.style.display = "none";
}
documant.documentElement.classList.remove(styles_1.CLASS_HIGHLIGHT_CURSOR2);
return;
}
if (foundElement && foundHighlight && foundHighlight.pointerInteraction) {
if (isMouseMove) {
foundElement.classList.add(styles_1.CLASS_HIGHLIGHT_HOVER);
if (foundHighlight.group !== exports.HIGHLIGHT_GROUP_PAGEBREAK) {
documant.documentElement.classList.add(styles_1.CLASS_HIGHLIGHT_CURSOR2);
}
const text = ((_a = foundHighlight.textPopup) === null || _a === void 0 ? void 0 : _a.text) ? foundHighlight.textPopup.text : undefined;
if (text && _highlightsContainer) {
_timeoutMouseMove = win.setTimeout(() => {
var _a, _b;
_timeoutMouseMove = undefined;
if (!_highlightsContainer) {
return;
}
const _highlightsFloatingUI = win.document.getElementById(styles_1.ID_HIGHLIGHTS_FLOATING);
if (!_highlightsFloatingUI) {
return;
}
const _highlightsFloatingUI_ARROW = _highlightsFloatingUI.firstElementChild;
if (!_highlightsFloatingUI_ARROW) {
return;
}
const _highlightsFloatingUI_TEXT = _highlightsFloatingUI_ARROW.nextElementSibling;
if (!_highlightsFloatingUI_TEXT) {
return;
}
const doDrawArrow = foundHighlight.drawType !== highlight_1.HighlightDrawTypeMarginBookmark;
_highlightsFloatingUI_ARROW.style.display = doDrawArrow ? "block" : "none";
const dir = ((_a = foundHighlight.textPopup) === null || _a === void 0 ? void 0 : _a.dir) ? foundHighlight.textPopup.dir : "ltr";
const lang = ((_b = foundHighlight.textPopup) === null || _b === void 0 ? void 0 : _b.lang) ? foundHighlight.textPopup.lang : "en";
const zoom = foundElement.__inverseZoom || 1;
if (dir) {
_highlightsFloatingUI_TEXT.setAttribute("dir", dir);
}
else {
_highlightsFloatingUI_TEXT.removeAttribute("dir");
}
if (lang) {
_highlightsFloatingUI_TEXT.setAttribute("lang", lang);
_highlightsFloatingUI_TEXT.setAttributeNS("http://www.w3.org/XML/1998/", "lang", lang);
}
else {
_highlightsFloatingUI_TEXT.removeAttribute("lang");
_highlightsFloatingUI_TEXT.removeAttributeNS("http://www.w3.org/XML/1998/", "lang");
}
_highlightsFloatingUI_TEXT.style.writingMode = "horizontal-tb";
_highlightsFloatingUI_TEXT.textContent = text;
if (!exports.ENABLE_FLOATING_UI) {
const xx = (x - xOffset) * scale;
const yy = (y - yOffset) * scale;
Object.assign(_highlightsFloatingUI.style, {
display: "block",
left: `${xx * zoom}px`,
top: `${yy * zoom}px`,
});
}
else {
Object.assign(_highlightsFloatingUI.style, {
display: "block",
left: "0px",
top: "-999999px",
opacity: "0",
});
const doDrawMargin = drawMargin(foundHighlight);
let anchor = null;
const all = foundElement.querySelectorAll("svg.R2_CLASS_HIGHLIGHT_CONTOUR > path");
if ((all === null || all === void 0 ? void 0 : all.length) > 0) {
anchor = all[(all === null || all === void 0 ? void 0 : all.length) - 1];
}
if (!anchor && doDrawMargin) {
anchor = foundElement.querySelector("svg.R2_CLASS_HIGHLIGHT_CONTOUR_MARGIN > path");
}
if (anchor) {
const paginated = (0, readium_css_inject_1.isPaginated)(documant);
const virtualElement = {
getBoundingClientRect() {
return {
width: 0,
height: 0,
x: x,
y: y,
top: y,
left: x,
right: x,
bottom: y,
};
},
};
let _highlightsFloatingUI_;
if (paginated) {
const css = win.getComputedStyle(_highlightsFloatingUI);
let width = parseFloat(css.width) || 0;
let height = parseFloat(css.height) || 0;
const offsetWidth = _highlightsFloatingUI.offsetWidth;
const offsetHeight = _highlightsFloatingUI.offsetHeight;
const shouldFallback = Math.round(width) !== offsetWidth || Math.round(height) !== offsetHeight;
if (shouldFallback) {
width = offsetWidth;
height = offsetHeight;
}
_highlightsFloatingUI_ = documant.createElementNS(SVG_XML_NAMESPACE, "svg");
_highlightsFloatingUI_.setAttribute("id", styles_1.ID_HIGHLIGHTS_FLOATING + "_");
Object.assign(_highlightsFloatingUI_.style, {
width: (width / zoom) + "px",
height: (height / zoom) + "px",
});
_highlightsContainer.append(_highlightsFloatingUI_);
}
const arrowLen = doDrawArrow ? _highlightsFloatingUI_ARROW.offsetWidth : 0;
const floatingOffset = doDrawArrow ? (Math.sqrt(2 * arrowLen ** 2) / 2) : 0;
(0, dom_1.computePosition)(anchor || virtualElement, paginated ? _highlightsFloatingUI_ : _highlightsFloatingUI, {
strategy: paginated ? "fixed" : "absolute",
placement: "bottom",
middleware: [
(0, dom_1.offset)(floatingOffset),
(0, dom_1.flip)(),
(0, dom_1.shift)({ padding: 4 }),
doDrawArrow ? (0, dom_1.arrow)({ padding: 8, element: _highlightsFloatingUI_ARROW }) : undefined,
].filter((v) => !!v),
})
.then(({ x: fuix, y: fuiy, middlewareData, placement }) => {
if (doDrawArrow && middlewareData.arrow && _highlightsFloatingUI_ARROW) {
const side = placement.split("-")[0];
const staticSide = {
top: "bottom",
right: "left",
bottom: "top",
left: "right",
}[side];
console.log("middlewareData.arrow", middlewareData.arrow.x, middlewareData.arrow.y);
const { x: xarrow, y: yarrow } = middlewareData.arrow;
if (xarrow != null || yarrow != null) {
Object.assign(_highlightsFloatingUI_ARROW.style, {
left: xarrow != null ? `${xarrow}px` : "",
top: yarrow != null ? `${yarrow}px` : "",
right: "",
bottom: "",
[staticSide]: `${-arrowLen / 2}px`,
transform: staticSide === "top" ? "rotate(45deg)" : "rotate(225deg)",
});
}
}
const xx = paginated ? (fuix - xOffset) * zoom : fuix;
const yy = paginated ? (fuiy - yOffset) * zoom : fuiy;
if (_highlightsFloatingUI) {
Object.assign(_highlightsFloatingUI.style, {
display: "block",
left: `${xx}px`,
top: `${yy}px`,
opacity: "1",
});
}
if (_highlightsFloatingUI_) {
_highlightsFloatingUI_.remove();
}
});
}
else {
const xx = (x - xOffset) * scale;
const yy = (y - yOffset) * scale;
Object.assign(_highlightsFloatingUI.style, {
display: "block",
left: `${xx * zoom}px`,
top: `${yy * zoom}px`,
opacity: "1",
});
}
}
}, TIMEOUT_MOUSE_MS);
}
}
else if ((ev.type === "mouseup" || ev.type === "click") && foundHighlight.group !== exports.HIGHLIGHT_GROUP_PAGEBREAK) {
documant.documentElement.classList.remove(styles_1.CLASS_HIGHLIGHT_CURSOR2);
const _highlightsFloatingUI = win.document.getElementById(styles_1.ID_HIGHLIGHTS_FLOATING);
if (_highlightsFloatingUI && _highlightsFloatingUI.style.display !== "none") {
_highlightsFloatingUI.style.display = "none";
}
ev.preventDefault();
ev.stopPropagation();
const payload = {
highlight: foundHighlight,
event: {
type: ev.type,
button: ev.button,
alt: ev.altKey,
shift: ev.shiftKey,
ctrl: ev.ctrlKey,
meta: ev.metaKey,
x: ev.clientX,
y: ev.clientY,
},
};
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_HIGHLIGHT_CLICK, payload);
}
}
else {
const _highlightsFloatingUI = win.document.getElementById(styles_1.ID_HIGHLIGHTS_FLOATING);
if (_highlightsFloatingUI && _highlightsFloatingUI.style.display !== "none") {
_highlightsFloatingUI.style.display = "none";
}
}
}
const computeInverseZoom = (bodyComputedStyle, rootComputedStyle) => {
let zoomStr = rootComputedStyle.zoom;
if (!zoomStr || zoomStr === "1") {
zoomStr = bodyComputedStyle.zoom;
}
if (zoomStr) {
const zoomFactor = parseFloat(zoomStr);
if (zoomFactor !== 0) {
const inverseZoom = 1 / zoomFactor;
return inverseZoom;
}
}
return 1;
};
function ensureHighlightsContainer(win, _bodyComputedStyle, _rootComputedStyle) {
const documant = win.document;
if (!_highlightsContainer) {
if (!bodyEventListenersSet) {
bodyEventListenersSet = true;
documant.body.addEventListener("mousedown", (ev) => {
lastMouseDownX = ev.clientX;
lastMouseDownY = ev.clientY;
}, false);
documant.body.addEventListener("mouseup", (ev) => {
if ((Math.abs(lastMouseDownX - ev.clientX) < 3) &&
(Math.abs(lastMouseDownY - ev.clientY) < 3)) {
processMouseEvent(win, ev);
}
}, false);
documant.body.addEventListener("mousemove", (ev) => {
processMouseEvent(win, ev);
}, false);
}
const _highlightsContainer_ = documant.createElement("div");
_highlightsContainer_.setAttribute("aria-hidden", "true");
_highlightsContainer_.setAttribute("id", styles_1.ID_HIGHLIGHTS_CONTAINER);
_highlightsContainer_.setAttribute("class", styles_1.CLASS_HIGHLIGHT_COMMON);
_highlightsContainer_.setAttribute("style", `width: ${win.READIUM2.isFixedLayout ? "-webkit-fill-available" : "auto"} !important; ` +
`height: ${win.READIUM2.isFixedLayout ? "-webkit-fill-available" : "auto"} !important; `);
const _highlightsFloatingUI = documant.createElement("div");
_highlightsFloatingUI.setAttribute("id", styles_1.ID_HIGHLIGHTS_FLOATING);
const _highlightsFloatingUI_ARROW = documant.createElement("div");
_highlightsFloatingUI.append(_highlightsFloatingUI_ARROW);
const _highlightsFloatingUI_TEXT = documant.createElement("div");
_highlightsFloatingUI.append(_highlightsFloatingUI_TEXT);
_highlightsContainer_.append(_highlightsFloatingUI);
documant.body.append(_highlightsContainer_);
_highlightsContainer = _highlightsContainer_;
}
return _highlightsContainer;
}
function hideAllhighlights(_documant) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- hideAllhighlights: " + _highlights.length);
}
if (exports.ENABLE_CSS_HIGHLIGHTS) {
CSS.highlights.clear();
}
if (_highlightsContainer) {
_highlightsContainer.remove();
_highlightsContainer = undefined;
}
}
function destroyAllhighlights(documant) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- destroyAllhighlights: " + _highlights.length);
}
hideAllhighlights(documant);
_highlights.splice(0, _highlights.length);
}
function destroyHighlight(documant, id) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- destroyHighlight: " + id + " ... " + _highlights.length);
}
let i = -1;
const highlight = _highlights.find((h, j) => {
i = j;
return h.id === id;
});
if (highlight && i >= 0 && i < _highlights.length) {
_highlights.splice(i, 1);
}
const highlightContainer = documant.getElementById(id);
if (highlightContainer) {
highlightContainer.remove();
}
if (exports.ENABLE_CSS_HIGHLIGHTS && highlight && highlight.rangeCssHighlight) {
const [_strRGB, cssHighlightID] = computeCssHighlightRGBID(highlight);
const cssHighlight = CSS.highlights.get(cssHighlightID);
if (cssHighlight && cssHighlight.has(highlight.rangeCssHighlight)) {
cssHighlight.delete(highlight.rangeCssHighlight);
}
}
}
function destroyHighlightsGroup(documant, group) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- destroyHighlightsGroup: " + group + " ... " + _highlights.length);
}
while (true) {
let i = -1;
const highlight = _highlights.find((h, j) => {
i = j;
return h.group === group;
});
if (highlight) {
if (i >= 0 && i < _highlights.length) {
_highlights.splice(i, 1);
}
const highlightContainer = documant.getElementById(highlight.id);
if (highlightContainer) {
highlightContainer.remove();
}
if (exports.ENABLE_CSS_HIGHLIGHTS && highlight.rangeCssHighlight) {
const [_strRGB, cssHighlightID] = computeCssHighlightRGBID(highlight);
const cssHighlight = CSS.highlights.get(cssHighlightID);
if (cssHighlight && cssHighlight.has(highlight.rangeCssHighlight)) {
cssHighlight.delete(highlight.rangeCssHighlight);
}
}
}
else {
break;
}
}
}
function recreateAllHighlightsRaw(win, highlights) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- recreateAllHighlightsRaw: " + _highlights.length + " ==> " + (highlights === null || highlights === void 0 ? void 0 : highlights.length));
}
const documant = win.document;
if (highlights === null || highlights === void 0 ? void 0 : highlights.length) {
if (_highlights.length) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- recreateAllHighlightsRaw DESTROY OLD BEFORE RESTORE BACKUP: " + _highlights.length + " ==> " + highlights.length);
}
destroyAllhighlights(documant);
}
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- recreateAllHighlightsRaw RESTORE BACKUP: " + _highlights.length + " ==> " + highlights.length);
}
_highlights.push(...highlights);
}
if (!_highlights.length) {
return;
}
if (!documant.body) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- NO BODY?! (retrying...): " + _highlights.length);
}
(0, exports.recreateAllHighlightsDebounced)(win);
return;
}
hideAllhighlights(documant);
const bodyRect = getBoundingClientRectOfDocumentBody(win);
const rootComputedStyle = win.getComputedStyle(documant.documentElement);
const bodyComputedStyle = win.getComputedStyle(documant.body);
const docFrag = documant.createDocumentFragment();
for (const highlight of _highlights) {
const r = adjustRangeInfo(win, highlight.range, highlight.selectionInfo);
if (r) {
highlight.range = r;
}
else if (r === null) {
}
else if (typeof r === "undefined") {
continue;
}
let div;
try {
div = createHighlightDom(win, highlight, bodyRect, bodyComputedStyle, rootComputedStyle);
}
catch (err) {
console.log("createHighlightDom ERROR:");
console.log(err);
}
if (div) {
docFrag.append(div);
}
}
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- createHighlightDom DONE: " + _highlights.length);
}
const highlightsContainer = ensureHighlightsContainer(win, bodyComputedStyle, rootComputedStyle);
highlightsContainer.append(docFrag);
}
exports.recreateAllHighlightsDebounced = debounce((win) => {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- recreateAllHighlightsDebounced: " + _highlights.length);
}
recreateAllHighlightsRaw(win);
}, 500);
function recreateAllHighlights(win) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- recreateAllHighlights: " + _highlights.length);
}
hideAllhighlights(win.document);
(0, exports.recreateAllHighlightsDebounced)(win);
}
function createHighlights(win, highDefs, pointerInteraction) {
if (IS_DEV) {
console.log("--HIGH WEBVIEW-- createHighlights: " + highDefs.length + " ... " + _highlights.length);
}
const documant = win.document;
const highlights = [];
const bodyRect = getBoundingClientRectOfDocumentBody(win);
const rootComputedStyle = win.getComputedStyle(documant.documentElement);
const bodyComputedStyle = win.getComputedStyle(documant.body);
const docFrag = documant.createDocumentFragment();
for (const highDef of highDefs) {
if (!highDef.selectionInfo && !highDef.range) {
highlights.push(null);
continue;
}
const hh = createHighlight(win, highDef.select