@preference-sl/pref-viewer 2.10.0-beta.14 → 2.10.0-beta.16
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/package.json +1 -1
- package/src/index.js +182 -45
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -47,7 +47,9 @@ import { DracoCompression } from "@babylonjs/core/Meshes/Compression/dracoCompre
|
|
|
47
47
|
import { initDb, loadModel } from "./gltf-storage.js";
|
|
48
48
|
|
|
49
49
|
class PrefViewer extends HTMLElement {
|
|
50
|
-
|
|
50
|
+
initialized = false;
|
|
51
|
+
loaded = false;
|
|
52
|
+
loading = false;
|
|
51
53
|
|
|
52
54
|
#data = {
|
|
53
55
|
containers: {
|
|
@@ -162,7 +164,7 @@ class PrefViewer extends HTMLElement {
|
|
|
162
164
|
break;
|
|
163
165
|
case "show-model":
|
|
164
166
|
data = value.toLowerCase?.() === "true";
|
|
165
|
-
if (this
|
|
167
|
+
if (this.initialized) {
|
|
166
168
|
data ? this.showModel() : this.hideModel();
|
|
167
169
|
} else {
|
|
168
170
|
this.#data.containers.model.show = data;
|
|
@@ -170,7 +172,7 @@ class PrefViewer extends HTMLElement {
|
|
|
170
172
|
break;
|
|
171
173
|
case "show-scene":
|
|
172
174
|
data = value.toLowerCase?.() === "true";
|
|
173
|
-
if (this
|
|
175
|
+
if (this.initialized) {
|
|
174
176
|
data ? this.showScene() : this.hideScene();
|
|
175
177
|
} else {
|
|
176
178
|
this.#data.containers.environment.show = data;
|
|
@@ -184,18 +186,19 @@ class PrefViewer extends HTMLElement {
|
|
|
184
186
|
const error = 'PrefViewer: provide "models" as array of model and environment';
|
|
185
187
|
console.error(error);
|
|
186
188
|
this.dispatchEvent(
|
|
187
|
-
new CustomEvent("
|
|
188
|
-
detail: { error: new Error(error) },
|
|
189
|
+
new CustomEvent("scene-error", {
|
|
189
190
|
bubbles: true,
|
|
191
|
+
cancelable: false,
|
|
190
192
|
composed: true,
|
|
193
|
+
detail: { error: new Error(error) },
|
|
191
194
|
})
|
|
192
195
|
);
|
|
193
196
|
return false;
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
this.#initializeBabylon();
|
|
200
|
+
this.initialized = true;
|
|
197
201
|
this.#loadContainers(true, true, true);
|
|
198
|
-
this.#initialized = true;
|
|
199
202
|
}
|
|
200
203
|
|
|
201
204
|
disconnectedCallback() {
|
|
@@ -225,14 +228,115 @@ class PrefViewer extends HTMLElement {
|
|
|
225
228
|
this.shadowRoot.append(this.#wrapper);
|
|
226
229
|
}
|
|
227
230
|
|
|
231
|
+
#setStatusSceneLoading() {
|
|
232
|
+
this.loaded = false;
|
|
233
|
+
this.loading = true;
|
|
234
|
+
if (this.hasAttribute("loaded")) {
|
|
235
|
+
this.removeAttribute("loaded");
|
|
236
|
+
}
|
|
237
|
+
this.setAttribute("loading", "");
|
|
238
|
+
this.dispatchEvent(
|
|
239
|
+
new CustomEvent("scene-loading", {
|
|
240
|
+
bubbles: true,
|
|
241
|
+
cancelable: false,
|
|
242
|
+
composed: true,
|
|
243
|
+
})
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
#setStatusSceneLoaded() {
|
|
248
|
+
this.loaded = true;
|
|
249
|
+
this.loading = false;
|
|
250
|
+
|
|
251
|
+
const toLoadDetail = {
|
|
252
|
+
container_model: !!this.#data.containers.model.changed,
|
|
253
|
+
container_environment: !!this.#data.containers.environment.changed,
|
|
254
|
+
container_materials: !!this.#data.containers.materials.changed,
|
|
255
|
+
options_camera: !!this.#data.options.camera.changed,
|
|
256
|
+
options_inneWallMaterial: !!this.#data.options.materials.innerWall.changed,
|
|
257
|
+
options_outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
|
|
258
|
+
options_innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
|
|
259
|
+
options_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
|
|
260
|
+
};
|
|
261
|
+
const loadedDetail = {
|
|
262
|
+
container_model: !!this.#data.containers.model.changed?.success,
|
|
263
|
+
container_environment: !!this.#data.containers.environment.changed?.success,
|
|
264
|
+
container_materials: !!this.#data.containers.materials.changed?.success,
|
|
265
|
+
options_camera: !!this.#data.options.camera.changed?.success,
|
|
266
|
+
options_inneWallMaterial: !!this.#data.options.materials.innerWall.changed?.success,
|
|
267
|
+
options_outerWallMaterial: !!this.#data.options.materials.outerWall.changed?.success,
|
|
268
|
+
options_innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed?.success,
|
|
269
|
+
options_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed?.success,
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const detail = {
|
|
273
|
+
tried: toLoadDetail,
|
|
274
|
+
success: loadedDetail,
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
if (this.hasAttribute("loading")) {
|
|
278
|
+
this.removeAttribute("loading");
|
|
279
|
+
}
|
|
280
|
+
this.setAttribute("loaded", "");
|
|
281
|
+
this.dispatchEvent(
|
|
282
|
+
new CustomEvent("scene-loaded", {
|
|
283
|
+
bubbles: true,
|
|
284
|
+
cancelable: false,
|
|
285
|
+
composed: true,
|
|
286
|
+
detail: detail,
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
#setStatusOptionsLoading() {
|
|
292
|
+
this.dispatchEvent(
|
|
293
|
+
new CustomEvent("options-loading", {
|
|
294
|
+
bubbles: true,
|
|
295
|
+
cancelable: false,
|
|
296
|
+
composed: true,
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
#setStatusOptionsLoaded() {
|
|
302
|
+
|
|
303
|
+
const toLoadDetail = {
|
|
304
|
+
inneWallMaterial: !!this.#data.options.materials.innerWall.changed,
|
|
305
|
+
outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
|
|
306
|
+
innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
|
|
307
|
+
outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
|
|
308
|
+
};
|
|
309
|
+
const loadedDetail = {
|
|
310
|
+
inneWallMaterial: !!this.#data.options.materials.innerWall.changed?.success,
|
|
311
|
+
outerWallMaterial: !!this.#data.options.materials.outerWall.changed?.success,
|
|
312
|
+
innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed?.success,
|
|
313
|
+
_outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed?.success,
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const detail = {
|
|
317
|
+
tried: toLoadDetail,
|
|
318
|
+
success: loadedDetail,
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
this.dispatchEvent(
|
|
322
|
+
new CustomEvent("options-loaded", {
|
|
323
|
+
bubbles: true,
|
|
324
|
+
cancelable: false,
|
|
325
|
+
composed: true,
|
|
326
|
+
detail: detail,
|
|
327
|
+
})
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
228
331
|
// Data
|
|
229
332
|
#checkCameraChanged(options) {
|
|
230
333
|
if (!options || !options.camera) {
|
|
231
334
|
return false;
|
|
232
335
|
}
|
|
233
|
-
|
|
234
|
-
this.#data.options.camera.
|
|
235
|
-
|
|
336
|
+
const cameraChanged = options.camera && options.camera !== this.#data.options.camera.value ? true : false
|
|
337
|
+
this.#data.options.camera.changed = cameraChanged ? { oldValue: this.#data.options.camera.value, success: false } : false;
|
|
338
|
+
this.#data.options.camera.value = cameraChanged ? options.camera : this.#data.options.camera.value;
|
|
339
|
+
return cameraChanged;
|
|
236
340
|
}
|
|
237
341
|
|
|
238
342
|
#checkMaterialsChanged(options) {
|
|
@@ -242,8 +346,9 @@ class PrefViewer extends HTMLElement {
|
|
|
242
346
|
let someChanged = false;
|
|
243
347
|
Object.keys(this.#data.options.materials).forEach((material) => {
|
|
244
348
|
const key = `${material}Material`;
|
|
245
|
-
|
|
246
|
-
this.#data.options.materials[material].
|
|
349
|
+
const materialChanged = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
|
|
350
|
+
this.#data.options.materials[material].changed = materialChanged ? { oldValue: this.#data.options.materials[material].value, success: false } : false;
|
|
351
|
+
this.#data.options.materials[material].value = materialChanged ? options[key] : this.#data.options.materials[material].value;
|
|
247
352
|
someChanged = someChanged || this.#data.options.materials[material].changed;
|
|
248
353
|
});
|
|
249
354
|
return someChanged;
|
|
@@ -252,6 +357,7 @@ class PrefViewer extends HTMLElement {
|
|
|
252
357
|
#storeChangedFlagsForContainer(container) {
|
|
253
358
|
container.timestamp = container.changed.timestamp;
|
|
254
359
|
container.size = container.changed.size;
|
|
360
|
+
container.changed.success = true;
|
|
255
361
|
}
|
|
256
362
|
|
|
257
363
|
#resetChangedFlags() {
|
|
@@ -340,8 +446,8 @@ class PrefViewer extends HTMLElement {
|
|
|
340
446
|
this.#camera.lowerRadiusLimit = 5;
|
|
341
447
|
this.#camera.upperRadiusLimit = 20;
|
|
342
448
|
this.#camera.metadata = { locked: false }
|
|
343
|
-
this.#camera = this.#camera;
|
|
344
449
|
this.#camera.attachControl(this.#canvas, true);
|
|
450
|
+
this.#scene.activeCamera = this.#camera;
|
|
345
451
|
}
|
|
346
452
|
|
|
347
453
|
#createLights() {
|
|
@@ -398,13 +504,13 @@ class PrefViewer extends HTMLElement {
|
|
|
398
504
|
if (xhr.status === 200) {
|
|
399
505
|
const size = parseInt(xhr.getResponseHeader("Content-Length"));
|
|
400
506
|
const timestamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
|
|
401
|
-
resolve(size, timestamp);
|
|
507
|
+
resolve([size, timestamp]);
|
|
402
508
|
} else {
|
|
403
|
-
resolve(0, null);
|
|
509
|
+
resolve([0, null]);
|
|
404
510
|
}
|
|
405
511
|
};
|
|
406
512
|
xhr.onerror = () => {
|
|
407
|
-
resolve(0, null);
|
|
513
|
+
resolve([0, null]);
|
|
408
514
|
};
|
|
409
515
|
xhr.send();
|
|
410
516
|
});
|
|
@@ -458,6 +564,7 @@ class PrefViewer extends HTMLElement {
|
|
|
458
564
|
}
|
|
459
565
|
|
|
460
566
|
#setOptionsMaterial(optionMaterial) {
|
|
567
|
+
debugger;
|
|
461
568
|
if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
|
|
462
569
|
return false;
|
|
463
570
|
}
|
|
@@ -468,10 +575,10 @@ class PrefViewer extends HTMLElement {
|
|
|
468
575
|
}
|
|
469
576
|
|
|
470
577
|
const containers = [];
|
|
471
|
-
if (this.#data.containers.model.assetContainer && (this.#data.containers.model.
|
|
578
|
+
if (this.#data.containers.model.assetContainer && (this.#data.containers.model.changed || this.#data.containers.materials.changed || optionMaterial.changed)) {
|
|
472
579
|
containers.push(this.#data.containers.model.assetContainer);
|
|
473
580
|
}
|
|
474
|
-
if (this.#data.containers.environment.assetContainer && (this.#data.containers.environment.
|
|
581
|
+
if (this.#data.containers.environment.assetContainer && (this.#data.containers.environment.changed || this.#data.containers.materials.changed || optionMaterial.changed)) {
|
|
475
582
|
containers.push(this.#data.containers.environment.assetContainer);
|
|
476
583
|
}
|
|
477
584
|
if (containers.length === 0) {
|
|
@@ -488,6 +595,12 @@ class PrefViewer extends HTMLElement {
|
|
|
488
595
|
})
|
|
489
596
|
);
|
|
490
597
|
|
|
598
|
+
if (someSetted) {
|
|
599
|
+
optionMaterial.changed.success = true;
|
|
600
|
+
} else {
|
|
601
|
+
optionMaterial.value = optionMaterial.changed.oldValue;
|
|
602
|
+
}
|
|
603
|
+
|
|
491
604
|
return someSetted;
|
|
492
605
|
}
|
|
493
606
|
|
|
@@ -501,21 +614,32 @@ class PrefViewer extends HTMLElement {
|
|
|
501
614
|
}
|
|
502
615
|
|
|
503
616
|
#setOptionsCamera() {
|
|
504
|
-
if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.
|
|
617
|
+
if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.changed && !this.#data.containers.environment.changed)) {
|
|
505
618
|
return false;
|
|
506
619
|
}
|
|
507
620
|
|
|
508
|
-
let camera = this.#data.containers.model.assetContainer?.cameras.find((
|
|
621
|
+
let camera = this.#data.containers.model.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.value) || this.#data.containers.environment.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.value) || null;
|
|
509
622
|
if (!camera) {
|
|
510
|
-
|
|
623
|
+
if (this.#data.options.camera.changed?.oldValue && this.#data.options.camera.changed?.oldValue !== this.#data.options.camera.value) {
|
|
624
|
+
camera = this.#data.containers.model.assetContainer?.cameras.find((thisCamera) => thisCamera.name === this.#data.options.camera.changed.oldValue) || this.#data.containers.environment.assetContainer?.cameras.find((thisCamera) => thisCamera.name === his.#data.options.camera.changed.oldValue) || null;
|
|
625
|
+
}
|
|
626
|
+
if (camera){
|
|
627
|
+
camera.metadata = { locked: this.#data.options.camera.changed.oldLocked };
|
|
628
|
+
this.#data.options.camera.value = this.#data.options.camera.changed.oldValue;
|
|
629
|
+
this.#data.options.camera.locked = this.#data.options.camera.changed.oldLocked;
|
|
630
|
+
} else {
|
|
631
|
+
camera = this.#camera;
|
|
632
|
+
this.#data.options.camera.value = null;
|
|
633
|
+
this.#data.options.camera.locked = this.#camera.metadata.locked;
|
|
634
|
+
}
|
|
635
|
+
this.#data.options.camera.changed.success = false;
|
|
636
|
+
} else {
|
|
637
|
+
camera.metadata = { locked: this.#data.options.camera.locked };
|
|
511
638
|
}
|
|
512
|
-
|
|
513
|
-
camera.metadata = { locked: this.#data.options.camera.locked };
|
|
514
|
-
if (!this.#data.options.camera.locked) {
|
|
639
|
+
if (!this.#data.options.camera.locked && this.#data.options.camera.value !== null) {
|
|
515
640
|
camera.attachControl(this.#canvas, true);
|
|
516
641
|
}
|
|
517
642
|
this.#scene.activeCamera = camera;
|
|
518
|
-
|
|
519
643
|
return true;
|
|
520
644
|
}
|
|
521
645
|
|
|
@@ -559,7 +683,7 @@ class PrefViewer extends HTMLElement {
|
|
|
559
683
|
if (object.timestamp === container.timestamp) {
|
|
560
684
|
return false;
|
|
561
685
|
} else {
|
|
562
|
-
container.changed = { timestamp: object.timestamp, size: object.size };
|
|
686
|
+
container.changed = { timestamp: object.timestamp, size: object.size, success: false };
|
|
563
687
|
}
|
|
564
688
|
}
|
|
565
689
|
|
|
@@ -578,17 +702,17 @@ class PrefViewer extends HTMLElement {
|
|
|
578
702
|
if (container.timestamp === null && container.size === size) {
|
|
579
703
|
return false;
|
|
580
704
|
} else {
|
|
581
|
-
container.changed = { timestamp: null, size: size };
|
|
705
|
+
container.changed = { timestamp: null, size: size, success: false };
|
|
582
706
|
}
|
|
583
707
|
}
|
|
584
708
|
} else {
|
|
585
709
|
const extMatch = source.match(/\.(gltf|glb)(\?|#|$)/i);
|
|
586
710
|
extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
|
|
587
|
-
const
|
|
588
|
-
if (container.
|
|
711
|
+
const [fileSize, fileTimestamp ] = await this.#getServerFileDataHeader(source);
|
|
712
|
+
if (container.size === fileSize && container.timestamp === fileTimestamp) {
|
|
589
713
|
return false;
|
|
590
714
|
} else {
|
|
591
|
-
container.changed = { timestamp: fileTimestamp, size: fileSize };
|
|
715
|
+
container.changed = { timestamp: fileTimestamp, size: fileSize, success: false };
|
|
592
716
|
}
|
|
593
717
|
}
|
|
594
718
|
|
|
@@ -605,11 +729,25 @@ class PrefViewer extends HTMLElement {
|
|
|
605
729
|
return LoadAssetContainerAsync(file || source, this.#scene, options);
|
|
606
730
|
}
|
|
607
731
|
|
|
608
|
-
async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
|
|
732
|
+
async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
|
|
609
733
|
const promiseArray = [];
|
|
610
734
|
promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
|
|
611
735
|
promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
|
|
612
736
|
promiseArray.push(loadMaterials ? this.#loadAssetContainer(this.#data.containers.materials) : false);
|
|
737
|
+
debugger;
|
|
738
|
+
const loadingDetail = {
|
|
739
|
+
model: !!this.#data.containers.model.changed,
|
|
740
|
+
environment: !!this.#data.containers.environment.changed,
|
|
741
|
+
materials: !!this.#data.containers.materials.changed,
|
|
742
|
+
options: {
|
|
743
|
+
camera: !!this.#data.options.camera.changed,
|
|
744
|
+
inneWallMaterial: !!this.#data.options.materials.innerWall.changed,
|
|
745
|
+
outerWallMaterial: !!this.#data.options.materials.outerWall.changed,
|
|
746
|
+
innerFloorMaterial: !!this.#data.options.materials.innerFloor.changed,
|
|
747
|
+
outerFloorMaterial: !!this.#data.options.materials.outerFloor.changed,
|
|
748
|
+
},
|
|
749
|
+
};
|
|
750
|
+
this.#setStatusSceneLoading(loadingDetail);
|
|
613
751
|
|
|
614
752
|
Promise.allSettled(promiseArray)
|
|
615
753
|
.then(async (values) => {
|
|
@@ -639,24 +777,18 @@ class PrefViewer extends HTMLElement {
|
|
|
639
777
|
this.#setOptionsMaterials();
|
|
640
778
|
this.#setOptionsCamera();
|
|
641
779
|
this.#setVisibilityOfWallAndFloorInModel();
|
|
642
|
-
|
|
780
|
+
this.#setStatusSceneLoaded();
|
|
643
781
|
this.#resetChangedFlags();
|
|
644
|
-
|
|
645
|
-
this.dispatchEvent(
|
|
646
|
-
new CustomEvent("model-loaded", {
|
|
647
|
-
detail: { success: "" },
|
|
648
|
-
bubbles: true,
|
|
649
|
-
composed: true,
|
|
650
|
-
})
|
|
651
|
-
);
|
|
652
782
|
})
|
|
653
783
|
.catch((error) => {
|
|
784
|
+
this.loaded = true;
|
|
654
785
|
console.error("PrefViewer: failed to load model", error);
|
|
655
786
|
this.dispatchEvent(
|
|
656
|
-
new CustomEvent("
|
|
657
|
-
detail: { error: error },
|
|
787
|
+
new CustomEvent("scene-error", {
|
|
658
788
|
bubbles: true,
|
|
789
|
+
cancelable: false,
|
|
659
790
|
composed: true,
|
|
791
|
+
detail: { error: error },
|
|
660
792
|
})
|
|
661
793
|
);
|
|
662
794
|
});
|
|
@@ -682,13 +814,16 @@ class PrefViewer extends HTMLElement {
|
|
|
682
814
|
this.#checkMaterialsChanged(config.options);
|
|
683
815
|
}
|
|
684
816
|
|
|
685
|
-
this
|
|
817
|
+
this.initialized && this.#loadContainers(true, true, true);
|
|
686
818
|
}
|
|
687
819
|
|
|
688
820
|
setOptions(options) {
|
|
689
821
|
if (!options) {
|
|
690
822
|
return false;
|
|
691
823
|
}
|
|
824
|
+
|
|
825
|
+
this.#setStatusOptionsLoading();
|
|
826
|
+
|
|
692
827
|
let someSetted = false;
|
|
693
828
|
if (this.#checkCameraChanged(options)) {
|
|
694
829
|
someSetted = someSetted || this.#setOptionsCamera();
|
|
@@ -696,8 +831,10 @@ class PrefViewer extends HTMLElement {
|
|
|
696
831
|
if (this.#checkMaterialsChanged(options)) {
|
|
697
832
|
someSetted = someSetted || this.#setOptionsMaterials();
|
|
698
833
|
}
|
|
834
|
+
|
|
835
|
+
this.#setStatusOptionsLoaded();
|
|
699
836
|
this.#resetChangedFlags();
|
|
700
|
-
|
|
837
|
+
|
|
701
838
|
return someSetted;
|
|
702
839
|
}
|
|
703
840
|
|
|
@@ -708,7 +845,7 @@ class PrefViewer extends HTMLElement {
|
|
|
708
845
|
}
|
|
709
846
|
this.#data.containers.model.storage = model.storage || null;
|
|
710
847
|
this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
|
|
711
|
-
this
|
|
848
|
+
this.initialized && this.#loadContainers(true, false, false);
|
|
712
849
|
}
|
|
713
850
|
|
|
714
851
|
loadScene(scene) {
|
|
@@ -718,7 +855,7 @@ class PrefViewer extends HTMLElement {
|
|
|
718
855
|
}
|
|
719
856
|
this.#data.containers.environment.storage = scene.storage || null;
|
|
720
857
|
this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
|
|
721
|
-
this
|
|
858
|
+
this.initialized && this.#loadContainers(false, true, false);
|
|
722
859
|
}
|
|
723
860
|
|
|
724
861
|
showModel() {
|