kviewer 0.0.1
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/README.md +134 -0
- package/dist/module.d.mts +15 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +26 -0
- package/dist/runtime/annotation/engine/config.d.ts +52 -0
- package/dist/runtime/annotation/engine/config.js +283 -0
- package/dist/runtime/annotation/engine/const.d.ts +6 -0
- package/dist/runtime/annotation/engine/const.js +7 -0
- package/dist/runtime/annotation/engine/cursor-preview.d.ts +2 -0
- package/dist/runtime/annotation/engine/cursor-preview.js +88 -0
- package/dist/runtime/annotation/engine/editor/editor.d.ts +69 -0
- package/dist/runtime/annotation/engine/editor/editor.js +233 -0
- package/dist/runtime/annotation/engine/editor/selector.d.ts +74 -0
- package/dist/runtime/annotation/engine/editor/selector.js +594 -0
- package/dist/runtime/annotation/engine/import-normalize.d.ts +5 -0
- package/dist/runtime/annotation/engine/import-normalize.js +99 -0
- package/dist/runtime/annotation/engine/input-device.d.ts +53 -0
- package/dist/runtime/annotation/engine/input-device.js +64 -0
- package/dist/runtime/annotation/engine/painter.d.ts +97 -0
- package/dist/runtime/annotation/engine/painter.js +591 -0
- package/dist/runtime/annotation/engine/store.d.ts +11 -0
- package/dist/runtime/annotation/engine/store.js +47 -0
- package/dist/runtime/annotation/engine/tools/arrow.d.ts +22 -0
- package/dist/runtime/annotation/engine/tools/arrow.js +126 -0
- package/dist/runtime/annotation/engine/tools/circle.d.ts +45 -0
- package/dist/runtime/annotation/engine/tools/circle.js +148 -0
- package/dist/runtime/annotation/engine/tools/cloud.d.ts +50 -0
- package/dist/runtime/annotation/engine/tools/cloud.js +244 -0
- package/dist/runtime/annotation/engine/tools/free-highlight.d.ts +43 -0
- package/dist/runtime/annotation/engine/tools/free-highlight.js +165 -0
- package/dist/runtime/annotation/engine/tools/free-text.d.ts +27 -0
- package/dist/runtime/annotation/engine/tools/free-text.js +114 -0
- package/dist/runtime/annotation/engine/tools/freehand.d.ts +44 -0
- package/dist/runtime/annotation/engine/tools/freehand.js +151 -0
- package/dist/runtime/annotation/engine/tools/highlight.d.ts +87 -0
- package/dist/runtime/annotation/engine/tools/highlight.js +215 -0
- package/dist/runtime/annotation/engine/tools/note.d.ts +9 -0
- package/dist/runtime/annotation/engine/tools/note.js +34 -0
- package/dist/runtime/annotation/engine/tools/rectangle.d.ts +45 -0
- package/dist/runtime/annotation/engine/tools/rectangle.js +142 -0
- package/dist/runtime/annotation/engine/tools/signature.d.ts +16 -0
- package/dist/runtime/annotation/engine/tools/signature.js +74 -0
- package/dist/runtime/annotation/engine/tools/stamp.d.ts +18 -0
- package/dist/runtime/annotation/engine/tools/stamp.js +94 -0
- package/dist/runtime/annotation/engine/types.d.ts +170 -0
- package/dist/runtime/annotation/engine/types.js +67 -0
- package/dist/runtime/annotation/engine/utils.d.ts +40 -0
- package/dist/runtime/annotation/engine/utils.js +257 -0
- package/dist/runtime/annotation/parsers/parseFormFields.d.ts +9 -0
- package/dist/runtime/annotation/parsers/parseFormFields.js +101 -0
- package/dist/runtime/annotation/pdf-export/download.d.ts +1 -0
- package/dist/runtime/annotation/pdf-export/download.js +10 -0
- package/dist/runtime/annotation/pdf-export/export-form-fields.d.ts +9 -0
- package/dist/runtime/annotation/pdf-export/export-form-fields.js +90 -0
- package/dist/runtime/annotation/pdf-export/export.d.ts +15 -0
- package/dist/runtime/annotation/pdf-export/export.js +145 -0
- package/dist/runtime/annotation/pdf-export/parse.d.ts +10 -0
- package/dist/runtime/annotation/pdf-export/parse.js +19 -0
- package/dist/runtime/annotation/pdf-export/parse_circle.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_circle.js +41 -0
- package/dist/runtime/annotation/pdf-export/parse_freetext.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_freetext.js +54 -0
- package/dist/runtime/annotation/pdf-export/parse_highlight.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_highlight.js +134 -0
- package/dist/runtime/annotation/pdf-export/parse_ink.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_ink.js +124 -0
- package/dist/runtime/annotation/pdf-export/parse_line.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_line.js +71 -0
- package/dist/runtime/annotation/pdf-export/parse_polyline.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_polyline.js +93 -0
- package/dist/runtime/annotation/pdf-export/parse_square.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_square.js +41 -0
- package/dist/runtime/annotation/pdf-export/parse_stamp.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_stamp.js +195 -0
- package/dist/runtime/annotation/pdf-export/parse_strikeout.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_strikeout.js +59 -0
- package/dist/runtime/annotation/pdf-export/parse_text.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_text.js +42 -0
- package/dist/runtime/annotation/pdf-export/parse_underline.d.ts +4 -0
- package/dist/runtime/annotation/pdf-export/parse_underline.js +59 -0
- package/dist/runtime/assets/kviewer.css +1 -0
- package/dist/runtime/components/AnnotationToolbar.d.vue.ts +3 -0
- package/dist/runtime/components/AnnotationToolbar.vue +125 -0
- package/dist/runtime/components/AnnotationToolbar.vue.d.ts +3 -0
- package/dist/runtime/components/FloatingPageIndicator.d.vue.ts +6 -0
- package/dist/runtime/components/FloatingPageIndicator.vue +93 -0
- package/dist/runtime/components/FloatingPageIndicator.vue.d.ts +6 -0
- package/dist/runtime/components/FormFieldLayer.d.vue.ts +11 -0
- package/dist/runtime/components/FormFieldLayer.vue +40 -0
- package/dist/runtime/components/FormFieldLayer.vue.d.ts +11 -0
- package/dist/runtime/components/PdfPage.d.vue.ts +9 -0
- package/dist/runtime/components/PdfPage.vue +199 -0
- package/dist/runtime/components/PdfPage.vue.d.ts +9 -0
- package/dist/runtime/components/ToolButton.d.vue.ts +13 -0
- package/dist/runtime/components/ToolButton.vue +26 -0
- package/dist/runtime/components/ToolButton.vue.d.ts +13 -0
- package/dist/runtime/components/Toolbar.d.vue.ts +3 -0
- package/dist/runtime/components/Toolbar.vue +11 -0
- package/dist/runtime/components/Toolbar.vue.d.ts +3 -0
- package/dist/runtime/components/Viewer.d.vue.ts +45 -0
- package/dist/runtime/components/Viewer.vue +617 -0
- package/dist/runtime/components/Viewer.vue.d.ts +45 -0
- package/dist/runtime/components/ViewerBar.d.vue.ts +3 -0
- package/dist/runtime/components/ViewerBar.vue +91 -0
- package/dist/runtime/components/ViewerBar.vue.d.ts +3 -0
- package/dist/runtime/components/ViewerTabs.d.vue.ts +381 -0
- package/dist/runtime/components/ViewerTabs.vue +171 -0
- package/dist/runtime/components/ViewerTabs.vue.d.ts +381 -0
- package/dist/runtime/components/form-fields/FormButton.d.vue.ts +7 -0
- package/dist/runtime/components/form-fields/FormButton.vue +39 -0
- package/dist/runtime/components/form-fields/FormButton.vue.d.ts +7 -0
- package/dist/runtime/components/form-fields/FormCheckbox.d.vue.ts +7 -0
- package/dist/runtime/components/form-fields/FormCheckbox.vue +28 -0
- package/dist/runtime/components/form-fields/FormCheckbox.vue.d.ts +7 -0
- package/dist/runtime/components/form-fields/FormDropdown.d.vue.ts +7 -0
- package/dist/runtime/components/form-fields/FormDropdown.vue +112 -0
- package/dist/runtime/components/form-fields/FormDropdown.vue.d.ts +7 -0
- package/dist/runtime/components/form-fields/FormFieldWrapper.d.vue.ts +8 -0
- package/dist/runtime/components/form-fields/FormFieldWrapper.vue +41 -0
- package/dist/runtime/components/form-fields/FormFieldWrapper.vue.d.ts +8 -0
- package/dist/runtime/components/form-fields/FormRadioButton.d.vue.ts +7 -0
- package/dist/runtime/components/form-fields/FormRadioButton.vue +30 -0
- package/dist/runtime/components/form-fields/FormRadioButton.vue.d.ts +7 -0
- package/dist/runtime/components/form-fields/FormSignatureField.d.vue.ts +7 -0
- package/dist/runtime/components/form-fields/FormSignatureField.vue +54 -0
- package/dist/runtime/components/form-fields/FormSignatureField.vue.d.ts +7 -0
- package/dist/runtime/components/form-fields/FormTextField.d.vue.ts +7 -0
- package/dist/runtime/components/form-fields/FormTextField.vue +66 -0
- package/dist/runtime/components/form-fields/FormTextField.vue.d.ts +7 -0
- package/dist/runtime/components/modals/FreeTextModal.d.vue.ts +25 -0
- package/dist/runtime/components/modals/FreeTextModal.vue +89 -0
- package/dist/runtime/components/modals/FreeTextModal.vue.d.ts +25 -0
- package/dist/runtime/components/modals/SignatureDrawModal.d.vue.ts +14 -0
- package/dist/runtime/components/modals/SignatureDrawModal.vue +120 -0
- package/dist/runtime/components/modals/SignatureDrawModal.vue.d.ts +14 -0
- package/dist/runtime/components/panels/SignaturePicker.d.vue.ts +3 -0
- package/dist/runtime/components/panels/SignaturePicker.vue +85 -0
- package/dist/runtime/components/panels/SignaturePicker.vue.d.ts +3 -0
- package/dist/runtime/components/panels/StampPicker.d.vue.ts +3 -0
- package/dist/runtime/components/panels/StampPicker.vue +46 -0
- package/dist/runtime/components/panels/StampPicker.vue.d.ts +3 -0
- package/dist/runtime/components/tools/ActionTools.d.vue.ts +3 -0
- package/dist/runtime/components/tools/ActionTools.vue +32 -0
- package/dist/runtime/components/tools/ActionTools.vue.d.ts +3 -0
- package/dist/runtime/components/tools/DrawingTools.d.vue.ts +6 -0
- package/dist/runtime/components/tools/DrawingTools.vue +57 -0
- package/dist/runtime/components/tools/DrawingTools.vue.d.ts +6 -0
- package/dist/runtime/components/tools/HandTool.d.vue.ts +3 -0
- package/dist/runtime/components/tools/HandTool.vue +14 -0
- package/dist/runtime/components/tools/HandTool.vue.d.ts +3 -0
- package/dist/runtime/components/tools/MarqueeTool.d.vue.ts +3 -0
- package/dist/runtime/components/tools/MarqueeTool.vue +15 -0
- package/dist/runtime/components/tools/MarqueeTool.vue.d.ts +3 -0
- package/dist/runtime/components/tools/PageInfo.d.vue.ts +3 -0
- package/dist/runtime/components/tools/PageInfo.vue +10 -0
- package/dist/runtime/components/tools/PageInfo.vue.d.ts +3 -0
- package/dist/runtime/components/tools/PageSettings.d.vue.ts +3 -0
- package/dist/runtime/components/tools/PageSettings.vue +92 -0
- package/dist/runtime/components/tools/PageSettings.vue.d.ts +3 -0
- package/dist/runtime/components/tools/SearchTool.d.vue.ts +3 -0
- package/dist/runtime/components/tools/SearchTool.vue +149 -0
- package/dist/runtime/components/tools/SearchTool.vue.d.ts +3 -0
- package/dist/runtime/components/tools/ToolProperties.d.vue.ts +7 -0
- package/dist/runtime/components/tools/ToolProperties.vue +174 -0
- package/dist/runtime/components/tools/ToolProperties.vue.d.ts +7 -0
- package/dist/runtime/components/tools/ZoomControls.d.vue.ts +3 -0
- package/dist/runtime/components/tools/ZoomControls.vue +59 -0
- package/dist/runtime/components/tools/ZoomControls.vue.d.ts +3 -0
- package/dist/runtime/composables/search-utils.d.ts +20 -0
- package/dist/runtime/composables/search-utils.js +55 -0
- package/dist/runtime/composables/useAnnotationEngine.d.ts +7 -0
- package/dist/runtime/composables/useAnnotationEngine.js +70 -0
- package/dist/runtime/composables/useAnnotationHistory.d.ts +12 -0
- package/dist/runtime/composables/useAnnotationHistory.js +69 -0
- package/dist/runtime/composables/useFormFields.d.ts +26 -0
- package/dist/runtime/composables/useFormFields.js +112 -0
- package/dist/runtime/composables/usePageProxyCache.d.ts +8 -0
- package/dist/runtime/composables/usePageProxyCache.js +73 -0
- package/dist/runtime/composables/usePageSettings.d.ts +16 -0
- package/dist/runtime/composables/usePageSettings.js +66 -0
- package/dist/runtime/composables/usePageVirtualization.d.ts +19 -0
- package/dist/runtime/composables/usePageVirtualization.js +203 -0
- package/dist/runtime/composables/useSearchIndex.d.ts +11 -0
- package/dist/runtime/composables/useSearchIndex.js +71 -0
- package/dist/runtime/composables/useViewerSearch.d.ts +32 -0
- package/dist/runtime/composables/useViewerSearch.js +418 -0
- package/dist/runtime/composables/useViewerState.d.ts +62 -0
- package/dist/runtime/composables/useViewerState.js +189 -0
- package/dist/runtime/composables/viewMode.d.ts +11 -0
- package/dist/runtime/composables/viewMode.js +19 -0
- package/dist/runtime/plugin.d.ts +2 -0
- package/dist/runtime/plugin.js +3 -0
- package/dist/runtime/public-types.d.ts +2 -0
- package/dist/runtime/public-types.js +0 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/types.d.mts +5 -0
- package/package.json +64 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import {
|
|
2
|
+
inject,
|
|
3
|
+
provide,
|
|
4
|
+
ref
|
|
5
|
+
} from "vue";
|
|
6
|
+
import {
|
|
7
|
+
findMatchesInText,
|
|
8
|
+
flattenMatchesByPage,
|
|
9
|
+
getRenderRange,
|
|
10
|
+
stepMatchIndex
|
|
11
|
+
} from "./search-utils.js";
|
|
12
|
+
const VIEWER_SEARCH_KEY = Symbol("kviewer-search");
|
|
13
|
+
export function provideViewerSearch() {
|
|
14
|
+
const isOpen = ref(false);
|
|
15
|
+
const query = ref("");
|
|
16
|
+
const matchCase = ref(false);
|
|
17
|
+
const wholeWord = ref(false);
|
|
18
|
+
const highlightAll = ref(true);
|
|
19
|
+
const currentMatch = ref(0);
|
|
20
|
+
const totalMatches = ref(0);
|
|
21
|
+
const notFound = ref(false);
|
|
22
|
+
const pageLayers = /* @__PURE__ */ new Map();
|
|
23
|
+
const matchesByPage = /* @__PURE__ */ new Map();
|
|
24
|
+
let flattenedMatches = [];
|
|
25
|
+
let selectedGlobalIndex = -1;
|
|
26
|
+
let inputElement = null;
|
|
27
|
+
let _searchIndex = null;
|
|
28
|
+
let _scrollToPage = null;
|
|
29
|
+
function setSearchIndex(index) {
|
|
30
|
+
_searchIndex = index;
|
|
31
|
+
}
|
|
32
|
+
function setScrollToPage(fn) {
|
|
33
|
+
_scrollToPage = fn;
|
|
34
|
+
}
|
|
35
|
+
function getSortedPageNumbers() {
|
|
36
|
+
return [...pageLayers.keys()].sort((a, b) => a - b);
|
|
37
|
+
}
|
|
38
|
+
function ensureDivElement(binding, divIdx) {
|
|
39
|
+
const current = binding.textDivs[divIdx];
|
|
40
|
+
if (!current) return null;
|
|
41
|
+
if (typeof Node !== "undefined" && current.nodeType === Node.TEXT_NODE) {
|
|
42
|
+
const span = document.createElement("span");
|
|
43
|
+
const parent = current.parentNode;
|
|
44
|
+
if (!parent) return null;
|
|
45
|
+
parent.replaceChild(span, current);
|
|
46
|
+
binding.textDivs[divIdx] = span;
|
|
47
|
+
return span;
|
|
48
|
+
}
|
|
49
|
+
return current;
|
|
50
|
+
}
|
|
51
|
+
function clearPageHighlights(binding) {
|
|
52
|
+
for (let i = 0; i < binding.textDivs.length; i++) {
|
|
53
|
+
const div = ensureDivElement(binding, i);
|
|
54
|
+
if (!div) continue;
|
|
55
|
+
div.textContent = binding.sourceTextByDiv[i] ?? "";
|
|
56
|
+
div.className = "";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function convertPageMatches(pageMatches, sourceTextByDiv) {
|
|
60
|
+
if (pageMatches.length === 0 || sourceTextByDiv.length === 0) return [];
|
|
61
|
+
let i = 0;
|
|
62
|
+
let iIndex = 0;
|
|
63
|
+
const end = sourceTextByDiv.length - 1;
|
|
64
|
+
const converted = [];
|
|
65
|
+
for (const pageMatch of pageMatches) {
|
|
66
|
+
let matchIdx = pageMatch.index;
|
|
67
|
+
while (i !== end && matchIdx >= iIndex + sourceTextByDiv[i].length) {
|
|
68
|
+
iIndex += sourceTextByDiv[i].length;
|
|
69
|
+
i++;
|
|
70
|
+
}
|
|
71
|
+
const begin = {
|
|
72
|
+
divIdx: i,
|
|
73
|
+
offset: matchIdx - iIndex
|
|
74
|
+
};
|
|
75
|
+
matchIdx += pageMatch.length;
|
|
76
|
+
while (i !== end && matchIdx > iIndex + sourceTextByDiv[i].length) {
|
|
77
|
+
iIndex += sourceTextByDiv[i].length;
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
const endMatch = {
|
|
81
|
+
divIdx: i,
|
|
82
|
+
offset: matchIdx - iIndex
|
|
83
|
+
};
|
|
84
|
+
converted.push({ begin, end: endMatch });
|
|
85
|
+
}
|
|
86
|
+
return converted;
|
|
87
|
+
}
|
|
88
|
+
function appendTextToDiv(binding, divIdx, fromOffset, toOffset, className) {
|
|
89
|
+
const div = ensureDivElement(binding, divIdx);
|
|
90
|
+
if (!div) return null;
|
|
91
|
+
const sourceText = binding.sourceTextByDiv[divIdx] ?? "";
|
|
92
|
+
const content = toOffset === void 0 ? sourceText.slice(fromOffset) : sourceText.slice(fromOffset, toOffset);
|
|
93
|
+
const node = document.createTextNode(content);
|
|
94
|
+
if (!className) {
|
|
95
|
+
div.append(node);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const span = document.createElement("span");
|
|
99
|
+
span.className = `${className} appended`;
|
|
100
|
+
span.append(node);
|
|
101
|
+
div.append(span);
|
|
102
|
+
return className.includes("selected") ? span : null;
|
|
103
|
+
}
|
|
104
|
+
function beginText(binding, begin, className) {
|
|
105
|
+
const div = ensureDivElement(binding, begin.divIdx);
|
|
106
|
+
if (!div) return null;
|
|
107
|
+
div.textContent = "";
|
|
108
|
+
return appendTextToDiv(binding, begin.divIdx, 0, begin.offset, className);
|
|
109
|
+
}
|
|
110
|
+
function getSelectedLocation() {
|
|
111
|
+
if (selectedGlobalIndex < 0 || selectedGlobalIndex >= flattenedMatches.length) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const selected = flattenedMatches[selectedGlobalIndex];
|
|
115
|
+
if (!selected) return null;
|
|
116
|
+
return {
|
|
117
|
+
pageNumber: selected.pageNumber,
|
|
118
|
+
matchIndex: selected.matchIndex
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function renderHighlightsForPage(pageNumber, shouldScrollSelected) {
|
|
122
|
+
const binding = pageLayers.get(pageNumber);
|
|
123
|
+
if (!binding) return;
|
|
124
|
+
clearPageHighlights(binding);
|
|
125
|
+
if (!isOpen.value) return;
|
|
126
|
+
const pageMatches = matchesByPage.get(pageNumber) ?? [];
|
|
127
|
+
if (pageMatches.length === 0) return;
|
|
128
|
+
const selectedLocation = getSelectedLocation();
|
|
129
|
+
const isSelectedPage = selectedLocation?.pageNumber === pageNumber;
|
|
130
|
+
const selectedMatchIndex = isSelectedPage ? selectedLocation?.matchIndex ?? -1 : -1;
|
|
131
|
+
const range = getRenderRange(
|
|
132
|
+
pageMatches.length,
|
|
133
|
+
highlightAll.value,
|
|
134
|
+
isSelectedPage,
|
|
135
|
+
selectedMatchIndex
|
|
136
|
+
);
|
|
137
|
+
if (!range) return;
|
|
138
|
+
const convertedMatches = convertPageMatches(pageMatches, binding.sourceTextByDiv);
|
|
139
|
+
if (convertedMatches.length === 0) return;
|
|
140
|
+
let prevEnd = null;
|
|
141
|
+
let lastDivIdx = -1;
|
|
142
|
+
let lastOffset = -1;
|
|
143
|
+
for (let i = range.start; i < range.end; i++) {
|
|
144
|
+
const match = convertedMatches[i];
|
|
145
|
+
if (!match) continue;
|
|
146
|
+
const begin = match.begin;
|
|
147
|
+
if (begin.divIdx === lastDivIdx && begin.offset === lastOffset) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
lastDivIdx = begin.divIdx;
|
|
151
|
+
lastOffset = begin.offset;
|
|
152
|
+
const end = match.end;
|
|
153
|
+
const isSelected = isSelectedPage && i === selectedMatchIndex;
|
|
154
|
+
const highlightSuffix = isSelected ? " selected" : "";
|
|
155
|
+
let selectedSpan = null;
|
|
156
|
+
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
|
|
157
|
+
if (prevEnd) {
|
|
158
|
+
appendTextToDiv(binding, prevEnd.divIdx, prevEnd.offset, void 0);
|
|
159
|
+
}
|
|
160
|
+
beginText(binding, begin);
|
|
161
|
+
} else {
|
|
162
|
+
appendTextToDiv(binding, prevEnd.divIdx, prevEnd.offset, begin.offset);
|
|
163
|
+
}
|
|
164
|
+
if (begin.divIdx === end.divIdx) {
|
|
165
|
+
selectedSpan = appendTextToDiv(
|
|
166
|
+
binding,
|
|
167
|
+
begin.divIdx,
|
|
168
|
+
begin.offset,
|
|
169
|
+
end.offset,
|
|
170
|
+
`highlight${highlightSuffix}`
|
|
171
|
+
);
|
|
172
|
+
} else {
|
|
173
|
+
selectedSpan = appendTextToDiv(
|
|
174
|
+
binding,
|
|
175
|
+
begin.divIdx,
|
|
176
|
+
begin.offset,
|
|
177
|
+
void 0,
|
|
178
|
+
`highlight begin${highlightSuffix}`
|
|
179
|
+
);
|
|
180
|
+
for (let mid = begin.divIdx + 1; mid < end.divIdx; mid++) {
|
|
181
|
+
const middleDiv = ensureDivElement(binding, mid);
|
|
182
|
+
if (!middleDiv) continue;
|
|
183
|
+
middleDiv.className = `highlight middle${highlightSuffix}`;
|
|
184
|
+
}
|
|
185
|
+
beginText(binding, end, `highlight end${highlightSuffix}`);
|
|
186
|
+
}
|
|
187
|
+
prevEnd = end;
|
|
188
|
+
if (isSelected && shouldScrollSelected && selectedSpan) {
|
|
189
|
+
selectedSpan.scrollIntoView({
|
|
190
|
+
block: "start",
|
|
191
|
+
inline: "center"
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (prevEnd) {
|
|
196
|
+
appendTextToDiv(binding, prevEnd.divIdx, prevEnd.offset, void 0);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function renderAllHighlights(shouldScrollSelected = false) {
|
|
200
|
+
for (const pageNumber of getSortedPageNumbers()) {
|
|
201
|
+
renderHighlightsForPage(pageNumber, shouldScrollSelected);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function clearAllHighlights() {
|
|
205
|
+
for (const binding of pageLayers.values()) {
|
|
206
|
+
clearPageHighlights(binding);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function updateCounters() {
|
|
210
|
+
totalMatches.value = flattenedMatches.length;
|
|
211
|
+
currentMatch.value = selectedGlobalIndex >= 0 ? selectedGlobalIndex + 1 : 0;
|
|
212
|
+
notFound.value = query.value.length > 0 && totalMatches.value === 0;
|
|
213
|
+
}
|
|
214
|
+
function recomputeMatches({ preferFirst = false, shouldScrollSelected = false } = {}) {
|
|
215
|
+
const selectedLocation = getSelectedLocation();
|
|
216
|
+
matchesByPage.clear();
|
|
217
|
+
flattenedMatches = [];
|
|
218
|
+
if (!query.value) {
|
|
219
|
+
selectedGlobalIndex = -1;
|
|
220
|
+
updateCounters();
|
|
221
|
+
if (isOpen.value) {
|
|
222
|
+
clearAllHighlights();
|
|
223
|
+
}
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (_searchIndex) {
|
|
227
|
+
const allPageNumbers = [];
|
|
228
|
+
for (let i = 1; i <= _searchIndex.totalPages; i++) {
|
|
229
|
+
allPageNumbers.push(i);
|
|
230
|
+
}
|
|
231
|
+
for (const pageNumber of allPageNumbers) {
|
|
232
|
+
const text = _searchIndex.getPageText(pageNumber);
|
|
233
|
+
if (text === null) continue;
|
|
234
|
+
const pageMatches = findMatchesInText(text, query.value, {
|
|
235
|
+
matchCase: matchCase.value,
|
|
236
|
+
wholeWord: wholeWord.value
|
|
237
|
+
});
|
|
238
|
+
if (pageMatches.length > 0) {
|
|
239
|
+
matchesByPage.set(pageNumber, pageMatches);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
flattenedMatches = flattenMatchesByPage(allPageNumbers, matchesByPage);
|
|
243
|
+
} else {
|
|
244
|
+
const pageNumbers = getSortedPageNumbers();
|
|
245
|
+
for (const pageNumber of pageNumbers) {
|
|
246
|
+
const binding = pageLayers.get(pageNumber);
|
|
247
|
+
if (!binding) continue;
|
|
248
|
+
const pageMatches = findMatchesInText(binding.fullText, query.value, {
|
|
249
|
+
matchCase: matchCase.value,
|
|
250
|
+
wholeWord: wholeWord.value
|
|
251
|
+
});
|
|
252
|
+
matchesByPage.set(pageNumber, pageMatches);
|
|
253
|
+
}
|
|
254
|
+
flattenedMatches = flattenMatchesByPage(pageNumbers, matchesByPage);
|
|
255
|
+
}
|
|
256
|
+
if (flattenedMatches.length === 0) {
|
|
257
|
+
selectedGlobalIndex = -1;
|
|
258
|
+
} else if (preferFirst) {
|
|
259
|
+
selectedGlobalIndex = 0;
|
|
260
|
+
} else if (selectedLocation) {
|
|
261
|
+
const preservedIndex = flattenedMatches.findIndex(
|
|
262
|
+
(entry) => entry.pageNumber === selectedLocation.pageNumber && entry.matchIndex === selectedLocation.matchIndex
|
|
263
|
+
);
|
|
264
|
+
selectedGlobalIndex = preservedIndex >= 0 ? preservedIndex : 0;
|
|
265
|
+
} else {
|
|
266
|
+
selectedGlobalIndex = 0;
|
|
267
|
+
}
|
|
268
|
+
updateCounters();
|
|
269
|
+
if (isOpen.value) {
|
|
270
|
+
renderAllHighlights(shouldScrollSelected);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function setPageBinding(pageNumber, textDivs, textContentItemsStr) {
|
|
274
|
+
const sourceTextByDiv = textDivs.map((div, index) => div.textContent ?? textContentItemsStr[index] ?? "");
|
|
275
|
+
pageLayers.set(pageNumber, {
|
|
276
|
+
textDivs,
|
|
277
|
+
sourceTextByDiv,
|
|
278
|
+
fullText: sourceTextByDiv.join("")
|
|
279
|
+
});
|
|
280
|
+
if (query.value) {
|
|
281
|
+
recomputeMatches();
|
|
282
|
+
} else if (isOpen.value) {
|
|
283
|
+
renderHighlightsForPage(pageNumber, false);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function open() {
|
|
287
|
+
if (isOpen.value) return;
|
|
288
|
+
isOpen.value = true;
|
|
289
|
+
renderAllHighlights();
|
|
290
|
+
}
|
|
291
|
+
function close() {
|
|
292
|
+
if (!isOpen.value) return;
|
|
293
|
+
isOpen.value = false;
|
|
294
|
+
clearAllHighlights();
|
|
295
|
+
}
|
|
296
|
+
function reset() {
|
|
297
|
+
close();
|
|
298
|
+
query.value = "";
|
|
299
|
+
matchCase.value = false;
|
|
300
|
+
wholeWord.value = false;
|
|
301
|
+
highlightAll.value = true;
|
|
302
|
+
currentMatch.value = 0;
|
|
303
|
+
totalMatches.value = 0;
|
|
304
|
+
notFound.value = false;
|
|
305
|
+
matchesByPage.clear();
|
|
306
|
+
flattenedMatches = [];
|
|
307
|
+
selectedGlobalIndex = -1;
|
|
308
|
+
pageLayers.clear();
|
|
309
|
+
inputElement = null;
|
|
310
|
+
_searchIndex = null;
|
|
311
|
+
_scrollToPage = null;
|
|
312
|
+
}
|
|
313
|
+
function setQuery(value) {
|
|
314
|
+
query.value = value;
|
|
315
|
+
recomputeMatches({ preferFirst: true, shouldScrollSelected: true });
|
|
316
|
+
}
|
|
317
|
+
function toggleMatchCase() {
|
|
318
|
+
matchCase.value = !matchCase.value;
|
|
319
|
+
recomputeMatches();
|
|
320
|
+
}
|
|
321
|
+
function toggleWholeWord() {
|
|
322
|
+
wholeWord.value = !wholeWord.value;
|
|
323
|
+
recomputeMatches();
|
|
324
|
+
}
|
|
325
|
+
function toggleHighlightAll() {
|
|
326
|
+
highlightAll.value = !highlightAll.value;
|
|
327
|
+
if (isOpen.value) {
|
|
328
|
+
renderAllHighlights();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function scrollToSelectedMatch() {
|
|
332
|
+
if (!_scrollToPage) return;
|
|
333
|
+
const location = getSelectedLocation();
|
|
334
|
+
if (!location) return;
|
|
335
|
+
if (!pageLayers.has(location.pageNumber)) {
|
|
336
|
+
_scrollToPage(location.pageNumber);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function findNext() {
|
|
340
|
+
selectedGlobalIndex = stepMatchIndex(selectedGlobalIndex, flattenedMatches.length, false);
|
|
341
|
+
updateCounters();
|
|
342
|
+
scrollToSelectedMatch();
|
|
343
|
+
if (isOpen.value) {
|
|
344
|
+
renderAllHighlights(true);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function findPrevious() {
|
|
348
|
+
selectedGlobalIndex = stepMatchIndex(selectedGlobalIndex, flattenedMatches.length, true);
|
|
349
|
+
updateCounters();
|
|
350
|
+
scrollToSelectedMatch();
|
|
351
|
+
if (isOpen.value) {
|
|
352
|
+
renderAllHighlights(true);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function registerPageLayer(pageNumber, textDivs, textContentItemsStr) {
|
|
356
|
+
setPageBinding(pageNumber, textDivs, textContentItemsStr);
|
|
357
|
+
}
|
|
358
|
+
function updatePageLayer(pageNumber, textDivs, textContentItemsStr) {
|
|
359
|
+
setPageBinding(pageNumber, textDivs, textContentItemsStr);
|
|
360
|
+
}
|
|
361
|
+
function unregisterPageLayer(pageNumber) {
|
|
362
|
+
const binding = pageLayers.get(pageNumber);
|
|
363
|
+
if (binding) {
|
|
364
|
+
clearPageHighlights(binding);
|
|
365
|
+
}
|
|
366
|
+
pageLayers.delete(pageNumber);
|
|
367
|
+
matchesByPage.delete(pageNumber);
|
|
368
|
+
if (query.value) {
|
|
369
|
+
recomputeMatches();
|
|
370
|
+
} else {
|
|
371
|
+
flattenedMatches = [];
|
|
372
|
+
selectedGlobalIndex = -1;
|
|
373
|
+
updateCounters();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function setInputElement(input) {
|
|
377
|
+
inputElement = input;
|
|
378
|
+
}
|
|
379
|
+
function focusInput() {
|
|
380
|
+
inputElement?.focus();
|
|
381
|
+
inputElement?.select();
|
|
382
|
+
}
|
|
383
|
+
const state = {
|
|
384
|
+
isOpen,
|
|
385
|
+
query,
|
|
386
|
+
matchCase,
|
|
387
|
+
wholeWord,
|
|
388
|
+
highlightAll,
|
|
389
|
+
currentMatch,
|
|
390
|
+
totalMatches,
|
|
391
|
+
notFound,
|
|
392
|
+
open,
|
|
393
|
+
close,
|
|
394
|
+
reset,
|
|
395
|
+
setQuery,
|
|
396
|
+
toggleMatchCase,
|
|
397
|
+
toggleWholeWord,
|
|
398
|
+
toggleHighlightAll,
|
|
399
|
+
findNext,
|
|
400
|
+
findPrevious,
|
|
401
|
+
registerPageLayer,
|
|
402
|
+
updatePageLayer,
|
|
403
|
+
unregisterPageLayer,
|
|
404
|
+
setInputElement,
|
|
405
|
+
focusInput,
|
|
406
|
+
setSearchIndex,
|
|
407
|
+
setScrollToPage
|
|
408
|
+
};
|
|
409
|
+
provide(VIEWER_SEARCH_KEY, state);
|
|
410
|
+
return state;
|
|
411
|
+
}
|
|
412
|
+
export function useViewerSearch() {
|
|
413
|
+
const state = inject(VIEWER_SEARCH_KEY);
|
|
414
|
+
if (!state) {
|
|
415
|
+
throw new Error("useViewerSearch() must be used inside a <KViewer> component");
|
|
416
|
+
}
|
|
417
|
+
return state;
|
|
418
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type Ref, type ShallowRef } from 'vue';
|
|
2
|
+
import type { PDFDocumentProxy } from 'pdfjs-dist';
|
|
3
|
+
import type { Painter } from '../annotation/engine/painter.js';
|
|
4
|
+
import { AnnotationType, type IAnnotationStore, type StampDefinition, type SignatureData, type SignatureHandlers } from '../annotation/engine/types.js';
|
|
5
|
+
import { type AnnotationHistory } from './useAnnotationHistory.js';
|
|
6
|
+
import { type FitMode } from './viewMode.js';
|
|
7
|
+
export type { FitMode, ViewMode } from './viewMode.js';
|
|
8
|
+
export { mapViewModeToFitMode, normalizeZoom } from './viewMode.js';
|
|
9
|
+
export type ActiveTool = 'hand' | 'marquee' | 'eraser' | AnnotationType;
|
|
10
|
+
export interface ViewerState {
|
|
11
|
+
scale: Ref<number>;
|
|
12
|
+
scaleOptions: number[];
|
|
13
|
+
fitMode: Ref<FitMode>;
|
|
14
|
+
containerDimensions: Ref<{
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}>;
|
|
18
|
+
pageDimensions: Ref<{
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
} | null>;
|
|
22
|
+
setFitMode: (mode: FitMode) => void;
|
|
23
|
+
zoomIn: () => void;
|
|
24
|
+
zoomOut: () => void;
|
|
25
|
+
setScale: (value: number) => void;
|
|
26
|
+
currentPage: Ref<number>;
|
|
27
|
+
totalPages: Ref<number>;
|
|
28
|
+
isLoading: Ref<boolean>;
|
|
29
|
+
activeTool: Ref<ActiveTool>;
|
|
30
|
+
doc: ShallowRef<PDFDocumentProxy | null>;
|
|
31
|
+
annotations: ShallowRef<Map<string, IAnnotationStore>>;
|
|
32
|
+
selectedAnnotation: Ref<IAnnotationStore | null>;
|
|
33
|
+
selectedAnnotations: Ref<IAnnotationStore[]>;
|
|
34
|
+
selectionRect: Ref<{
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
} | null>;
|
|
40
|
+
painter: ShallowRef<Painter | null>;
|
|
41
|
+
stamps: Ref<StampDefinition[]>;
|
|
42
|
+
activeStamp: Ref<StampDefinition | null>;
|
|
43
|
+
signatures: Ref<SignatureData[]>;
|
|
44
|
+
activeSignature: Ref<SignatureData | null>;
|
|
45
|
+
signatureHandlers: SignatureHandlers | null;
|
|
46
|
+
loadSignatures: () => Promise<void>;
|
|
47
|
+
saveSignature: (imageUrl: string) => Promise<SignatureData | null>;
|
|
48
|
+
deleteSignature: (id: string) => Promise<void>;
|
|
49
|
+
selectTool: (tool: ActiveTool, dataTransfer?: string | null) => void;
|
|
50
|
+
deleteAnnotation: (id: string) => void;
|
|
51
|
+
getAnnotations: () => IAnnotationStore[];
|
|
52
|
+
stylusMode: Ref<boolean>;
|
|
53
|
+
setStylusMode: (enabled: boolean) => void;
|
|
54
|
+
scrollToPage: (pageNumber: number) => void;
|
|
55
|
+
history: AnnotationHistory;
|
|
56
|
+
}
|
|
57
|
+
export interface ViewerStateProvider {
|
|
58
|
+
state: ViewerState;
|
|
59
|
+
setScrollToPageFn: (fn: (pageNumber: number) => void) => void;
|
|
60
|
+
}
|
|
61
|
+
export declare function provideViewerState(): ViewerStateProvider;
|
|
62
|
+
export declare function useViewerState(): ViewerState;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ref,
|
|
3
|
+
shallowRef,
|
|
4
|
+
provide,
|
|
5
|
+
inject,
|
|
6
|
+
triggerRef,
|
|
7
|
+
watch
|
|
8
|
+
} from "vue";
|
|
9
|
+
import {
|
|
10
|
+
AnnotationType
|
|
11
|
+
} from "../annotation/engine/types.js";
|
|
12
|
+
import { annotationDefinitions } from "../annotation/engine/config.js";
|
|
13
|
+
import { createAnnotationHistory } from "./useAnnotationHistory.js";
|
|
14
|
+
import { computeScaleForFitMode } from "./viewMode.js";
|
|
15
|
+
export { mapViewModeToFitMode, normalizeZoom } from "./viewMode.js";
|
|
16
|
+
const VIEWER_STATE_KEY = Symbol("kviewer-state");
|
|
17
|
+
const SCALE_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2];
|
|
18
|
+
export function provideViewerState() {
|
|
19
|
+
const scale = ref(1);
|
|
20
|
+
const currentPage = ref(1);
|
|
21
|
+
const totalPages = ref(0);
|
|
22
|
+
const isLoading = ref(false);
|
|
23
|
+
const activeTool = ref("hand");
|
|
24
|
+
const doc = shallowRef(null);
|
|
25
|
+
const annotations = shallowRef(/* @__PURE__ */ new Map());
|
|
26
|
+
const selectedAnnotation = ref(null);
|
|
27
|
+
const selectedAnnotations = ref([]);
|
|
28
|
+
const selectionRect = ref(null);
|
|
29
|
+
const painter = shallowRef(null);
|
|
30
|
+
const fitMode = ref("fit-width");
|
|
31
|
+
const containerDimensions = ref({ width: 0, height: 0 });
|
|
32
|
+
const pageDimensions = ref(null);
|
|
33
|
+
watch(
|
|
34
|
+
[fitMode, containerDimensions, pageDimensions],
|
|
35
|
+
([mode, container, page]) => {
|
|
36
|
+
if (mode === "custom" || !page || !container.width || !container.height) return;
|
|
37
|
+
scale.value = computeScaleForFitMode(mode, container, page, scale.value);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
function setFitMode(mode) {
|
|
41
|
+
fitMode.value = mode;
|
|
42
|
+
}
|
|
43
|
+
function setScale(value) {
|
|
44
|
+
fitMode.value = "custom";
|
|
45
|
+
scale.value = value;
|
|
46
|
+
}
|
|
47
|
+
function zoomIn() {
|
|
48
|
+
const currentIndex = SCALE_OPTIONS.indexOf(scale.value);
|
|
49
|
+
if (currentIndex >= 0 && currentIndex < SCALE_OPTIONS.length - 1) {
|
|
50
|
+
setScale(SCALE_OPTIONS[currentIndex + 1]);
|
|
51
|
+
} else if (currentIndex === -1) {
|
|
52
|
+
const next = SCALE_OPTIONS.find((s) => s > scale.value);
|
|
53
|
+
if (next !== void 0) setScale(next);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function zoomOut() {
|
|
57
|
+
const currentIndex = SCALE_OPTIONS.indexOf(scale.value);
|
|
58
|
+
if (currentIndex > 0) {
|
|
59
|
+
setScale(SCALE_OPTIONS[currentIndex - 1]);
|
|
60
|
+
} else if (currentIndex === -1) {
|
|
61
|
+
const prev = [...SCALE_OPTIONS].reverse().find((s) => s < scale.value);
|
|
62
|
+
if (prev !== void 0) setScale(prev);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const stylusMode = ref(false);
|
|
66
|
+
function setStylusMode(enabled) {
|
|
67
|
+
stylusMode.value = enabled;
|
|
68
|
+
if (painter.value) {
|
|
69
|
+
painter.value.refreshStylusMode();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const stamps = ref([]);
|
|
73
|
+
const activeStamp = ref(null);
|
|
74
|
+
const signatures = ref([]);
|
|
75
|
+
const activeSignature = ref(null);
|
|
76
|
+
let _signatureHandlers = null;
|
|
77
|
+
async function loadSignatures() {
|
|
78
|
+
if (!_signatureHandlers) return;
|
|
79
|
+
signatures.value = await _signatureHandlers.onLoad();
|
|
80
|
+
}
|
|
81
|
+
async function saveSignature(imageUrl) {
|
|
82
|
+
if (!_signatureHandlers) return null;
|
|
83
|
+
const sig = await _signatureHandlers.onSave(imageUrl);
|
|
84
|
+
signatures.value = [...signatures.value, sig];
|
|
85
|
+
return sig;
|
|
86
|
+
}
|
|
87
|
+
async function deleteSignature(id) {
|
|
88
|
+
if (!_signatureHandlers) return;
|
|
89
|
+
await _signatureHandlers.onDelete(id);
|
|
90
|
+
signatures.value = signatures.value.filter((s) => s.id !== id);
|
|
91
|
+
if (activeSignature.value?.id === id) activeSignature.value = null;
|
|
92
|
+
}
|
|
93
|
+
function selectTool(tool, dataTransfer) {
|
|
94
|
+
activeTool.value = tool;
|
|
95
|
+
selectedAnnotation.value = null;
|
|
96
|
+
selectedAnnotations.value = [];
|
|
97
|
+
selectionRect.value = null;
|
|
98
|
+
if (!painter.value) return;
|
|
99
|
+
if (typeof tool === "number") {
|
|
100
|
+
const annotationDef = annotationDefinitions.find(
|
|
101
|
+
(d) => d.type === tool
|
|
102
|
+
);
|
|
103
|
+
painter.value.activate(annotationDef ?? null, dataTransfer ?? null);
|
|
104
|
+
} else if (tool === "marquee") {
|
|
105
|
+
painter.value.activateMarquee();
|
|
106
|
+
} else if (tool === "eraser") {
|
|
107
|
+
painter.value.activateEraser();
|
|
108
|
+
} else {
|
|
109
|
+
const selectDef = annotationDefinitions.find(
|
|
110
|
+
(d) => d.type === AnnotationType.SELECT
|
|
111
|
+
);
|
|
112
|
+
painter.value.activate(selectDef ?? null, null);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function deleteAnnotation(id) {
|
|
116
|
+
if (painter.value) {
|
|
117
|
+
painter.value.delete(id, true);
|
|
118
|
+
annotations.value.delete(id);
|
|
119
|
+
triggerRef(annotations);
|
|
120
|
+
selectedAnnotation.value = null;
|
|
121
|
+
selectionRect.value = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function getAnnotations() {
|
|
125
|
+
return painter.value?.getData() ?? [];
|
|
126
|
+
}
|
|
127
|
+
let _scrollToPageFn = null;
|
|
128
|
+
function scrollToPage(pageNumber) {
|
|
129
|
+
_scrollToPageFn?.(pageNumber);
|
|
130
|
+
}
|
|
131
|
+
const history = createAnnotationHistory(annotations, painter);
|
|
132
|
+
const state = {
|
|
133
|
+
scale,
|
|
134
|
+
scaleOptions: SCALE_OPTIONS,
|
|
135
|
+
fitMode,
|
|
136
|
+
containerDimensions,
|
|
137
|
+
pageDimensions,
|
|
138
|
+
setFitMode,
|
|
139
|
+
zoomIn,
|
|
140
|
+
zoomOut,
|
|
141
|
+
setScale,
|
|
142
|
+
currentPage,
|
|
143
|
+
totalPages,
|
|
144
|
+
isLoading,
|
|
145
|
+
activeTool,
|
|
146
|
+
doc,
|
|
147
|
+
annotations,
|
|
148
|
+
selectedAnnotation,
|
|
149
|
+
selectedAnnotations,
|
|
150
|
+
selectionRect,
|
|
151
|
+
painter,
|
|
152
|
+
stamps,
|
|
153
|
+
activeStamp,
|
|
154
|
+
signatures,
|
|
155
|
+
activeSignature,
|
|
156
|
+
get signatureHandlers() {
|
|
157
|
+
return _signatureHandlers;
|
|
158
|
+
},
|
|
159
|
+
set signatureHandlers(v) {
|
|
160
|
+
_signatureHandlers = v;
|
|
161
|
+
},
|
|
162
|
+
loadSignatures,
|
|
163
|
+
saveSignature,
|
|
164
|
+
deleteSignature,
|
|
165
|
+
selectTool,
|
|
166
|
+
deleteAnnotation,
|
|
167
|
+
getAnnotations,
|
|
168
|
+
stylusMode,
|
|
169
|
+
setStylusMode,
|
|
170
|
+
scrollToPage,
|
|
171
|
+
history
|
|
172
|
+
};
|
|
173
|
+
provide(VIEWER_STATE_KEY, state);
|
|
174
|
+
return {
|
|
175
|
+
state,
|
|
176
|
+
setScrollToPageFn(fn) {
|
|
177
|
+
_scrollToPageFn = fn;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
export function useViewerState() {
|
|
182
|
+
const state = inject(VIEWER_STATE_KEY);
|
|
183
|
+
if (!state) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
"useViewerState() must be used inside a <KViewer> component"
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return state;
|
|
189
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ViewMode = 'fit-width' | 'fit-page' | 'zoom';
|
|
2
|
+
export type FitMode = 'fit-width' | 'fit-page' | 'custom';
|
|
3
|
+
export declare function mapViewModeToFitMode(mode: ViewMode): FitMode;
|
|
4
|
+
export declare function normalizeZoom(zoom: number): number;
|
|
5
|
+
export declare function computeScaleForFitMode(mode: FitMode, container: {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}, page: {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
}, currentScale: number): number;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function mapViewModeToFitMode(mode) {
|
|
2
|
+
return mode === "zoom" ? "custom" : mode;
|
|
3
|
+
}
|
|
4
|
+
export function normalizeZoom(zoom) {
|
|
5
|
+
if (!Number.isFinite(zoom) || zoom <= 0) {
|
|
6
|
+
return 1;
|
|
7
|
+
}
|
|
8
|
+
return zoom;
|
|
9
|
+
}
|
|
10
|
+
export function computeScaleForFitMode(mode, container, page, currentScale) {
|
|
11
|
+
switch (mode) {
|
|
12
|
+
case "fit-width":
|
|
13
|
+
return container.width / page.width;
|
|
14
|
+
case "fit-page":
|
|
15
|
+
return Math.min(container.width / page.width, container.height / page.height);
|
|
16
|
+
default:
|
|
17
|
+
return currentScale;
|
|
18
|
+
}
|
|
19
|
+
}
|