@a3s-lab/office 0.2.2 → 0.4.0
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/COLLABORATION_ROADMAP.md +426 -0
- package/README.md +649 -10
- package/dist/0~1403.js +1 -1
- package/dist/0~2805.js +1279 -0
- package/dist/{0~use-office-draft.js → 0~345.js} +30 -1
- package/dist/0~3539.js +1 -1
- package/dist/0~3557.js +1 -1
- package/dist/0~3635.js +1 -1
- package/dist/0~4595.js +123 -12
- package/dist/0~4980.js +154 -0
- package/dist/0~5050.js +124 -113
- package/dist/{0~9512.js → 0~6090.js} +540 -3
- package/dist/0~7048.js +92 -66
- package/dist/0~7614.js +2 -1
- package/dist/0~7754.js +5653 -0
- package/dist/0~9445.js +1 -1
- package/dist/0~document-editor.js +4992 -3323
- package/dist/0~markdown-editor.js +250 -44
- package/dist/0~pdf-viewer.js +1016 -24
- package/dist/0~presentation-editor.js +179 -8
- package/dist/0~spreadsheet-editor.js +3371 -578
- package/dist/0~work-docx-export.js +6801 -658
- package/dist/0~work-docx-import.js +1388 -795
- package/dist/0~work-office-diagnostics.js +524 -30
- package/dist/0~work-pptx-export.js +2 -1
- package/dist/0~work-pptx-import.js +1 -2
- package/dist/0~work-presentation-charts.js +1 -1
- package/dist/2591.js +197 -0
- package/dist/3818.js +1090 -0
- package/dist/4104.js +970 -60
- package/dist/432.js +171 -14
- package/dist/4476.js +2008 -0
- package/dist/4560.js +674 -0
- package/dist/4650.js +70 -0
- package/dist/{1134.js → 5184.js} +183 -1
- package/dist/6489.js +18 -18
- package/dist/7060.js +132 -0
- package/dist/8715.js +2 -136
- package/dist/8928.js +16778 -0
- package/dist/9787.js +209 -0
- package/dist/core.d.ts +29 -9
- package/dist/core.js +10 -2
- package/dist/index.js +13 -3
- package/dist/internal/collaboration/office-collaboration-flat-json.d.ts +13 -0
- package/dist/internal/collaboration/office-collaboration-json.d.ts +4 -0
- package/dist/internal/collaboration/office-collaboration-presence.d.ts +86 -0
- package/dist/internal/collaboration/office-collaboration-transport.d.ts +42 -0
- package/dist/internal/collaboration/office-collaboration.d.ts +85 -0
- package/dist/internal/collaboration/office-document-collaboration-bibliography.d.ts +7 -0
- package/dist/internal/collaboration/office-document-collaboration-claims.d.ts +9 -0
- package/dist/internal/collaboration/office-document-collaboration-comments.d.ts +7 -0
- package/dist/internal/collaboration/office-document-collaboration-sidecar-utils.d.ts +27 -0
- package/dist/internal/collaboration/office-document-collaboration-sidecars.d.ts +16 -0
- package/dist/internal/collaboration/office-document-collaboration.d.ts +45 -0
- package/dist/internal/collaboration/office-markdown-collaboration.d.ts +31 -0
- package/dist/internal/collaboration/office-pdf-collaboration-claims.d.ts +4 -0
- package/dist/internal/collaboration/office-pdf-collaboration-conflicts.d.ts +2 -0
- package/dist/internal/collaboration/office-pdf-collaboration-model.d.ts +26 -0
- package/dist/internal/collaboration/office-pdf-collaboration-records.d.ts +21 -0
- package/dist/internal/collaboration/office-pdf-collaboration-types.d.ts +91 -0
- package/dist/internal/collaboration/office-pdf-collaboration-validation.d.ts +4 -0
- package/dist/internal/collaboration/office-pdf-collaboration.d.ts +35 -0
- package/dist/internal/collaboration/office-presentation-collaboration-model.d.ts +25 -0
- package/dist/internal/collaboration/office-presentation-collaboration-records.d.ts +22 -0
- package/dist/internal/collaboration/office-presentation-collaboration-validation.d.ts +4 -0
- package/dist/internal/collaboration/office-presentation-collaboration.d.ts +32 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-cells.d.ts +13 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-claims.d.ts +4 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-conflicts.d.ts +2 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-flat-json.d.ts +10 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-model.d.ts +31 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +17 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-validation.d.ts +4 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration.d.ts +32 -0
- package/dist/internal/design-system/primitives/navigation/tabs.d.ts +3 -1
- package/dist/internal/features/work/components/work-document-page-border.d.ts +6 -0
- package/dist/internal/features/work/editors/document-command-catalog.d.ts +536 -0
- package/dist/internal/features/work/editors/document-editor-focus.d.ts +1 -1
- package/dist/internal/features/work/editors/document-editor-support.d.ts +7 -3
- package/dist/internal/features/work/editors/document-editor.d.ts +8 -2
- package/dist/internal/features/work/editors/document-external-content.d.ts +14 -0
- package/dist/internal/features/work/editors/document-format-clipboard.d.ts +6 -0
- package/dist/internal/features/work/editors/document-format-tools.d.ts +4 -0
- package/dist/internal/features/work/editors/document-layout-panel.d.ts +4 -1
- package/dist/internal/features/work/editors/document-page-chrome-wps-shortcuts.d.ts +2 -0
- package/dist/internal/features/work/editors/document-page-layout-ribbon.d.ts +14 -0
- package/dist/internal/features/work/editors/document-page-stack.d.ts +10 -1
- package/dist/internal/features/work/editors/document-page-thumbnail.d.ts +2 -0
- package/dist/internal/features/work/editors/document-pagination-run-coordinator.d.ts +26 -0
- package/dist/internal/features/work/editors/document-picture-properties-dialog-model.d.ts +20 -1
- package/dist/internal/features/work/editors/document-review-navigation.d.ts +9 -0
- package/dist/internal/features/work/editors/document-statistics-dialog.d.ts +7 -0
- package/dist/internal/features/work/editors/document-status-bar.d.ts +2 -1
- package/dist/internal/features/work/editors/document-table-properties-dialog-model.d.ts +4 -1
- package/dist/internal/features/work/editors/document-toolbar.d.ts +19 -42
- package/dist/internal/features/work/editors/document-wps-shortcuts.d.ts +12 -0
- package/dist/internal/features/work/editors/document-zoom.d.ts +17 -0
- package/dist/internal/features/work/editors/markdown-editor-focus.d.ts +1 -1
- package/dist/internal/features/work/editors/markdown-editor.d.ts +5 -1
- package/dist/internal/features/work/editors/markdown-toolbar.d.ts +2 -1
- package/dist/internal/features/work/editors/office-collaboration-participants.d.ts +3 -0
- package/dist/internal/features/work/editors/office-collaboration-presence-context.d.ts +17 -0
- package/dist/internal/features/work/editors/office-collaboration-presence-ui.d.ts +25 -0
- package/dist/internal/features/work/editors/office-editor-focus-handoff.d.ts +27 -0
- package/dist/internal/features/work/editors/pdf-annotation-controller.d.ts +5 -0
- package/dist/internal/features/work/editors/pdf-collaboration-presence.d.ts +3 -0
- package/dist/internal/features/work/editors/pdf-collaboration-projection.d.ts +10 -0
- package/dist/internal/features/work/editors/pdf-evidence-contract.d.ts +36 -0
- package/dist/internal/features/work/editors/pdf-evidence-overlay.d.ts +37 -0
- package/dist/internal/features/work/editors/pdf-toolbar.d.ts +2 -1
- package/dist/internal/features/work/editors/pdf-viewer-controller.d.ts +7 -1
- package/dist/internal/features/work/editors/pdf-viewer.d.ts +11 -1
- package/dist/internal/features/work/editors/presentation-collaboration-presence.d.ts +5 -0
- package/dist/internal/features/work/editors/presentation-editor-focus.d.ts +3 -2
- package/dist/internal/features/work/editors/presentation-editor-types.d.ts +3 -0
- package/dist/internal/features/work/editors/presentation-editor.d.ts +1 -1
- package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +9 -0
- package/dist/internal/features/work/editors/spreadsheet-cell-clear.d.ts +3 -0
- package/dist/internal/features/work/editors/spreadsheet-cell-merge.d.ts +12 -0
- package/dist/internal/features/work/editors/spreadsheet-clipboard-shortcuts.d.ts +3 -7
- package/dist/internal/features/work/editors/spreadsheet-collaboration-presence.d.ts +9 -0
- package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +464 -0
- package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +45 -9
- package/dist/internal/features/work/editors/spreadsheet-context-menu.d.ts +2 -0
- package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +9 -28
- package/dist/internal/features/work/editors/spreadsheet-editor.d.ts +8 -2
- package/dist/internal/features/work/editors/spreadsheet-format-painter.d.ts +27 -0
- package/dist/internal/features/work/editors/spreadsheet-freeze-panes.d.ts +14 -0
- package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +3 -2
- package/dist/internal/features/work/editors/use-document-pagination.d.ts +6 -1
- package/dist/internal/features/work/editors/use-document-review-conflicts.d.ts +28 -0
- package/dist/internal/features/work/editors/use-spreadsheet-auto-filter.d.ts +21 -0
- package/dist/internal/features/work/editors/use-spreadsheet-collaboration.d.ts +27 -0
- package/dist/internal/features/work/editors/use-spreadsheet-format-painter.d.ts +18 -0
- package/dist/internal/features/work/editors/work-office-chrome.d.ts +22 -3
- package/dist/internal/features/work/editors/work-office-ribbon-overflow.d.ts +2 -0
- package/dist/internal/features/work/work-document-bookmark-references.d.ts +37 -0
- package/dist/internal/features/work/work-document-bookmarks.d.ts +29 -0
- package/dist/internal/features/work/work-document-caption-nodes.d.ts +4 -1
- package/dist/internal/features/work/work-document-comments.d.ts +1 -1
- package/dist/internal/features/work/work-document-equations.d.ts +513 -0
- package/dist/internal/features/work/work-document-extensions.d.ts +1 -0
- package/dist/internal/features/work/work-document-field-identity.d.ts +2 -0
- package/dist/internal/features/work/work-document-field-node.d.ts +2 -2
- package/dist/internal/features/work/work-document-fields.d.ts +7 -0
- package/dist/internal/features/work/work-document-image-identity.d.ts +30 -0
- package/dist/internal/features/work/work-document-image-layout.d.ts +46 -1
- package/dist/internal/features/work/work-document-image-wrap-contour.d.ts +16 -0
- package/dist/internal/features/work/work-document-incremental-layout.d.ts +2 -2
- package/dist/internal/features/work/work-document-model-codec.d.ts +4 -1
- package/dist/internal/features/work/work-document-note-integrity.d.ts +2 -0
- package/dist/internal/features/work/work-document-page-borders.d.ts +25 -0
- package/dist/internal/features/work/work-document-page-capture.d.ts +8 -0
- package/dist/internal/features/work/work-document-page-frames.d.ts +15 -0
- package/dist/internal/features/work/work-document-page-margins.d.ts +56 -0
- package/dist/internal/features/work/work-document-page-size.d.ts +47 -0
- package/dist/internal/features/work/work-document-pagination-measurement.d.ts +1 -2
- package/dist/internal/features/work/work-document-pagination-types.d.ts +7 -2
- package/dist/internal/features/work/work-document-pagination.d.ts +2 -2
- package/dist/internal/features/work/work-document-paragraph-borders.d.ts +32 -0
- package/dist/internal/features/work/work-document-paragraph-identity.d.ts +26 -0
- package/dist/internal/features/work/work-document-paragraph-shading.d.ts +18 -0
- package/dist/internal/features/work/work-document-review-conflicts.d.ts +35 -0
- package/dist/internal/features/work/work-document-section.d.ts +4 -0
- package/dist/internal/features/work/work-document-snapshot.d.ts +19 -0
- package/dist/internal/features/work/work-document-source.d.ts +23 -0
- package/dist/internal/features/work/work-document-table-column-widths.d.ts +7 -0
- package/dist/internal/features/work/work-document-table-property-changes.d.ts +3 -0
- package/dist/internal/features/work/work-document-table-row-identity.d.ts +15 -0
- package/dist/internal/features/work/work-document-table-sizing.d.ts +3 -0
- package/dist/internal/features/work/work-document-text-layout.d.ts +3 -1
- package/dist/internal/features/work/work-document-word-line-metrics.d.ts +2 -0
- package/dist/internal/features/work/work-docx-bookmark-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-bookmark-import.d.ts +24 -0
- package/dist/internal/features/work/work-docx-bookmarks.d.ts +17 -0
- package/dist/internal/features/work/work-docx-comment-durable-id-preservation.d.ts +2 -0
- package/dist/internal/features/work/work-docx-comment-export.d.ts +3 -0
- package/dist/internal/features/work/work-docx-comment-metadata.d.ts +2 -0
- package/dist/internal/features/work/work-docx-drawing-extension-preservation.d.ts +4 -0
- package/dist/internal/features/work/work-docx-equation-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-equation-export.d.ts +14 -0
- package/dist/internal/features/work/work-docx-equation-import.d.ts +30 -0
- package/dist/internal/features/work/work-docx-equation-story.d.ts +9 -0
- package/dist/internal/features/work/work-docx-export-formatting.d.ts +3 -1
- package/dist/internal/features/work/work-docx-export-image.d.ts +5 -1
- package/dist/internal/features/work/work-docx-export.d.ts +1 -1
- package/dist/internal/features/work/work-docx-field-instructions.d.ts +8 -0
- package/dist/internal/features/work/work-docx-font-table-preservation.d.ts +3 -0
- package/dist/internal/features/work/work-docx-ignorable-extension-preservation.d.ts +15 -0
- package/dist/internal/features/work/work-docx-image-crop.d.ts +12 -0
- package/dist/internal/features/work/work-docx-image-identity.d.ts +17 -0
- package/dist/internal/features/work/work-docx-image-layer.d.ts +12 -0
- package/dist/internal/features/work/work-docx-image-layout-import.d.ts +14 -2
- package/dist/internal/features/work/work-docx-image-wrap.d.ts +15 -0
- package/dist/internal/features/work/work-docx-import.d.ts +13 -3
- package/dist/internal/features/work/work-docx-list-export.d.ts +18 -0
- package/dist/internal/features/work/work-docx-list-import.d.ts +14 -0
- package/dist/internal/features/work/work-docx-note-comment-content-control-block-preservation.d.ts +18 -0
- package/dist/internal/features/work/work-docx-note-comment-content-control-model.d.ts +47 -0
- package/dist/internal/features/work/work-docx-note-comment-content-control-preservation.d.ts +4 -0
- package/dist/internal/features/work/work-docx-note-comment-content-control-properties.d.ts +17 -0
- package/dist/internal/features/work/work-docx-note-comment-content-control-table-model.d.ts +17 -0
- package/dist/internal/features/work/work-docx-note-comment-content-control-xml.d.ts +14 -0
- package/dist/internal/features/work/work-docx-note-comment-extension-preservation.d.ts +2 -0
- package/dist/internal/features/work/work-docx-note-comment-hyperlink-content.d.ts +40 -0
- package/dist/internal/features/work/work-docx-note-comment-hyperlink-preservation.d.ts +5 -0
- package/dist/internal/features/work/work-docx-note-comment-hyperlink-relationships.d.ts +35 -0
- package/dist/internal/features/work/work-docx-note-comment-identity.d.ts +15 -0
- package/dist/internal/features/work/work-docx-note-comment-run-preservation.d.ts +4 -0
- package/dist/internal/features/work/work-docx-note-comment-run-properties.d.ts +2 -0
- package/dist/internal/features/work/work-docx-note-image-import.d.ts +12 -0
- package/dist/internal/features/work/work-docx-note-image-relationships.d.ts +1 -0
- package/dist/internal/features/work/work-docx-numbering-extension-preservation.d.ts +6 -0
- package/dist/internal/features/work/work-docx-numbering.d.ts +1 -0
- package/dist/internal/features/work/work-docx-page-borders-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-page-borders-import.d.ts +10 -0
- package/dist/internal/features/work/work-docx-page-margins-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-page-margins-import.d.ts +18 -0
- package/dist/internal/features/work/work-docx-page-size-diagnostics.d.ts +2 -0
- package/dist/internal/features/work/work-docx-page-size-import.d.ts +17 -0
- package/dist/internal/features/work/work-docx-paragraph-borders-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-paragraph-borders-export.d.ts +18 -0
- package/dist/internal/features/work/work-docx-paragraph-borders-import.d.ts +24 -0
- package/dist/internal/features/work/work-docx-paragraph-default-collapsed.d.ts +19 -0
- package/dist/internal/features/work/work-docx-paragraph-extension-preservation.d.ts +2 -0
- package/dist/internal/features/work/work-docx-paragraph-identity-import.d.ts +10 -0
- package/dist/internal/features/work/work-docx-paragraph-identity.d.ts +18 -0
- package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +6 -1
- package/dist/internal/features/work/work-docx-paragraph-shading-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-paragraph-shading-export.d.ts +5 -0
- package/dist/internal/features/work/work-docx-paragraph-shading-import.d.ts +18 -0
- package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +3 -0
- package/dist/internal/features/work/work-docx-settings-preservation.d.ts +10 -0
- package/dist/internal/features/work/work-docx-settings-xml.d.ts +16 -0
- package/dist/internal/features/work/work-docx-style-extension-preservation.d.ts +2 -0
- package/dist/internal/features/work/work-docx-table-cell-export.d.ts +2 -1
- package/dist/internal/features/work/work-docx-table-cell-import.d.ts +3 -0
- package/dist/internal/features/work/work-docx-table-extension-preservation.d.ts +2 -0
- package/dist/internal/features/work/work-docx-table-row-import.d.ts +2 -0
- package/dist/internal/features/work/work-docx-table-sizing-import.d.ts +1 -0
- package/dist/internal/features/work/work-docx-theme-reference.d.ts +23 -0
- package/dist/internal/features/work/work-docx-theme.d.ts +4 -1
- package/dist/internal/features/work/work-docx-twips.d.ts +12 -0
- package/dist/internal/features/work/work-file-contract.d.ts +1 -0
- package/dist/internal/features/work/work-file-io.d.ts +1 -1
- package/dist/internal/features/work/work-markdown-extensions.d.ts +4 -1
- package/dist/internal/features/work/work-ooxml-package-preservation.d.ts +12 -0
- package/dist/internal/features/work/work-ooxml-package-security.d.ts +6 -0
- package/dist/internal/features/work/work-ooxml-relationship-preservation.d.ts +10 -0
- package/dist/internal/features/work/work-ooxml-xml.d.ts +2 -0
- package/dist/internal/features/work/work-pdf-export.d.ts +10 -0
- package/dist/internal/features/work/work-repository.d.ts +2 -0
- package/dist/internal/features/work/work-types.d.ts +15 -2
- package/dist/internal/kernel/office-kernel-client-types.d.ts +1 -0
- package/dist/internal/kernel/office-kernel-protocol.d.ts +7 -0
- package/dist/internal/kernel/office-kernel-version.d.ts +1 -1
- package/dist/office-kernel.wasm +0 -0
- package/dist/office-kernel.worker.js +93 -41
- package/dist/react.d.ts +18 -12
- package/dist/react.js +1 -1
- package/dist/styles.css +1367 -16
- package/dist/vue.d.ts +48 -5
- package/dist/vue.js +42 -3
- package/dist/web-component.d.ts +24 -2
- package/dist/web-component.js +101 -2
- package/docs/latest/en/browser-editor-architecture.md +262 -47
- package/package.json +29 -4
- package/dist/0~152.js +0 -94
- package/dist/0~2582.js +0 -485
- package/dist/0~4750.js +0 -939
- package/dist/0~5861.js +0 -596
- package/dist/0~work-document-extensions.js +0 -3045
- package/dist/0~work-document-model-codec.js +0 -42
- package/dist/0~work-docx-bibliography.js +0 -347
- package/dist/0~work-docx-page-color.js +0 -42
- package/dist/2881.js +0 -1455
- package/dist/8728.js +0 -723
package/dist/0~pdf-viewer.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { __webpack_require__ } from "./0~rslib-runtime.js";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { AnnotationPlugin, DocumentManagerPlugin, ExportPlugin, HistoryPlugin, PDFViewer, ScrollPlugin, SearchPlugin, ThumbnailPlugin, ZoomMode, ZoomPlugin } from "@embedpdf/react-pdf-viewer";
|
|
3
|
+
import { AnnotationPlugin, DocumentManagerPlugin, ExportPlugin, FormPlugin, HistoryPlugin, PDFViewer, PdfAnnotationSubtype, ScrollPlugin, SearchPlugin, ThumbnailPlugin, ViewportPlugin, ZoomMode, ZoomPlugin } from "@embedpdf/react-pdf-viewer";
|
|
4
4
|
import { AlertCircle, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Ellipsis, GalleryVerticalEnd, Highlighter, Loader2, Minus, MousePointer2, MoveHorizontal, Pencil, Plus, Redo2, Save, Scan, Search, SlidersHorizontal, Strikethrough, Trash2, Type, Underline, Undo2, X } from "lucide-react";
|
|
5
5
|
import { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { readOfficePdfCollaborationSource as readWorkOfficePdfCollaborationSource, createOfficePdfCollaborationBinding as createWorkOfficePdfCollaborationBinding, assertPdfCollaborationSource as assertWorkOfficePdfCollaborationSource } from "./3818.js";
|
|
6
7
|
import { createOfficeEditorExtension, useOfficeEditorRuntime, useOfficeEditorKeyboardShortcuts } from "./0~3557.js";
|
|
7
8
|
import { isOfficeShortcutBlocked, OfficeColorPicker } from "./0~3635.js";
|
|
8
|
-
import {
|
|
9
|
-
import { StateView } from "./432.js";
|
|
9
|
+
import { officePresenceColorStyle, moveOfficeMenuFocus, useOfficeRemoteParticipants, WorkOfficeCollaborationParticipants, Popover, OfficePresenceAvatar, useOfficePublishPresenceLocation, button_Button, icon_button_IconButton, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom } from "./0~6090.js";
|
|
10
|
+
import { StateView, useOfficeCollaborationLocationNavigator, PDF_EVIDENCE_COORDINATE_BASIS } from "./432.js";
|
|
10
11
|
var pdf_viewer_namespaceObject = {};
|
|
11
12
|
__webpack_require__.r(pdf_viewer_namespaceObject);
|
|
12
13
|
__webpack_require__.d(pdf_viewer_namespaceObject, {
|
|
@@ -92,6 +93,25 @@ function usePdfAnnotationController(registry) {
|
|
|
92
93
|
})));
|
|
93
94
|
if (deletions.length > 0) scope.deleteAnnotations(deletions);
|
|
94
95
|
}, []);
|
|
96
|
+
const getSelectionLocation = useCallback(()=>{
|
|
97
|
+
const scope = activeAnnotationScope(capabilitiesRef.current);
|
|
98
|
+
const selected = safely(()=>scope?.getSelectedAnnotations());
|
|
99
|
+
if (selected?.length !== 1 || !selected[0]) return null;
|
|
100
|
+
return {
|
|
101
|
+
annotationId: selected[0].object.id,
|
|
102
|
+
pageIndex: selected[0].object.pageIndex
|
|
103
|
+
};
|
|
104
|
+
}, []);
|
|
105
|
+
const locateAnnotation = useCallback((pageIndex, annotationId)=>{
|
|
106
|
+
const scope = activeAnnotationScope(capabilitiesRef.current);
|
|
107
|
+
if (!scope) return false;
|
|
108
|
+
const annotation = safely(()=>scope.getAnnotationById(annotationId));
|
|
109
|
+
if (!annotation || annotation.object.pageIndex !== pageIndex) return false;
|
|
110
|
+
return Boolean(safely(()=>{
|
|
111
|
+
scope.selectAnnotation(pageIndex, annotationId);
|
|
112
|
+
return true;
|
|
113
|
+
}));
|
|
114
|
+
}, []);
|
|
95
115
|
const setAnnotationColor = useCallback((color)=>{
|
|
96
116
|
const normalizedColor = normalizeAnnotationColor(color);
|
|
97
117
|
const capabilities = capabilitiesRef.current;
|
|
@@ -133,12 +153,16 @@ function usePdfAnnotationController(registry) {
|
|
|
133
153
|
return useMemo(()=>({
|
|
134
154
|
state,
|
|
135
155
|
deleteSelection,
|
|
156
|
+
getSelectionLocation,
|
|
157
|
+
locateAnnotation,
|
|
136
158
|
setAnnotationColor,
|
|
137
159
|
setAnnotationOpacity,
|
|
138
160
|
setAnnotationStrokeWidth,
|
|
139
161
|
selectTool
|
|
140
162
|
}), [
|
|
141
163
|
deleteSelection,
|
|
164
|
+
getSelectionLocation,
|
|
165
|
+
locateAnnotation,
|
|
142
166
|
setAnnotationColor,
|
|
143
167
|
setAnnotationOpacity,
|
|
144
168
|
setAnnotationStrokeWidth,
|
|
@@ -238,6 +262,457 @@ function safely(action) {
|
|
|
238
262
|
return;
|
|
239
263
|
}
|
|
240
264
|
}
|
|
265
|
+
const COLLABORATIVE_PDF_ANNOTATION_TYPES = new Set([
|
|
266
|
+
PdfAnnotationSubtype.FREETEXT,
|
|
267
|
+
PdfAnnotationSubtype.HIGHLIGHT,
|
|
268
|
+
PdfAnnotationSubtype.UNDERLINE,
|
|
269
|
+
PdfAnnotationSubtype.STRIKEOUT,
|
|
270
|
+
PdfAnnotationSubtype.INK
|
|
271
|
+
]);
|
|
272
|
+
function createWorkPdfCollaborationProjection(registry, session) {
|
|
273
|
+
const binding = createWorkOfficePdfCollaborationBinding(session);
|
|
274
|
+
const initialization = new AbortController();
|
|
275
|
+
let destroyed = false;
|
|
276
|
+
let failed = false;
|
|
277
|
+
let failure;
|
|
278
|
+
let projecting = false;
|
|
279
|
+
let scopes = null;
|
|
280
|
+
let previousRecords = new Map();
|
|
281
|
+
const pendingAnnotations = new Map();
|
|
282
|
+
let pendingFormValues = null;
|
|
283
|
+
const errorListeners = new Set();
|
|
284
|
+
const stop = [];
|
|
285
|
+
const close = ()=>{
|
|
286
|
+
initialization.abort();
|
|
287
|
+
scopes = null;
|
|
288
|
+
pendingAnnotations.clear();
|
|
289
|
+
pendingFormValues = null;
|
|
290
|
+
for (const unsubscribe of stop.splice(0))unsubscribe();
|
|
291
|
+
try {
|
|
292
|
+
binding.destroy();
|
|
293
|
+
} catch {}
|
|
294
|
+
};
|
|
295
|
+
const reportError = (error)=>{
|
|
296
|
+
if (destroyed || failed) return;
|
|
297
|
+
failed = true;
|
|
298
|
+
failure = error;
|
|
299
|
+
close();
|
|
300
|
+
for (const listener of errorListeners)listener(error);
|
|
301
|
+
};
|
|
302
|
+
const project = (content)=>{
|
|
303
|
+
if (!scopes || destroyed || failed) return;
|
|
304
|
+
projecting = true;
|
|
305
|
+
try {
|
|
306
|
+
projectAnnotations(scopes.annotations, scopes.baseAnnotations, previousRecords, content.annotations, pendingAnnotations);
|
|
307
|
+
previousRecords = new Map(content.annotations.map((record)=>[
|
|
308
|
+
record.id,
|
|
309
|
+
record
|
|
310
|
+
]));
|
|
311
|
+
const projectedFormValues = projectedPdfFormValues(scopes.form, scopes.baseFormValues, content.formValues);
|
|
312
|
+
if (projectedFormValues && scopes.form) {
|
|
313
|
+
pendingFormValues = projectedFormValues.expected;
|
|
314
|
+
applyPdfFormValues(scopes.form, projectedFormValues.updates, reportError);
|
|
315
|
+
}
|
|
316
|
+
purgeViewerHistory(scopes.history);
|
|
317
|
+
} finally{
|
|
318
|
+
projecting = false;
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
const ready = registry.pluginsReady().then(async ()=>{
|
|
322
|
+
if (destroyed || failed) return;
|
|
323
|
+
const plugins = pdfProjectionPlugins(registry);
|
|
324
|
+
const annotationsLoaded = await waitForPdfAnnotationsLoaded(registry, plugins, initialization.signal);
|
|
325
|
+
if (!annotationsLoaded || destroyed || failed) return;
|
|
326
|
+
scopes = pdfProjectionScopes(plugins);
|
|
327
|
+
const activeScopes = scopes;
|
|
328
|
+
stop.push(activeScopes.annotations.onAnnotationEvent((event)=>{
|
|
329
|
+
if (destroyed || projecting || 'loaded' === event.type) return;
|
|
330
|
+
if (!event.committed || event.documentId !== activeScopes.documentId) return;
|
|
331
|
+
try {
|
|
332
|
+
const pending = pendingAnnotations.get(event.annotation.id);
|
|
333
|
+
if (projectedAnnotationEventMatches(pending, event)) {
|
|
334
|
+
pendingAnnotations.delete(event.annotation.id);
|
|
335
|
+
purgeViewerHistory(activeScopes.history);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
commitAnnotationEvent(binding, event);
|
|
339
|
+
purgeViewerHistory(activeScopes.history);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
reportError(error);
|
|
342
|
+
}
|
|
343
|
+
}));
|
|
344
|
+
if (activeScopes.form) {
|
|
345
|
+
const form = activeScopes.form;
|
|
346
|
+
stop.push(form.onFieldValueChange(()=>{
|
|
347
|
+
if (destroyed || projecting) return;
|
|
348
|
+
try {
|
|
349
|
+
const values = form.getFormValues();
|
|
350
|
+
if (pendingFormValues) {
|
|
351
|
+
if (pdfJsonEqual(values, pendingFormValues)) {
|
|
352
|
+
pendingFormValues = null;
|
|
353
|
+
purgeViewerHistory(activeScopes.history);
|
|
354
|
+
}
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
commitFormValues(binding, activeScopes.baseFormValues, form, values);
|
|
358
|
+
purgeViewerHistory(activeScopes.history);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
reportError(error);
|
|
361
|
+
}
|
|
362
|
+
}));
|
|
363
|
+
stop.push(form.onFormReady(()=>{
|
|
364
|
+
if (destroyed) return;
|
|
365
|
+
try {
|
|
366
|
+
const projectedFormValues = projectedPdfFormValues(form, activeScopes.baseFormValues, binding.content().formValues);
|
|
367
|
+
if (projectedFormValues) {
|
|
368
|
+
pendingFormValues = projectedFormValues.expected;
|
|
369
|
+
applyPdfFormValues(form, projectedFormValues.updates, reportError);
|
|
370
|
+
}
|
|
371
|
+
purgeViewerHistory(activeScopes.history);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
reportError(error);
|
|
374
|
+
}
|
|
375
|
+
}));
|
|
376
|
+
}
|
|
377
|
+
project(binding.content());
|
|
378
|
+
}).catch((error)=>{
|
|
379
|
+
reportError(error);
|
|
380
|
+
throw error;
|
|
381
|
+
});
|
|
382
|
+
stop.push(binding.subscribe(({ content })=>{
|
|
383
|
+
project(content);
|
|
384
|
+
}));
|
|
385
|
+
stop.push(binding.subscribeError(reportError));
|
|
386
|
+
return {
|
|
387
|
+
binding,
|
|
388
|
+
ready,
|
|
389
|
+
subscribeError (listener) {
|
|
390
|
+
if (failed) {
|
|
391
|
+
queueMicrotask(()=>listener(failure));
|
|
392
|
+
return ()=>void 0;
|
|
393
|
+
}
|
|
394
|
+
errorListeners.add(listener);
|
|
395
|
+
return ()=>errorListeners.delete(listener);
|
|
396
|
+
},
|
|
397
|
+
destroy () {
|
|
398
|
+
if (destroyed) return;
|
|
399
|
+
destroyed = true;
|
|
400
|
+
close();
|
|
401
|
+
errorListeners.clear();
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function pdfProjectionPlugins(registry) {
|
|
406
|
+
const annotation = registry.getPlugin(AnnotationPlugin.id)?.provides();
|
|
407
|
+
const documentId = registry.getPlugin(DocumentManagerPlugin.id)?.provides().getActiveDocumentId();
|
|
408
|
+
if (!annotation || !documentId) throw new Error('PDF collaboration requires an open EmbedPDF annotation document.');
|
|
409
|
+
const form = registry.getPlugin(FormPlugin.id)?.provides().forDocument(documentId) ?? null;
|
|
410
|
+
const history = registry.getPlugin(HistoryPlugin.id)?.provides().forDocument(documentId) ?? null;
|
|
411
|
+
return {
|
|
412
|
+
annotation,
|
|
413
|
+
documentId,
|
|
414
|
+
form,
|
|
415
|
+
history
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function pdfProjectionScopes({ annotation, documentId, form, history }) {
|
|
419
|
+
const annotations = annotation.forDocument(documentId);
|
|
420
|
+
return {
|
|
421
|
+
annotations,
|
|
422
|
+
baseAnnotations: new Map(annotations.getAnnotations().map(({ object })=>[
|
|
423
|
+
object.id,
|
|
424
|
+
viewerAnnotation(portableViewerAnnotation(object))
|
|
425
|
+
])),
|
|
426
|
+
baseFormValues: form?.getFormValues() ?? {},
|
|
427
|
+
documentId,
|
|
428
|
+
form,
|
|
429
|
+
history
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
async function waitForPdfAnnotationsLoaded(registry, { annotation, documentId }, signal) {
|
|
433
|
+
if (signal.aborted) return false;
|
|
434
|
+
const document1 = registry.getPlugin(DocumentManagerPlugin.id)?.provides().getDocument(documentId);
|
|
435
|
+
if (!document1) throw new Error('PDF collaboration requires an open EmbedPDF annotation document.');
|
|
436
|
+
const scope = annotation.forDocument(documentId);
|
|
437
|
+
let resolveLoaded = ()=>void 0;
|
|
438
|
+
const loaded = new Promise((resolve)=>{
|
|
439
|
+
resolveLoaded = resolve;
|
|
440
|
+
});
|
|
441
|
+
const stopLoaded = scope.onAnnotationEvent((event)=>{
|
|
442
|
+
if ('loaded' === event.type && event.documentId === documentId) resolveLoaded();
|
|
443
|
+
});
|
|
444
|
+
let resolveAborted = ()=>void 0;
|
|
445
|
+
const aborted = new Promise((resolve)=>{
|
|
446
|
+
resolveAborted = resolve;
|
|
447
|
+
});
|
|
448
|
+
const onAbort = ()=>resolveAborted();
|
|
449
|
+
signal.addEventListener('abort', onAbort, {
|
|
450
|
+
once: true
|
|
451
|
+
});
|
|
452
|
+
if (signal.aborted) onAbort();
|
|
453
|
+
try {
|
|
454
|
+
const expected = await Promise.race([
|
|
455
|
+
registry.getEngine().getAllAnnotations(document1).toPromise(),
|
|
456
|
+
aborted.then(()=>null)
|
|
457
|
+
]);
|
|
458
|
+
if (!expected || signal.aborted) return false;
|
|
459
|
+
const expectedIds = new Set(Object.values(expected).flatMap((records)=>records.map(({ id })=>id)));
|
|
460
|
+
if (pdfAnnotationIdsMatch(scope, expectedIds)) return true;
|
|
461
|
+
await Promise.race([
|
|
462
|
+
loaded,
|
|
463
|
+
aborted
|
|
464
|
+
]);
|
|
465
|
+
if (signal.aborted) return false;
|
|
466
|
+
if (pdfAnnotationIdsMatch(scope, expectedIds)) return true;
|
|
467
|
+
throw new Error('PDF collaboration could not capture the source baseline.');
|
|
468
|
+
} finally{
|
|
469
|
+
signal.removeEventListener('abort', onAbort);
|
|
470
|
+
stopLoaded();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function pdfAnnotationIdsMatch(scope, expectedIds) {
|
|
474
|
+
const actualIds = new Set(scope.getAnnotations().map(({ object })=>object.id));
|
|
475
|
+
return expectedIds.size === actualIds.size && [
|
|
476
|
+
...expectedIds
|
|
477
|
+
].every((id)=>actualIds.has(id));
|
|
478
|
+
}
|
|
479
|
+
function purgeViewerHistory(history) {
|
|
480
|
+
history?.purgeByMetadata(()=>true);
|
|
481
|
+
}
|
|
482
|
+
function commitAnnotationEvent(binding, event) {
|
|
483
|
+
const previous = binding.content();
|
|
484
|
+
const current = previous.annotations.find(({ id })=>id === event.annotation.id);
|
|
485
|
+
assertCollaborativePdfAnnotation(event.annotation);
|
|
486
|
+
let annotations = previous.annotations;
|
|
487
|
+
if ('delete' === event.type) {
|
|
488
|
+
if (current?.deleted) return;
|
|
489
|
+
annotations = current ? previous.annotations.map((record)=>record.id === current.id ? {
|
|
490
|
+
...record,
|
|
491
|
+
deleted: true
|
|
492
|
+
} : record) : [
|
|
493
|
+
...previous.annotations,
|
|
494
|
+
{
|
|
495
|
+
id: event.annotation.id,
|
|
496
|
+
pageIndex: event.pageIndex,
|
|
497
|
+
source: 'base',
|
|
498
|
+
annotation: portableViewerAnnotation(event.annotation),
|
|
499
|
+
deleted: true
|
|
500
|
+
}
|
|
501
|
+
];
|
|
502
|
+
} else {
|
|
503
|
+
const annotation = portableViewerAnnotation(event.annotation);
|
|
504
|
+
annotations = current ? previous.annotations.map((record)=>record.id === current.id ? {
|
|
505
|
+
...record,
|
|
506
|
+
annotation,
|
|
507
|
+
pageIndex: event.pageIndex
|
|
508
|
+
} : record) : [
|
|
509
|
+
...previous.annotations,
|
|
510
|
+
{
|
|
511
|
+
id: event.annotation.id,
|
|
512
|
+
pageIndex: event.pageIndex,
|
|
513
|
+
source: 'create' === event.type ? 'created' : 'base',
|
|
514
|
+
annotation
|
|
515
|
+
}
|
|
516
|
+
];
|
|
517
|
+
}
|
|
518
|
+
binding.replace(previous, {
|
|
519
|
+
...previous,
|
|
520
|
+
annotations
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
function commitFormValues(binding, baseValues, scope, values) {
|
|
524
|
+
const previous = binding.content();
|
|
525
|
+
const fields = new Map(scope.getFormFields().map((field)=>[
|
|
526
|
+
field.name,
|
|
527
|
+
field
|
|
528
|
+
]));
|
|
529
|
+
const formValues = Object.entries(values).filter(([id, value])=>{
|
|
530
|
+
const field = fields.get(id);
|
|
531
|
+
if (!field) throw new Error(`PDF collaboration form field '${id}' does not exist.`);
|
|
532
|
+
if (field.readOnly && value !== baseValues[id]) throw new Error(`PDF collaboration form field '${id}' is read-only.`);
|
|
533
|
+
return value !== baseValues[id];
|
|
534
|
+
}).map(([id, value])=>({
|
|
535
|
+
id,
|
|
536
|
+
value
|
|
537
|
+
})).sort((left, right)=>left.id.localeCompare(right.id));
|
|
538
|
+
binding.replace(previous, {
|
|
539
|
+
...previous,
|
|
540
|
+
formValues
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
function projectAnnotations(scope, baseAnnotations, previous, records, pending) {
|
|
544
|
+
assertPdfAnnotationSources(baseAnnotations, records);
|
|
545
|
+
const current = new Map(scope.getAnnotations().map(({ object })=>[
|
|
546
|
+
object.id,
|
|
547
|
+
object
|
|
548
|
+
]));
|
|
549
|
+
const nextIds = new Set(records.map(({ id })=>id));
|
|
550
|
+
for (const [id, record] of previous){
|
|
551
|
+
if (nextIds.has(id)) continue;
|
|
552
|
+
const existing = current.get(id);
|
|
553
|
+
if ('created' === record.source) {
|
|
554
|
+
if (existing) {
|
|
555
|
+
pending.set(id, {
|
|
556
|
+
expected: 'deleted',
|
|
557
|
+
previous: existing
|
|
558
|
+
});
|
|
559
|
+
scope.deleteAnnotation(existing.pageIndex, id);
|
|
560
|
+
}
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
const base = baseAnnotations.get(id);
|
|
564
|
+
if (!(!base || pdfJsonEqual(existing, base))) {
|
|
565
|
+
pending.set(id, {
|
|
566
|
+
expected: base,
|
|
567
|
+
previous: existing
|
|
568
|
+
});
|
|
569
|
+
if (existing) scope.updateAnnotation(existing.pageIndex, id, base);
|
|
570
|
+
else scope.importAnnotations([
|
|
571
|
+
{
|
|
572
|
+
annotation: base
|
|
573
|
+
}
|
|
574
|
+
]);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
for (const record of records){
|
|
578
|
+
const existing = current.get(record.id);
|
|
579
|
+
if (record.deleted) {
|
|
580
|
+
if (existing) {
|
|
581
|
+
pending.set(record.id, {
|
|
582
|
+
expected: 'deleted',
|
|
583
|
+
previous: existing
|
|
584
|
+
});
|
|
585
|
+
scope.deleteAnnotation(existing.pageIndex, existing.id);
|
|
586
|
+
}
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
const expected = viewerAnnotation(record.annotation);
|
|
590
|
+
assertCollaborativePdfAnnotation(expected);
|
|
591
|
+
if (!existing) {
|
|
592
|
+
pending.set(record.id, {
|
|
593
|
+
expected
|
|
594
|
+
});
|
|
595
|
+
scope.importAnnotations([
|
|
596
|
+
{
|
|
597
|
+
annotation: expected
|
|
598
|
+
}
|
|
599
|
+
]);
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
if (!projectedPdfAnnotationEqual(existing, expected, 'base' === record.source ? baseAnnotations.get(record.id) : void 0)) {
|
|
603
|
+
pending.set(record.id, {
|
|
604
|
+
expected,
|
|
605
|
+
previous: existing
|
|
606
|
+
});
|
|
607
|
+
scope.updateAnnotation(existing.pageIndex, existing.id, {
|
|
608
|
+
...expected,
|
|
609
|
+
id: existing.id,
|
|
610
|
+
pageIndex: existing.pageIndex
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
function assertPdfAnnotationSources(baseAnnotations, records) {
|
|
616
|
+
for (const record of records){
|
|
617
|
+
const inSource = baseAnnotations.has(record.id);
|
|
618
|
+
if ('base' === record.source && !inSource) throw new Error(`PDF collaboration base annotation '${record.id}' does not exist in the source PDF.`);
|
|
619
|
+
if ('created' === record.source && inSource) throw new Error(`PDF collaboration annotation '${record.id}' conflicts with a source annotation.`);
|
|
620
|
+
const base = baseAnnotations.get(record.id);
|
|
621
|
+
if (base && (base.pageIndex !== record.pageIndex || base.type !== record.annotation.type)) throw new Error(`PDF collaboration base annotation '${record.id}' has a different source identity.`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function assertCollaborativePdfAnnotation(annotation) {
|
|
625
|
+
if (COLLABORATIVE_PDF_ANNOTATION_TYPES.has(annotation.type)) return;
|
|
626
|
+
throw new Error(`PDF collaboration does not support annotation type '${annotation.type}'.`);
|
|
627
|
+
}
|
|
628
|
+
function projectedPdfFormValues(scope, baseValues, records) {
|
|
629
|
+
if (!scope) return null;
|
|
630
|
+
const fields = new Map(scope.getFormFields().map((field)=>[
|
|
631
|
+
field.name,
|
|
632
|
+
field
|
|
633
|
+
]));
|
|
634
|
+
for (const { id, value } of records){
|
|
635
|
+
const field = fields.get(id);
|
|
636
|
+
if (!field) throw new Error(`PDF collaboration form field '${id}' does not exist.`);
|
|
637
|
+
if (field.readOnly && value !== baseValues[id]) throw new Error(`PDF collaboration form field '${id}' is read-only.`);
|
|
638
|
+
}
|
|
639
|
+
const expected = {
|
|
640
|
+
...baseValues,
|
|
641
|
+
...Object.fromEntries(records.map(({ id, value })=>[
|
|
642
|
+
id,
|
|
643
|
+
value
|
|
644
|
+
]))
|
|
645
|
+
};
|
|
646
|
+
const current = scope.getFormValues();
|
|
647
|
+
const updates = Object.fromEntries(Object.entries(expected).filter(([id, value])=>current[id] !== value));
|
|
648
|
+
if (0 === Object.keys(updates).length) return null;
|
|
649
|
+
return {
|
|
650
|
+
expected,
|
|
651
|
+
updates
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function applyPdfFormValues(scope, values, onError) {
|
|
655
|
+
scope.setFormValues(values).toPromise().catch(onError);
|
|
656
|
+
}
|
|
657
|
+
function projectedAnnotationEventMatches(pending, event) {
|
|
658
|
+
if (void 0 === pending) return false;
|
|
659
|
+
if ('deleted' === pending.expected) return 'delete' === event.type;
|
|
660
|
+
return 'delete' !== event.type && projectedPdfAnnotationEqual(event.annotation, pending.expected, pending.previous);
|
|
661
|
+
}
|
|
662
|
+
function projectedPdfAnnotationEqual(actual, expected, previous) {
|
|
663
|
+
const normalizedActual = portableViewerAnnotation(actual);
|
|
664
|
+
const normalizedExpected = portableViewerAnnotation(expected);
|
|
665
|
+
const normalizedPrevious = previous ? portableViewerAnnotation(previous) : void 0;
|
|
666
|
+
for (const key of Object.keys(normalizedActual))if (!Object.hasOwn(normalizedExpected, key)) {
|
|
667
|
+
if ('author' === key || normalizedPrevious && Object.hasOwn(normalizedPrevious, key) && pdfJsonEqual(normalizedActual[key], normalizedPrevious[key])) delete normalizedActual[key];
|
|
668
|
+
}
|
|
669
|
+
return pdfJsonEqual(normalizedActual, normalizedExpected);
|
|
670
|
+
}
|
|
671
|
+
function portableViewerAnnotation(annotation) {
|
|
672
|
+
return clonePdfValue(annotation);
|
|
673
|
+
}
|
|
674
|
+
function viewerAnnotation(annotation) {
|
|
675
|
+
return revivePdfDates(annotation);
|
|
676
|
+
}
|
|
677
|
+
function clonePdfValue(value) {
|
|
678
|
+
if (value instanceof Date) return value.toISOString();
|
|
679
|
+
if (Array.isArray(value)) return value.map(clonePdfValue);
|
|
680
|
+
if (!value || 'object' != typeof value) return value;
|
|
681
|
+
return Object.fromEntries(Object.entries(value).flatMap(([key, child])=>void 0 === child ? [] : [
|
|
682
|
+
[
|
|
683
|
+
key,
|
|
684
|
+
clonePdfValue(child)
|
|
685
|
+
]
|
|
686
|
+
]));
|
|
687
|
+
}
|
|
688
|
+
function revivePdfDates(value, key) {
|
|
689
|
+
if (Array.isArray(value)) return value.map((child)=>revivePdfDates(child));
|
|
690
|
+
if (!value || 'object' != typeof value) {
|
|
691
|
+
if (('created' === key || 'modified' === key) && 'string' == typeof value) {
|
|
692
|
+
const timestamp = Date.parse(value);
|
|
693
|
+
if (Number.isFinite(timestamp)) return new Date(timestamp);
|
|
694
|
+
}
|
|
695
|
+
return value;
|
|
696
|
+
}
|
|
697
|
+
return Object.fromEntries(Object.entries(value).map(([childKey, child])=>[
|
|
698
|
+
childKey,
|
|
699
|
+
revivePdfDates(child, childKey)
|
|
700
|
+
]));
|
|
701
|
+
}
|
|
702
|
+
function pdfJsonEqual(left, right) {
|
|
703
|
+
return canonicalPdfJson(left) === canonicalPdfJson(right);
|
|
704
|
+
}
|
|
705
|
+
function canonicalPdfJson(value) {
|
|
706
|
+
return JSON.stringify(sortPdfJson(clonePdfValue(value)));
|
|
707
|
+
}
|
|
708
|
+
function sortPdfJson(value) {
|
|
709
|
+
if (Array.isArray(value)) return value.map(sortPdfJson);
|
|
710
|
+
if (!value || 'object' != typeof value) return value;
|
|
711
|
+
return Object.fromEntries(Object.entries(value).sort(([left], [right])=>left.localeCompare(right)).map(([key, child])=>[
|
|
712
|
+
key,
|
|
713
|
+
sortPdfJson(child)
|
|
714
|
+
]));
|
|
715
|
+
}
|
|
241
716
|
function createPdfEditorExtensions() {
|
|
242
717
|
return [
|
|
243
718
|
createOfficeEditorExtension({
|
|
@@ -406,6 +881,353 @@ function canZoom(viewer) {
|
|
|
406
881
|
function canSave({ editable, save, viewer }) {
|
|
407
882
|
return editable && save.enabled && documentReady(viewer) && viewer.state.features.export;
|
|
408
883
|
}
|
|
884
|
+
function PdfCollaborationPresenceLayer({ pageIndex }) {
|
|
885
|
+
const participants = useOfficeRemoteParticipants().filter((participant)=>participant.location?.kind === 'pdf' && participant.location.pageIndex === pageIndex);
|
|
886
|
+
if (!participants.length) return null;
|
|
887
|
+
return /*#__PURE__*/ jsx("div", {
|
|
888
|
+
className: "work-pdf-remote-presence-layer",
|
|
889
|
+
"data-pdf-presence-page": pageIndex,
|
|
890
|
+
"aria-hidden": "true",
|
|
891
|
+
children: participants.map((participant)=>{
|
|
892
|
+
const location = participant.location;
|
|
893
|
+
if (location?.kind !== 'pdf') return null;
|
|
894
|
+
return /*#__PURE__*/ jsxs("span", {
|
|
895
|
+
className: "work-pdf-remote-participant",
|
|
896
|
+
"data-activity": participant.activity,
|
|
897
|
+
"data-annotation-id": location.annotationId,
|
|
898
|
+
"data-participant-id": participant.actor.id,
|
|
899
|
+
style: officePresenceColorStyle(participant),
|
|
900
|
+
children: [
|
|
901
|
+
/*#__PURE__*/ jsx(OfficePresenceAvatar, {
|
|
902
|
+
compact: true,
|
|
903
|
+
participant: participant
|
|
904
|
+
}),
|
|
905
|
+
/*#__PURE__*/ jsxs("span", {
|
|
906
|
+
children: [
|
|
907
|
+
/*#__PURE__*/ jsx("strong", {
|
|
908
|
+
children: participant.actor.name
|
|
909
|
+
}),
|
|
910
|
+
/*#__PURE__*/ jsx("small", {
|
|
911
|
+
children: location.annotationId ? '正在查看批注' : '正在查看此页'
|
|
912
|
+
})
|
|
913
|
+
]
|
|
914
|
+
})
|
|
915
|
+
]
|
|
916
|
+
}, participant.presenceId);
|
|
917
|
+
})
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
const MAX_EVIDENCE_REGIONS_PER_PAGE = 2000;
|
|
921
|
+
const MAX_REGION_TARGETS = 128;
|
|
922
|
+
const MAX_ID_LENGTH = 512;
|
|
923
|
+
const PAGE_ASPECT_RATIO_TOLERANCE = 0.005;
|
|
924
|
+
function PdfEvidenceOverlayLayer({ currentPage, evidenceOverlay, onEvidenceRegionSelect, registry, selectedEvidenceRegionId, sourceKey }) {
|
|
925
|
+
const [runtime, setRuntime] = useState(null);
|
|
926
|
+
const [pageState, setPageState] = useState({
|
|
927
|
+
status: 'idle'
|
|
928
|
+
});
|
|
929
|
+
const [viewportRevision, setViewportRevision] = useState(0);
|
|
930
|
+
const lastNavigationRef = useRef(null);
|
|
931
|
+
useEffect(()=>{
|
|
932
|
+
let disposed = false;
|
|
933
|
+
registry.pluginsReady().then(()=>{
|
|
934
|
+
if (!disposed) setRuntime(readEvidenceRuntime(registry));
|
|
935
|
+
}).catch((error)=>{
|
|
936
|
+
if (!disposed) setPageState({
|
|
937
|
+
message: evidenceErrorMessage(error),
|
|
938
|
+
status: 'error'
|
|
939
|
+
});
|
|
940
|
+
});
|
|
941
|
+
return ()=>{
|
|
942
|
+
disposed = true;
|
|
943
|
+
};
|
|
944
|
+
}, [
|
|
945
|
+
registry
|
|
946
|
+
]);
|
|
947
|
+
useEffect(()=>{
|
|
948
|
+
if (!runtime) return;
|
|
949
|
+
let frame = 0;
|
|
950
|
+
const update = ()=>{
|
|
951
|
+
if (frame) return;
|
|
952
|
+
frame = window.requestAnimationFrame(()=>{
|
|
953
|
+
frame = 0;
|
|
954
|
+
setViewportRevision((value)=>value + 1);
|
|
955
|
+
});
|
|
956
|
+
};
|
|
957
|
+
const unsubscribe = [
|
|
958
|
+
runtime.scroll.onScroll(()=>update()),
|
|
959
|
+
runtime.scroll.onLayoutChange(()=>update()),
|
|
960
|
+
runtime.viewport.onScrollChange(()=>update()),
|
|
961
|
+
runtime.viewport.onViewportResize(()=>update()),
|
|
962
|
+
runtime.zoom?.onStateChange(()=>update())
|
|
963
|
+
].filter((stop)=>Boolean(stop));
|
|
964
|
+
return ()=>{
|
|
965
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
966
|
+
for (const stop of unsubscribe)stop();
|
|
967
|
+
};
|
|
968
|
+
}, [
|
|
969
|
+
runtime
|
|
970
|
+
]);
|
|
971
|
+
useEffect(()=>{
|
|
972
|
+
const abort = new AbortController();
|
|
973
|
+
if (!runtime || currentPage < 1) {
|
|
974
|
+
setPageState({
|
|
975
|
+
status: 'idle'
|
|
976
|
+
});
|
|
977
|
+
return ()=>abort.abort();
|
|
978
|
+
}
|
|
979
|
+
const identityError = validateOverlayIdentity(evidenceOverlay, sourceKey);
|
|
980
|
+
if (identityError) {
|
|
981
|
+
setPageState({
|
|
982
|
+
message: identityError,
|
|
983
|
+
status: 'error'
|
|
984
|
+
});
|
|
985
|
+
return ()=>abort.abort();
|
|
986
|
+
}
|
|
987
|
+
setPageState({
|
|
988
|
+
status: 'loading'
|
|
989
|
+
});
|
|
990
|
+
evidenceOverlay.loadPage(currentPage, abort.signal).then((page)=>{
|
|
991
|
+
if (abort.signal.aborted) return;
|
|
992
|
+
if (page) validatePdfEvidencePage(page, evidenceOverlay, runtime, currentPage);
|
|
993
|
+
setPageState({
|
|
994
|
+
page,
|
|
995
|
+
status: 'ready'
|
|
996
|
+
});
|
|
997
|
+
}).catch((error)=>{
|
|
998
|
+
if (!abort.signal.aborted) setPageState({
|
|
999
|
+
message: evidenceErrorMessage(error),
|
|
1000
|
+
status: 'error'
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
return ()=>abort.abort();
|
|
1004
|
+
}, [
|
|
1005
|
+
currentPage,
|
|
1006
|
+
evidenceOverlay,
|
|
1007
|
+
runtime,
|
|
1008
|
+
sourceKey
|
|
1009
|
+
]);
|
|
1010
|
+
const page = 'ready' === pageState.status ? pageState.page : null;
|
|
1011
|
+
const regions = useMemo(()=>page && runtime ? positionEvidenceRegions(page, runtime, viewportRevision) : [], [
|
|
1012
|
+
page,
|
|
1013
|
+
runtime,
|
|
1014
|
+
viewportRevision
|
|
1015
|
+
]);
|
|
1016
|
+
useEffect(()=>{
|
|
1017
|
+
if (!runtime || !page || !selectedEvidenceRegionId) return;
|
|
1018
|
+
const selected = page.regions.find((region)=>region.id === selectedEvidenceRegionId);
|
|
1019
|
+
if (!selected) return;
|
|
1020
|
+
const navigationKey = `${page.pageNumber}:${selected.id}`;
|
|
1021
|
+
if (lastNavigationRef.current === navigationKey) return;
|
|
1022
|
+
lastNavigationRef.current = navigationKey;
|
|
1023
|
+
scrollEvidenceRegionIntoView(runtime, page, selected);
|
|
1024
|
+
}, [
|
|
1025
|
+
page,
|
|
1026
|
+
runtime,
|
|
1027
|
+
selectedEvidenceRegionId
|
|
1028
|
+
]);
|
|
1029
|
+
useEffect(()=>{
|
|
1030
|
+
if (!runtime || !selectedEvidenceRegionId || !evidenceOverlay.locateRegion || page?.regions.some((region)=>region.id === selectedEvidenceRegionId)) return;
|
|
1031
|
+
const abort = new AbortController();
|
|
1032
|
+
evidenceOverlay.locateRegion(selectedEvidenceRegionId, abort.signal).then((location)=>{
|
|
1033
|
+
if (!abort.signal.aborted && location && location.pageNumber !== currentPage) scrollToEvidencePage(runtime, location.pageNumber);
|
|
1034
|
+
}).catch(()=>void 0);
|
|
1035
|
+
return ()=>abort.abort();
|
|
1036
|
+
}, [
|
|
1037
|
+
currentPage,
|
|
1038
|
+
evidenceOverlay,
|
|
1039
|
+
page,
|
|
1040
|
+
runtime,
|
|
1041
|
+
selectedEvidenceRegionId
|
|
1042
|
+
]);
|
|
1043
|
+
if ('error' === pageState.status) return /*#__PURE__*/ jsx("div", {
|
|
1044
|
+
className: "work-pdf-evidence-status",
|
|
1045
|
+
role: "status",
|
|
1046
|
+
title: pageState.message,
|
|
1047
|
+
children: "当前页定位不可用"
|
|
1048
|
+
});
|
|
1049
|
+
if ('ready' === pageState.status && !pageState.page) return /*#__PURE__*/ jsx("div", {
|
|
1050
|
+
className: "work-pdf-evidence-status",
|
|
1051
|
+
role: "status",
|
|
1052
|
+
children: "当前页暂无安全定位"
|
|
1053
|
+
});
|
|
1054
|
+
if (!page || 0 === regions.length) return null;
|
|
1055
|
+
return /*#__PURE__*/ jsx("fieldset", {
|
|
1056
|
+
className: "work-pdf-evidence-overlay",
|
|
1057
|
+
"aria-label": "解析证据定位",
|
|
1058
|
+
children: regions.map(({ region, style })=>{
|
|
1059
|
+
const selected = region.id === selectedEvidenceRegionId;
|
|
1060
|
+
return /*#__PURE__*/ jsx("button", {
|
|
1061
|
+
type: "button",
|
|
1062
|
+
className: "work-pdf-evidence-region",
|
|
1063
|
+
"data-selected": selected || void 0,
|
|
1064
|
+
style: style,
|
|
1065
|
+
"aria-label": region.label ?? `解析区域 ${region.id}`,
|
|
1066
|
+
"aria-pressed": selected,
|
|
1067
|
+
title: region.label,
|
|
1068
|
+
onClick: ()=>onEvidenceRegionSelect?.(region)
|
|
1069
|
+
}, region.id);
|
|
1070
|
+
})
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
function readEvidenceRuntime(registry) {
|
|
1074
|
+
const documentManager = registry.getPlugin(DocumentManagerPlugin.id)?.provides();
|
|
1075
|
+
const scroll = registry.getPlugin(ScrollPlugin.id)?.provides();
|
|
1076
|
+
const viewport = registry.getPlugin(ViewportPlugin.id)?.provides();
|
|
1077
|
+
if (!documentManager || !scroll || !viewport) throw new Error('Required PDF evidence capabilities are unavailable.');
|
|
1078
|
+
return {
|
|
1079
|
+
documentManager,
|
|
1080
|
+
scroll,
|
|
1081
|
+
viewport,
|
|
1082
|
+
zoom: registry.getPlugin(ZoomPlugin.id)?.provides() ?? null
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function validateOverlayIdentity(overlay, sourceKey) {
|
|
1086
|
+
if (!sourceKey || sourceKey !== overlay.sourceSha256) return 'The evidence source identity does not match the PDF source.';
|
|
1087
|
+
if (!isSha256(overlay.sourceSha256) || !isSha256(overlay.renderProfileSha256)) return 'The evidence overlay contains an invalid SHA-256 identity.';
|
|
1088
|
+
if (overlay.coordinateBasis !== PDF_EVIDENCE_COORDINATE_BASIS) return 'The evidence overlay uses an unsupported coordinate basis.';
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1091
|
+
function validatePdfEvidencePage(page, overlay, runtime, requestedPage) {
|
|
1092
|
+
if (page.pageNumber !== requestedPage || page.sourceSha256 !== overlay.sourceSha256 || page.renderProfileSha256 !== overlay.renderProfileSha256 || page.coordinateBasis !== PDF_EVIDENCE_COORDINATE_BASIS || 'source' !== page.canvasKind) throw new Error('The evidence page identity is invalid.');
|
|
1093
|
+
if (!boundedId(page.canvasId) || !positiveFinite(page.canvasWidth) || !positiveFinite(page.canvasHeight)) throw new Error('The evidence canvas identity or dimensions are invalid.');
|
|
1094
|
+
const documentPage = runtime.documentManager.getActiveDocument()?.pages[requestedPage - 1];
|
|
1095
|
+
if (!documentPage) throw new Error('The PDF page is unavailable.');
|
|
1096
|
+
const expectedRotation = 90 * documentPage.rotation;
|
|
1097
|
+
if (page.rotationDegrees !== expectedRotation) throw new Error('The evidence canvas rotation does not match the PDF page.');
|
|
1098
|
+
const rotatedWidth = documentPage.rotation % 2 ? documentPage.size.height : documentPage.size.width;
|
|
1099
|
+
const rotatedHeight = documentPage.rotation % 2 ? documentPage.size.width : documentPage.size.height;
|
|
1100
|
+
const expectedRatio = rotatedWidth / rotatedHeight;
|
|
1101
|
+
const evidenceRatio = page.canvasWidth / page.canvasHeight;
|
|
1102
|
+
if (Math.abs(evidenceRatio / expectedRatio - 1) > PAGE_ASPECT_RATIO_TOLERANCE) throw new Error('The evidence canvas aspect ratio does not match the PDF page.');
|
|
1103
|
+
if (page.regions.length > MAX_EVIDENCE_REGIONS_PER_PAGE) throw new Error('The evidence page exceeds the bounded region limit.');
|
|
1104
|
+
const ids = new Set();
|
|
1105
|
+
for (const region of page.regions){
|
|
1106
|
+
if (!boundedId(region.id) || ids.has(region.id)) throw new Error('The evidence page contains an invalid or duplicate region identity.');
|
|
1107
|
+
ids.add(region.id);
|
|
1108
|
+
if (region.targetIds.length > MAX_REGION_TARGETS || 0 === region.sourceRegionIds.length || region.sourceRegionIds.length > MAX_EVIDENCE_REGIONS_PER_PAGE || region.targetIds.some((id)=>!boundedId(id)) || region.sourceRegionIds.some((id)=>!boundedId(id)) || new Set(region.targetIds).size !== region.targetIds.length || new Set(region.sourceRegionIds).size !== region.sourceRegionIds.length) throw new Error('The evidence region identity receipts are invalid.');
|
|
1109
|
+
validateBounds(region.bounds);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
function validateBounds(bounds) {
|
|
1113
|
+
const values = [
|
|
1114
|
+
bounds.left,
|
|
1115
|
+
bounds.top,
|
|
1116
|
+
bounds.right,
|
|
1117
|
+
bounds.bottom
|
|
1118
|
+
];
|
|
1119
|
+
if (values.some((value)=>!Number.isInteger(value) || value < 0 || value > PDF_EVIDENCE_COORDINATE_BASIS) || bounds.right <= bounds.left || bounds.bottom <= bounds.top) throw new Error('The evidence region bounds are invalid.');
|
|
1120
|
+
}
|
|
1121
|
+
function positionEvidenceRegions(page, runtime, _revision) {
|
|
1122
|
+
const documentId = runtime.documentManager.getActiveDocumentId();
|
|
1123
|
+
const documentPage = runtime.documentManager.getActiveDocument()?.pages[page.pageNumber - 1];
|
|
1124
|
+
if (!documentId || !documentPage) return [];
|
|
1125
|
+
const scroll = runtime.scroll.forDocument(documentId);
|
|
1126
|
+
const viewport = runtime.viewport.forDocument(documentId);
|
|
1127
|
+
const metrics = viewport.getMetrics();
|
|
1128
|
+
const viewportGap = runtime.viewport.getViewportGap();
|
|
1129
|
+
const zoom = runtime.zoom?.forDocument(documentId).getState().currentZoomLevel ?? 1;
|
|
1130
|
+
const contentWidth = scroll.getLayout().totalContentSize.width;
|
|
1131
|
+
const horizontalCenterOffset = pdfEvidenceHorizontalCenterOffset(metrics.clientWidth, viewportGap, contentWidth, zoom);
|
|
1132
|
+
const width = documentPage.rotation % 2 ? documentPage.size.height : documentPage.size.width;
|
|
1133
|
+
const height = documentPage.rotation % 2 ? documentPage.size.width : documentPage.size.height;
|
|
1134
|
+
return page.regions.flatMap((region)=>{
|
|
1135
|
+
const rect = pdfEvidenceBoundsToPageRect(region.bounds, width, height);
|
|
1136
|
+
const positioned = scroll.getRectPositionForPage(page.pageNumber - 1, rect, void 0, 0);
|
|
1137
|
+
if (!positioned) return [];
|
|
1138
|
+
return [
|
|
1139
|
+
{
|
|
1140
|
+
region,
|
|
1141
|
+
style: {
|
|
1142
|
+
height: positioned.size.height,
|
|
1143
|
+
left: positioned.origin.x + viewportGap - metrics.scrollLeft + horizontalCenterOffset + metrics.clientLeft,
|
|
1144
|
+
top: positioned.origin.y + viewportGap - metrics.scrollTop + metrics.clientTop,
|
|
1145
|
+
width: positioned.size.width
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
];
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
function scrollEvidenceRegionIntoView(runtime, page, region) {
|
|
1152
|
+
const documentId = runtime.documentManager.getActiveDocumentId();
|
|
1153
|
+
const documentPage = runtime.documentManager.getActiveDocument()?.pages[page.pageNumber - 1];
|
|
1154
|
+
if (!documentId || !documentPage) return;
|
|
1155
|
+
const width = documentPage.rotation % 2 ? documentPage.size.height : documentPage.size.width;
|
|
1156
|
+
const height = documentPage.rotation % 2 ? documentPage.size.width : documentPage.size.height;
|
|
1157
|
+
const rect = pdfEvidenceBoundsToPageRect(region.bounds, width, height);
|
|
1158
|
+
const rotatedCenter = {
|
|
1159
|
+
x: rect.origin.x + rect.size.width / 2,
|
|
1160
|
+
y: rect.origin.y + rect.size.height / 2
|
|
1161
|
+
};
|
|
1162
|
+
const pageCoordinates = pdfEvidencePointToUnrotatedPage(rotatedCenter, documentPage.size.width, documentPage.size.height, documentPage.rotation);
|
|
1163
|
+
runtime.scroll.forDocument(documentId).scrollToPage({
|
|
1164
|
+
alignX: 50,
|
|
1165
|
+
alignY: 32,
|
|
1166
|
+
behavior: 'auto',
|
|
1167
|
+
pageCoordinates,
|
|
1168
|
+
pageNumber: page.pageNumber
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
function scrollToEvidencePage(runtime, pageNumber) {
|
|
1172
|
+
const documentId = runtime.documentManager.getActiveDocumentId();
|
|
1173
|
+
if (!documentId || !Number.isInteger(pageNumber) || pageNumber < 1) return;
|
|
1174
|
+
const scroll = runtime.scroll.forDocument(documentId);
|
|
1175
|
+
if (pageNumber > scroll.getTotalPages()) return;
|
|
1176
|
+
scroll.scrollToPage({
|
|
1177
|
+
behavior: 'auto',
|
|
1178
|
+
pageNumber
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
function pdfEvidenceBoundsToPageRect(bounds, width, height) {
|
|
1182
|
+
return {
|
|
1183
|
+
origin: {
|
|
1184
|
+
x: bounds.left / PDF_EVIDENCE_COORDINATE_BASIS * width,
|
|
1185
|
+
y: bounds.top / PDF_EVIDENCE_COORDINATE_BASIS * height
|
|
1186
|
+
},
|
|
1187
|
+
size: {
|
|
1188
|
+
height: (bounds.bottom - bounds.top) / PDF_EVIDENCE_COORDINATE_BASIS * height,
|
|
1189
|
+
width: (bounds.right - bounds.left) / PDF_EVIDENCE_COORDINATE_BASIS * width
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
function pdfEvidencePointToUnrotatedPage(point, pageWidth, pageHeight, rotation) {
|
|
1194
|
+
switch(rotation){
|
|
1195
|
+
case 1:
|
|
1196
|
+
return {
|
|
1197
|
+
x: point.y,
|
|
1198
|
+
y: pageHeight - point.x
|
|
1199
|
+
};
|
|
1200
|
+
case 2:
|
|
1201
|
+
return {
|
|
1202
|
+
x: pageWidth - point.x,
|
|
1203
|
+
y: pageHeight - point.y
|
|
1204
|
+
};
|
|
1205
|
+
case 3:
|
|
1206
|
+
return {
|
|
1207
|
+
x: pageWidth - point.y,
|
|
1208
|
+
y: point.x
|
|
1209
|
+
};
|
|
1210
|
+
default:
|
|
1211
|
+
return point;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
function pdfEvidenceHorizontalCenterOffset(viewportClientWidth, viewportGap, contentWidth, zoom) {
|
|
1215
|
+
const availableWidth = viewportClientWidth - 2 * viewportGap;
|
|
1216
|
+
const renderedContentWidth = contentWidth * zoom;
|
|
1217
|
+
return Math.max(0, (availableWidth - renderedContentWidth) / 2);
|
|
1218
|
+
}
|
|
1219
|
+
function boundedId(value) {
|
|
1220
|
+
return value.length > 0 && value.length <= MAX_ID_LENGTH;
|
|
1221
|
+
}
|
|
1222
|
+
function positiveFinite(value) {
|
|
1223
|
+
return Number.isFinite(value) && value > 0;
|
|
1224
|
+
}
|
|
1225
|
+
function isSha256(value) {
|
|
1226
|
+
return /^[a-f0-9]{64}$/.test(value);
|
|
1227
|
+
}
|
|
1228
|
+
function evidenceErrorMessage(error) {
|
|
1229
|
+
return error instanceof Error && error.message ? error.message : 'Unable to load PDF evidence.';
|
|
1230
|
+
}
|
|
409
1231
|
const PDF_THUMBNAIL_ITEM_HEIGHT = 190;
|
|
410
1232
|
const PDF_THUMBNAIL_WINDOW_THRESHOLD = 48;
|
|
411
1233
|
const PDF_THUMBNAIL_OVERSCAN = 5;
|
|
@@ -701,7 +1523,8 @@ const pdfKeyboardShortcuts = {
|
|
|
701
1523
|
zoomIn: 'Control+= Meta+= Control+Shift++ Meta+Shift++',
|
|
702
1524
|
zoomOut: 'Control+- Meta+-'
|
|
703
1525
|
};
|
|
704
|
-
function PdfToolbar({ annotationState, can, commands, editable, pageNavigation, saveLabel, saveState, searchInputRef, state }) {
|
|
1526
|
+
function PdfToolbar({ annotationState, can, commands, editable, pageNavigation, saveAvailable, saveLabel, saveState, searchInputRef, state }) {
|
|
1527
|
+
const showSave = saveAvailable ?? editable;
|
|
705
1528
|
const [pageValue, setPageValue] = useState('');
|
|
706
1529
|
const [searchValue, setSearchValue] = useState('');
|
|
707
1530
|
const cancelPageBlurCommitRef = useRef(false);
|
|
@@ -736,7 +1559,7 @@ function PdfToolbar({ annotationState, can, commands, editable, pageNavigation,
|
|
|
736
1559
|
role: "toolbar",
|
|
737
1560
|
"aria-label": "PDF 工具栏",
|
|
738
1561
|
children: [
|
|
739
|
-
|
|
1562
|
+
showSave && /*#__PURE__*/ jsxs("div", {
|
|
740
1563
|
className: "work-pdf-toolbar-group work-pdf-save",
|
|
741
1564
|
children: [
|
|
742
1565
|
/*#__PURE__*/ jsxs("output", {
|
|
@@ -1106,6 +1929,9 @@ function PdfToolbar({ annotationState, can, commands, editable, pageNavigation,
|
|
|
1106
1929
|
children: "页宽"
|
|
1107
1930
|
})
|
|
1108
1931
|
]
|
|
1932
|
+
}),
|
|
1933
|
+
/*#__PURE__*/ jsx(WorkOfficeCollaborationParticipants, {
|
|
1934
|
+
variant: "toolbar"
|
|
1109
1935
|
})
|
|
1110
1936
|
]
|
|
1111
1937
|
});
|
|
@@ -1534,6 +2360,7 @@ function searchStatus(state) {
|
|
|
1534
2360
|
if (0 === search.total) return '0 / 0';
|
|
1535
2361
|
return `${search.activeResultIndex + 1} / ${search.total}`;
|
|
1536
2362
|
}
|
|
2363
|
+
const PDF_PAGE_NAVIGATION_RETRY_MS = 500;
|
|
1537
2364
|
const EMPTY_FEATURES = {
|
|
1538
2365
|
export: false,
|
|
1539
2366
|
history: false,
|
|
@@ -1562,15 +2389,20 @@ const initialPdfViewerControllerState = {
|
|
|
1562
2389
|
zoomMode: null,
|
|
1563
2390
|
zoomPercent: 100
|
|
1564
2391
|
};
|
|
1565
|
-
function usePdfViewerController(registry) {
|
|
2392
|
+
function usePdfViewerController(registry, historyOverride) {
|
|
1566
2393
|
const capabilitiesRef = useRef(null);
|
|
1567
|
-
const pendingPageRef = useRef(
|
|
2394
|
+
const pendingPageRef = useRef({
|
|
2395
|
+
page: null,
|
|
2396
|
+
retryTimer: null
|
|
2397
|
+
});
|
|
1568
2398
|
const [state, setState] = useState(initialPdfViewerControllerState);
|
|
2399
|
+
const historyOverrideRef = useRef(historyOverride);
|
|
2400
|
+
historyOverrideRef.current = historyOverride;
|
|
1569
2401
|
useEffect(()=>{
|
|
1570
2402
|
let disposed = false;
|
|
1571
2403
|
const unsubscribe = [];
|
|
1572
2404
|
capabilitiesRef.current = null;
|
|
1573
|
-
pendingPageRef
|
|
2405
|
+
clearPendingPdfPageNavigation(pendingPageRef);
|
|
1574
2406
|
setState(initialPdfViewerControllerState);
|
|
1575
2407
|
if (!registry) return;
|
|
1576
2408
|
registry.pluginsReady().then(()=>{
|
|
@@ -1581,7 +2413,7 @@ function usePdfViewerController(registry) {
|
|
|
1581
2413
|
if (!disposed) setState(readControllerState(capabilities));
|
|
1582
2414
|
};
|
|
1583
2415
|
const syncDocument = ()=>{
|
|
1584
|
-
pendingPageRef
|
|
2416
|
+
clearPendingPdfPageNavigation(pendingPageRef);
|
|
1585
2417
|
sync();
|
|
1586
2418
|
};
|
|
1587
2419
|
pdf_viewer_controller_subscribe(unsubscribe, capabilities.documentManager?.onActiveDocumentChanged, syncDocument);
|
|
@@ -1591,7 +2423,7 @@ function usePdfViewerController(registry) {
|
|
|
1591
2423
|
pdf_viewer_controller_subscribe(unsubscribe, capabilities.scroll?.onLayoutReady, sync);
|
|
1592
2424
|
const stopPageChangeState = pdf_viewer_controller_safely(()=>capabilities.scroll?.onPageChangeState((event)=>{
|
|
1593
2425
|
if (disposed || event.state.isChanging) return;
|
|
1594
|
-
const pendingPage = pendingPageRef.current;
|
|
2426
|
+
const pendingPage = pendingPageRef.current.page;
|
|
1595
2427
|
if (null === pendingPage) return;
|
|
1596
2428
|
withActiveDocument(capabilities, ({ scroll }, documentId)=>{
|
|
1597
2429
|
if (event.documentId !== documentId) return;
|
|
@@ -1614,7 +2446,7 @@ function usePdfViewerController(registry) {
|
|
|
1614
2446
|
return ()=>{
|
|
1615
2447
|
disposed = true;
|
|
1616
2448
|
capabilitiesRef.current = null;
|
|
1617
|
-
pendingPageRef
|
|
2449
|
+
clearPendingPdfPageNavigation(pendingPageRef);
|
|
1618
2450
|
for (const stop of unsubscribe)stop();
|
|
1619
2451
|
};
|
|
1620
2452
|
}, [
|
|
@@ -1708,11 +2540,15 @@ function usePdfViewerController(registry) {
|
|
|
1708
2540
|
});
|
|
1709
2541
|
}, []);
|
|
1710
2542
|
const undo = useCallback(()=>{
|
|
2543
|
+
const collaborationHistory = historyOverrideRef.current;
|
|
2544
|
+
if (collaborationHistory) return void collaborationHistory.undo();
|
|
1711
2545
|
withActiveDocument(capabilitiesRef.current, ({ history }, documentId)=>{
|
|
1712
2546
|
history?.forDocument(documentId).undo();
|
|
1713
2547
|
});
|
|
1714
2548
|
}, []);
|
|
1715
2549
|
const redo = useCallback(()=>{
|
|
2550
|
+
const collaborationHistory = historyOverrideRef.current;
|
|
2551
|
+
if (collaborationHistory) return void collaborationHistory.redo();
|
|
1716
2552
|
withActiveDocument(capabilitiesRef.current, ({ history }, documentId)=>{
|
|
1717
2553
|
history?.forDocument(documentId).redo();
|
|
1718
2554
|
});
|
|
@@ -1728,8 +2564,20 @@ function usePdfViewerController(registry) {
|
|
|
1728
2564
|
type: 'application/pdf'
|
|
1729
2565
|
});
|
|
1730
2566
|
}, []);
|
|
2567
|
+
const projectedState = useMemo(()=>historyOverride ? {
|
|
2568
|
+
...state,
|
|
2569
|
+
canRedo: historyOverride.canRedo,
|
|
2570
|
+
canUndo: historyOverride.canUndo,
|
|
2571
|
+
features: {
|
|
2572
|
+
...state.features,
|
|
2573
|
+
history: true
|
|
2574
|
+
}
|
|
2575
|
+
} : state, [
|
|
2576
|
+
historyOverride,
|
|
2577
|
+
state
|
|
2578
|
+
]);
|
|
1731
2579
|
return useMemo(()=>({
|
|
1732
|
-
state,
|
|
2580
|
+
state: projectedState,
|
|
1733
2581
|
clearSearch,
|
|
1734
2582
|
fitPage,
|
|
1735
2583
|
fitWidth,
|
|
@@ -1745,7 +2593,7 @@ function usePdfViewerController(registry) {
|
|
|
1745
2593
|
zoomIn,
|
|
1746
2594
|
zoomOut
|
|
1747
2595
|
}), [
|
|
1748
|
-
|
|
2596
|
+
projectedState,
|
|
1749
2597
|
clearSearch,
|
|
1750
2598
|
fitPage,
|
|
1751
2599
|
fitWidth,
|
|
@@ -1821,21 +2669,31 @@ function withActiveDocument(capabilities, action) {
|
|
|
1821
2669
|
if (!capabilities || !documentId) return;
|
|
1822
2670
|
pdf_viewer_controller_safely(()=>action(capabilities, documentId));
|
|
1823
2671
|
}
|
|
1824
|
-
function requestPdfPageNavigation(scope, page, pendingPage) {
|
|
2672
|
+
function requestPdfPageNavigation(scope, page, pendingPage, force = false) {
|
|
1825
2673
|
const totalPages = scope.getTotalPages();
|
|
1826
2674
|
if (totalPages < 1 || !Number.isFinite(page)) return;
|
|
1827
2675
|
const nextPage = Math.min(totalPages, Math.max(1, Math.round(page)));
|
|
1828
2676
|
const pageChangeInProgress = pdf_viewer_controller_safely(()=>scope.getPageChangeState().isChanging) ?? false;
|
|
1829
|
-
if (pageChangeInProgress) {
|
|
1830
|
-
pendingPage.current = nextPage;
|
|
2677
|
+
if (pageChangeInProgress && !force) {
|
|
2678
|
+
pendingPage.current.page = nextPage;
|
|
2679
|
+
pendingPage.current.retryTimer ??= setTimeout(()=>{
|
|
2680
|
+
const queuedPage = pendingPage.current.page;
|
|
2681
|
+
if (null === queuedPage) return;
|
|
2682
|
+
requestPdfPageNavigation(scope, queuedPage, pendingPage, true);
|
|
2683
|
+
}, PDF_PAGE_NAVIGATION_RETRY_MS);
|
|
1831
2684
|
return;
|
|
1832
2685
|
}
|
|
1833
|
-
pendingPage
|
|
2686
|
+
clearPendingPdfPageNavigation(pendingPage);
|
|
1834
2687
|
scope.scrollToPage({
|
|
1835
2688
|
pageNumber: nextPage,
|
|
1836
|
-
behavior: 'auto'
|
|
2689
|
+
behavior: force ? 'instant' : 'auto'
|
|
1837
2690
|
});
|
|
1838
2691
|
}
|
|
2692
|
+
function clearPendingPdfPageNavigation(pendingPage) {
|
|
2693
|
+
if (null !== pendingPage.current.retryTimer) clearTimeout(pendingPage.current.retryTimer);
|
|
2694
|
+
pendingPage.current.page = null;
|
|
2695
|
+
pendingPage.current.retryTimer = null;
|
|
2696
|
+
}
|
|
1839
2697
|
function pdf_viewer_controller_subscribe(unsubscribe, event, listener) {
|
|
1840
2698
|
if (!event) return;
|
|
1841
2699
|
const stop = pdf_viewer_controller_safely(()=>event(()=>listener()));
|
|
@@ -1864,23 +2722,34 @@ const a3sPdfUiSchema = {
|
|
|
1864
2722
|
overlays: {},
|
|
1865
2723
|
selectionMenus: {}
|
|
1866
2724
|
};
|
|
1867
|
-
function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel = '保存', sourceKey, wasmUrl }) {
|
|
2725
|
+
function PdfViewer({ collaboration, evidenceOverlay, fileName = 'document.pdf', loadSource, onCollaborationChange, onEvidenceRegionSelect, onPageChange, onSave, saveLabel = '保存', selectedEvidenceRegionId, sourceKey, wasmUrl, worker = true }) {
|
|
1868
2726
|
const [sourceUrl, setSourceUrl] = useState(null);
|
|
1869
2727
|
const [loadError, setLoadError] = useState(null);
|
|
1870
2728
|
const [saveState, setSaveState] = useState('idle');
|
|
1871
2729
|
const [retryCount, setRetryCount] = useState(0);
|
|
1872
2730
|
const [registry, setRegistry] = useState(null);
|
|
2731
|
+
const [, refreshCollaborationHistory] = useState(0);
|
|
1873
2732
|
const [mobilePageNavigationOpen, setMobilePageNavigationOpen] = useState(false);
|
|
1874
2733
|
const pdfRootRef = useRef(null);
|
|
1875
2734
|
const searchInputRef = useRef(null);
|
|
1876
2735
|
const mobilePageNavigationId = useId();
|
|
1877
2736
|
const mobilePageNavigationToggleRef = useRef(null);
|
|
1878
2737
|
const mobilePageNavigationCloseRef = useRef(null);
|
|
1879
|
-
const
|
|
2738
|
+
const collaborationProjectionRef = useRef(void 0);
|
|
2739
|
+
const collaborationHistory = collaboration ? {
|
|
2740
|
+
canRedo: collaborationProjectionRef.current?.binding.canRedo() ?? false,
|
|
2741
|
+
canUndo: collaborationProjectionRef.current?.binding.canUndo() ?? false,
|
|
2742
|
+
redo: ()=>collaborationProjectionRef.current?.binding.redo(),
|
|
2743
|
+
undo: ()=>collaborationProjectionRef.current?.binding.undo()
|
|
2744
|
+
} : void 0;
|
|
2745
|
+
const controller = usePdfViewerController(registry, collaborationHistory);
|
|
1880
2746
|
const annotation = usePdfAnnotationController(registry);
|
|
1881
2747
|
const viewerReady = controller.state.ready && controller.state.documentOpen;
|
|
1882
2748
|
const mobilePageNavigationModal = usePdfMobilePageNavigationModal();
|
|
1883
2749
|
const mobilePageNavigationModalOpen = mobilePageNavigationOpen && mobilePageNavigationModal;
|
|
2750
|
+
const editable = collaboration ? 'edit' === collaboration.mode : Boolean(onSave);
|
|
2751
|
+
const collaborationRef = useRef(collaboration);
|
|
2752
|
+
if (collaborationRef.current !== collaboration) throw new Error('PdfViewer collaboration sessions cannot be replaced while mounted. Remount the viewer for another shared PDF.');
|
|
1884
2753
|
const closeMobilePageNavigation = useCallback(()=>{
|
|
1885
2754
|
setMobilePageNavigationOpen(false);
|
|
1886
2755
|
}, []);
|
|
@@ -1902,7 +2771,9 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
1902
2771
|
setSourceUrl(null);
|
|
1903
2772
|
setLoadError(null);
|
|
1904
2773
|
setMobilePageNavigationOpen(false);
|
|
1905
|
-
loadSource().then((source)=>{
|
|
2774
|
+
loadSource().then(async (source)=>{
|
|
2775
|
+
if (disposed) return;
|
|
2776
|
+
if (collaboration) await assertPdfCollaborationBlob(collaboration, source);
|
|
1906
2777
|
if (disposed) return;
|
|
1907
2778
|
objectUrl = URL.createObjectURL('application/pdf' === source.type ? source : new Blob([
|
|
1908
2779
|
source
|
|
@@ -1918,6 +2789,7 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
1918
2789
|
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
1919
2790
|
};
|
|
1920
2791
|
}, [
|
|
2792
|
+
collaboration,
|
|
1921
2793
|
loadSource,
|
|
1922
2794
|
retryCount,
|
|
1923
2795
|
sourceKey
|
|
@@ -1927,6 +2799,69 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
1927
2799
|
}, [
|
|
1928
2800
|
controller.state.error
|
|
1929
2801
|
]);
|
|
2802
|
+
useEffect(()=>{
|
|
2803
|
+
if (!collaboration || !viewerReady) return;
|
|
2804
|
+
if (controller.state.totalPages < 1) return;
|
|
2805
|
+
const expectedPages = readWorkPdfSourcePageCount(collaboration);
|
|
2806
|
+
if (controller.state.totalPages !== expectedPages) {
|
|
2807
|
+
setRegistry(null);
|
|
2808
|
+
setLoadError(`The loaded PDF has ${controller.state.totalPages} pages, but collaboration artifact '${collaboration.artifactId}' requires ${expectedPages}.`);
|
|
2809
|
+
}
|
|
2810
|
+
}, [
|
|
2811
|
+
collaboration,
|
|
2812
|
+
controller.state.totalPages,
|
|
2813
|
+
viewerReady
|
|
2814
|
+
]);
|
|
2815
|
+
useEffect(()=>{
|
|
2816
|
+
if (!registry || !collaboration || !viewerReady) return;
|
|
2817
|
+
if (controller.state.totalPages < 1) return;
|
|
2818
|
+
const expectedPages = readWorkPdfSourcePageCount(collaboration);
|
|
2819
|
+
if (controller.state.totalPages !== expectedPages) return;
|
|
2820
|
+
const projection = createWorkPdfCollaborationProjection(registry, collaboration);
|
|
2821
|
+
collaborationProjectionRef.current = projection;
|
|
2822
|
+
const handleProjectionError = (error)=>{
|
|
2823
|
+
if (collaborationProjectionRef.current !== projection) return;
|
|
2824
|
+
collaborationProjectionRef.current = void 0;
|
|
2825
|
+
setRegistry(null);
|
|
2826
|
+
setLoadError(pdfErrorMessage(error));
|
|
2827
|
+
};
|
|
2828
|
+
const unsubscribeError = projection.subscribeError(handleProjectionError);
|
|
2829
|
+
projection.ready.catch(handleProjectionError);
|
|
2830
|
+
const unsubscribeHistory = projection.binding.subscribeHistory(()=>refreshCollaborationHistory((value)=>value + 1));
|
|
2831
|
+
refreshCollaborationHistory((value)=>value + 1);
|
|
2832
|
+
return ()=>{
|
|
2833
|
+
unsubscribeError();
|
|
2834
|
+
unsubscribeHistory();
|
|
2835
|
+
if (collaborationProjectionRef.current === projection) collaborationProjectionRef.current = void 0;
|
|
2836
|
+
projection.destroy();
|
|
2837
|
+
};
|
|
2838
|
+
}, [
|
|
2839
|
+
collaboration,
|
|
2840
|
+
controller.state.totalPages,
|
|
2841
|
+
registry,
|
|
2842
|
+
viewerReady
|
|
2843
|
+
]);
|
|
2844
|
+
useEffect(()=>{
|
|
2845
|
+
if (!collaboration || !onCollaborationChange) return;
|
|
2846
|
+
const handleUpdate = ()=>{
|
|
2847
|
+
const projection = collaborationProjectionRef.current;
|
|
2848
|
+
if (!projection) return;
|
|
2849
|
+
queueMicrotask(()=>{
|
|
2850
|
+
if (collaborationProjectionRef.current === projection) onCollaborationChange(projection.binding.content());
|
|
2851
|
+
});
|
|
2852
|
+
};
|
|
2853
|
+
collaboration.document.on('update', handleUpdate);
|
|
2854
|
+
return ()=>collaboration.document.off('update', handleUpdate);
|
|
2855
|
+
}, [
|
|
2856
|
+
collaboration,
|
|
2857
|
+
onCollaborationChange
|
|
2858
|
+
]);
|
|
2859
|
+
useEffect(()=>{
|
|
2860
|
+
if (controller.state.currentPage > 0) onPageChange?.(controller.state.currentPage);
|
|
2861
|
+
}, [
|
|
2862
|
+
controller.state.currentPage,
|
|
2863
|
+
onPageChange
|
|
2864
|
+
]);
|
|
1930
2865
|
useEffect(()=>{
|
|
1931
2866
|
if (!sourceUrl || viewerReady || loadError) return;
|
|
1932
2867
|
const timeout = window.setTimeout(()=>{
|
|
@@ -1956,7 +2891,7 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
1956
2891
|
const pdfExtensions = useMemo(createPdfEditorExtensions, []);
|
|
1957
2892
|
const pdfEditor = useOfficeEditorRuntime({
|
|
1958
2893
|
annotation,
|
|
1959
|
-
editable
|
|
2894
|
+
editable,
|
|
1960
2895
|
focusSearch: ()=>{
|
|
1961
2896
|
searchInputRef.current?.focus();
|
|
1962
2897
|
searchInputRef.current?.select();
|
|
@@ -1968,6 +2903,33 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
1968
2903
|
viewer: controller
|
|
1969
2904
|
}, pdfExtensions);
|
|
1970
2905
|
const pdfCommands = pdfEditor.commands;
|
|
2906
|
+
const selectedAnnotationLocation = annotation.getSelectionLocation();
|
|
2907
|
+
const pdfPresenceLocation = viewerReady && controller.state.currentPage > 0 ? {
|
|
2908
|
+
kind: 'pdf',
|
|
2909
|
+
pageIndex: selectedAnnotationLocation?.pageIndex ?? controller.state.currentPage - 1,
|
|
2910
|
+
...selectedAnnotationLocation ? {
|
|
2911
|
+
annotationId: selectedAnnotationLocation.annotationId
|
|
2912
|
+
} : {}
|
|
2913
|
+
} : null;
|
|
2914
|
+
useOfficePublishPresenceLocation(pdfPresenceLocation);
|
|
2915
|
+
const navigateToPdfParticipant = useCallback((participant)=>{
|
|
2916
|
+
const location = participant.location;
|
|
2917
|
+
if (location?.kind !== 'pdf' || !viewerReady || location.pageIndex >= controller.state.totalPages) return false;
|
|
2918
|
+
controller.goToPage(location.pageIndex + 1);
|
|
2919
|
+
if (location.annotationId) annotation.locateAnnotation(location.pageIndex, location.annotationId);
|
|
2920
|
+
requestAnimationFrame(()=>{
|
|
2921
|
+
const target = pdfRootRef.current?.querySelector('.work-pdf-embed');
|
|
2922
|
+
target?.focus({
|
|
2923
|
+
preventScroll: true
|
|
2924
|
+
});
|
|
2925
|
+
});
|
|
2926
|
+
return true;
|
|
2927
|
+
}, [
|
|
2928
|
+
annotation,
|
|
2929
|
+
controller,
|
|
2930
|
+
viewerReady
|
|
2931
|
+
]);
|
|
2932
|
+
useOfficeCollaborationLocationNavigator(navigateToPdfParticipant);
|
|
1971
2933
|
useOfficeEditorKeyboardShortcuts(pdfEditor, {
|
|
1972
2934
|
capture: true,
|
|
1973
2935
|
enabled: Boolean(sourceUrl),
|
|
@@ -2012,7 +2974,8 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
2012
2974
|
annotationState: annotation.state,
|
|
2013
2975
|
can: pdfEditor.can(),
|
|
2014
2976
|
commands: pdfCommands,
|
|
2015
|
-
editable:
|
|
2977
|
+
editable: editable,
|
|
2978
|
+
saveAvailable: editable && Boolean(onSave),
|
|
2016
2979
|
pageNavigation: viewerReady && registry && controller.state.totalPages > 0 ? {
|
|
2017
2980
|
controlsId: mobilePageNavigationId,
|
|
2018
2981
|
expanded: mobilePageNavigationOpen,
|
|
@@ -2050,8 +3013,11 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
2050
3013
|
}),
|
|
2051
3014
|
/*#__PURE__*/ jsxs("div", {
|
|
2052
3015
|
className: "work-pdf-embed",
|
|
3016
|
+
role: "application",
|
|
3017
|
+
"aria-label": "PDF 页面画布",
|
|
2053
3018
|
"aria-busy": !viewerReady,
|
|
2054
3019
|
"data-ready": viewerReady || void 0,
|
|
3020
|
+
tabIndex: 0,
|
|
2055
3021
|
children: [
|
|
2056
3022
|
/*#__PURE__*/ jsx(PDFViewer, {
|
|
2057
3023
|
className: "work-pdf-native-viewer",
|
|
@@ -2061,6 +3027,7 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
2061
3027
|
},
|
|
2062
3028
|
config: {
|
|
2063
3029
|
src: sourceUrl,
|
|
3030
|
+
worker,
|
|
2064
3031
|
wasmUrl: wasmUrl ?? new URL(PDFIUM_WASM_PATH, window.location.href).href,
|
|
2065
3032
|
tabBar: 'never',
|
|
2066
3033
|
theme: {
|
|
@@ -2102,7 +3069,7 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
2102
3069
|
ui: null,
|
|
2103
3070
|
signature: null
|
|
2104
3071
|
},
|
|
2105
|
-
disabledCategories:
|
|
3072
|
+
disabledCategories: editable ? void 0 : [
|
|
2106
3073
|
'annotation',
|
|
2107
3074
|
'redaction',
|
|
2108
3075
|
'form',
|
|
@@ -2111,6 +3078,17 @@ function PdfViewer({ fileName = 'document.pdf', loadSource, onSave, saveLabel =
|
|
|
2111
3078
|
},
|
|
2112
3079
|
onReady: setRegistry
|
|
2113
3080
|
}, sourceUrl),
|
|
3081
|
+
viewerReady && controller.state.currentPage > 0 && /*#__PURE__*/ jsx(PdfCollaborationPresenceLayer, {
|
|
3082
|
+
pageIndex: controller.state.currentPage - 1
|
|
3083
|
+
}),
|
|
3084
|
+
evidenceOverlay && registry && viewerReady && /*#__PURE__*/ jsx(PdfEvidenceOverlayLayer, {
|
|
3085
|
+
currentPage: controller.state.currentPage,
|
|
3086
|
+
evidenceOverlay: evidenceOverlay,
|
|
3087
|
+
onEvidenceRegionSelect: onEvidenceRegionSelect,
|
|
3088
|
+
registry: registry,
|
|
3089
|
+
selectedEvidenceRegionId: selectedEvidenceRegionId,
|
|
3090
|
+
sourceKey: sourceKey
|
|
3091
|
+
}),
|
|
2114
3092
|
!viewerReady && /*#__PURE__*/ jsxs("div", {
|
|
2115
3093
|
className: "work-pdf-loading",
|
|
2116
3094
|
role: "status",
|
|
@@ -2133,6 +3111,20 @@ function pdfErrorMessage(error) {
|
|
|
2133
3111
|
if (error instanceof Error && error.message) return error.message;
|
|
2134
3112
|
return 'Unable to read this PDF file.';
|
|
2135
3113
|
}
|
|
3114
|
+
async function assertPdfCollaborationBlob(session, source) {
|
|
3115
|
+
const expected = readWorkOfficePdfCollaborationSource(session);
|
|
3116
|
+
if (source.size !== expected.byteLength) throw new Error(`The loaded PDF source does not match collaboration artifact '${session.artifactId}'.`);
|
|
3117
|
+
const subtle = globalThis.crypto?.subtle;
|
|
3118
|
+
if (!subtle) throw new Error('SHA-256 PDF source verification is unavailable.');
|
|
3119
|
+
const digest = new Uint8Array(await subtle.digest('SHA-256', await source.arrayBuffer()));
|
|
3120
|
+
assertWorkOfficePdfCollaborationSource(session, {
|
|
3121
|
+
...expected,
|
|
3122
|
+
sha256: Array.from(digest, (value)=>value.toString(16).padStart(2, '0')).join('')
|
|
3123
|
+
});
|
|
3124
|
+
}
|
|
3125
|
+
function readWorkPdfSourcePageCount(session) {
|
|
3126
|
+
return readWorkOfficePdfCollaborationSource(session).pageCount;
|
|
3127
|
+
}
|
|
2136
3128
|
function usePdfMobilePageNavigationModal() {
|
|
2137
3129
|
const [matches, setMatches] = useState(()=>pdfMediaQueryMatches(PDF_MOBILE_PAGE_NAVIGATION_QUERY));
|
|
2138
3130
|
useEffect(()=>{
|