3dviewer-sdk 1.0.28 → 1.1.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/dist/index.d.mts +37 -10
- package/dist/index.d.ts +37 -10
- package/dist/index.js +300 -89
- package/dist/index.mjs +300 -89
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -139,7 +139,7 @@ var NodeModule = class {
|
|
|
139
139
|
constructor(viewer) {
|
|
140
140
|
this.viewer = viewer;
|
|
141
141
|
this.on = {
|
|
142
|
-
|
|
142
|
+
// SDK no longer supports first-node-only select events; listen to selectionChange for the full node list.
|
|
143
143
|
selectionChange: (cb) => this.viewer._on("node:selection-change", cb)
|
|
144
144
|
};
|
|
145
145
|
}
|
|
@@ -186,52 +186,75 @@ var FilesModule = class {
|
|
|
186
186
|
// Upload file to conversion server and keep generated baseFileId in session.
|
|
187
187
|
async upload(file) {
|
|
188
188
|
const target = this.resolveFile(file);
|
|
189
|
-
return this.withOperation(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
189
|
+
return this.withOperation(
|
|
190
|
+
{ stage: "uploading", message: "Uploading file..." },
|
|
191
|
+
async () => {
|
|
192
|
+
var _a;
|
|
193
|
+
this.viewer._emit("files:upload:start", { fileName: target.name });
|
|
194
|
+
await this.uploadInternal(target);
|
|
195
|
+
const baseFileId = ((_a = this.getUploadSessionForFile(target)) == null ? void 0 : _a.baseFileId) || "";
|
|
196
|
+
this.viewer._emit("files:upload:success", {
|
|
197
|
+
fileName: target.name,
|
|
198
|
+
baseFileId
|
|
199
|
+
});
|
|
200
|
+
return { fileName: target.name, baseFileId };
|
|
201
|
+
}
|
|
202
|
+
);
|
|
197
203
|
}
|
|
198
204
|
// Trigger conversion flow and resolve final viewer metadata.
|
|
199
205
|
async convert(file, options = {}) {
|
|
200
206
|
const target = this.resolveFile(file);
|
|
201
|
-
return this.withOperation(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
return this.withOperation(
|
|
208
|
+
{ stage: "converting", message: "Converting file..." },
|
|
209
|
+
async () => {
|
|
210
|
+
this.viewer._emit("files:conversion:start", { fileName: target.name });
|
|
211
|
+
try {
|
|
212
|
+
const prepared = await this.convertInternal(target, options);
|
|
213
|
+
this.viewer._emit("files:conversion:success", prepared);
|
|
214
|
+
return prepared;
|
|
215
|
+
} catch (e) {
|
|
216
|
+
this.viewer._emit("files:conversion:error", {
|
|
217
|
+
fileName: target.name,
|
|
218
|
+
error: this.toErrorMessage(e)
|
|
219
|
+
});
|
|
220
|
+
throw e;
|
|
221
|
+
}
|
|
210
222
|
}
|
|
211
|
-
|
|
223
|
+
);
|
|
212
224
|
}
|
|
213
225
|
// Convenience API: upload first, then convert in one call.
|
|
214
226
|
async prepare(file, options = {}) {
|
|
215
227
|
const target = this.resolveFile(file);
|
|
216
|
-
return this.withOperation(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
228
|
+
return this.withOperation(
|
|
229
|
+
{ stage: "uploading", message: "Preparing file..." },
|
|
230
|
+
async () => {
|
|
231
|
+
await this.uploadInternal(target);
|
|
232
|
+
const prepared = await this.convertInternal(target, options);
|
|
233
|
+
return prepared;
|
|
234
|
+
}
|
|
235
|
+
);
|
|
221
236
|
}
|
|
222
237
|
// Trigger the newer downloadUrl-based conversion flow.
|
|
223
238
|
async convertV2(options) {
|
|
224
|
-
return this.withOperation(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
return this.withOperation(
|
|
240
|
+
{ stage: "converting", message: "Converting file..." },
|
|
241
|
+
async () => {
|
|
242
|
+
this.viewer._emit("files:conversion:start", {
|
|
243
|
+
fileName: options.filename
|
|
244
|
+
});
|
|
245
|
+
try {
|
|
246
|
+
const prepared = await this.convertV2Internal(options);
|
|
247
|
+
this.viewer._emit("files:conversion:success", prepared);
|
|
248
|
+
return prepared;
|
|
249
|
+
} catch (e) {
|
|
250
|
+
this.viewer._emit("files:conversion:error", {
|
|
251
|
+
fileName: options.filename,
|
|
252
|
+
error: this.toErrorMessage(e)
|
|
253
|
+
});
|
|
254
|
+
throw e;
|
|
255
|
+
}
|
|
233
256
|
}
|
|
234
|
-
|
|
257
|
+
);
|
|
235
258
|
}
|
|
236
259
|
// Check stream file info by one or more baseFileId values.
|
|
237
260
|
async checkFileInfo(baseFileIds) {
|
|
@@ -247,7 +270,9 @@ var FilesModule = class {
|
|
|
247
270
|
body: JSON.stringify(payload)
|
|
248
271
|
});
|
|
249
272
|
if (!response.ok) {
|
|
250
|
-
throw new Error(
|
|
273
|
+
throw new Error(
|
|
274
|
+
`Check file info failed (${response.status} ${response.statusText})`
|
|
275
|
+
);
|
|
251
276
|
}
|
|
252
277
|
const text = await response.text();
|
|
253
278
|
if (!text) return null;
|
|
@@ -265,27 +290,34 @@ var FilesModule = class {
|
|
|
265
290
|
this.viewer.open(url);
|
|
266
291
|
this.viewer._emit("files:render:success", { url });
|
|
267
292
|
} catch (e) {
|
|
268
|
-
this.viewer._emit("files:render:error", {
|
|
293
|
+
this.viewer._emit("files:render:error", {
|
|
294
|
+
url,
|
|
295
|
+
error: this.toErrorMessage(e)
|
|
296
|
+
});
|
|
269
297
|
throw e;
|
|
270
298
|
}
|
|
271
299
|
}
|
|
272
300
|
// Full pipeline: upload + convert + open iframe.
|
|
273
301
|
async render(file, options = {}) {
|
|
274
302
|
const target = this.resolveFile(file);
|
|
275
|
-
return this.withOperation(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
303
|
+
return this.withOperation(
|
|
304
|
+
{ stage: "uploading", message: "Uploading + converting + opening..." },
|
|
305
|
+
async () => {
|
|
306
|
+
await this.upload(target);
|
|
307
|
+
const prepared = await this.convert(target, options);
|
|
308
|
+
this.updateState({ stage: "rendering", message: "Opening viewer..." });
|
|
309
|
+
this.open(prepared);
|
|
310
|
+
this.viewer._emit("files:load:success", prepared);
|
|
311
|
+
return prepared;
|
|
312
|
+
}
|
|
313
|
+
);
|
|
283
314
|
}
|
|
284
315
|
// Resolve file argument, fallback to options.file, and persist it back.
|
|
285
316
|
resolveFile(file) {
|
|
286
317
|
const optFile = this.viewer.getOptions().file;
|
|
287
318
|
const target = file || optFile;
|
|
288
|
-
if (!target)
|
|
319
|
+
if (!target)
|
|
320
|
+
throw new Error("No file provided. Pass a File or set options.file");
|
|
289
321
|
this.viewer.patchOptions({ file: target });
|
|
290
322
|
return target;
|
|
291
323
|
}
|
|
@@ -306,7 +338,8 @@ var FilesModule = class {
|
|
|
306
338
|
if (viewerUrl) {
|
|
307
339
|
try {
|
|
308
340
|
const pathname = new URL(viewerUrl, window.location.href).pathname;
|
|
309
|
-
if (pathname && pathname !== "/")
|
|
341
|
+
if (pathname && pathname !== "/")
|
|
342
|
+
return this.normalizeViewerPath(pathname);
|
|
310
343
|
} catch {
|
|
311
344
|
}
|
|
312
345
|
}
|
|
@@ -323,14 +356,18 @@ var FilesModule = class {
|
|
|
323
356
|
const configuredViewerBaseUrl = this.config.baseUrl || this.viewer.getOptions().baseUrl;
|
|
324
357
|
if (configuredViewerBaseUrl) {
|
|
325
358
|
try {
|
|
326
|
-
return this.normalizeBaseUrl(
|
|
359
|
+
return this.normalizeBaseUrl(
|
|
360
|
+
new URL(configuredViewerBaseUrl, window.location.href).origin
|
|
361
|
+
);
|
|
327
362
|
} catch {
|
|
328
363
|
}
|
|
329
364
|
}
|
|
330
365
|
const viewerUrl = this.viewer.getOptions().url;
|
|
331
366
|
if (viewerUrl) {
|
|
332
367
|
try {
|
|
333
|
-
return this.normalizeBaseUrl(
|
|
368
|
+
return this.normalizeBaseUrl(
|
|
369
|
+
new URL(viewerUrl, window.location.href).origin
|
|
370
|
+
);
|
|
334
371
|
} catch {
|
|
335
372
|
}
|
|
336
373
|
}
|
|
@@ -351,7 +388,8 @@ var FilesModule = class {
|
|
|
351
388
|
}
|
|
352
389
|
// Create a UUID-like baseFileId when caller does not provide one.
|
|
353
390
|
createBaseFileId() {
|
|
354
|
-
if (typeof crypto !== "undefined" && "randomUUID" in crypto)
|
|
391
|
+
if (typeof crypto !== "undefined" && "randomUUID" in crypto)
|
|
392
|
+
return crypto.randomUUID();
|
|
355
393
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
356
394
|
const r = Math.floor(Math.random() * 16);
|
|
357
395
|
const v = c === "x" ? r : r & 3 | 8;
|
|
@@ -382,15 +420,25 @@ var FilesModule = class {
|
|
|
382
420
|
const session = existing || this.createUploadSession(file);
|
|
383
421
|
const hostConversion = this.resolveHostConversion();
|
|
384
422
|
const path = this.getUploadPath();
|
|
385
|
-
const url = `${hostConversion}/api/File/upload?path=${encodeURIComponent(
|
|
423
|
+
const url = `${hostConversion}/api/File/upload?path=${encodeURIComponent(
|
|
424
|
+
path
|
|
425
|
+
)}`;
|
|
386
426
|
const formData = new FormData();
|
|
387
427
|
formData.append("file", file, file.name);
|
|
388
|
-
const res = await fetch(url, {
|
|
389
|
-
|
|
428
|
+
const res = await fetch(url, {
|
|
429
|
+
method: "POST",
|
|
430
|
+
body: formData,
|
|
431
|
+
headers: { Accept: "text/plain" }
|
|
432
|
+
});
|
|
433
|
+
if (!res.ok)
|
|
434
|
+
throw new Error(`Upload failed (${res.status} ${res.statusText})`);
|
|
390
435
|
this.lastUploadSession = session;
|
|
391
436
|
} catch (e) {
|
|
392
437
|
const msg = this.toErrorMessage(e);
|
|
393
|
-
this.viewer._emit("files:upload:error", {
|
|
438
|
+
this.viewer._emit("files:upload:error", {
|
|
439
|
+
fileName: file.name,
|
|
440
|
+
error: msg
|
|
441
|
+
});
|
|
394
442
|
throw e;
|
|
395
443
|
}
|
|
396
444
|
}
|
|
@@ -544,11 +592,20 @@ var FilesModule = class {
|
|
|
544
592
|
const baseMajorRev = (_b = cacheResult.baseMajorRev) != null ? _b : 0;
|
|
545
593
|
const baseMinorRev = (_c = cacheResult.baseMinorRev) != null ? _c : 0;
|
|
546
594
|
const fileName = cacheResult.filename || cacheResult.fileName || file.name;
|
|
547
|
-
const cacheListItem = {
|
|
595
|
+
const cacheListItem = {
|
|
596
|
+
baseFileId,
|
|
597
|
+
baseMajorRev,
|
|
598
|
+
baseMinorRev,
|
|
599
|
+
fileName
|
|
600
|
+
};
|
|
548
601
|
if (cacheResult.cacheStatus !== 2) {
|
|
549
|
-
throw new Error(
|
|
602
|
+
throw new Error(
|
|
603
|
+
`Conversion not ready after first request (cacheStatus=${(_d = cacheResult.cacheStatus) != null ? _d : "unknown"})`
|
|
604
|
+
);
|
|
550
605
|
}
|
|
551
|
-
const query = new URLSearchParams({
|
|
606
|
+
const query = new URLSearchParams({
|
|
607
|
+
fileList: JSON.stringify([cacheListItem])
|
|
608
|
+
}).toString();
|
|
552
609
|
const viewerBase = this.resolveViewerOrigin();
|
|
553
610
|
const viewerPath = this.resolveViewerPath();
|
|
554
611
|
const url = `${viewerBase}${viewerPath}?${query}`;
|
|
@@ -563,10 +620,19 @@ var FilesModule = class {
|
|
|
563
620
|
const baseMinorRev = (_e = (_d = cacheResult.baseMinorRev) != null ? _d : options.baseMinorRev) != null ? _e : 0;
|
|
564
621
|
const fileName = cacheResult.filename || cacheResult.fileName || options.filename;
|
|
565
622
|
if (cacheResult.cacheStatus !== void 0 && cacheResult.cacheStatus !== 2) {
|
|
566
|
-
throw new Error(
|
|
623
|
+
throw new Error(
|
|
624
|
+
`Conversion not ready after v2 request (cacheStatus=${cacheResult.cacheStatus})`
|
|
625
|
+
);
|
|
567
626
|
}
|
|
568
|
-
const cacheListItem = {
|
|
569
|
-
|
|
627
|
+
const cacheListItem = {
|
|
628
|
+
baseFileId,
|
|
629
|
+
baseMajorRev,
|
|
630
|
+
baseMinorRev,
|
|
631
|
+
fileName
|
|
632
|
+
};
|
|
633
|
+
const query = new URLSearchParams({
|
|
634
|
+
fileList: JSON.stringify([cacheListItem])
|
|
635
|
+
}).toString();
|
|
570
636
|
const viewerBase = this.resolveViewerOrigin();
|
|
571
637
|
const viewerPath = this.resolveViewerPath();
|
|
572
638
|
const url = `${viewerBase}${viewerPath}?${query}`;
|
|
@@ -577,6 +643,15 @@ var FilesModule = class {
|
|
|
577
643
|
const elapsedMs = this.operationStartTime > 0 ? Date.now() - this.operationStartTime : 0;
|
|
578
644
|
this.state = { ...this.state, ...next, elapsedMs };
|
|
579
645
|
this.viewer._emit("files:state", this.state);
|
|
646
|
+
this.viewer._emit("loading:change", {
|
|
647
|
+
loading: this.state.isLoading,
|
|
648
|
+
phase: this.toViewerLoadingPhase(this.state.stage)
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
toViewerLoadingPhase(stage) {
|
|
652
|
+
if (stage === "error") return "error";
|
|
653
|
+
if (stage === "idle" || stage === "completed") return "ready";
|
|
654
|
+
return "loading";
|
|
580
655
|
}
|
|
581
656
|
// Shared wrapper to handle loading state lifecycle and top-level errors.
|
|
582
657
|
async withOperation(initial, run) {
|
|
@@ -588,7 +663,11 @@ var FilesModule = class {
|
|
|
588
663
|
});
|
|
589
664
|
try {
|
|
590
665
|
const result = await run();
|
|
591
|
-
this.updateState({
|
|
666
|
+
this.updateState({
|
|
667
|
+
isLoading: false,
|
|
668
|
+
stage: "completed",
|
|
669
|
+
message: "Completed"
|
|
670
|
+
});
|
|
592
671
|
return result;
|
|
593
672
|
} catch (e) {
|
|
594
673
|
const msg = this.toErrorMessage(e);
|
|
@@ -958,7 +1037,11 @@ var ModelTreeModule = class {
|
|
|
958
1037
|
}
|
|
959
1038
|
selectNodes(nodeIds) {
|
|
960
1039
|
const normalizedNodeIds = this.normalizeNodeIds(nodeIds);
|
|
961
|
-
console.log("[3dviewer-sdk] modelTree.selectNodes", {
|
|
1040
|
+
console.log("[3dviewer-sdk] modelTree.selectNodes post message", {
|
|
1041
|
+
nodeIds,
|
|
1042
|
+
normalizedNodeIds,
|
|
1043
|
+
willClearSelection: normalizedNodeIds.length === 0
|
|
1044
|
+
});
|
|
962
1045
|
this.postTreeSelectNode({
|
|
963
1046
|
nodeIds: normalizedNodeIds
|
|
964
1047
|
});
|
|
@@ -1237,12 +1320,50 @@ var Viewer3D = class {
|
|
|
1237
1320
|
this.containerEl = null;
|
|
1238
1321
|
this.iframeEl = null;
|
|
1239
1322
|
this.initialized = false;
|
|
1323
|
+
this.viewerReady = false;
|
|
1324
|
+
this.readyPayload = null;
|
|
1325
|
+
this.readyWaiters = [];
|
|
1326
|
+
this.loadingState = {
|
|
1327
|
+
loading: false,
|
|
1328
|
+
phase: "ready"
|
|
1329
|
+
};
|
|
1240
1330
|
this.emitter = new Emitter();
|
|
1241
1331
|
this.handleMessage = (event) => {
|
|
1242
|
-
var _a, _b, _c
|
|
1332
|
+
var _a, _b, _c;
|
|
1243
1333
|
const data = event.data;
|
|
1244
1334
|
if (!data || typeof data !== "object") return;
|
|
1245
1335
|
switch (data.type) {
|
|
1336
|
+
case "viewer-loading-change" /* LOADING_CHANGE */: {
|
|
1337
|
+
const payload = data.payload;
|
|
1338
|
+
if (!payload) break;
|
|
1339
|
+
this.setLoadingState({
|
|
1340
|
+
loading: Boolean(payload.loading),
|
|
1341
|
+
phase: payload.phase,
|
|
1342
|
+
viewId: payload.viewId ? String(payload.viewId) : void 0,
|
|
1343
|
+
modelFileId: payload.modelFileId ? String(payload.modelFileId) : void 0,
|
|
1344
|
+
timestamp: payload.timestamp ? Number(payload.timestamp) : void 0
|
|
1345
|
+
});
|
|
1346
|
+
break;
|
|
1347
|
+
}
|
|
1348
|
+
case "viewer-ready" /* READY */: {
|
|
1349
|
+
const payload = data.payload;
|
|
1350
|
+
const readyPayload = {
|
|
1351
|
+
ready: true,
|
|
1352
|
+
viewId: (payload == null ? void 0 : payload.viewId) ? String(payload.viewId) : void 0,
|
|
1353
|
+
modelFileId: (payload == null ? void 0 : payload.modelFileId) ? String(payload.modelFileId) : void 0,
|
|
1354
|
+
timestamp: Number(payload == null ? void 0 : payload.timestamp) || Date.now()
|
|
1355
|
+
};
|
|
1356
|
+
this.setLoadingState({
|
|
1357
|
+
loading: false,
|
|
1358
|
+
phase: "ready",
|
|
1359
|
+
viewId: readyPayload.viewId,
|
|
1360
|
+
modelFileId: readyPayload.modelFileId,
|
|
1361
|
+
timestamp: readyPayload.timestamp
|
|
1362
|
+
});
|
|
1363
|
+
this.resolveReady(readyPayload);
|
|
1364
|
+
this._emit("viewer:ready", readyPayload);
|
|
1365
|
+
break;
|
|
1366
|
+
}
|
|
1246
1367
|
case "viewer-home-click" /* HOME_CLICK */:
|
|
1247
1368
|
this._emit("camera:home", { timestamp: Date.now() });
|
|
1248
1369
|
break;
|
|
@@ -1257,9 +1378,6 @@ var Viewer3D = class {
|
|
|
1257
1378
|
});
|
|
1258
1379
|
break;
|
|
1259
1380
|
}
|
|
1260
|
-
case "viewer-node-select" /* NODE_SELECT */:
|
|
1261
|
-
this._emit("node:select", { nodeId: String((_b = (_a = data.payload) == null ? void 0 : _a.nodeId) != null ? _b : ""), timestamp: Date.now() });
|
|
1262
|
-
break;
|
|
1263
1381
|
case "viewer-node-selection-change" /* NODE_SELECTION_CHANGE */: {
|
|
1264
1382
|
const payload = data.payload;
|
|
1265
1383
|
const rawNodeIds = payload == null ? void 0 : payload.nodeIds;
|
|
@@ -1271,7 +1389,9 @@ var Viewer3D = class {
|
|
|
1271
1389
|
break;
|
|
1272
1390
|
}
|
|
1273
1391
|
case "viewer-pan-change" /* PAN_CHANGE */:
|
|
1274
|
-
this._emit("interaction:pan-change", {
|
|
1392
|
+
this._emit("interaction:pan-change", {
|
|
1393
|
+
enabled: Boolean((_a = data.payload) == null ? void 0 : _a.enabled)
|
|
1394
|
+
});
|
|
1275
1395
|
break;
|
|
1276
1396
|
case "viewer-pdf-plan-mode" /* PDF_PLAN_MODE */: {
|
|
1277
1397
|
const payload = data.payload;
|
|
@@ -1329,7 +1449,8 @@ var Viewer3D = class {
|
|
|
1329
1449
|
}
|
|
1330
1450
|
case "viewer-tree-node-ids" /* TREE_NODE_IDS */: {
|
|
1331
1451
|
const payload = data.payload;
|
|
1332
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.nodeIds))
|
|
1452
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.nodeIds))
|
|
1453
|
+
break;
|
|
1333
1454
|
this._emit("modelTree:node-ids", {
|
|
1334
1455
|
requestId: String(payload.requestId),
|
|
1335
1456
|
nodeIds: payload.nodeIds.map(String),
|
|
@@ -1339,7 +1460,8 @@ var Viewer3D = class {
|
|
|
1339
1460
|
}
|
|
1340
1461
|
case "viewer-tree-nodes" /* TREE_NODES */: {
|
|
1341
1462
|
const payload = data.payload;
|
|
1342
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.nodes))
|
|
1463
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.nodes))
|
|
1464
|
+
break;
|
|
1343
1465
|
this._emit("modelTree:nodes", {
|
|
1344
1466
|
requestId: String(payload.requestId),
|
|
1345
1467
|
nodes: payload.nodes.filter((node) => node && typeof node === "object").map((node) => {
|
|
@@ -1365,7 +1487,8 @@ var Viewer3D = class {
|
|
|
1365
1487
|
}
|
|
1366
1488
|
case "viewer-sheets-list" /* SHEETS_LIST */: {
|
|
1367
1489
|
const payload = data.payload;
|
|
1368
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.sheets))
|
|
1490
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.sheets))
|
|
1491
|
+
break;
|
|
1369
1492
|
this._emit("sheets:list", {
|
|
1370
1493
|
requestId: String(payload.requestId),
|
|
1371
1494
|
sheets: payload.sheets.map((sheet) => {
|
|
@@ -1377,17 +1500,18 @@ var Viewer3D = class {
|
|
|
1377
1500
|
viewId: sheet.viewId ? String(sheet.viewId) : void 0
|
|
1378
1501
|
};
|
|
1379
1502
|
}),
|
|
1380
|
-
activeSheetId: (
|
|
1503
|
+
activeSheetId: (_b = payload.activeSheetId) != null ? _b : null,
|
|
1381
1504
|
timestamp: Number(payload.timestamp) || Date.now()
|
|
1382
1505
|
});
|
|
1383
1506
|
break;
|
|
1384
1507
|
}
|
|
1385
1508
|
case "viewer-object-properties-list" /* OBJECT_PROPERTIES_LIST */: {
|
|
1386
1509
|
const payload = data.payload;
|
|
1387
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.properties))
|
|
1510
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.properties))
|
|
1511
|
+
break;
|
|
1388
1512
|
this._emit("object-properties:list", {
|
|
1389
1513
|
requestId: String(payload.requestId),
|
|
1390
|
-
selectionKey: String((
|
|
1514
|
+
selectionKey: String((_c = payload.selectionKey) != null ? _c : ""),
|
|
1391
1515
|
nodeIds: Array.isArray(payload.nodeIds) ? payload.nodeIds.map(String) : [],
|
|
1392
1516
|
persistentIds: Array.isArray(payload.persistentIds) ? payload.persistentIds.map(String) : [],
|
|
1393
1517
|
properties: payload.properties.filter((item) => item && typeof item === "object").map((item) => ({ ...item })),
|
|
@@ -1397,7 +1521,8 @@ var Viewer3D = class {
|
|
|
1397
1521
|
}
|
|
1398
1522
|
case "viewer-linked-objects-list" /* LINKED_OBJECTS_LIST */: {
|
|
1399
1523
|
const payload = data.payload;
|
|
1400
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.linkedObjects))
|
|
1524
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.linkedObjects))
|
|
1525
|
+
break;
|
|
1401
1526
|
this._emit("linked-objects:list", {
|
|
1402
1527
|
requestId: String(payload.requestId),
|
|
1403
1528
|
linkedObjects: payload.linkedObjects.filter((item) => item && typeof item === "object").map((item) => ({ ...item })),
|
|
@@ -1407,11 +1532,12 @@ var Viewer3D = class {
|
|
|
1407
1532
|
}
|
|
1408
1533
|
case "viewer-states-objects-list" /* STATES_OBJECTS_LIST */: {
|
|
1409
1534
|
const payload = data.payload;
|
|
1410
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.statesObjects))
|
|
1535
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.statesObjects))
|
|
1536
|
+
break;
|
|
1411
1537
|
this._emit("states-objects:list", {
|
|
1412
1538
|
requestId: String(payload.requestId),
|
|
1413
1539
|
statesObjects: payload.statesObjects.map((item) => {
|
|
1414
|
-
var _a2, _b2, _c2,
|
|
1540
|
+
var _a2, _b2, _c2, _d, _e, _f, _g;
|
|
1415
1541
|
return {
|
|
1416
1542
|
id: String((_a2 = item.id) != null ? _a2 : ""),
|
|
1417
1543
|
name: String((_b2 = item.name) != null ? _b2 : ""),
|
|
@@ -1424,7 +1550,7 @@ var Viewer3D = class {
|
|
|
1424
1550
|
};
|
|
1425
1551
|
}) : [],
|
|
1426
1552
|
states: {
|
|
1427
|
-
color: String((
|
|
1553
|
+
color: String((_e = (_d = item.states) == null ? void 0 : _d.color) != null ? _e : ""),
|
|
1428
1554
|
type: String((_g = (_f = item.states) == null ? void 0 : _f.type) != null ? _g : "")
|
|
1429
1555
|
}
|
|
1430
1556
|
};
|
|
@@ -1435,7 +1561,8 @@ var Viewer3D = class {
|
|
|
1435
1561
|
}
|
|
1436
1562
|
case "viewer-markup-list" /* MARKUP_LIST */: {
|
|
1437
1563
|
const payload = data.payload;
|
|
1438
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.markups))
|
|
1564
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.markups))
|
|
1565
|
+
break;
|
|
1439
1566
|
this._emit("markup:list", {
|
|
1440
1567
|
requestId: String(payload.requestId),
|
|
1441
1568
|
markups: payload.markups.map((markup) => {
|
|
@@ -1504,6 +1631,36 @@ var Viewer3D = class {
|
|
|
1504
1631
|
var _a;
|
|
1505
1632
|
return (_a = this.options.url) != null ? _a : null;
|
|
1506
1633
|
}
|
|
1634
|
+
on(event, cb) {
|
|
1635
|
+
return this._on(event, cb);
|
|
1636
|
+
}
|
|
1637
|
+
off(event, cb) {
|
|
1638
|
+
this._off(event, cb);
|
|
1639
|
+
}
|
|
1640
|
+
getLoadingState() {
|
|
1641
|
+
return { ...this.loadingState };
|
|
1642
|
+
}
|
|
1643
|
+
ready(options) {
|
|
1644
|
+
if (this.viewerReady && this.readyPayload) {
|
|
1645
|
+
return Promise.resolve({ ...this.readyPayload });
|
|
1646
|
+
}
|
|
1647
|
+
const timeoutMs = options == null ? void 0 : options.timeoutMs;
|
|
1648
|
+
return new Promise((resolve, reject) => {
|
|
1649
|
+
const waiter = {
|
|
1650
|
+
resolve: (payload) => resolve({ ...payload }),
|
|
1651
|
+
reject
|
|
1652
|
+
};
|
|
1653
|
+
if (typeof timeoutMs === "number" && timeoutMs > 0) {
|
|
1654
|
+
waiter.timer = setTimeout(() => {
|
|
1655
|
+
this.readyWaiters = this.readyWaiters.filter(
|
|
1656
|
+
(item) => item !== waiter
|
|
1657
|
+
);
|
|
1658
|
+
reject(new Error("Timeout while waiting for viewer to be ready"));
|
|
1659
|
+
}, timeoutMs);
|
|
1660
|
+
}
|
|
1661
|
+
this.readyWaiters.push(waiter);
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1507
1664
|
// ===== lifecycle =====
|
|
1508
1665
|
init() {
|
|
1509
1666
|
if (this.initialized) return;
|
|
@@ -1515,7 +1672,12 @@ var Viewer3D = class {
|
|
|
1515
1672
|
async render(file) {
|
|
1516
1673
|
this.ensureInit();
|
|
1517
1674
|
if (this.iframeEl) return;
|
|
1675
|
+
this.resetReadyState();
|
|
1518
1676
|
if (!this.options.url) return this.files.render(file);
|
|
1677
|
+
this.setLoadingState({
|
|
1678
|
+
loading: true,
|
|
1679
|
+
phase: "loading"
|
|
1680
|
+
});
|
|
1519
1681
|
const iframe = document.createElement("iframe");
|
|
1520
1682
|
iframe.src = this.withInitialOptions(this.options.url);
|
|
1521
1683
|
iframe.style.border = "none";
|
|
@@ -1523,13 +1685,19 @@ var Viewer3D = class {
|
|
|
1523
1685
|
iframe.style.height = this.options.height || "100%";
|
|
1524
1686
|
iframe.width = this.options.width || "100%";
|
|
1525
1687
|
iframe.height = this.options.height || "100%";
|
|
1526
|
-
if (this.options.sandbox)
|
|
1688
|
+
if (this.options.sandbox)
|
|
1689
|
+
iframe.setAttribute("sandbox", this.options.sandbox);
|
|
1527
1690
|
this.containerEl.appendChild(iframe);
|
|
1528
1691
|
this.iframeEl = iframe;
|
|
1529
1692
|
}
|
|
1530
1693
|
open(url) {
|
|
1531
1694
|
this.ensureInit();
|
|
1532
1695
|
this.options.url = url;
|
|
1696
|
+
this.resetReadyState();
|
|
1697
|
+
this.setLoadingState({
|
|
1698
|
+
loading: true,
|
|
1699
|
+
phase: "loading"
|
|
1700
|
+
});
|
|
1533
1701
|
const finalUrl = this.withInitialOptions(url);
|
|
1534
1702
|
if (!this.iframeEl) {
|
|
1535
1703
|
this.render();
|
|
@@ -1548,16 +1716,27 @@ var Viewer3D = class {
|
|
|
1548
1716
|
this.iframeEl = null;
|
|
1549
1717
|
this.containerEl = null;
|
|
1550
1718
|
this.initialized = false;
|
|
1719
|
+
this.rejectReadyWaiters(
|
|
1720
|
+
new Error("Viewer was destroyed before becoming ready")
|
|
1721
|
+
);
|
|
1551
1722
|
}
|
|
1552
1723
|
ensureInit() {
|
|
1553
|
-
if (!this.initialized)
|
|
1724
|
+
if (!this.initialized)
|
|
1725
|
+
throw new Error("Call viewer.init() before using viewer");
|
|
1554
1726
|
}
|
|
1555
1727
|
withInitialOptions(url) {
|
|
1728
|
+
var _a;
|
|
1556
1729
|
try {
|
|
1557
1730
|
const parsedUrl = new URL(url, window.location.href);
|
|
1558
1731
|
const initialToolbar = this.normalizeInitialToolbar();
|
|
1559
1732
|
if (initialToolbar) {
|
|
1560
|
-
parsedUrl.searchParams.set(
|
|
1733
|
+
parsedUrl.searchParams.set(
|
|
1734
|
+
"useToolbar",
|
|
1735
|
+
JSON.stringify(initialToolbar)
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
if (((_a = this.options.ui) == null ? void 0 : _a.loadingIndicator) === false) {
|
|
1739
|
+
parsedUrl.searchParams.set("loadingIndicator", "false");
|
|
1561
1740
|
}
|
|
1562
1741
|
return parsedUrl.toString();
|
|
1563
1742
|
} catch {
|
|
@@ -1571,17 +1750,25 @@ var Viewer3D = class {
|
|
|
1571
1750
|
return { [initialToolbar]: true };
|
|
1572
1751
|
}
|
|
1573
1752
|
if (Array.isArray(initialToolbar)) {
|
|
1574
|
-
return initialToolbar.reduce(
|
|
1575
|
-
result
|
|
1576
|
-
|
|
1577
|
-
|
|
1753
|
+
return initialToolbar.reduce(
|
|
1754
|
+
(result, target) => {
|
|
1755
|
+
result[target] = true;
|
|
1756
|
+
return result;
|
|
1757
|
+
},
|
|
1758
|
+
{}
|
|
1759
|
+
);
|
|
1578
1760
|
}
|
|
1579
|
-
const entries = Object.entries(initialToolbar).filter(
|
|
1761
|
+
const entries = Object.entries(initialToolbar).filter(
|
|
1762
|
+
([, enabled]) => enabled === true
|
|
1763
|
+
);
|
|
1580
1764
|
if (entries.length === 0) return null;
|
|
1581
|
-
return entries.reduce(
|
|
1582
|
-
result[target]
|
|
1583
|
-
|
|
1584
|
-
|
|
1765
|
+
return entries.reduce(
|
|
1766
|
+
(result, [target]) => {
|
|
1767
|
+
result[target] = true;
|
|
1768
|
+
return result;
|
|
1769
|
+
},
|
|
1770
|
+
{}
|
|
1771
|
+
);
|
|
1585
1772
|
}
|
|
1586
1773
|
// ===== typed internal events used by modules =====
|
|
1587
1774
|
_on(event, cb) {
|
|
@@ -1593,6 +1780,30 @@ var Viewer3D = class {
|
|
|
1593
1780
|
_emit(event, payload) {
|
|
1594
1781
|
this.emitter.emit(event, payload);
|
|
1595
1782
|
}
|
|
1783
|
+
resetReadyState() {
|
|
1784
|
+
this.viewerReady = false;
|
|
1785
|
+
this.readyPayload = null;
|
|
1786
|
+
}
|
|
1787
|
+
setLoadingState(payload) {
|
|
1788
|
+
this.loadingState = { ...payload };
|
|
1789
|
+
this._emit("loading:change", this.loadingState);
|
|
1790
|
+
}
|
|
1791
|
+
resolveReady(payload) {
|
|
1792
|
+
this.viewerReady = true;
|
|
1793
|
+
this.readyPayload = { ...payload };
|
|
1794
|
+
this.readyWaiters.forEach((waiter) => {
|
|
1795
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
1796
|
+
waiter.resolve(payload);
|
|
1797
|
+
});
|
|
1798
|
+
this.readyWaiters = [];
|
|
1799
|
+
}
|
|
1800
|
+
rejectReadyWaiters(error) {
|
|
1801
|
+
this.readyWaiters.forEach((waiter) => {
|
|
1802
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
1803
|
+
waiter.reject(error);
|
|
1804
|
+
});
|
|
1805
|
+
this.readyWaiters = [];
|
|
1806
|
+
}
|
|
1596
1807
|
// ===== postMessage bridge =====
|
|
1597
1808
|
postToViewer(type, payload) {
|
|
1598
1809
|
var _a;
|