@rhc-office/sdk 6.6.256
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 +176 -0
- package/dist/api/annotation-tool.d.ts +127 -0
- package/dist/api/annotation-tool.d.ts.map +1 -0
- package/dist/api/callbacks.d.ts +25 -0
- package/dist/api/callbacks.d.ts.map +1 -0
- package/dist/api/common.d.ts +83 -0
- package/dist/api/common.d.ts.map +1 -0
- package/dist/api/crypto-tool.d.ts +9 -0
- package/dist/api/crypto-tool.d.ts.map +1 -0
- package/dist/api/digital-sign-environment.d.ts +100 -0
- package/dist/api/digital-sign-environment.d.ts.map +1 -0
- package/dist/api/document-sdk.d.ts +111 -0
- package/dist/api/document-sdk.d.ts.map +1 -0
- package/dist/api/document-tool.d.ts +68 -0
- package/dist/api/document-tool.d.ts.map +1 -0
- package/dist/api/ekey-tool.d.ts +8 -0
- package/dist/api/ekey-tool.d.ts.map +1 -0
- package/dist/api/extension-tool.d.ts +5 -0
- package/dist/api/extension-tool.d.ts.map +1 -0
- package/dist/api/find-tool.d.ts +6 -0
- package/dist/api/find-tool.d.ts.map +1 -0
- package/dist/api/menu-visibility.d.ts +16 -0
- package/dist/api/menu-visibility.d.ts.map +1 -0
- package/dist/api/networking-tool.d.ts +7 -0
- package/dist/api/networking-tool.d.ts.map +1 -0
- package/dist/api/page-tool.d.ts +28 -0
- package/dist/api/page-tool.d.ts.map +1 -0
- package/dist/api/pdf-formfiller.d.ts +12 -0
- package/dist/api/pdf-formfiller.d.ts.map +1 -0
- package/dist/api/review-tool.d.ts +71 -0
- package/dist/api/review-tool.d.ts.map +1 -0
- package/dist/api/sign-server.d.ts +32 -0
- package/dist/api/sign-server.d.ts.map +1 -0
- package/dist/api/sign-tool.d.ts +31 -0
- package/dist/api/sign-tool.d.ts.map +1 -0
- package/dist/api/symbology-tool.d.ts +4 -0
- package/dist/api/symbology-tool.d.ts.map +1 -0
- package/dist/api/template-sign.d.ts +88 -0
- package/dist/api/template-sign.d.ts.map +1 -0
- package/dist/api/ui-tool.d.ts +35 -0
- package/dist/api/ui-tool.d.ts.map +1 -0
- package/dist/api/watermark.d.ts +25 -0
- package/dist/api/watermark.d.ts.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1061 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +2 -0
- package/dist/index.umd.cjs.map +1 -0
- package/dist/tools/DocumentToolImpl.d.ts +27 -0
- package/dist/tools/DocumentToolImpl.d.ts.map +1 -0
- package/dist/tools/FindToolImpl.d.ts +10 -0
- package/dist/tools/FindToolImpl.d.ts.map +1 -0
- package/dist/tools/NetworkingToolImpl.d.ts +10 -0
- package/dist/tools/NetworkingToolImpl.d.ts.map +1 -0
- package/dist/tools/PageToolImpl.d.ts +31 -0
- package/dist/tools/PageToolImpl.d.ts.map +1 -0
- package/dist/tools/PdfFormFillerImpl.d.ts +13 -0
- package/dist/tools/PdfFormFillerImpl.d.ts.map +1 -0
- package/dist/tools/Phase1ToolPlaceholder.d.ts +5 -0
- package/dist/tools/Phase1ToolPlaceholder.d.ts.map +1 -0
- package/dist/tools/SDKValueObjects.d.ts +55 -0
- package/dist/tools/SDKValueObjects.d.ts.map +1 -0
- package/dist/tools/UIToolImpl.d.ts +31 -0
- package/dist/tools/UIToolImpl.d.ts.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/viewer/AdapterProtocol.d.ts +78 -0
- package/dist/viewer/AdapterProtocol.d.ts.map +1 -0
- package/dist/viewer/BridgeToolAdapter.d.ts +23 -0
- package/dist/viewer/BridgeToolAdapter.d.ts.map +1 -0
- package/dist/viewer/DocumentSDK.d.ts +85 -0
- package/dist/viewer/DocumentSDK.d.ts.map +1 -0
- package/dist/viewer/ReaderBridgeClient.d.ts +31 -0
- package/dist/viewer/ReaderBridgeClient.d.ts.map +1 -0
- package/dist/viewer/ReaderConfiguration.d.ts +11 -0
- package/dist/viewer/ReaderConfiguration.d.ts.map +1 -0
- package/dist/viewer/ReaderScriptLoader.d.ts +10 -0
- package/dist/viewer/ReaderScriptLoader.d.ts.map +1 -0
- package/dist/viewer/ReaderStateStore.d.ts +21 -0
- package/dist/viewer/ReaderStateStore.d.ts.map +1 -0
- package/dist/viewer/SdkCallbackRegistry.d.ts +18 -0
- package/dist/viewer/SdkCallbackRegistry.d.ts.map +1 -0
- package/dist/viewer/index.d.ts +2 -0
- package/dist/viewer/index.d.ts.map +1 -0
- package/package.json +48 -0
- package/src/api/annotation-tool.ts +199 -0
- package/src/api/callbacks.ts +59 -0
- package/src/api/common.ts +117 -0
- package/src/api/crypto-tool.ts +10 -0
- package/src/api/digital-sign-environment.ts +411 -0
- package/src/api/document-sdk.ts +152 -0
- package/src/api/document-tool.ts +106 -0
- package/src/api/ekey-tool.ts +11 -0
- package/src/api/extension-tool.ts +5 -0
- package/src/api/find-tool.ts +7 -0
- package/src/api/menu-visibility.ts +17 -0
- package/src/api/networking-tool.ts +9 -0
- package/src/api/page-tool.ts +56 -0
- package/src/api/pdf-formfiller.ts +13 -0
- package/src/api/review-tool.ts +105 -0
- package/src/api/sign-server.ts +53 -0
- package/src/api/sign-tool.ts +50 -0
- package/src/api/symbology-tool.ts +11 -0
- package/src/api/template-sign.ts +102 -0
- package/src/api/ui-tool.ts +66 -0
- package/src/api/watermark.ts +35 -0
- package/src/index.ts +22 -0
- package/src/tools/DocumentToolImpl.ts +158 -0
- package/src/tools/FindToolImpl.ts +32 -0
- package/src/tools/NetworkingToolImpl.ts +36 -0
- package/src/tools/PageToolImpl.ts +181 -0
- package/src/tools/PdfFormFillerImpl.ts +67 -0
- package/src/tools/Phase1ToolPlaceholder.ts +35 -0
- package/src/tools/SDKValueObjects.ts +172 -0
- package/src/tools/UIToolImpl.ts +145 -0
- package/src/tools/index.ts +8 -0
- package/src/viewer/AdapterProtocol.ts +114 -0
- package/src/viewer/BridgeToolAdapter.ts +137 -0
- package/src/viewer/DocumentSDK.ts +688 -0
- package/src/viewer/ReaderBridgeClient.ts +216 -0
- package/src/viewer/ReaderConfiguration.ts +59 -0
- package/src/viewer/ReaderScriptLoader.ts +130 -0
- package/src/viewer/ReaderStateStore.ts +55 -0
- package/src/viewer/SdkCallbackRegistry.ts +89 -0
- package/src/viewer/index.ts +1 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RHC_OFFICE_ADAPTER_GLOBAL,
|
|
3
|
+
RHC_OFFICE_ADAPTER_PROTOCOL,
|
|
4
|
+
RHC_OFFICE_ADAPTER_READY_EVENT,
|
|
5
|
+
RHC_OFFICE_ADAPTER_VERSION,
|
|
6
|
+
type AdapterCapabilityManifest,
|
|
7
|
+
type AdapterGlobal,
|
|
8
|
+
type AdapterRequest,
|
|
9
|
+
type AdapterResponse,
|
|
10
|
+
type AdapterToolName,
|
|
11
|
+
} from './AdapterProtocol';
|
|
12
|
+
|
|
13
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 5000;
|
|
14
|
+
const DEFAULT_READY_TIMEOUT_MS = 5000;
|
|
15
|
+
|
|
16
|
+
type BrowserGlobal = typeof globalThis & {
|
|
17
|
+
[RHC_OFFICE_ADAPTER_GLOBAL]?: AdapterGlobal;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const createRequestId = (): string => {
|
|
21
|
+
const cryptoApi = globalThis.crypto;
|
|
22
|
+
if (typeof cryptoApi?.randomUUID === 'function') {
|
|
23
|
+
return cryptoApi.randomUUID();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return `adapter-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getAdapterGlobal = (): AdapterGlobal | undefined => {
|
|
30
|
+
return (globalThis as BrowserGlobal)[RHC_OFFICE_ADAPTER_GLOBAL];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export class ReaderBridgeError extends Error {
|
|
34
|
+
readonly code: string;
|
|
35
|
+
readonly details?: unknown;
|
|
36
|
+
|
|
37
|
+
constructor(code: string, message: string, details?: unknown) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = 'ReaderBridgeError';
|
|
40
|
+
this.code = code;
|
|
41
|
+
this.details = details;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class ReaderBridgeClient {
|
|
46
|
+
private readerId: string | null = null;
|
|
47
|
+
private readyTimeoutMs: number;
|
|
48
|
+
private requestTimeoutMs: number;
|
|
49
|
+
|
|
50
|
+
constructor(options?: { readyTimeoutMs?: number; requestTimeoutMs?: number }) {
|
|
51
|
+
this.readyTimeoutMs = options?.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
|
|
52
|
+
this.requestTimeoutMs = options?.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
configureTimeouts(options?: { readyTimeoutMs?: number; requestTimeoutMs?: number }): void {
|
|
56
|
+
this.readyTimeoutMs = options?.readyTimeoutMs ?? this.readyTimeoutMs;
|
|
57
|
+
this.requestTimeoutMs = options?.requestTimeoutMs ?? this.requestTimeoutMs;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
setReaderId(readerId: string | null): void {
|
|
61
|
+
this.readerId = readerId;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getReaderId(): string | null {
|
|
65
|
+
return this.readerId;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async request<TResult = unknown, TParams = unknown>(
|
|
69
|
+
tool: AdapterToolName,
|
|
70
|
+
method: string,
|
|
71
|
+
params?: TParams,
|
|
72
|
+
options?: {
|
|
73
|
+
timeoutMs?: number;
|
|
74
|
+
},
|
|
75
|
+
): Promise<TResult> {
|
|
76
|
+
const response = await this.requestRaw<TResult, TParams>(tool, method, params, options);
|
|
77
|
+
if (response.ok) {
|
|
78
|
+
return response.result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new ReaderBridgeError(
|
|
82
|
+
response.error.code,
|
|
83
|
+
response.error.message,
|
|
84
|
+
response.error.details,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async requestRaw<TResult = unknown, TParams = unknown>(
|
|
89
|
+
tool: AdapterToolName,
|
|
90
|
+
method: string,
|
|
91
|
+
params?: TParams,
|
|
92
|
+
options?: {
|
|
93
|
+
timeoutMs?: number;
|
|
94
|
+
},
|
|
95
|
+
): Promise<AdapterResponse<TResult>> {
|
|
96
|
+
if (!this.readerId) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
requestId: '',
|
|
100
|
+
error: {
|
|
101
|
+
code: 'READER_NOT_READY',
|
|
102
|
+
message: 'Reader is not mounted.',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const adapter = await this.waitForAdapter(this.readerId, options?.timeoutMs);
|
|
108
|
+
if (!adapter) {
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
requestId: '',
|
|
112
|
+
error: {
|
|
113
|
+
code: 'ADAPTER_UNAVAILABLE',
|
|
114
|
+
message: 'Editor adapter is not available.',
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const request: AdapterRequest<TParams> = {
|
|
120
|
+
protocol: RHC_OFFICE_ADAPTER_PROTOCOL,
|
|
121
|
+
version: RHC_OFFICE_ADAPTER_VERSION,
|
|
122
|
+
requestId: createRequestId(),
|
|
123
|
+
readerId: this.readerId,
|
|
124
|
+
tool,
|
|
125
|
+
method,
|
|
126
|
+
params,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return this.withTimeout(
|
|
130
|
+
adapter.request(request) as Promise<AdapterResponse<TResult>>,
|
|
131
|
+
request.requestId,
|
|
132
|
+
options?.timeoutMs ?? this.requestTimeoutMs,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
getCapabilities(): AdapterCapabilityManifest | null {
|
|
137
|
+
if (!this.readerId) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return getAdapterGlobal()?.getCapabilities(this.readerId) ?? null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private async waitForAdapter(
|
|
145
|
+
readerId: string,
|
|
146
|
+
timeoutMs = this.readyTimeoutMs,
|
|
147
|
+
): Promise<AdapterGlobal | null> {
|
|
148
|
+
const existingAdapter = getAdapterGlobal();
|
|
149
|
+
if (existingAdapter?.getCapabilities(readerId)) {
|
|
150
|
+
return existingAdapter;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return new Promise<AdapterGlobal | null>((resolve) => {
|
|
154
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
155
|
+
|
|
156
|
+
const cleanup = (): void => {
|
|
157
|
+
if (timeoutId) {
|
|
158
|
+
clearTimeout(timeoutId);
|
|
159
|
+
}
|
|
160
|
+
globalThis.removeEventListener(RHC_OFFICE_ADAPTER_READY_EVENT, onReady as EventListener);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const onReady = (event: Event): void => {
|
|
164
|
+
const detail = event instanceof CustomEvent ? event.detail : undefined;
|
|
165
|
+
if (detail?.readerId !== readerId) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const adapter = getAdapterGlobal();
|
|
170
|
+
cleanup();
|
|
171
|
+
resolve(adapter ?? null);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
globalThis.addEventListener(RHC_OFFICE_ADAPTER_READY_EVENT, onReady as EventListener);
|
|
175
|
+
timeoutId = setTimeout(() => {
|
|
176
|
+
cleanup();
|
|
177
|
+
resolve(getAdapterGlobal()?.getCapabilities(readerId) ? getAdapterGlobal()! : null);
|
|
178
|
+
}, timeoutMs);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private async withTimeout<TResult>(
|
|
183
|
+
promise: Promise<AdapterResponse<TResult>>,
|
|
184
|
+
requestId: string,
|
|
185
|
+
timeoutMs: number,
|
|
186
|
+
): Promise<AdapterResponse<TResult>> {
|
|
187
|
+
return new Promise<AdapterResponse<TResult>>((resolve) => {
|
|
188
|
+
const timeoutId = setTimeout(() => {
|
|
189
|
+
resolve({
|
|
190
|
+
ok: false,
|
|
191
|
+
requestId,
|
|
192
|
+
error: {
|
|
193
|
+
code: 'TIMEOUT',
|
|
194
|
+
message: `Editor adapter request timed out after ${timeoutMs}ms.`,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}, timeoutMs);
|
|
198
|
+
|
|
199
|
+
promise
|
|
200
|
+
.then((response) => resolve(response))
|
|
201
|
+
.catch((error: unknown) => {
|
|
202
|
+
resolve({
|
|
203
|
+
ok: false,
|
|
204
|
+
requestId,
|
|
205
|
+
error: {
|
|
206
|
+
code: 'EXECUTION_FAILED',
|
|
207
|
+
message: error instanceof Error ? error.message : String(error),
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
})
|
|
211
|
+
.finally(() => {
|
|
212
|
+
clearTimeout(timeoutId);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { IReaderEmbedOptions } from '../api/document-sdk';
|
|
2
|
+
|
|
3
|
+
export type SupportedReaderTheme = 'light' | 'dark' | 'high-contrast' | 'auto';
|
|
4
|
+
|
|
5
|
+
export interface NormalizedReaderEmbedOptions extends IReaderEmbedOptions {
|
|
6
|
+
officeServer: string;
|
|
7
|
+
scrollIntoView: boolean;
|
|
8
|
+
theme?: SupportedReaderTheme;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const normalizeTheme = (theme?: string): SupportedReaderTheme | undefined => {
|
|
12
|
+
if (!theme) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const normalizedTheme = theme.trim().toLowerCase();
|
|
17
|
+
if (normalizedTheme === 'application') {
|
|
18
|
+
return 'auto';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
normalizedTheme === 'light' ||
|
|
23
|
+
normalizedTheme === 'dark' ||
|
|
24
|
+
normalizedTheme === 'high-contrast' ||
|
|
25
|
+
normalizedTheme === 'auto'
|
|
26
|
+
) {
|
|
27
|
+
return normalizedTheme;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const normalizeAppUrl = (appUrl: string): string => {
|
|
34
|
+
const normalizedUrl = new URL(appUrl, globalThis.location?.href ?? 'http://localhost/');
|
|
35
|
+
normalizedUrl.hash = '';
|
|
36
|
+
if (!normalizedUrl.pathname.endsWith('/')) {
|
|
37
|
+
normalizedUrl.pathname = `${normalizedUrl.pathname}/`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return normalizedUrl.toString();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const createBootstrapUrl = (appUrl: string): string => {
|
|
44
|
+
return new URL('editors.bootstrap.js', appUrl).toString();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const normalizeReaderEmbedOptions = (
|
|
48
|
+
appUrl: string,
|
|
49
|
+
configuration: IReaderEmbedOptions,
|
|
50
|
+
): NormalizedReaderEmbedOptions => {
|
|
51
|
+
const normalizedAppUrl = normalizeAppUrl(appUrl);
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...configuration,
|
|
55
|
+
officeServer: normalizedAppUrl,
|
|
56
|
+
scrollIntoView: configuration.scrollIntoView ?? true,
|
|
57
|
+
theme: normalizeTheme(configuration.theme),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createBootstrapUrl } from './ReaderConfiguration';
|
|
2
|
+
|
|
3
|
+
export const READER_CUSTOM_ELEMENT_TAG = 'rhc-office-editor';
|
|
4
|
+
|
|
5
|
+
const READER_LOADER_REGISTRY_KEY = '__RHC_OFFICE_SDK_READER_LOADER__';
|
|
6
|
+
|
|
7
|
+
interface ReaderLoaderRegistry {
|
|
8
|
+
activeAppUrl: string | null;
|
|
9
|
+
loadPromises: Map<string, Promise<void>>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type BrowserGlobal = typeof globalThis & {
|
|
13
|
+
[READER_LOADER_REGISTRY_KEY]?: ReaderLoaderRegistry;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getReaderLoaderRegistry = (): ReaderLoaderRegistry => {
|
|
17
|
+
const browserGlobal = globalThis as BrowserGlobal;
|
|
18
|
+
if (!browserGlobal[READER_LOADER_REGISTRY_KEY]) {
|
|
19
|
+
browserGlobal[READER_LOADER_REGISTRY_KEY] = {
|
|
20
|
+
activeAppUrl: null,
|
|
21
|
+
loadPromises: new Map<string, Promise<void>>(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return browserGlobal[READER_LOADER_REGISTRY_KEY];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const findScriptElementBySource = (source: string): HTMLScriptElement | null => {
|
|
29
|
+
return (
|
|
30
|
+
Array.from(document.querySelectorAll('script')).find((element) => element.src === source) ??
|
|
31
|
+
null
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export class ReaderScriptLoadError extends Error {
|
|
36
|
+
constructor(bootstrapUrl: string) {
|
|
37
|
+
super(`Failed to load reader bootstrap script: ${bootstrapUrl}`);
|
|
38
|
+
this.name = 'ReaderScriptLoadError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class ReaderSourceConflictError extends Error {
|
|
43
|
+
constructor(activeAppUrl: string, requestedAppUrl: string) {
|
|
44
|
+
super(
|
|
45
|
+
`Reader Web Component "${READER_CUSTOM_ELEMENT_TAG}" is already bound to ${activeAppUrl} and cannot be reloaded from ${requestedAppUrl}.`,
|
|
46
|
+
);
|
|
47
|
+
this.name = 'ReaderSourceConflictError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const assertCompatibleReaderSource = (appUrl: string): void => {
|
|
52
|
+
const registry = getReaderLoaderRegistry();
|
|
53
|
+
if (registry.activeAppUrl && registry.activeAppUrl !== appUrl) {
|
|
54
|
+
throw new ReaderSourceConflictError(registry.activeAppUrl, appUrl);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const ensureReaderScriptLoaded = (appUrl: string): Promise<void> => {
|
|
59
|
+
const registry = getReaderLoaderRegistry();
|
|
60
|
+
assertCompatibleReaderSource(appUrl);
|
|
61
|
+
|
|
62
|
+
const existingLoadPromise = registry.loadPromises.get(appUrl);
|
|
63
|
+
if (existingLoadPromise) {
|
|
64
|
+
return existingLoadPromise;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (globalThis.customElements?.get(READER_CUSTOM_ELEMENT_TAG)) {
|
|
68
|
+
registry.activeAppUrl = appUrl;
|
|
69
|
+
const resolvedPromise = Promise.resolve();
|
|
70
|
+
registry.loadPromises.set(appUrl, resolvedPromise);
|
|
71
|
+
return resolvedPromise;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const bootstrapUrl = createBootstrapUrl(appUrl);
|
|
75
|
+
const existingScriptElement = findScriptElementBySource(bootstrapUrl);
|
|
76
|
+
registry.activeAppUrl = appUrl;
|
|
77
|
+
|
|
78
|
+
const loadPromise = new Promise<void>((resolve, reject) => {
|
|
79
|
+
const rejectScriptLoad = (scriptElement?: HTMLScriptElement): void => {
|
|
80
|
+
scriptElement?.remove();
|
|
81
|
+
reject(new ReaderScriptLoadError(bootstrapUrl));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const resolveWhenDefined = (): void => {
|
|
85
|
+
void globalThis.customElements
|
|
86
|
+
.whenDefined(READER_CUSTOM_ELEMENT_TAG)
|
|
87
|
+
.then(() => {
|
|
88
|
+
resolve();
|
|
89
|
+
})
|
|
90
|
+
.catch(reject);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (existingScriptElement) {
|
|
94
|
+
if (globalThis.customElements?.get(READER_CUSTOM_ELEMENT_TAG)) {
|
|
95
|
+
resolve();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
existingScriptElement.addEventListener(
|
|
100
|
+
'error',
|
|
101
|
+
() => reject(new ReaderScriptLoadError(bootstrapUrl)),
|
|
102
|
+
{
|
|
103
|
+
once: true,
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
resolveWhenDefined();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const scriptElement = document.createElement('script');
|
|
111
|
+
scriptElement.src = bootstrapUrl;
|
|
112
|
+
scriptElement.async = true;
|
|
113
|
+
scriptElement.dataset.rhcOfficeSdkReader = appUrl;
|
|
114
|
+
scriptElement.addEventListener('load', resolveWhenDefined, { once: true });
|
|
115
|
+
scriptElement.addEventListener('error', () => rejectScriptLoad(scriptElement), { once: true });
|
|
116
|
+
document.head.appendChild(scriptElement);
|
|
117
|
+
}).catch((error: unknown) => {
|
|
118
|
+
registry.loadPromises.delete(appUrl);
|
|
119
|
+
if (
|
|
120
|
+
!globalThis.customElements?.get(READER_CUSTOM_ELEMENT_TAG) &&
|
|
121
|
+
registry.activeAppUrl === appUrl
|
|
122
|
+
) {
|
|
123
|
+
registry.activeAppUrl = null;
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
registry.loadPromises.set(appUrl, loadPromise);
|
|
129
|
+
return loadPromise;
|
|
130
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AdapterStatePatch } from './AdapterProtocol';
|
|
2
|
+
|
|
3
|
+
export interface ReaderStateSnapshot {
|
|
4
|
+
annotationEnabled: boolean;
|
|
5
|
+
annotationMode?: string;
|
|
6
|
+
documentModified: boolean;
|
|
7
|
+
documentOpened: boolean;
|
|
8
|
+
documentType?: string;
|
|
9
|
+
extensionState: 'connected' | 'disconnected';
|
|
10
|
+
pageCount: number;
|
|
11
|
+
pageIndex: number;
|
|
12
|
+
pageMode: number;
|
|
13
|
+
zoomLevel: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const DEFAULT_READER_STATE: ReaderStateSnapshot = {
|
|
17
|
+
annotationEnabled: false,
|
|
18
|
+
documentModified: false,
|
|
19
|
+
documentOpened: false,
|
|
20
|
+
extensionState: 'disconnected',
|
|
21
|
+
pageCount: 0,
|
|
22
|
+
pageIndex: 1,
|
|
23
|
+
pageMode: 0,
|
|
24
|
+
zoomLevel: 100,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class ReaderStateStore {
|
|
28
|
+
private state: ReaderStateSnapshot = { ...DEFAULT_READER_STATE };
|
|
29
|
+
|
|
30
|
+
reset(): void {
|
|
31
|
+
this.state = { ...DEFAULT_READER_STATE };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
update(patch?: AdapterStatePatch): void {
|
|
35
|
+
if (!patch) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.state = {
|
|
40
|
+
...this.state,
|
|
41
|
+
...patch,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setDocumentOpened(opened: boolean): void {
|
|
46
|
+
this.state = {
|
|
47
|
+
...this.state,
|
|
48
|
+
documentOpened: opened,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
snapshot(): ReaderStateSnapshot {
|
|
53
|
+
return { ...this.state };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnnotationEventCallback,
|
|
3
|
+
DigitalSignatureRetrieveCallback,
|
|
4
|
+
DocumentClosedCallback,
|
|
5
|
+
DocumentSavedCallback,
|
|
6
|
+
ExtensionStateChangedCallback,
|
|
7
|
+
PageChangeCallback,
|
|
8
|
+
PageModeChangeCallback,
|
|
9
|
+
} from '../api/callbacks';
|
|
10
|
+
import type { IDigitalAnnotationInfo } from '../api/annotation-tool';
|
|
11
|
+
|
|
12
|
+
export class SdkCallbackRegistry {
|
|
13
|
+
readonly annotationEvents: AnnotationEventCallback[] = [];
|
|
14
|
+
readonly annotationPersist: Array<(event: unknown) => void> = [];
|
|
15
|
+
readonly annotationRetrieve: Array<(event: unknown) => void> = [];
|
|
16
|
+
readonly digitalAnnotationRetrieve: Array<(annotations: IDigitalAnnotationInfo[]) => void> = [];
|
|
17
|
+
readonly digitalSignatureParse: DigitalSignatureRetrieveCallback[] = [];
|
|
18
|
+
readonly digitalSignatureRetrieve: DigitalSignatureRetrieveCallback[] = [];
|
|
19
|
+
readonly documentClosed: DocumentClosedCallback[] = [];
|
|
20
|
+
readonly documentOpened: Array<(status: string, error: string) => void> = [];
|
|
21
|
+
readonly documentSaved: DocumentSavedCallback[] = [];
|
|
22
|
+
readonly extensionStateChanged: ExtensionStateChangedCallback[] = [];
|
|
23
|
+
readonly pageChange: PageChangeCallback[] = [];
|
|
24
|
+
readonly pageModeChange: PageModeChangeCallback[] = [];
|
|
25
|
+
|
|
26
|
+
emit(event: string, payload: unknown): void {
|
|
27
|
+
switch (event) {
|
|
28
|
+
case 'documentOpened':
|
|
29
|
+
case 'documentLoaded':
|
|
30
|
+
this.documentOpened.forEach((callback) => callback('ok', ''));
|
|
31
|
+
return;
|
|
32
|
+
case 'documentSaved':
|
|
33
|
+
this.documentSaved.forEach((callback) => callback(payload));
|
|
34
|
+
return;
|
|
35
|
+
case 'documentClosed':
|
|
36
|
+
this.documentClosed.forEach((callback) => callback(payload));
|
|
37
|
+
return;
|
|
38
|
+
case 'pageChange': {
|
|
39
|
+
const pagePayload = payload as { pageIndex?: number; pageCount?: number };
|
|
40
|
+
this.pageChange.forEach((callback) =>
|
|
41
|
+
callback(pagePayload.pageIndex ?? 1, pagePayload.pageCount ?? 0),
|
|
42
|
+
);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
case 'pageModeChange': {
|
|
46
|
+
const pagePayload = payload as { pageMode?: number };
|
|
47
|
+
this.pageModeChange.forEach((callback) => callback(pagePayload.pageMode ?? 0));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
case 'annotationEvent': {
|
|
51
|
+
const annotationPayload = payload as { event?: string; payload?: unknown };
|
|
52
|
+
this.annotationEvents.forEach((callback) =>
|
|
53
|
+
callback(annotationPayload.event ?? 'annotationEvent', annotationPayload.payload),
|
|
54
|
+
);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
case 'annotationPersist':
|
|
58
|
+
this.annotationPersist.forEach((callback) => callback(payload));
|
|
59
|
+
return;
|
|
60
|
+
case 'annotationRetrieve':
|
|
61
|
+
this.annotationRetrieve.forEach((callback) => callback(payload));
|
|
62
|
+
return;
|
|
63
|
+
case 'digitalAnnotationRetrieve':
|
|
64
|
+
this.digitalAnnotationRetrieve.forEach((callback) =>
|
|
65
|
+
callback(Array.isArray(payload) ? (payload as IDigitalAnnotationInfo[]) : []),
|
|
66
|
+
);
|
|
67
|
+
return;
|
|
68
|
+
case 'digitalSignatureRetrieve':
|
|
69
|
+
this.digitalSignatureRetrieve.forEach((callback) =>
|
|
70
|
+
callback(Array.isArray(payload) ? payload : []),
|
|
71
|
+
);
|
|
72
|
+
return;
|
|
73
|
+
case 'digitalSignatureParse':
|
|
74
|
+
this.digitalSignatureParse.forEach((callback) =>
|
|
75
|
+
callback(Array.isArray(payload) ? payload : []),
|
|
76
|
+
);
|
|
77
|
+
return;
|
|
78
|
+
case 'extensionStateChanged': {
|
|
79
|
+
const extensionPayload = payload as { state?: 'connected' | 'disconnected' };
|
|
80
|
+
this.extensionStateChanged.forEach((callback) =>
|
|
81
|
+
callback(extensionPayload.state ?? 'disconnected'),
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
default:
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DocumentSDK';
|