@embedpdf/plugin-annotation 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +80 -43
- package/dist/index.js.map +1 -1
- package/dist/lib/helpers.d.ts +8 -2
- package/dist/lib/types.d.ts +44 -6
- package/dist/preact/adapter.d.ts +5 -0
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +267 -7
- package/dist/preact/index.js.map +1 -1
- package/dist/react/adapter.d.ts +5 -0
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +267 -7
- package/dist/react/index.js.map +1 -1
- package/dist/shared-preact/components/annotation-container.d.ts +3 -2
- package/dist/shared-preact/components/annotations/free-text-paint.d.ts +10 -0
- package/dist/shared-preact/components/annotations/free-text.d.ts +13 -0
- package/dist/shared-react/components/annotation-container.d.ts +3 -2
- package/dist/shared-react/components/annotations/free-text-paint.d.ts +10 -0
- package/dist/shared-react/components/annotations/free-text.d.ts +13 -0
- package/package.json +9 -9
package/dist/react/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { usePlugin, useCapability } from "@embedpdf/core/react";
|
|
2
|
-
import { AnnotationPlugin, patching, getAnnotationsByPageIndex, getSelectedAnnotationByPageIndex, isInk, isSquare, isCircle, isUnderline, isStrikeout, isSquiggly, isHighlight, isLine, isPolyline, isPolygon,
|
|
2
|
+
import { AnnotationPlugin, patching, getAnnotationsByPageIndex, getSelectedAnnotationByPageIndex, isInk, isSquare, isCircle, isUnderline, isStrikeout, isSquiggly, isHighlight, isLine, isPolyline, isPolygon, isFreeText } from "@embedpdf/plugin-annotation";
|
|
3
3
|
import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
|
|
4
|
-
import { restoreOffset, rectEquals, PdfAnnotationBorderStyle, PdfAnnotationSubtype, expandRect, rectFromPoints, blendModeToCss, PdfBlendMode } from "@embedpdf/models";
|
|
4
|
+
import { restoreOffset, rectEquals, PdfAnnotationBorderStyle, PdfAnnotationSubtype, expandRect, rectFromPoints, textAlignmentToCss, standardFontCss, PdfVerticalAlignment, blendModeToCss, PdfBlendMode } from "@embedpdf/models";
|
|
5
5
|
import { usePointerHandlers } from "@embedpdf/plugin-interaction-manager/react";
|
|
6
6
|
import { useSelectionCapability } from "@embedpdf/plugin-selection/react";
|
|
7
7
|
import { Fragment, useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from "react";
|
|
8
8
|
const useAnnotationPlugin = () => usePlugin(AnnotationPlugin.id);
|
|
9
9
|
const useAnnotationCapability = () => useCapability(AnnotationPlugin.id);
|
|
10
|
+
const mapDoubleClick = (handler) => handler ? { onDoubleClick: handler } : {};
|
|
10
11
|
function getCounterRotation(rect, rotation) {
|
|
11
12
|
const { width: w, height: h } = rect.size;
|
|
12
13
|
switch (rotation % 4) {
|
|
@@ -337,6 +338,7 @@ function AnnotationContainer({
|
|
|
337
338
|
computeVertices,
|
|
338
339
|
computePatch,
|
|
339
340
|
selectionMenu,
|
|
341
|
+
onDoubleClick,
|
|
340
342
|
...props
|
|
341
343
|
}) {
|
|
342
344
|
const { provides: annotationProvides } = useAnnotationCapability();
|
|
@@ -375,6 +377,7 @@ function AnnotationContainer({
|
|
|
375
377
|
"div",
|
|
376
378
|
{
|
|
377
379
|
...rootHandlers,
|
|
380
|
+
...mapDoubleClick(onDoubleClick),
|
|
378
381
|
style: {
|
|
379
382
|
position: "absolute",
|
|
380
383
|
outline: isSelected ? "1px solid #007ACC" : "none",
|
|
@@ -385,6 +388,9 @@ function AnnotationContainer({
|
|
|
385
388
|
height: `${currentRect.size.height * scale}px`,
|
|
386
389
|
pointerEvents: isSelected ? "auto" : "none",
|
|
387
390
|
cursor: isSelected && isDraggable ? "move" : "default",
|
|
391
|
+
...isSelected && {
|
|
392
|
+
zIndex: 3
|
|
393
|
+
},
|
|
388
394
|
...style
|
|
389
395
|
},
|
|
390
396
|
...props,
|
|
@@ -1191,6 +1197,78 @@ const patchPolygon = (orig, ctx) => {
|
|
|
1191
1197
|
vertices: moved
|
|
1192
1198
|
};
|
|
1193
1199
|
};
|
|
1200
|
+
function FreeText({
|
|
1201
|
+
isSelected,
|
|
1202
|
+
isEditing,
|
|
1203
|
+
annotation,
|
|
1204
|
+
pageIndex,
|
|
1205
|
+
scale,
|
|
1206
|
+
onClick
|
|
1207
|
+
}) {
|
|
1208
|
+
const editorRef = useRef(null);
|
|
1209
|
+
const { provides: annotationProvides } = useAnnotationCapability();
|
|
1210
|
+
useEffect(() => {
|
|
1211
|
+
if (isEditing && editorRef.current) {
|
|
1212
|
+
const editor = editorRef.current;
|
|
1213
|
+
editor.focus();
|
|
1214
|
+
const selection = window.getSelection();
|
|
1215
|
+
if (selection) {
|
|
1216
|
+
const range = document.createRange();
|
|
1217
|
+
range.selectNodeContents(editor);
|
|
1218
|
+
range.collapse(false);
|
|
1219
|
+
selection.removeAllRanges();
|
|
1220
|
+
selection.addRange(range);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}, [isEditing]);
|
|
1224
|
+
const handleBlur = () => {
|
|
1225
|
+
if (!annotationProvides) return;
|
|
1226
|
+
if (!editorRef.current) return;
|
|
1227
|
+
annotationProvides.updateAnnotation(pageIndex, annotation.localId, {
|
|
1228
|
+
contents: editorRef.current.innerText
|
|
1229
|
+
});
|
|
1230
|
+
};
|
|
1231
|
+
return /* @__PURE__ */ jsx(
|
|
1232
|
+
"div",
|
|
1233
|
+
{
|
|
1234
|
+
style: {
|
|
1235
|
+
position: "absolute",
|
|
1236
|
+
width: annotation.object.rect.size.width * scale,
|
|
1237
|
+
height: annotation.object.rect.size.height * scale,
|
|
1238
|
+
cursor: isSelected && !isEditing ? "move" : "default",
|
|
1239
|
+
pointerEvents: isSelected && !isEditing ? "none" : "auto",
|
|
1240
|
+
zIndex: 2
|
|
1241
|
+
},
|
|
1242
|
+
onPointerDown: onClick,
|
|
1243
|
+
children: /* @__PURE__ */ jsx(
|
|
1244
|
+
"span",
|
|
1245
|
+
{
|
|
1246
|
+
ref: editorRef,
|
|
1247
|
+
onBlur: handleBlur,
|
|
1248
|
+
style: {
|
|
1249
|
+
color: annotation.object.fontColor,
|
|
1250
|
+
fontSize: annotation.object.fontSize * scale,
|
|
1251
|
+
fontFamily: standardFontCss(annotation.object.fontFamily),
|
|
1252
|
+
textAlign: textAlignmentToCss(annotation.object.textAlign),
|
|
1253
|
+
flexDirection: "column",
|
|
1254
|
+
justifyContent: annotation.object.verticalAlign === PdfVerticalAlignment.Top ? "flex-start" : annotation.object.verticalAlign === PdfVerticalAlignment.Middle ? "center" : "flex-end",
|
|
1255
|
+
display: "flex",
|
|
1256
|
+
backgroundColor: annotation.object.backgroundColor,
|
|
1257
|
+
opacity: annotation.object.opacity,
|
|
1258
|
+
width: "100%",
|
|
1259
|
+
height: "100%",
|
|
1260
|
+
lineHeight: "1.18",
|
|
1261
|
+
overflow: "hidden",
|
|
1262
|
+
cursor: isEditing ? "text" : "pointer"
|
|
1263
|
+
},
|
|
1264
|
+
contentEditable: isEditing,
|
|
1265
|
+
suppressContentEditableWarning: true,
|
|
1266
|
+
children: annotation.object.contents
|
|
1267
|
+
}
|
|
1268
|
+
)
|
|
1269
|
+
}
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1194
1272
|
function Annotations(annotationsProps) {
|
|
1195
1273
|
const { pageIndex, scale, selectionMenu } = annotationsProps;
|
|
1196
1274
|
const { provides: annotationProvides } = useAnnotationCapability();
|
|
@@ -1198,6 +1276,7 @@ function Annotations(annotationsProps) {
|
|
|
1198
1276
|
const [annotations, setAnnotations] = useState([]);
|
|
1199
1277
|
const { register } = usePointerHandlers({ pageIndex });
|
|
1200
1278
|
const [selectionState, setSelectionState] = useState(null);
|
|
1279
|
+
const [editingId, setEditingId] = useState(null);
|
|
1201
1280
|
useEffect(() => {
|
|
1202
1281
|
if (annotationProvides) {
|
|
1203
1282
|
annotationProvides.onStateChange((state) => {
|
|
@@ -1211,6 +1290,7 @@ function Annotations(annotationsProps) {
|
|
|
1211
1290
|
onPointerDown: (_, pe) => {
|
|
1212
1291
|
if (pe.target === pe.currentTarget && annotationProvides) {
|
|
1213
1292
|
annotationProvides.deselectAnnotation();
|
|
1293
|
+
setEditingId(null);
|
|
1214
1294
|
}
|
|
1215
1295
|
}
|
|
1216
1296
|
}),
|
|
@@ -1222,6 +1302,7 @@ function Annotations(annotationsProps) {
|
|
|
1222
1302
|
if (annotationProvides && selectionProvides) {
|
|
1223
1303
|
annotationProvides.selectAnnotation(pageIndex, annotation.localId);
|
|
1224
1304
|
selectionProvides.clear();
|
|
1305
|
+
setEditingId(null);
|
|
1225
1306
|
}
|
|
1226
1307
|
},
|
|
1227
1308
|
[annotationProvides, selectionProvides, pageIndex]
|
|
@@ -1231,6 +1312,7 @@ function Annotations(annotationsProps) {
|
|
|
1231
1312
|
}, [register, handlers]);
|
|
1232
1313
|
return /* @__PURE__ */ jsx(Fragment$1, { children: annotations.map((annotation) => {
|
|
1233
1314
|
const isSelected = (selectionState == null ? void 0 : selectionState.localId) === annotation.localId;
|
|
1315
|
+
const isEditing = editingId === annotation.localId;
|
|
1234
1316
|
if (isInk(annotation)) {
|
|
1235
1317
|
return /* @__PURE__ */ jsx(
|
|
1236
1318
|
AnnotationContainer,
|
|
@@ -1546,6 +1628,42 @@ function Annotations(annotationsProps) {
|
|
|
1546
1628
|
annotation.localId
|
|
1547
1629
|
);
|
|
1548
1630
|
}
|
|
1631
|
+
if (isFreeText(annotation)) {
|
|
1632
|
+
return /* @__PURE__ */ jsx(
|
|
1633
|
+
AnnotationContainer,
|
|
1634
|
+
{
|
|
1635
|
+
trackedAnnotation: annotation,
|
|
1636
|
+
isSelected,
|
|
1637
|
+
isDraggable: true,
|
|
1638
|
+
isResizable: true,
|
|
1639
|
+
selectionMenu,
|
|
1640
|
+
outlineOffset: 6,
|
|
1641
|
+
onDoubleClick: (e) => {
|
|
1642
|
+
e.stopPropagation();
|
|
1643
|
+
setEditingId(annotation.localId);
|
|
1644
|
+
},
|
|
1645
|
+
style: {
|
|
1646
|
+
mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
|
|
1647
|
+
},
|
|
1648
|
+
...annotationsProps,
|
|
1649
|
+
children: (object) => /* @__PURE__ */ jsx(
|
|
1650
|
+
FreeText,
|
|
1651
|
+
{
|
|
1652
|
+
isSelected,
|
|
1653
|
+
isEditing,
|
|
1654
|
+
annotation: {
|
|
1655
|
+
...annotation,
|
|
1656
|
+
object
|
|
1657
|
+
},
|
|
1658
|
+
pageIndex,
|
|
1659
|
+
scale,
|
|
1660
|
+
onClick: (e) => handleClick(e, annotation)
|
|
1661
|
+
}
|
|
1662
|
+
)
|
|
1663
|
+
},
|
|
1664
|
+
annotation.localId
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1549
1667
|
return null;
|
|
1550
1668
|
}) });
|
|
1551
1669
|
}
|
|
@@ -1570,8 +1688,9 @@ function TextMarkup({ pageIndex, scale }) {
|
|
|
1570
1688
|
return off;
|
|
1571
1689
|
}, [annotationProvides]);
|
|
1572
1690
|
if (!boundingRect) return null;
|
|
1573
|
-
|
|
1574
|
-
|
|
1691
|
+
if (!activeTool.defaults) return null;
|
|
1692
|
+
switch (activeTool.defaults.subtype) {
|
|
1693
|
+
case PdfAnnotationSubtype.UNDERLINE:
|
|
1575
1694
|
return /* @__PURE__ */ jsx(
|
|
1576
1695
|
"div",
|
|
1577
1696
|
{
|
|
@@ -1592,7 +1711,7 @@ function TextMarkup({ pageIndex, scale }) {
|
|
|
1592
1711
|
)
|
|
1593
1712
|
}
|
|
1594
1713
|
);
|
|
1595
|
-
case
|
|
1714
|
+
case PdfAnnotationSubtype.HIGHLIGHT:
|
|
1596
1715
|
return /* @__PURE__ */ jsx(
|
|
1597
1716
|
"div",
|
|
1598
1717
|
{
|
|
@@ -1613,7 +1732,7 @@ function TextMarkup({ pageIndex, scale }) {
|
|
|
1613
1732
|
)
|
|
1614
1733
|
}
|
|
1615
1734
|
);
|
|
1616
|
-
case
|
|
1735
|
+
case PdfAnnotationSubtype.STRIKEOUT:
|
|
1617
1736
|
return /* @__PURE__ */ jsx(
|
|
1618
1737
|
"div",
|
|
1619
1738
|
{
|
|
@@ -1634,7 +1753,7 @@ function TextMarkup({ pageIndex, scale }) {
|
|
|
1634
1753
|
)
|
|
1635
1754
|
}
|
|
1636
1755
|
);
|
|
1637
|
-
case
|
|
1756
|
+
case PdfAnnotationSubtype.SQUIGGLY:
|
|
1638
1757
|
return /* @__PURE__ */ jsx(
|
|
1639
1758
|
"div",
|
|
1640
1759
|
{
|
|
@@ -2536,6 +2655,138 @@ const PolygonPaint = ({
|
|
|
2536
2655
|
}
|
|
2537
2656
|
);
|
|
2538
2657
|
};
|
|
2658
|
+
const FreeTextPaint = ({
|
|
2659
|
+
pageIndex,
|
|
2660
|
+
scale,
|
|
2661
|
+
pageWidth,
|
|
2662
|
+
pageHeight,
|
|
2663
|
+
cursor = "text"
|
|
2664
|
+
}) => {
|
|
2665
|
+
const { provides: annotationProvides } = useAnnotationCapability();
|
|
2666
|
+
const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
|
|
2667
|
+
useEffect(() => annotationProvides == null ? void 0 : annotationProvides.onActiveToolChange(setActiveTool), [annotationProvides]);
|
|
2668
|
+
if (!activeTool.defaults || activeTool.defaults.subtype !== PdfAnnotationSubtype.FREETEXT)
|
|
2669
|
+
return null;
|
|
2670
|
+
const toolFontColor = activeTool.defaults.fontColor ?? "#000000";
|
|
2671
|
+
const toolOpacity = activeTool.defaults.opacity ?? 1;
|
|
2672
|
+
const toolFontSize = activeTool.defaults.fontSize ?? 12;
|
|
2673
|
+
const toolFontFamily = activeTool.defaults.fontFamily;
|
|
2674
|
+
const toolBackgroundColor = activeTool.defaults.backgroundColor ?? "transparent";
|
|
2675
|
+
const toolTextAlign = activeTool.defaults.textAlign;
|
|
2676
|
+
const toolVerticalAlign = activeTool.defaults.verticalAlign;
|
|
2677
|
+
const toolContent = activeTool.defaults.content ?? "Insert text here";
|
|
2678
|
+
const { register } = usePointerHandlers({ modeId: "freeText", pageIndex });
|
|
2679
|
+
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
|
|
2680
|
+
const pageWidthPDF = pageWidth / scale;
|
|
2681
|
+
const pageHeightPDF = pageHeight / scale;
|
|
2682
|
+
const [start, setStart] = useState(null);
|
|
2683
|
+
const [current, setCurrent] = useState(null);
|
|
2684
|
+
const commitFreeText = (p1, p2) => {
|
|
2685
|
+
const minX2 = Math.min(p1.x, p2.x);
|
|
2686
|
+
const minY2 = Math.min(p1.y, p2.y);
|
|
2687
|
+
const maxX2 = Math.max(p1.x, p2.x);
|
|
2688
|
+
const maxY2 = Math.max(p1.y, p2.y);
|
|
2689
|
+
const w = maxX2 - minX2;
|
|
2690
|
+
const h = maxY2 - minY2;
|
|
2691
|
+
if (w < 1 || h < 1) return;
|
|
2692
|
+
const rect = {
|
|
2693
|
+
origin: { x: minX2, y: minY2 },
|
|
2694
|
+
size: { width: w, height: h }
|
|
2695
|
+
};
|
|
2696
|
+
const anno = {
|
|
2697
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2698
|
+
rect,
|
|
2699
|
+
contents: toolContent,
|
|
2700
|
+
fontColor: toolFontColor,
|
|
2701
|
+
fontSize: toolFontSize,
|
|
2702
|
+
fontFamily: toolFontFamily,
|
|
2703
|
+
opacity: toolOpacity,
|
|
2704
|
+
backgroundColor: toolBackgroundColor,
|
|
2705
|
+
textAlign: toolTextAlign,
|
|
2706
|
+
verticalAlign: toolVerticalAlign,
|
|
2707
|
+
pageIndex,
|
|
2708
|
+
id: Date.now() + Math.random()
|
|
2709
|
+
};
|
|
2710
|
+
annotationProvides.createAnnotation(pageIndex, anno);
|
|
2711
|
+
annotationProvides.setActiveVariant(null);
|
|
2712
|
+
annotationProvides.selectAnnotation(pageIndex, anno.id);
|
|
2713
|
+
};
|
|
2714
|
+
const handlers = useMemo(
|
|
2715
|
+
() => ({
|
|
2716
|
+
onPointerDown: (pos, evt) => {
|
|
2717
|
+
var _a, _b;
|
|
2718
|
+
const x = clamp(pos.x, 0, pageWidthPDF);
|
|
2719
|
+
const y = clamp(pos.y, 0, pageHeightPDF);
|
|
2720
|
+
setStart({ x, y });
|
|
2721
|
+
setCurrent({ x, y });
|
|
2722
|
+
(_b = (_a = evt.target) == null ? void 0 : _a.setPointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
|
|
2723
|
+
},
|
|
2724
|
+
onPointerMove: (pos) => {
|
|
2725
|
+
if (!start) return;
|
|
2726
|
+
const x = clamp(pos.x, 0, pageWidthPDF);
|
|
2727
|
+
const y = clamp(pos.y, 0, pageHeightPDF);
|
|
2728
|
+
setCurrent({ x, y });
|
|
2729
|
+
},
|
|
2730
|
+
onPointerUp: (_, evt) => {
|
|
2731
|
+
var _a, _b;
|
|
2732
|
+
if (start && current && annotationProvides) {
|
|
2733
|
+
commitFreeText(start, current);
|
|
2734
|
+
}
|
|
2735
|
+
(_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
|
|
2736
|
+
setStart(null);
|
|
2737
|
+
setCurrent(null);
|
|
2738
|
+
},
|
|
2739
|
+
onPointerCancel: (_, evt) => {
|
|
2740
|
+
var _a, _b;
|
|
2741
|
+
(_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
|
|
2742
|
+
setStart(null);
|
|
2743
|
+
setCurrent(null);
|
|
2744
|
+
}
|
|
2745
|
+
}),
|
|
2746
|
+
[start, current, annotationProvides, pageWidthPDF, pageHeightPDF]
|
|
2747
|
+
);
|
|
2748
|
+
useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
|
|
2749
|
+
if (!start || !current) return null;
|
|
2750
|
+
const minX = Math.min(start.x, current.x);
|
|
2751
|
+
const minY = Math.min(start.y, current.y);
|
|
2752
|
+
const maxX = Math.max(start.x, current.x);
|
|
2753
|
+
const maxY = Math.max(start.y, current.y);
|
|
2754
|
+
const dw = maxX - minX;
|
|
2755
|
+
const dh = maxY - minY;
|
|
2756
|
+
return /* @__PURE__ */ jsx(
|
|
2757
|
+
"svg",
|
|
2758
|
+
{
|
|
2759
|
+
style: {
|
|
2760
|
+
position: "absolute",
|
|
2761
|
+
left: minX * scale,
|
|
2762
|
+
top: minY * scale,
|
|
2763
|
+
width: dw * scale,
|
|
2764
|
+
height: dh * scale,
|
|
2765
|
+
pointerEvents: "none",
|
|
2766
|
+
zIndex: 2
|
|
2767
|
+
},
|
|
2768
|
+
width: dw * scale,
|
|
2769
|
+
height: dh * scale,
|
|
2770
|
+
viewBox: `0 0 ${dw} ${dh}`,
|
|
2771
|
+
children: /* @__PURE__ */ jsx(
|
|
2772
|
+
"rect",
|
|
2773
|
+
{
|
|
2774
|
+
x: 0,
|
|
2775
|
+
y: 0,
|
|
2776
|
+
width: dw,
|
|
2777
|
+
height: dh,
|
|
2778
|
+
fill: "transparent",
|
|
2779
|
+
style: {
|
|
2780
|
+
stroke: toolFontColor,
|
|
2781
|
+
strokeWidth: 1,
|
|
2782
|
+
strokeDasharray: "4,4",
|
|
2783
|
+
cursor
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
)
|
|
2787
|
+
}
|
|
2788
|
+
);
|
|
2789
|
+
};
|
|
2539
2790
|
function AnnotationLayer({
|
|
2540
2791
|
pageIndex,
|
|
2541
2792
|
scale,
|
|
@@ -2611,6 +2862,15 @@ function AnnotationLayer({
|
|
|
2611
2862
|
pageWidth,
|
|
2612
2863
|
pageHeight
|
|
2613
2864
|
}
|
|
2865
|
+
),
|
|
2866
|
+
/* @__PURE__ */ jsx(
|
|
2867
|
+
FreeTextPaint,
|
|
2868
|
+
{
|
|
2869
|
+
pageIndex,
|
|
2870
|
+
scale,
|
|
2871
|
+
pageWidth,
|
|
2872
|
+
pageHeight
|
|
2873
|
+
}
|
|
2614
2874
|
)
|
|
2615
2875
|
]
|
|
2616
2876
|
}
|