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.js
CHANGED
|
@@ -165,7 +165,7 @@ var NodeModule = class {
|
|
|
165
165
|
constructor(viewer) {
|
|
166
166
|
this.viewer = viewer;
|
|
167
167
|
this.on = {
|
|
168
|
-
|
|
168
|
+
// SDK no longer supports first-node-only select events; listen to selectionChange for the full node list.
|
|
169
169
|
selectionChange: (cb) => this.viewer._on("node:selection-change", cb)
|
|
170
170
|
};
|
|
171
171
|
}
|
|
@@ -212,52 +212,75 @@ var FilesModule = class {
|
|
|
212
212
|
// Upload file to conversion server and keep generated baseFileId in session.
|
|
213
213
|
async upload(file) {
|
|
214
214
|
const target = this.resolveFile(file);
|
|
215
|
-
return this.withOperation(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
215
|
+
return this.withOperation(
|
|
216
|
+
{ stage: "uploading", message: "Uploading file..." },
|
|
217
|
+
async () => {
|
|
218
|
+
var _a;
|
|
219
|
+
this.viewer._emit("files:upload:start", { fileName: target.name });
|
|
220
|
+
await this.uploadInternal(target);
|
|
221
|
+
const baseFileId = ((_a = this.getUploadSessionForFile(target)) == null ? void 0 : _a.baseFileId) || "";
|
|
222
|
+
this.viewer._emit("files:upload:success", {
|
|
223
|
+
fileName: target.name,
|
|
224
|
+
baseFileId
|
|
225
|
+
});
|
|
226
|
+
return { fileName: target.name, baseFileId };
|
|
227
|
+
}
|
|
228
|
+
);
|
|
223
229
|
}
|
|
224
230
|
// Trigger conversion flow and resolve final viewer metadata.
|
|
225
231
|
async convert(file, options = {}) {
|
|
226
232
|
const target = this.resolveFile(file);
|
|
227
|
-
return this.withOperation(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
return this.withOperation(
|
|
234
|
+
{ stage: "converting", message: "Converting file..." },
|
|
235
|
+
async () => {
|
|
236
|
+
this.viewer._emit("files:conversion:start", { fileName: target.name });
|
|
237
|
+
try {
|
|
238
|
+
const prepared = await this.convertInternal(target, options);
|
|
239
|
+
this.viewer._emit("files:conversion:success", prepared);
|
|
240
|
+
return prepared;
|
|
241
|
+
} catch (e) {
|
|
242
|
+
this.viewer._emit("files:conversion:error", {
|
|
243
|
+
fileName: target.name,
|
|
244
|
+
error: this.toErrorMessage(e)
|
|
245
|
+
});
|
|
246
|
+
throw e;
|
|
247
|
+
}
|
|
236
248
|
}
|
|
237
|
-
|
|
249
|
+
);
|
|
238
250
|
}
|
|
239
251
|
// Convenience API: upload first, then convert in one call.
|
|
240
252
|
async prepare(file, options = {}) {
|
|
241
253
|
const target = this.resolveFile(file);
|
|
242
|
-
return this.withOperation(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
return this.withOperation(
|
|
255
|
+
{ stage: "uploading", message: "Preparing file..." },
|
|
256
|
+
async () => {
|
|
257
|
+
await this.uploadInternal(target);
|
|
258
|
+
const prepared = await this.convertInternal(target, options);
|
|
259
|
+
return prepared;
|
|
260
|
+
}
|
|
261
|
+
);
|
|
247
262
|
}
|
|
248
263
|
// Trigger the newer downloadUrl-based conversion flow.
|
|
249
264
|
async convertV2(options) {
|
|
250
|
-
return this.withOperation(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
265
|
+
return this.withOperation(
|
|
266
|
+
{ stage: "converting", message: "Converting file..." },
|
|
267
|
+
async () => {
|
|
268
|
+
this.viewer._emit("files:conversion:start", {
|
|
269
|
+
fileName: options.filename
|
|
270
|
+
});
|
|
271
|
+
try {
|
|
272
|
+
const prepared = await this.convertV2Internal(options);
|
|
273
|
+
this.viewer._emit("files:conversion:success", prepared);
|
|
274
|
+
return prepared;
|
|
275
|
+
} catch (e) {
|
|
276
|
+
this.viewer._emit("files:conversion:error", {
|
|
277
|
+
fileName: options.filename,
|
|
278
|
+
error: this.toErrorMessage(e)
|
|
279
|
+
});
|
|
280
|
+
throw e;
|
|
281
|
+
}
|
|
259
282
|
}
|
|
260
|
-
|
|
283
|
+
);
|
|
261
284
|
}
|
|
262
285
|
// Check stream file info by one or more baseFileId values.
|
|
263
286
|
async checkFileInfo(baseFileIds) {
|
|
@@ -273,7 +296,9 @@ var FilesModule = class {
|
|
|
273
296
|
body: JSON.stringify(payload)
|
|
274
297
|
});
|
|
275
298
|
if (!response.ok) {
|
|
276
|
-
throw new Error(
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Check file info failed (${response.status} ${response.statusText})`
|
|
301
|
+
);
|
|
277
302
|
}
|
|
278
303
|
const text = await response.text();
|
|
279
304
|
if (!text) return null;
|
|
@@ -291,27 +316,34 @@ var FilesModule = class {
|
|
|
291
316
|
this.viewer.open(url);
|
|
292
317
|
this.viewer._emit("files:render:success", { url });
|
|
293
318
|
} catch (e) {
|
|
294
|
-
this.viewer._emit("files:render:error", {
|
|
319
|
+
this.viewer._emit("files:render:error", {
|
|
320
|
+
url,
|
|
321
|
+
error: this.toErrorMessage(e)
|
|
322
|
+
});
|
|
295
323
|
throw e;
|
|
296
324
|
}
|
|
297
325
|
}
|
|
298
326
|
// Full pipeline: upload + convert + open iframe.
|
|
299
327
|
async render(file, options = {}) {
|
|
300
328
|
const target = this.resolveFile(file);
|
|
301
|
-
return this.withOperation(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
329
|
+
return this.withOperation(
|
|
330
|
+
{ stage: "uploading", message: "Uploading + converting + opening..." },
|
|
331
|
+
async () => {
|
|
332
|
+
await this.upload(target);
|
|
333
|
+
const prepared = await this.convert(target, options);
|
|
334
|
+
this.updateState({ stage: "rendering", message: "Opening viewer..." });
|
|
335
|
+
this.open(prepared);
|
|
336
|
+
this.viewer._emit("files:load:success", prepared);
|
|
337
|
+
return prepared;
|
|
338
|
+
}
|
|
339
|
+
);
|
|
309
340
|
}
|
|
310
341
|
// Resolve file argument, fallback to options.file, and persist it back.
|
|
311
342
|
resolveFile(file) {
|
|
312
343
|
const optFile = this.viewer.getOptions().file;
|
|
313
344
|
const target = file || optFile;
|
|
314
|
-
if (!target)
|
|
345
|
+
if (!target)
|
|
346
|
+
throw new Error("No file provided. Pass a File or set options.file");
|
|
315
347
|
this.viewer.patchOptions({ file: target });
|
|
316
348
|
return target;
|
|
317
349
|
}
|
|
@@ -332,7 +364,8 @@ var FilesModule = class {
|
|
|
332
364
|
if (viewerUrl) {
|
|
333
365
|
try {
|
|
334
366
|
const pathname = new URL(viewerUrl, window.location.href).pathname;
|
|
335
|
-
if (pathname && pathname !== "/")
|
|
367
|
+
if (pathname && pathname !== "/")
|
|
368
|
+
return this.normalizeViewerPath(pathname);
|
|
336
369
|
} catch {
|
|
337
370
|
}
|
|
338
371
|
}
|
|
@@ -349,14 +382,18 @@ var FilesModule = class {
|
|
|
349
382
|
const configuredViewerBaseUrl = this.config.baseUrl || this.viewer.getOptions().baseUrl;
|
|
350
383
|
if (configuredViewerBaseUrl) {
|
|
351
384
|
try {
|
|
352
|
-
return this.normalizeBaseUrl(
|
|
385
|
+
return this.normalizeBaseUrl(
|
|
386
|
+
new URL(configuredViewerBaseUrl, window.location.href).origin
|
|
387
|
+
);
|
|
353
388
|
} catch {
|
|
354
389
|
}
|
|
355
390
|
}
|
|
356
391
|
const viewerUrl = this.viewer.getOptions().url;
|
|
357
392
|
if (viewerUrl) {
|
|
358
393
|
try {
|
|
359
|
-
return this.normalizeBaseUrl(
|
|
394
|
+
return this.normalizeBaseUrl(
|
|
395
|
+
new URL(viewerUrl, window.location.href).origin
|
|
396
|
+
);
|
|
360
397
|
} catch {
|
|
361
398
|
}
|
|
362
399
|
}
|
|
@@ -377,7 +414,8 @@ var FilesModule = class {
|
|
|
377
414
|
}
|
|
378
415
|
// Create a UUID-like baseFileId when caller does not provide one.
|
|
379
416
|
createBaseFileId() {
|
|
380
|
-
if (typeof crypto !== "undefined" && "randomUUID" in crypto)
|
|
417
|
+
if (typeof crypto !== "undefined" && "randomUUID" in crypto)
|
|
418
|
+
return crypto.randomUUID();
|
|
381
419
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
382
420
|
const r = Math.floor(Math.random() * 16);
|
|
383
421
|
const v = c === "x" ? r : r & 3 | 8;
|
|
@@ -408,15 +446,25 @@ var FilesModule = class {
|
|
|
408
446
|
const session = existing || this.createUploadSession(file);
|
|
409
447
|
const hostConversion = this.resolveHostConversion();
|
|
410
448
|
const path = this.getUploadPath();
|
|
411
|
-
const url = `${hostConversion}/api/File/upload?path=${encodeURIComponent(
|
|
449
|
+
const url = `${hostConversion}/api/File/upload?path=${encodeURIComponent(
|
|
450
|
+
path
|
|
451
|
+
)}`;
|
|
412
452
|
const formData = new FormData();
|
|
413
453
|
formData.append("file", file, file.name);
|
|
414
|
-
const res = await fetch(url, {
|
|
415
|
-
|
|
454
|
+
const res = await fetch(url, {
|
|
455
|
+
method: "POST",
|
|
456
|
+
body: formData,
|
|
457
|
+
headers: { Accept: "text/plain" }
|
|
458
|
+
});
|
|
459
|
+
if (!res.ok)
|
|
460
|
+
throw new Error(`Upload failed (${res.status} ${res.statusText})`);
|
|
416
461
|
this.lastUploadSession = session;
|
|
417
462
|
} catch (e) {
|
|
418
463
|
const msg = this.toErrorMessage(e);
|
|
419
|
-
this.viewer._emit("files:upload:error", {
|
|
464
|
+
this.viewer._emit("files:upload:error", {
|
|
465
|
+
fileName: file.name,
|
|
466
|
+
error: msg
|
|
467
|
+
});
|
|
420
468
|
throw e;
|
|
421
469
|
}
|
|
422
470
|
}
|
|
@@ -570,11 +618,20 @@ var FilesModule = class {
|
|
|
570
618
|
const baseMajorRev = (_b = cacheResult.baseMajorRev) != null ? _b : 0;
|
|
571
619
|
const baseMinorRev = (_c = cacheResult.baseMinorRev) != null ? _c : 0;
|
|
572
620
|
const fileName = cacheResult.filename || cacheResult.fileName || file.name;
|
|
573
|
-
const cacheListItem = {
|
|
621
|
+
const cacheListItem = {
|
|
622
|
+
baseFileId,
|
|
623
|
+
baseMajorRev,
|
|
624
|
+
baseMinorRev,
|
|
625
|
+
fileName
|
|
626
|
+
};
|
|
574
627
|
if (cacheResult.cacheStatus !== 2) {
|
|
575
|
-
throw new Error(
|
|
628
|
+
throw new Error(
|
|
629
|
+
`Conversion not ready after first request (cacheStatus=${(_d = cacheResult.cacheStatus) != null ? _d : "unknown"})`
|
|
630
|
+
);
|
|
576
631
|
}
|
|
577
|
-
const query = new URLSearchParams({
|
|
632
|
+
const query = new URLSearchParams({
|
|
633
|
+
fileList: JSON.stringify([cacheListItem])
|
|
634
|
+
}).toString();
|
|
578
635
|
const viewerBase = this.resolveViewerOrigin();
|
|
579
636
|
const viewerPath = this.resolveViewerPath();
|
|
580
637
|
const url = `${viewerBase}${viewerPath}?${query}`;
|
|
@@ -589,10 +646,19 @@ var FilesModule = class {
|
|
|
589
646
|
const baseMinorRev = (_e = (_d = cacheResult.baseMinorRev) != null ? _d : options.baseMinorRev) != null ? _e : 0;
|
|
590
647
|
const fileName = cacheResult.filename || cacheResult.fileName || options.filename;
|
|
591
648
|
if (cacheResult.cacheStatus !== void 0 && cacheResult.cacheStatus !== 2) {
|
|
592
|
-
throw new Error(
|
|
649
|
+
throw new Error(
|
|
650
|
+
`Conversion not ready after v2 request (cacheStatus=${cacheResult.cacheStatus})`
|
|
651
|
+
);
|
|
593
652
|
}
|
|
594
|
-
const cacheListItem = {
|
|
595
|
-
|
|
653
|
+
const cacheListItem = {
|
|
654
|
+
baseFileId,
|
|
655
|
+
baseMajorRev,
|
|
656
|
+
baseMinorRev,
|
|
657
|
+
fileName
|
|
658
|
+
};
|
|
659
|
+
const query = new URLSearchParams({
|
|
660
|
+
fileList: JSON.stringify([cacheListItem])
|
|
661
|
+
}).toString();
|
|
596
662
|
const viewerBase = this.resolveViewerOrigin();
|
|
597
663
|
const viewerPath = this.resolveViewerPath();
|
|
598
664
|
const url = `${viewerBase}${viewerPath}?${query}`;
|
|
@@ -603,6 +669,15 @@ var FilesModule = class {
|
|
|
603
669
|
const elapsedMs = this.operationStartTime > 0 ? Date.now() - this.operationStartTime : 0;
|
|
604
670
|
this.state = { ...this.state, ...next, elapsedMs };
|
|
605
671
|
this.viewer._emit("files:state", this.state);
|
|
672
|
+
this.viewer._emit("loading:change", {
|
|
673
|
+
loading: this.state.isLoading,
|
|
674
|
+
phase: this.toViewerLoadingPhase(this.state.stage)
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
toViewerLoadingPhase(stage) {
|
|
678
|
+
if (stage === "error") return "error";
|
|
679
|
+
if (stage === "idle" || stage === "completed") return "ready";
|
|
680
|
+
return "loading";
|
|
606
681
|
}
|
|
607
682
|
// Shared wrapper to handle loading state lifecycle and top-level errors.
|
|
608
683
|
async withOperation(initial, run) {
|
|
@@ -614,7 +689,11 @@ var FilesModule = class {
|
|
|
614
689
|
});
|
|
615
690
|
try {
|
|
616
691
|
const result = await run();
|
|
617
|
-
this.updateState({
|
|
692
|
+
this.updateState({
|
|
693
|
+
isLoading: false,
|
|
694
|
+
stage: "completed",
|
|
695
|
+
message: "Completed"
|
|
696
|
+
});
|
|
618
697
|
return result;
|
|
619
698
|
} catch (e) {
|
|
620
699
|
const msg = this.toErrorMessage(e);
|
|
@@ -984,7 +1063,11 @@ var ModelTreeModule = class {
|
|
|
984
1063
|
}
|
|
985
1064
|
selectNodes(nodeIds) {
|
|
986
1065
|
const normalizedNodeIds = this.normalizeNodeIds(nodeIds);
|
|
987
|
-
console.log("[3dviewer-sdk] modelTree.selectNodes", {
|
|
1066
|
+
console.log("[3dviewer-sdk] modelTree.selectNodes post message", {
|
|
1067
|
+
nodeIds,
|
|
1068
|
+
normalizedNodeIds,
|
|
1069
|
+
willClearSelection: normalizedNodeIds.length === 0
|
|
1070
|
+
});
|
|
988
1071
|
this.postTreeSelectNode({
|
|
989
1072
|
nodeIds: normalizedNodeIds
|
|
990
1073
|
});
|
|
@@ -1263,12 +1346,50 @@ var Viewer3D = class {
|
|
|
1263
1346
|
this.containerEl = null;
|
|
1264
1347
|
this.iframeEl = null;
|
|
1265
1348
|
this.initialized = false;
|
|
1349
|
+
this.viewerReady = false;
|
|
1350
|
+
this.readyPayload = null;
|
|
1351
|
+
this.readyWaiters = [];
|
|
1352
|
+
this.loadingState = {
|
|
1353
|
+
loading: false,
|
|
1354
|
+
phase: "ready"
|
|
1355
|
+
};
|
|
1266
1356
|
this.emitter = new Emitter();
|
|
1267
1357
|
this.handleMessage = (event) => {
|
|
1268
|
-
var _a, _b, _c
|
|
1358
|
+
var _a, _b, _c;
|
|
1269
1359
|
const data = event.data;
|
|
1270
1360
|
if (!data || typeof data !== "object") return;
|
|
1271
1361
|
switch (data.type) {
|
|
1362
|
+
case "viewer-loading-change" /* LOADING_CHANGE */: {
|
|
1363
|
+
const payload = data.payload;
|
|
1364
|
+
if (!payload) break;
|
|
1365
|
+
this.setLoadingState({
|
|
1366
|
+
loading: Boolean(payload.loading),
|
|
1367
|
+
phase: payload.phase,
|
|
1368
|
+
viewId: payload.viewId ? String(payload.viewId) : void 0,
|
|
1369
|
+
modelFileId: payload.modelFileId ? String(payload.modelFileId) : void 0,
|
|
1370
|
+
timestamp: payload.timestamp ? Number(payload.timestamp) : void 0
|
|
1371
|
+
});
|
|
1372
|
+
break;
|
|
1373
|
+
}
|
|
1374
|
+
case "viewer-ready" /* READY */: {
|
|
1375
|
+
const payload = data.payload;
|
|
1376
|
+
const readyPayload = {
|
|
1377
|
+
ready: true,
|
|
1378
|
+
viewId: (payload == null ? void 0 : payload.viewId) ? String(payload.viewId) : void 0,
|
|
1379
|
+
modelFileId: (payload == null ? void 0 : payload.modelFileId) ? String(payload.modelFileId) : void 0,
|
|
1380
|
+
timestamp: Number(payload == null ? void 0 : payload.timestamp) || Date.now()
|
|
1381
|
+
};
|
|
1382
|
+
this.setLoadingState({
|
|
1383
|
+
loading: false,
|
|
1384
|
+
phase: "ready",
|
|
1385
|
+
viewId: readyPayload.viewId,
|
|
1386
|
+
modelFileId: readyPayload.modelFileId,
|
|
1387
|
+
timestamp: readyPayload.timestamp
|
|
1388
|
+
});
|
|
1389
|
+
this.resolveReady(readyPayload);
|
|
1390
|
+
this._emit("viewer:ready", readyPayload);
|
|
1391
|
+
break;
|
|
1392
|
+
}
|
|
1272
1393
|
case "viewer-home-click" /* HOME_CLICK */:
|
|
1273
1394
|
this._emit("camera:home", { timestamp: Date.now() });
|
|
1274
1395
|
break;
|
|
@@ -1283,9 +1404,6 @@ var Viewer3D = class {
|
|
|
1283
1404
|
});
|
|
1284
1405
|
break;
|
|
1285
1406
|
}
|
|
1286
|
-
case "viewer-node-select" /* NODE_SELECT */:
|
|
1287
|
-
this._emit("node:select", { nodeId: String((_b = (_a = data.payload) == null ? void 0 : _a.nodeId) != null ? _b : ""), timestamp: Date.now() });
|
|
1288
|
-
break;
|
|
1289
1407
|
case "viewer-node-selection-change" /* NODE_SELECTION_CHANGE */: {
|
|
1290
1408
|
const payload = data.payload;
|
|
1291
1409
|
const rawNodeIds = payload == null ? void 0 : payload.nodeIds;
|
|
@@ -1297,7 +1415,9 @@ var Viewer3D = class {
|
|
|
1297
1415
|
break;
|
|
1298
1416
|
}
|
|
1299
1417
|
case "viewer-pan-change" /* PAN_CHANGE */:
|
|
1300
|
-
this._emit("interaction:pan-change", {
|
|
1418
|
+
this._emit("interaction:pan-change", {
|
|
1419
|
+
enabled: Boolean((_a = data.payload) == null ? void 0 : _a.enabled)
|
|
1420
|
+
});
|
|
1301
1421
|
break;
|
|
1302
1422
|
case "viewer-pdf-plan-mode" /* PDF_PLAN_MODE */: {
|
|
1303
1423
|
const payload = data.payload;
|
|
@@ -1355,7 +1475,8 @@ var Viewer3D = class {
|
|
|
1355
1475
|
}
|
|
1356
1476
|
case "viewer-tree-node-ids" /* TREE_NODE_IDS */: {
|
|
1357
1477
|
const payload = data.payload;
|
|
1358
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.nodeIds))
|
|
1478
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.nodeIds))
|
|
1479
|
+
break;
|
|
1359
1480
|
this._emit("modelTree:node-ids", {
|
|
1360
1481
|
requestId: String(payload.requestId),
|
|
1361
1482
|
nodeIds: payload.nodeIds.map(String),
|
|
@@ -1365,7 +1486,8 @@ var Viewer3D = class {
|
|
|
1365
1486
|
}
|
|
1366
1487
|
case "viewer-tree-nodes" /* TREE_NODES */: {
|
|
1367
1488
|
const payload = data.payload;
|
|
1368
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.nodes))
|
|
1489
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.nodes))
|
|
1490
|
+
break;
|
|
1369
1491
|
this._emit("modelTree:nodes", {
|
|
1370
1492
|
requestId: String(payload.requestId),
|
|
1371
1493
|
nodes: payload.nodes.filter((node) => node && typeof node === "object").map((node) => {
|
|
@@ -1391,7 +1513,8 @@ var Viewer3D = class {
|
|
|
1391
1513
|
}
|
|
1392
1514
|
case "viewer-sheets-list" /* SHEETS_LIST */: {
|
|
1393
1515
|
const payload = data.payload;
|
|
1394
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.sheets))
|
|
1516
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.sheets))
|
|
1517
|
+
break;
|
|
1395
1518
|
this._emit("sheets:list", {
|
|
1396
1519
|
requestId: String(payload.requestId),
|
|
1397
1520
|
sheets: payload.sheets.map((sheet) => {
|
|
@@ -1403,17 +1526,18 @@ var Viewer3D = class {
|
|
|
1403
1526
|
viewId: sheet.viewId ? String(sheet.viewId) : void 0
|
|
1404
1527
|
};
|
|
1405
1528
|
}),
|
|
1406
|
-
activeSheetId: (
|
|
1529
|
+
activeSheetId: (_b = payload.activeSheetId) != null ? _b : null,
|
|
1407
1530
|
timestamp: Number(payload.timestamp) || Date.now()
|
|
1408
1531
|
});
|
|
1409
1532
|
break;
|
|
1410
1533
|
}
|
|
1411
1534
|
case "viewer-object-properties-list" /* OBJECT_PROPERTIES_LIST */: {
|
|
1412
1535
|
const payload = data.payload;
|
|
1413
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.properties))
|
|
1536
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.properties))
|
|
1537
|
+
break;
|
|
1414
1538
|
this._emit("object-properties:list", {
|
|
1415
1539
|
requestId: String(payload.requestId),
|
|
1416
|
-
selectionKey: String((
|
|
1540
|
+
selectionKey: String((_c = payload.selectionKey) != null ? _c : ""),
|
|
1417
1541
|
nodeIds: Array.isArray(payload.nodeIds) ? payload.nodeIds.map(String) : [],
|
|
1418
1542
|
persistentIds: Array.isArray(payload.persistentIds) ? payload.persistentIds.map(String) : [],
|
|
1419
1543
|
properties: payload.properties.filter((item) => item && typeof item === "object").map((item) => ({ ...item })),
|
|
@@ -1423,7 +1547,8 @@ var Viewer3D = class {
|
|
|
1423
1547
|
}
|
|
1424
1548
|
case "viewer-linked-objects-list" /* LINKED_OBJECTS_LIST */: {
|
|
1425
1549
|
const payload = data.payload;
|
|
1426
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.linkedObjects))
|
|
1550
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.linkedObjects))
|
|
1551
|
+
break;
|
|
1427
1552
|
this._emit("linked-objects:list", {
|
|
1428
1553
|
requestId: String(payload.requestId),
|
|
1429
1554
|
linkedObjects: payload.linkedObjects.filter((item) => item && typeof item === "object").map((item) => ({ ...item })),
|
|
@@ -1433,11 +1558,12 @@ var Viewer3D = class {
|
|
|
1433
1558
|
}
|
|
1434
1559
|
case "viewer-states-objects-list" /* STATES_OBJECTS_LIST */: {
|
|
1435
1560
|
const payload = data.payload;
|
|
1436
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.statesObjects))
|
|
1561
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.statesObjects))
|
|
1562
|
+
break;
|
|
1437
1563
|
this._emit("states-objects:list", {
|
|
1438
1564
|
requestId: String(payload.requestId),
|
|
1439
1565
|
statesObjects: payload.statesObjects.map((item) => {
|
|
1440
|
-
var _a2, _b2, _c2,
|
|
1566
|
+
var _a2, _b2, _c2, _d, _e, _f, _g;
|
|
1441
1567
|
return {
|
|
1442
1568
|
id: String((_a2 = item.id) != null ? _a2 : ""),
|
|
1443
1569
|
name: String((_b2 = item.name) != null ? _b2 : ""),
|
|
@@ -1450,7 +1576,7 @@ var Viewer3D = class {
|
|
|
1450
1576
|
};
|
|
1451
1577
|
}) : [],
|
|
1452
1578
|
states: {
|
|
1453
|
-
color: String((
|
|
1579
|
+
color: String((_e = (_d = item.states) == null ? void 0 : _d.color) != null ? _e : ""),
|
|
1454
1580
|
type: String((_g = (_f = item.states) == null ? void 0 : _f.type) != null ? _g : "")
|
|
1455
1581
|
}
|
|
1456
1582
|
};
|
|
@@ -1461,7 +1587,8 @@ var Viewer3D = class {
|
|
|
1461
1587
|
}
|
|
1462
1588
|
case "viewer-markup-list" /* MARKUP_LIST */: {
|
|
1463
1589
|
const payload = data.payload;
|
|
1464
|
-
if (!payload || !payload.requestId || !Array.isArray(payload.markups))
|
|
1590
|
+
if (!payload || !payload.requestId || !Array.isArray(payload.markups))
|
|
1591
|
+
break;
|
|
1465
1592
|
this._emit("markup:list", {
|
|
1466
1593
|
requestId: String(payload.requestId),
|
|
1467
1594
|
markups: payload.markups.map((markup) => {
|
|
@@ -1530,6 +1657,36 @@ var Viewer3D = class {
|
|
|
1530
1657
|
var _a;
|
|
1531
1658
|
return (_a = this.options.url) != null ? _a : null;
|
|
1532
1659
|
}
|
|
1660
|
+
on(event, cb) {
|
|
1661
|
+
return this._on(event, cb);
|
|
1662
|
+
}
|
|
1663
|
+
off(event, cb) {
|
|
1664
|
+
this._off(event, cb);
|
|
1665
|
+
}
|
|
1666
|
+
getLoadingState() {
|
|
1667
|
+
return { ...this.loadingState };
|
|
1668
|
+
}
|
|
1669
|
+
ready(options) {
|
|
1670
|
+
if (this.viewerReady && this.readyPayload) {
|
|
1671
|
+
return Promise.resolve({ ...this.readyPayload });
|
|
1672
|
+
}
|
|
1673
|
+
const timeoutMs = options == null ? void 0 : options.timeoutMs;
|
|
1674
|
+
return new Promise((resolve, reject) => {
|
|
1675
|
+
const waiter = {
|
|
1676
|
+
resolve: (payload) => resolve({ ...payload }),
|
|
1677
|
+
reject
|
|
1678
|
+
};
|
|
1679
|
+
if (typeof timeoutMs === "number" && timeoutMs > 0) {
|
|
1680
|
+
waiter.timer = setTimeout(() => {
|
|
1681
|
+
this.readyWaiters = this.readyWaiters.filter(
|
|
1682
|
+
(item) => item !== waiter
|
|
1683
|
+
);
|
|
1684
|
+
reject(new Error("Timeout while waiting for viewer to be ready"));
|
|
1685
|
+
}, timeoutMs);
|
|
1686
|
+
}
|
|
1687
|
+
this.readyWaiters.push(waiter);
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1533
1690
|
// ===== lifecycle =====
|
|
1534
1691
|
init() {
|
|
1535
1692
|
if (this.initialized) return;
|
|
@@ -1541,7 +1698,12 @@ var Viewer3D = class {
|
|
|
1541
1698
|
async render(file) {
|
|
1542
1699
|
this.ensureInit();
|
|
1543
1700
|
if (this.iframeEl) return;
|
|
1701
|
+
this.resetReadyState();
|
|
1544
1702
|
if (!this.options.url) return this.files.render(file);
|
|
1703
|
+
this.setLoadingState({
|
|
1704
|
+
loading: true,
|
|
1705
|
+
phase: "loading"
|
|
1706
|
+
});
|
|
1545
1707
|
const iframe = document.createElement("iframe");
|
|
1546
1708
|
iframe.src = this.withInitialOptions(this.options.url);
|
|
1547
1709
|
iframe.style.border = "none";
|
|
@@ -1549,13 +1711,19 @@ var Viewer3D = class {
|
|
|
1549
1711
|
iframe.style.height = this.options.height || "100%";
|
|
1550
1712
|
iframe.width = this.options.width || "100%";
|
|
1551
1713
|
iframe.height = this.options.height || "100%";
|
|
1552
|
-
if (this.options.sandbox)
|
|
1714
|
+
if (this.options.sandbox)
|
|
1715
|
+
iframe.setAttribute("sandbox", this.options.sandbox);
|
|
1553
1716
|
this.containerEl.appendChild(iframe);
|
|
1554
1717
|
this.iframeEl = iframe;
|
|
1555
1718
|
}
|
|
1556
1719
|
open(url) {
|
|
1557
1720
|
this.ensureInit();
|
|
1558
1721
|
this.options.url = url;
|
|
1722
|
+
this.resetReadyState();
|
|
1723
|
+
this.setLoadingState({
|
|
1724
|
+
loading: true,
|
|
1725
|
+
phase: "loading"
|
|
1726
|
+
});
|
|
1559
1727
|
const finalUrl = this.withInitialOptions(url);
|
|
1560
1728
|
if (!this.iframeEl) {
|
|
1561
1729
|
this.render();
|
|
@@ -1574,16 +1742,27 @@ var Viewer3D = class {
|
|
|
1574
1742
|
this.iframeEl = null;
|
|
1575
1743
|
this.containerEl = null;
|
|
1576
1744
|
this.initialized = false;
|
|
1745
|
+
this.rejectReadyWaiters(
|
|
1746
|
+
new Error("Viewer was destroyed before becoming ready")
|
|
1747
|
+
);
|
|
1577
1748
|
}
|
|
1578
1749
|
ensureInit() {
|
|
1579
|
-
if (!this.initialized)
|
|
1750
|
+
if (!this.initialized)
|
|
1751
|
+
throw new Error("Call viewer.init() before using viewer");
|
|
1580
1752
|
}
|
|
1581
1753
|
withInitialOptions(url) {
|
|
1754
|
+
var _a;
|
|
1582
1755
|
try {
|
|
1583
1756
|
const parsedUrl = new URL(url, window.location.href);
|
|
1584
1757
|
const initialToolbar = this.normalizeInitialToolbar();
|
|
1585
1758
|
if (initialToolbar) {
|
|
1586
|
-
parsedUrl.searchParams.set(
|
|
1759
|
+
parsedUrl.searchParams.set(
|
|
1760
|
+
"useToolbar",
|
|
1761
|
+
JSON.stringify(initialToolbar)
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
if (((_a = this.options.ui) == null ? void 0 : _a.loadingIndicator) === false) {
|
|
1765
|
+
parsedUrl.searchParams.set("loadingIndicator", "false");
|
|
1587
1766
|
}
|
|
1588
1767
|
return parsedUrl.toString();
|
|
1589
1768
|
} catch {
|
|
@@ -1597,17 +1776,25 @@ var Viewer3D = class {
|
|
|
1597
1776
|
return { [initialToolbar]: true };
|
|
1598
1777
|
}
|
|
1599
1778
|
if (Array.isArray(initialToolbar)) {
|
|
1600
|
-
return initialToolbar.reduce(
|
|
1601
|
-
result
|
|
1602
|
-
|
|
1603
|
-
|
|
1779
|
+
return initialToolbar.reduce(
|
|
1780
|
+
(result, target) => {
|
|
1781
|
+
result[target] = true;
|
|
1782
|
+
return result;
|
|
1783
|
+
},
|
|
1784
|
+
{}
|
|
1785
|
+
);
|
|
1604
1786
|
}
|
|
1605
|
-
const entries = Object.entries(initialToolbar).filter(
|
|
1787
|
+
const entries = Object.entries(initialToolbar).filter(
|
|
1788
|
+
([, enabled]) => enabled === true
|
|
1789
|
+
);
|
|
1606
1790
|
if (entries.length === 0) return null;
|
|
1607
|
-
return entries.reduce(
|
|
1608
|
-
result[target]
|
|
1609
|
-
|
|
1610
|
-
|
|
1791
|
+
return entries.reduce(
|
|
1792
|
+
(result, [target]) => {
|
|
1793
|
+
result[target] = true;
|
|
1794
|
+
return result;
|
|
1795
|
+
},
|
|
1796
|
+
{}
|
|
1797
|
+
);
|
|
1611
1798
|
}
|
|
1612
1799
|
// ===== typed internal events used by modules =====
|
|
1613
1800
|
_on(event, cb) {
|
|
@@ -1619,6 +1806,30 @@ var Viewer3D = class {
|
|
|
1619
1806
|
_emit(event, payload) {
|
|
1620
1807
|
this.emitter.emit(event, payload);
|
|
1621
1808
|
}
|
|
1809
|
+
resetReadyState() {
|
|
1810
|
+
this.viewerReady = false;
|
|
1811
|
+
this.readyPayload = null;
|
|
1812
|
+
}
|
|
1813
|
+
setLoadingState(payload) {
|
|
1814
|
+
this.loadingState = { ...payload };
|
|
1815
|
+
this._emit("loading:change", this.loadingState);
|
|
1816
|
+
}
|
|
1817
|
+
resolveReady(payload) {
|
|
1818
|
+
this.viewerReady = true;
|
|
1819
|
+
this.readyPayload = { ...payload };
|
|
1820
|
+
this.readyWaiters.forEach((waiter) => {
|
|
1821
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
1822
|
+
waiter.resolve(payload);
|
|
1823
|
+
});
|
|
1824
|
+
this.readyWaiters = [];
|
|
1825
|
+
}
|
|
1826
|
+
rejectReadyWaiters(error) {
|
|
1827
|
+
this.readyWaiters.forEach((waiter) => {
|
|
1828
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
1829
|
+
waiter.reject(error);
|
|
1830
|
+
});
|
|
1831
|
+
this.readyWaiters = [];
|
|
1832
|
+
}
|
|
1622
1833
|
// ===== postMessage bridge =====
|
|
1623
1834
|
postToViewer(type, payload) {
|
|
1624
1835
|
var _a;
|