@preference-sl/pref-viewer 2.13.0-beta.0 → 2.13.0-beta.2
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 +5 -5
- package/src/babylonjs-animation-controller.js +2 -2
- package/src/babylonjs-controller.js +522 -274
- package/src/index.js +2 -0
- package/src/localization/i18n.js +94 -0
- package/src/localization/translations.js +104 -0
- package/src/pref-viewer-3d-data.js +28 -0
- package/src/pref-viewer-3d.js +46 -10
- package/src/pref-viewer-menu-3d.js +557 -0
- package/src/pref-viewer-task.js +1 -0
- package/src/pref-viewer.js +532 -200
- package/src/styles.js +302 -10
package/src/pref-viewer.js
CHANGED
|
@@ -1,94 +1,86 @@
|
|
|
1
1
|
import PrefViewerTask from "./pref-viewer-task.js";
|
|
2
2
|
import { PrefViewerStyles } from "./styles.js";
|
|
3
|
+
import { DEFAULT_LOCALE, resolveLocale, setLocale, SUPPORTED_LOCALES } from "./localization/i18n.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* PrefViewer - Custom Web Component for
|
|
6
|
+
* PrefViewer - Custom Web Component for immersive 2D/3D product visualization with localization, persistence, and download tooling.
|
|
6
7
|
*
|
|
7
8
|
* Overview:
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
9
|
+
* - Hosts synchronized 2D (SVG) and 3D (Babylon.js) canvases plus a render-settings menu inside a single shadow DOM wrapper.
|
|
10
|
+
* - Queues mutations (config/model/scene/materials/drawing/options/culture) to guarantee deterministic execution and avoid race conditions.
|
|
11
|
+
* - Normalizes remote URLs, Base64 payloads, and IndexedDB lookups before forwarding jobs to the BabylonJSController stack.
|
|
12
|
+
* - Persists the active locale to localStorage, mirrors it to PrefViewerMenu3D, and keeps the shared i18n module in sync with the chosen culture.
|
|
13
|
+
* - Surfaces a dialog API that powers built-in download flows (GLB, glTF+ZIP, USDZ) for model-only, scene-only, or combined asset exports.
|
|
14
|
+
* - Emits granular lifecycle custom events so host applications can react to loading progress, drawing zoom changes, and menu interactions.
|
|
15
|
+
* - Exposes imperative methods for toggling visibility, updating options, switching modes, and requesting downloads without attribute juggling.
|
|
16
|
+
* - Automatically reflects supported attributes back to the DOM so templates, frameworks, and manual scripting stay aligned with viewer state.
|
|
15
17
|
*
|
|
16
18
|
* Usage:
|
|
17
|
-
* -
|
|
18
|
-
* -
|
|
19
|
-
* -
|
|
19
|
+
* - Drop the `<pref-viewer>` custom element into any document or framework wrapper and supply configuration via attributes or setters.
|
|
20
|
+
* - Feed serialized JSON strings or plain objects to `loadConfig`, `loadModel`, `loadScene`, `loadMaterials`, `loadDrawing`, or `setOptions`.
|
|
21
|
+
* - Drive localization by setting the `culture` attribute/property or invoking `setCulture("es-ES")`, which propagates to the menu and dialog copy.
|
|
22
|
+
* - Trigger downloads through the provided public methods or open the interactive dialog with `openDialog()` for user-driven selection.
|
|
23
|
+
* - Listen for `scene-loading`, `scene-loaded`, `drawing-loading`, `drawing-loaded`, and `drawing-zoom-changed` to integrate with surrounding UX.
|
|
20
24
|
*
|
|
21
25
|
* Reactive Attributes:
|
|
22
|
-
* - config:
|
|
23
|
-
* - model:
|
|
24
|
-
* -
|
|
25
|
-
* -
|
|
26
|
-
* -
|
|
27
|
-
* -
|
|
28
|
-
* - mode: Viewer mode ("2d" or "3d").
|
|
26
|
+
* - config: Configuration descriptor that can bundle model/scene/materials/drawing/culture hints.
|
|
27
|
+
* - model / scene / materials / drawing: Independent asset entry points (URLs, Base64, indexed data) for each subsystem.
|
|
28
|
+
* - options: JSON describing render toggles (AA, SSAO, IBL, shadows) plus misc viewer knobs.
|
|
29
|
+
* - culture: Locale identifier (RFC-5646 style) that resolves against `SUPPORTED_LOCALES` before applying.
|
|
30
|
+
* - mode: Switches between `2d` and `3d`, automatically hiding/showing the relevant subcomponents and menu states.
|
|
31
|
+
* - show-model / show-scene: Boolean flags to toggle visibility without reloading the underlying resources.
|
|
29
32
|
*
|
|
30
|
-
* Public Methods:
|
|
31
|
-
* - loadConfig
|
|
32
|
-
* -
|
|
33
|
-
* -
|
|
34
|
-
* -
|
|
35
|
-
* -
|
|
36
|
-
* -
|
|
37
|
-
* - setMode(mode): Sets the viewer mode to "2d" or "3d" and updates component visibility.
|
|
38
|
-
* - showModel(): Shows the 3D model.
|
|
39
|
-
* - hideModel(): Hides the 3D model.
|
|
40
|
-
* - showScene(): Shows the 3D environment/scene.
|
|
41
|
-
* - hideScene(): Hides the 3D environment/scene.
|
|
42
|
-
* - zoomCenter(): Centers the 2D drawing view.
|
|
43
|
-
* - zoomExtentsAll(): Zooms the 2D drawing to fit all content.
|
|
44
|
-
* - zoomIn(): Zooms in on the 2D drawing.
|
|
45
|
-
* - zoomOut(): Zooms out of the 2D drawing.
|
|
46
|
-
* - downloadModelGLB(): Downloads the current 3D model as a GLB file.
|
|
47
|
-
* - downloadModelGLTF(): Downloads the current 3D model as a glTF ZIP file.
|
|
48
|
-
* - downloadModelUSDZ(): Downloads the current 3D model as a USDZ file.
|
|
49
|
-
* - downloadModelAndSceneGLB(): Downloads both the model and scene as a GLB file.
|
|
50
|
-
* - downloadModelAndSceneGLTF(): Downloads both the model and scene as a glTF ZIP file.
|
|
51
|
-
* - downloadModelAndSceneUSDZ(): Downloads both the model and scene as a USDZ file.
|
|
52
|
-
* - downloadSceneGLB(): Downloads the environment as a GLB file.
|
|
53
|
-
* - downloadSceneGLTF(): Downloads the environment as a glTF ZIP file.
|
|
54
|
-
* - downloadSceneUSDZ(): Downloads the environment as a USDZ file.
|
|
55
|
-
* - openDialog(title, content, footer): Opens a modal dialog with the specified title, content, and footer.
|
|
56
|
-
* - closeDialog(): Closes the currently open dialog, if any, and removes it from the DOM.
|
|
33
|
+
* Public Methods (selection):
|
|
34
|
+
* - loadConfig / loadModel / loadScene / loadMaterials / loadDrawing: Queue asset ingestion jobs.
|
|
35
|
+
* - setOptions / setMode / setCulture: Update runtime behavior, render mode, or locale.
|
|
36
|
+
* - showModel / hideModel / showScene / hideScene: Toggle visibility using the internal task queue for consistent sequencing.
|
|
37
|
+
* - zoomCenter / zoomExtentsAll / zoomIn / zoomOut: Forward zoom commands to the 2D controller when active.
|
|
38
|
+
* - downloadModel / downloadScene / downloadModelAndScene: Export assets in GLB, glTF ZIP, or USDZ flavors.
|
|
39
|
+
* - openDialog / closeDialog: Manage PrefViewerDialog instances rendered inside the shadow tree.
|
|
57
40
|
*
|
|
58
41
|
* Public Properties:
|
|
59
|
-
* - isInitialized
|
|
60
|
-
* - isLoaded: Indicates if the viewer has finished loading.
|
|
61
|
-
* - isLoading: Indicates if the viewer is currently loading.
|
|
62
|
-
* - isMode2D: Indicates if the viewer is in 2D mode.
|
|
63
|
-
* - isMode3D: Indicates if the viewer is in 3D mode.
|
|
42
|
+
* - culture, isInitialized, isLoaded, isLoading, isMode2D, isMode3D expose runtime state for host inspection.
|
|
64
43
|
*
|
|
65
44
|
* Events:
|
|
66
|
-
* -
|
|
67
|
-
* - "scene-loaded": Dispatched when a 3D loading operation completes.
|
|
68
|
-
* - "drawing-loading": Dispatched when a 2D drawing loading operation starts.
|
|
69
|
-
* - "drawing-loaded": Dispatched when a 2D drawing loading operation completes.
|
|
70
|
-
* - "drawing-zoom-changed": Dispatched when the 2D drawing zoom/pan state changes.
|
|
45
|
+
* - `scene-loading` / `scene-loaded` announce Babylon work, `drawing-loading` / `drawing-loaded` cover SVG pipelines, `drawing-zoom-changed` proxies pan/zoom delta.
|
|
71
46
|
*
|
|
72
47
|
* Notes:
|
|
73
|
-
* -
|
|
74
|
-
* -
|
|
75
|
-
* -
|
|
48
|
+
* - Internally wires PrefViewerMenu3D hover/apply events to PrefViewer3D render settings, ensuring persisted toggles stay in sync with BabylonJSController.
|
|
49
|
+
* - Cleans up dialogs, listeners, and subcomponents on disconnect to prevent leaks when frameworks mount/unmount the custom element.
|
|
50
|
+
* - Uses localStorage-backed culture persistence and attribute reflection safeguards to keep templates, menu, and global i18n aligned.
|
|
51
|
+
* - Designed for embeddable configurators, product showcases, and sales tooling that require responsive 2D/3D switching plus offline-friendly exports.
|
|
76
52
|
*/
|
|
77
53
|
export default class PrefViewer extends HTMLElement {
|
|
54
|
+
// Internal state flags
|
|
78
55
|
#isInitialized = false;
|
|
79
56
|
#isLoaded = false;
|
|
80
57
|
#isLoading = false;
|
|
81
58
|
#mode = "3d";
|
|
82
59
|
|
|
60
|
+
// Task queue for sequential processing
|
|
83
61
|
#taskQueue = [];
|
|
84
62
|
|
|
63
|
+
// Localization/culture management
|
|
64
|
+
#CULTURE_STORAGE_KEY = "pref-viewer/culture";
|
|
65
|
+
#cultureInitial = DEFAULT_LOCALE;
|
|
66
|
+
#cultureList = SUPPORTED_LOCALES;
|
|
67
|
+
#culture = "";
|
|
68
|
+
#cultureSuppressAttribute = false;
|
|
69
|
+
|
|
70
|
+
// References to internal components
|
|
85
71
|
#wrapper = null;
|
|
86
72
|
#component2D = null;
|
|
87
73
|
#component3D = null;
|
|
88
74
|
#dialog = null;
|
|
75
|
+
#menu3D = null;
|
|
89
76
|
|
|
77
|
+
// Event handlers
|
|
90
78
|
#handlers = {
|
|
91
79
|
on2DZoomChanged: null,
|
|
80
|
+
onMenuApply: null,
|
|
81
|
+
onViewerHoverStart: null,
|
|
82
|
+
onViewerHoverEnd: null,
|
|
83
|
+
on3DSceneLoaded: null,
|
|
92
84
|
};
|
|
93
85
|
|
|
94
86
|
/**
|
|
@@ -99,6 +91,12 @@ export default class PrefViewer extends HTMLElement {
|
|
|
99
91
|
constructor() {
|
|
100
92
|
super();
|
|
101
93
|
this.attachShadow({ mode: "open" });
|
|
94
|
+
const storedCulture = this.#cultureReadPersisted();
|
|
95
|
+
if (storedCulture) {
|
|
96
|
+
this.#culture = resolveLocale(storedCulture);
|
|
97
|
+
} else {
|
|
98
|
+
this.#culture = setLocale(this.#cultureInitial);
|
|
99
|
+
}
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
/**
|
|
@@ -107,7 +105,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
107
105
|
* @returns {string[]} Array of attribute names to observe.
|
|
108
106
|
*/
|
|
109
107
|
static get observedAttributes() {
|
|
110
|
-
return ["config", "drawing", "materials", "mode", "model", "scene", "options", "show-model", "show-scene"];
|
|
108
|
+
return ["config", "culture", "drawing", "materials", "mode", "model", "scene", "options", "show-model", "show-scene"];
|
|
111
109
|
}
|
|
112
110
|
|
|
113
111
|
/**
|
|
@@ -125,6 +123,12 @@ export default class PrefViewer extends HTMLElement {
|
|
|
125
123
|
case "config":
|
|
126
124
|
this.loadConfig(value);
|
|
127
125
|
break;
|
|
126
|
+
case "culture":
|
|
127
|
+
if (this.#cultureSuppressAttribute) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.setCulture(value);
|
|
131
|
+
break;
|
|
128
132
|
case "drawing":
|
|
129
133
|
this.loadDrawing(value);
|
|
130
134
|
break;
|
|
@@ -180,6 +184,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
180
184
|
|
|
181
185
|
this.#createComponent3D();
|
|
182
186
|
this.#createComponent2D();
|
|
187
|
+
this.#createMenu3D();
|
|
183
188
|
|
|
184
189
|
if (!this.hasAttribute("mode")) {
|
|
185
190
|
this.setMode();
|
|
@@ -195,6 +200,10 @@ export default class PrefViewer extends HTMLElement {
|
|
|
195
200
|
* @returns {void}
|
|
196
201
|
*/
|
|
197
202
|
disconnectedCallback() {
|
|
203
|
+
if (this.#wrapper) {
|
|
204
|
+
this.#wrapper.removeEventListener("mouseenter", this.#handlers.onViewerHoverStart);
|
|
205
|
+
this.#wrapper.removeEventListener("mouseleave", this.#handlers.onViewerHoverEnd);
|
|
206
|
+
}
|
|
198
207
|
if (this.#dialog) {
|
|
199
208
|
this.#dialog?.remove();
|
|
200
209
|
}
|
|
@@ -203,8 +212,14 @@ export default class PrefViewer extends HTMLElement {
|
|
|
203
212
|
this.#component2D.remove();
|
|
204
213
|
}
|
|
205
214
|
if (this.#component3D) {
|
|
215
|
+
this.#component3D.removeEventListener("scene-loaded", this.#handlers.on3DSceneLoaded);
|
|
206
216
|
this.#component3D.remove();
|
|
207
217
|
}
|
|
218
|
+
if (this.#menu3D) {
|
|
219
|
+
this.#menu3D.removeEventListener("pref-viewer-menu-apply", this.#handlers.onMenuApply);
|
|
220
|
+
this.#menu3D.remove();
|
|
221
|
+
this.#menu3D = null;
|
|
222
|
+
}
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
/**
|
|
@@ -230,9 +245,192 @@ export default class PrefViewer extends HTMLElement {
|
|
|
230
245
|
#createComponent3D() {
|
|
231
246
|
this.#component3D = document.createElement("pref-viewer-3d");
|
|
232
247
|
this.#component3D.setAttribute("visible", "false");
|
|
248
|
+
this.#handlers.on3DSceneLoaded = () => {
|
|
249
|
+
this.#menu3DSyncSettings();
|
|
250
|
+
this.#menu3D?.setApplying(false);
|
|
251
|
+
};
|
|
252
|
+
this.#component3D.addEventListener("scene-loaded", this.#handlers.on3DSceneLoaded);
|
|
233
253
|
this.#wrapper.appendChild(this.#component3D);
|
|
234
254
|
}
|
|
235
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Creates (or recreates) the PrefViewerMenu3D element, wires hover/apply handlers, and syncs it with the 3D component.
|
|
258
|
+
* When a menu already exists it is removed so the DOM stays clean.
|
|
259
|
+
* @private
|
|
260
|
+
* @returns {void}
|
|
261
|
+
*/
|
|
262
|
+
#createMenu3D() {
|
|
263
|
+
if (!this.#wrapper) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (this.#menu3D) {
|
|
267
|
+
this.#menu3D.removeEventListener("pref-viewer-menu-apply", this.#handlers.onMenuApply);
|
|
268
|
+
this.#menu3D.remove();
|
|
269
|
+
}
|
|
270
|
+
this.#menu3D = document.createElement("pref-viewer-menu-3d");
|
|
271
|
+
if (typeof this.#menu3D.setCulture === "function") {
|
|
272
|
+
this.#menu3D.setCulture(this.#culture);
|
|
273
|
+
} else {
|
|
274
|
+
this.#menu3D.setAttribute("culture", this.#culture);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!this.#handlers.onMenuApply) {
|
|
278
|
+
this.#handlers.onMenuApply = this.#onMenuApply.bind(this);
|
|
279
|
+
}
|
|
280
|
+
this.#handlers.onViewerHoverStart = () => this.#menu3D.setViewerHover(true);
|
|
281
|
+
this.#handlers.onViewerHoverEnd = () => this.#menu3D.setViewerHover(false);
|
|
282
|
+
|
|
283
|
+
this.#menu3D.addEventListener("pref-viewer-menu-apply", this.#handlers.onMenuApply);
|
|
284
|
+
this.#wrapper.addEventListener("mouseenter", this.#handlers.onViewerHoverStart);
|
|
285
|
+
this.#wrapper.addEventListener("mouseleave", this.#handlers.onViewerHoverEnd);
|
|
286
|
+
|
|
287
|
+
this.#wrapper.appendChild(this.#menu3D);
|
|
288
|
+
this.#menu3DSyncSettings();
|
|
289
|
+
this.#menu3DUpdateAvailability();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Reads the last persisted locale from localStorage so the viewer restores user preference.
|
|
294
|
+
* @private
|
|
295
|
+
* @returns {string|null} Resolved locale or null when unavailable.
|
|
296
|
+
*/
|
|
297
|
+
#cultureReadPersisted() {
|
|
298
|
+
if (typeof window === "undefined") {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
return window.localStorage?.getItem(this.#CULTURE_STORAGE_KEY);
|
|
303
|
+
} catch (_error) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Persists the active locale in localStorage so it survives reloads and sessions.
|
|
310
|
+
* @private
|
|
311
|
+
* @param {string} culture - Locale identifier to store.
|
|
312
|
+
* @returns {void}
|
|
313
|
+
*/
|
|
314
|
+
#culturePersist(culture) {
|
|
315
|
+
if (typeof window === "undefined") {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
window.localStorage?.setItem(this.#CULTURE_STORAGE_KEY, culture);
|
|
320
|
+
} catch (_error) {}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Mirrors the internal `#culture` value back to the `culture` attribute without feedback loops.
|
|
325
|
+
* @private
|
|
326
|
+
* @param {string} value - Locale identifier that should be reflected.
|
|
327
|
+
* @returns {void}
|
|
328
|
+
*/
|
|
329
|
+
#cultureReflectAttribute(value) {
|
|
330
|
+
if (this.#cultureSuppressAttribute) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (this.getAttribute("culture") === value) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
this.#cultureSuppressAttribute = true;
|
|
337
|
+
this.setAttribute("culture", value);
|
|
338
|
+
this.#cultureSuppressAttribute = false;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Synchronizes the menu switches with the current render settings reported by PrefViewer3D.
|
|
343
|
+
* Skips the update when either the menu or the getter API is unavailable.
|
|
344
|
+
* @private
|
|
345
|
+
* @returns {void}
|
|
346
|
+
*/
|
|
347
|
+
#menu3DSyncSettings() {
|
|
348
|
+
if (!this.#menu3D || !this.#component3D?.getRenderSettings) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const settings = this.#component3D.getRenderSettings();
|
|
352
|
+
if (settings) {
|
|
353
|
+
this.#menu3D.setSettings(settings);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Enables or disables the render menu depending on the active viewer mode.
|
|
359
|
+
* Clears hover/open states when the viewer switches to 2D so stale UI does not linger.
|
|
360
|
+
* @private
|
|
361
|
+
* @returns {void}
|
|
362
|
+
*/
|
|
363
|
+
#menu3DUpdateAvailability() {
|
|
364
|
+
if (!this.#menu3D) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const isMode3D = this.#mode === "3d";
|
|
368
|
+
if (!isMode3D) {
|
|
369
|
+
this.#menu3D.removeAttribute("data-viewer-hover");
|
|
370
|
+
this.#menu3D.removeAttribute("data-open");
|
|
371
|
+
}
|
|
372
|
+
this.#menu3D.setEnabled?.(isMode3D);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Applies render toggles via PrefViewer3D, showing progress in the menu and resyncing on completion.
|
|
377
|
+
* When no changes occur, the menu is simply refreshed to match the controller snapshot.
|
|
378
|
+
* @private
|
|
379
|
+
* @param {object} settings - Partial render settings (AA, SSAO, IBL, shadows) requested by the menu.
|
|
380
|
+
* @returns {Promise<void>}
|
|
381
|
+
*/
|
|
382
|
+
async #applyRenderSettings(settings) {
|
|
383
|
+
if (!this.#component3D) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.#menu3D?.setApplying(true);
|
|
387
|
+
try {
|
|
388
|
+
const result = await this.#component3D.applyRenderSettings(settings);
|
|
389
|
+
if (!result?.changed) {
|
|
390
|
+
const controllerSettings = this.#component3D.getRenderSettings();
|
|
391
|
+
if (controllerSettings) {
|
|
392
|
+
this.#menu3D?.setSettings(controllerSettings);
|
|
393
|
+
}
|
|
394
|
+
this.#menu3D?.setApplying(false);
|
|
395
|
+
}
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.error("PrefViewer: failed to apply render settings", error);
|
|
398
|
+
this.#menu3D?.setApplying(false, true);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Resolves the requested culture, updates internal/global state, and persists the selection.
|
|
404
|
+
* @private
|
|
405
|
+
* @param {string} [cultureId] - Desired locale to activate.
|
|
406
|
+
* @param {object} [options] - Extra flags for the update.
|
|
407
|
+
* @param {boolean} [options.reflectAttribute=false] - Whether to mirror the attribute.
|
|
408
|
+
* @returns {boolean} True when the culture actually changes.
|
|
409
|
+
*/
|
|
410
|
+
#applyCulture(cultureId, options = {}) {
|
|
411
|
+
let changed = false;
|
|
412
|
+
if (!cultureId || typeof cultureId !== "string") {
|
|
413
|
+
return changed;
|
|
414
|
+
}
|
|
415
|
+
const cultureInList = this.#cultureList.find((c) => c.toLowerCase() === cultureId.toLowerCase());
|
|
416
|
+
if (!cultureInList) {
|
|
417
|
+
return changed;
|
|
418
|
+
}
|
|
419
|
+
const { reflectAttribute = false } = options;
|
|
420
|
+
const resolved = resolveLocale(cultureId);
|
|
421
|
+
changed = resolved !== this.#culture;
|
|
422
|
+
if (reflectAttribute) {
|
|
423
|
+
this.#cultureReflectAttribute(resolved);
|
|
424
|
+
}
|
|
425
|
+
if (changed) {
|
|
426
|
+
this.#culture = resolved;
|
|
427
|
+
setLocale(resolved);
|
|
428
|
+
this.#menu3D?.setCulture?.(resolved);
|
|
429
|
+
this.#culturePersist(resolved);
|
|
430
|
+
}
|
|
431
|
+
return changed;
|
|
432
|
+
}
|
|
433
|
+
|
|
236
434
|
/**
|
|
237
435
|
* Adds a new task to the internal queue for processing.
|
|
238
436
|
* If the viewer is initialized and not currently loading, immediately processes the next task.
|
|
@@ -260,10 +458,16 @@ export default class PrefViewer extends HTMLElement {
|
|
|
260
458
|
}
|
|
261
459
|
const task = this.#taskQueue[0];
|
|
262
460
|
this.#taskQueue.shift();
|
|
461
|
+
if (this.#dialog) {
|
|
462
|
+
this.closeDialog();
|
|
463
|
+
}
|
|
263
464
|
switch (task.type) {
|
|
264
465
|
case PrefViewerTask.Types.Config:
|
|
265
466
|
this.#processConfig(task.value);
|
|
266
467
|
break;
|
|
468
|
+
case PrefViewerTask.Types.Culture:
|
|
469
|
+
this.#processCulture(task.value);
|
|
470
|
+
break;
|
|
267
471
|
case PrefViewerTask.Types.Drawing:
|
|
268
472
|
this.#processDrawing(task.value);
|
|
269
473
|
break;
|
|
@@ -396,6 +600,22 @@ export default class PrefViewer extends HTMLElement {
|
|
|
396
600
|
this.dispatchEvent(new CustomEvent("drawing-zoom-changed", customEventOptions));
|
|
397
601
|
}
|
|
398
602
|
|
|
603
|
+
/**
|
|
604
|
+
* Handles the custom "pref-viewer-menu-apply" event emitted by the menu component.
|
|
605
|
+
* Forwards the requested settings to the render-application pipeline.
|
|
606
|
+
* @private
|
|
607
|
+
* @param {CustomEvent} event - Menu event containing the `settings` payload.
|
|
608
|
+
* @returns {void}
|
|
609
|
+
*/
|
|
610
|
+
#onMenuApply(event) {
|
|
611
|
+
event.stopPropagation();
|
|
612
|
+
const settings = event.detail?.settings;
|
|
613
|
+
if (!settings) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
this.#applyRenderSettings(settings);
|
|
617
|
+
}
|
|
618
|
+
|
|
399
619
|
/**
|
|
400
620
|
* Processes a configuration object by loading it into the 3D component.
|
|
401
621
|
* Dispatches loading events and processes the next task when finished.
|
|
@@ -415,6 +635,17 @@ export default class PrefViewer extends HTMLElement {
|
|
|
415
635
|
});
|
|
416
636
|
}
|
|
417
637
|
|
|
638
|
+
/**
|
|
639
|
+
* Handles queued culture changes by applying the locale and advancing the task queue.
|
|
640
|
+
* @private
|
|
641
|
+
* @param {string} culture - Locale identifier coming from config, attributes, or API calls.
|
|
642
|
+
* @returns {void}
|
|
643
|
+
*/
|
|
644
|
+
#processCulture(culture) {
|
|
645
|
+
this.#applyCulture(culture, { reflectAttribute: true });
|
|
646
|
+
this.#processNextTask();
|
|
647
|
+
}
|
|
648
|
+
|
|
418
649
|
/**
|
|
419
650
|
* Processes a drawing object by loading it into the 2D component.
|
|
420
651
|
* Processes the next task when finished.
|
|
@@ -517,31 +748,119 @@ export default class PrefViewer extends HTMLElement {
|
|
|
517
748
|
*/
|
|
518
749
|
|
|
519
750
|
/**
|
|
520
|
-
*
|
|
751
|
+
* Initiates download of the current complete scene (3D model and environment) in GLB format.
|
|
521
752
|
* @public
|
|
522
|
-
* @param {string} [mode=this.#mode] - The mode to set ("2d" or "3d").
|
|
523
753
|
* @returns {void}
|
|
524
754
|
*/
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
console.warn(`PrefViewer: invalid mode "${mode}". Allowed modes are "2d" and "3d".`);
|
|
529
|
-
mode = this.#mode;
|
|
755
|
+
downloadModelAndSceneGLB() {
|
|
756
|
+
if (!this.#component3D) {
|
|
757
|
+
return;
|
|
530
758
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
759
|
+
|
|
760
|
+
this.#component3D.downloadModelAndSceneGLB();
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Initiates download of the current complete scene (3D model and environment) in GLTF format.
|
|
765
|
+
* @public
|
|
766
|
+
* @returns {void}
|
|
767
|
+
*/
|
|
768
|
+
downloadModelAndSceneGLTF() {
|
|
769
|
+
if (!this.#component3D) {
|
|
770
|
+
return;
|
|
538
771
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
772
|
+
|
|
773
|
+
this.#component3D.downloadModelAndSceneGLTF();
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Initiates download of the current complete scene (3D model and environment) in USDZ format.
|
|
778
|
+
* @public
|
|
779
|
+
* @returns {void}
|
|
780
|
+
*/
|
|
781
|
+
downloadModelAndSceneUSDZ() {
|
|
782
|
+
if (!this.#component3D) {
|
|
783
|
+
return;
|
|
544
784
|
}
|
|
785
|
+
|
|
786
|
+
this.#component3D.downloadModelAndSceneUSDZ();
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Initiates download of the current 3D model in GLB format.
|
|
791
|
+
* @public
|
|
792
|
+
* @returns {void}
|
|
793
|
+
*/
|
|
794
|
+
downloadModelGLB() {
|
|
795
|
+
if (!this.#component3D) {
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
this.#component3D.downloadModelGLB();
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Initiates download of the current 3D model in GLTF format.
|
|
804
|
+
* @public
|
|
805
|
+
* @returns {void}
|
|
806
|
+
*/
|
|
807
|
+
downloadModelGLTF() {
|
|
808
|
+
if (!this.#component3D) {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
this.#component3D.downloadModelGLTF();
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Initiates download of the current 3D model in USDZ format.
|
|
817
|
+
* @public
|
|
818
|
+
* @returns {void}
|
|
819
|
+
*/
|
|
820
|
+
downloadModelUSDZ() {
|
|
821
|
+
if (!this.#component3D) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
this.#component3D.downloadModelUSDZ();
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Initiates download of the current 3D environment in GLB format.
|
|
830
|
+
* @public
|
|
831
|
+
* @returns {void}
|
|
832
|
+
*/
|
|
833
|
+
downloadSceneGLB() {
|
|
834
|
+
if (!this.#component3D) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
this.#component3D.downloadSceneGLB();
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Initiates download of the current 3D environment in GLTF format.
|
|
843
|
+
* @public
|
|
844
|
+
* @returns {void}
|
|
845
|
+
*/
|
|
846
|
+
downloadSceneGLTF() {
|
|
847
|
+
if (!this.#component3D) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
this.#component3D.downloadSceneGLTF();
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Initiates download of the current 3D environment in USDZ format.
|
|
856
|
+
* @public
|
|
857
|
+
* @returns {void}
|
|
858
|
+
*/
|
|
859
|
+
downloadSceneUSDZ() {
|
|
860
|
+
if (!this.#component3D) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
this.#component3D.downloadSceneUSDZ();
|
|
545
864
|
}
|
|
546
865
|
|
|
547
866
|
/**
|
|
@@ -556,10 +875,41 @@ export default class PrefViewer extends HTMLElement {
|
|
|
556
875
|
if (!config) {
|
|
557
876
|
return false;
|
|
558
877
|
}
|
|
878
|
+
this.#addTaskToQueue(config, "config");
|
|
559
879
|
if (config.drawing) {
|
|
560
880
|
this.#addTaskToQueue(config.drawing, "drawing");
|
|
561
881
|
}
|
|
562
|
-
|
|
882
|
+
if (config.culture) {
|
|
883
|
+
this.#addTaskToQueue(config.culture, "culture");
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Loads a drawing object or JSON string and adds it to the task queue.
|
|
889
|
+
* @public
|
|
890
|
+
* @param {object|string} drawing - Drawing object or JSON string.
|
|
891
|
+
* @returns {boolean|void} Returns false if drawing is invalid; otherwise void.
|
|
892
|
+
*/
|
|
893
|
+
loadDrawing(drawing) {
|
|
894
|
+
drawing = typeof drawing === "string" ? JSON.parse(drawing) : drawing;
|
|
895
|
+
if (!drawing) {
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
this.#addTaskToQueue(drawing, "drawing");
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Loads materials object or JSON string and adds it to the task queue.
|
|
903
|
+
* @public
|
|
904
|
+
* @param {object|string} materials - Materials object or JSON string.
|
|
905
|
+
* @returns {boolean|void} Returns false if materials are invalid; otherwise void.
|
|
906
|
+
*/
|
|
907
|
+
loadMaterials(materials) {
|
|
908
|
+
materials = typeof materials === "string" ? JSON.parse(materials) : materials;
|
|
909
|
+
if (!materials) {
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
912
|
+
this.#addTaskToQueue(materials, "materials");
|
|
563
913
|
}
|
|
564
914
|
|
|
565
915
|
/**
|
|
@@ -591,31 +941,42 @@ export default class PrefViewer extends HTMLElement {
|
|
|
591
941
|
}
|
|
592
942
|
|
|
593
943
|
/**
|
|
594
|
-
*
|
|
944
|
+
* Sets the active culture for UI translations and propagates it to child components.
|
|
595
945
|
* @public
|
|
596
|
-
* @param {
|
|
597
|
-
* @returns {
|
|
946
|
+
* @param {string} [cultureId] - Locale identifier, e.g., "en-EN".
|
|
947
|
+
* @returns {void}
|
|
598
948
|
*/
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
if (!materials) {
|
|
602
|
-
return false;
|
|
603
|
-
}
|
|
604
|
-
this.#addTaskToQueue(materials, "materials");
|
|
949
|
+
setCulture(cultureId) {
|
|
950
|
+
this.#addTaskToQueue(cultureId, "culture");
|
|
605
951
|
}
|
|
606
952
|
|
|
607
953
|
/**
|
|
608
|
-
*
|
|
954
|
+
* Sets the viewer mode to "2d" or "3d" and updates component visibility accordingly.
|
|
609
955
|
* @public
|
|
610
|
-
* @param {
|
|
611
|
-
* @returns {
|
|
956
|
+
* @param {string} [mode=this.#mode] - The mode to set ("2d" or "3d").
|
|
957
|
+
* @returns {void}
|
|
612
958
|
*/
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
if (
|
|
616
|
-
|
|
959
|
+
setMode(mode = this.#mode) {
|
|
960
|
+
mode = mode.toLowerCase();
|
|
961
|
+
if (mode !== "2d" && mode !== "3d") {
|
|
962
|
+
console.warn(`PrefViewer: invalid mode "${mode}". Allowed modes are "2d" and "3d".`);
|
|
963
|
+
mode = this.#mode;
|
|
964
|
+
}
|
|
965
|
+
this.#mode = mode;
|
|
966
|
+
if (mode === "2d") {
|
|
967
|
+
this.#component3D?.hide();
|
|
968
|
+
this.#component2D?.show();
|
|
969
|
+
} else {
|
|
970
|
+
this.#component2D?.hide();
|
|
971
|
+
this.#component3D?.show();
|
|
972
|
+
}
|
|
973
|
+
this.#menu3DUpdateAvailability();
|
|
974
|
+
if (this.getAttribute("mode") !== mode) {
|
|
975
|
+
this.setAttribute("mode", mode);
|
|
976
|
+
if (this.#dialog) {
|
|
977
|
+
this.closeDialog();
|
|
978
|
+
}
|
|
617
979
|
}
|
|
618
|
-
this.#addTaskToQueue(drawing, "drawing");
|
|
619
980
|
}
|
|
620
981
|
|
|
621
982
|
/**
|
|
@@ -632,6 +993,39 @@ export default class PrefViewer extends HTMLElement {
|
|
|
632
993
|
this.#addTaskToQueue(options, "options");
|
|
633
994
|
}
|
|
634
995
|
|
|
996
|
+
/**
|
|
997
|
+
* Opens a modal dialog with the specified title, content, and footer.
|
|
998
|
+
* @public
|
|
999
|
+
* @param {string} title - The dialog title to display in the header.
|
|
1000
|
+
* @param {string} content - The HTML content to display in the dialog body.
|
|
1001
|
+
* @param {string} footer - The HTML content to display in the dialog footer (e.g., action buttons).
|
|
1002
|
+
* @returns {HTMLElement} The created dialog element.
|
|
1003
|
+
* @description
|
|
1004
|
+
* If a dialog is already open, it is closed before opening the new one.
|
|
1005
|
+
* The dialog is appended to the viewer's shadow DOM and returned for further manipulation.
|
|
1006
|
+
*/
|
|
1007
|
+
openDialog(title, content, footer) {
|
|
1008
|
+
if (this.#dialog && this.#dialog.hasAttribute("open")) {
|
|
1009
|
+
this.#dialog.close();
|
|
1010
|
+
}
|
|
1011
|
+
this.#dialog = document.createElement("pref-viewer-dialog");
|
|
1012
|
+
this.shadowRoot.querySelector(".pref-viewer-wrapper").appendChild(this.#dialog);
|
|
1013
|
+
const opened = this.#dialog.open(title, content, footer);
|
|
1014
|
+
return opened ? this.#dialog : null;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Closes the currently open dialog, if any, and removes it from the DOM.
|
|
1019
|
+
* @public
|
|
1020
|
+
* @returns {void}
|
|
1021
|
+
*/
|
|
1022
|
+
closeDialog() {
|
|
1023
|
+
if (this.#dialog) {
|
|
1024
|
+
this.#dialog.close();
|
|
1025
|
+
this.#dialog = null;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
635
1029
|
/**
|
|
636
1030
|
* Shows the 3D model by setting its visibility to true.
|
|
637
1031
|
* Adds a visibility task to the queue for processing.
|
|
@@ -733,160 +1127,98 @@ export default class PrefViewer extends HTMLElement {
|
|
|
733
1127
|
}
|
|
734
1128
|
|
|
735
1129
|
/**
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
1130
|
+
* ---------------------------
|
|
1131
|
+
* Public properties (setters)
|
|
1132
|
+
* ---------------------------
|
|
739
1133
|
*/
|
|
740
|
-
downloadModelGLB() {
|
|
741
|
-
if (!this.#component3D) {
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
this.#component3D.downloadModelGLB();
|
|
746
|
-
}
|
|
747
1134
|
|
|
748
1135
|
/**
|
|
749
|
-
*
|
|
1136
|
+
* Accepts a config object or JSON string and forwards it to `loadConfig()`.
|
|
750
1137
|
* @public
|
|
751
|
-
* @
|
|
1138
|
+
* @param {object|string} value - Configuration payload or serialized JSON.
|
|
752
1139
|
*/
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
this.#component3D.downloadModelGLTF();
|
|
1140
|
+
set config(value) {
|
|
1141
|
+
this.loadConfig(value);
|
|
759
1142
|
}
|
|
760
1143
|
|
|
761
1144
|
/**
|
|
762
|
-
*
|
|
1145
|
+
* Mirrors `setCulture()` so templates can change the locale via attributes or props.
|
|
763
1146
|
* @public
|
|
764
|
-
* @
|
|
1147
|
+
* @param {string} value - Locale identifier such as "es-ES".
|
|
765
1148
|
*/
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
this.#component3D.downloadModelUSDZ();
|
|
1149
|
+
set culture(value) {
|
|
1150
|
+
this.setCulture(value);
|
|
772
1151
|
}
|
|
773
1152
|
|
|
774
1153
|
/**
|
|
775
|
-
*
|
|
1154
|
+
* Routes incoming drawing data to `loadDrawing()` for queued processing.
|
|
776
1155
|
* @public
|
|
777
|
-
* @
|
|
1156
|
+
* @param {object|string} value - Drawing payload or serialized JSON.
|
|
778
1157
|
*/
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
this.#component3D.downloadModelAndSceneGLB();
|
|
1158
|
+
set drawing(value) {
|
|
1159
|
+
this.loadDrawing(value);
|
|
785
1160
|
}
|
|
786
1161
|
|
|
787
1162
|
/**
|
|
788
|
-
*
|
|
1163
|
+
* Convenience bridge to `loadMaterials()` for template bindings.
|
|
789
1164
|
* @public
|
|
790
|
-
* @
|
|
1165
|
+
* @param {object|string} value - Materials definition or JSON string.
|
|
791
1166
|
*/
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
this.#component3D.downloadModelAndSceneGLTF();
|
|
1167
|
+
set materials(value) {
|
|
1168
|
+
this.loadMaterials(value);
|
|
798
1169
|
}
|
|
799
1170
|
|
|
800
1171
|
/**
|
|
801
|
-
*
|
|
1172
|
+
* Delegates to `setMode()` so consumers can switch between 2D/3D through a setter.
|
|
802
1173
|
* @public
|
|
803
|
-
* @
|
|
1174
|
+
* @param {string} value - Desired viewer mode, e.g., "2d" or "3d".
|
|
804
1175
|
*/
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
this.#component3D.downloadModelAndSceneUSDZ();
|
|
1176
|
+
set mode(value) {
|
|
1177
|
+
this.setMode(value);
|
|
811
1178
|
}
|
|
812
1179
|
|
|
813
1180
|
/**
|
|
814
|
-
*
|
|
1181
|
+
* Forwards models supplied via property assignment to `loadModel()`.
|
|
815
1182
|
* @public
|
|
816
|
-
* @
|
|
1183
|
+
* @param {object|string} value - Model payload or serialized JSON.
|
|
817
1184
|
*/
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
this.#component3D.downloadSceneGLB();
|
|
1185
|
+
set model(value) {
|
|
1186
|
+
this.loadModel(value);
|
|
824
1187
|
}
|
|
825
1188
|
|
|
826
1189
|
/**
|
|
827
|
-
*
|
|
1190
|
+
* Sends option updates to `setOptions()` enabling reactive bindings.
|
|
828
1191
|
* @public
|
|
829
|
-
* @
|
|
1192
|
+
* @param {object|string} value - Options object or JSON string.
|
|
830
1193
|
*/
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
return;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
this.#component3D.downloadSceneGLTF();
|
|
1194
|
+
set options(value) {
|
|
1195
|
+
this.setOptions(value);
|
|
837
1196
|
}
|
|
838
1197
|
|
|
839
1198
|
/**
|
|
840
|
-
*
|
|
1199
|
+
* Redirects scene assignments to `loadScene()` for normalized handling.
|
|
841
1200
|
* @public
|
|
842
|
-
* @
|
|
1201
|
+
* @param {object|string} value - Scene payload or serialized JSON.
|
|
843
1202
|
*/
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
this.#component3D.downloadSceneUSDZ();
|
|
1203
|
+
set scene(value) {
|
|
1204
|
+
this.loadScene(value);
|
|
849
1205
|
}
|
|
850
1206
|
|
|
851
1207
|
/**
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* @param {string} content - The HTML content to display in the dialog body.
|
|
856
|
-
* @param {string} footer - The HTML content to display in the dialog footer (e.g., action buttons).
|
|
857
|
-
* @returns {HTMLElement} The created dialog element.
|
|
858
|
-
* @description
|
|
859
|
-
* If a dialog is already open, it is closed before opening the new one.
|
|
860
|
-
* The dialog is appended to the viewer's shadow DOM and returned for further manipulation.
|
|
1208
|
+
* ---------------------------
|
|
1209
|
+
* Public properties (getters)
|
|
1210
|
+
* ---------------------------
|
|
861
1211
|
*/
|
|
862
|
-
openDialog(title, content, footer) {
|
|
863
|
-
if (this.#dialog && this.#dialog.hasAttribute("open")) {
|
|
864
|
-
this.#dialog.close();
|
|
865
|
-
}
|
|
866
|
-
this.#dialog = document.createElement("pref-viewer-dialog");
|
|
867
|
-
this.shadowRoot.querySelector(".pref-viewer-wrapper").appendChild(this.#dialog);
|
|
868
|
-
const opened = this.#dialog.open(title, content, footer);
|
|
869
|
-
return opened ? this.#dialog : null;
|
|
870
|
-
}
|
|
871
1212
|
|
|
872
1213
|
/**
|
|
873
|
-
*
|
|
1214
|
+
* Exposes the currently active locale so hosts can inspect which translations are applied.
|
|
874
1215
|
* @public
|
|
875
|
-
* @returns {
|
|
1216
|
+
* @returns {string} Locale identifier, e.g., "en-EN".
|
|
876
1217
|
*/
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
this.#dialog.close();
|
|
880
|
-
this.#dialog = null;
|
|
881
|
-
}
|
|
1218
|
+
get culture() {
|
|
1219
|
+
return this.#culture;
|
|
882
1220
|
}
|
|
883
1221
|
|
|
884
|
-
/**
|
|
885
|
-
* ---------------------------
|
|
886
|
-
* Public properties
|
|
887
|
-
* ---------------------------
|
|
888
|
-
*/
|
|
889
|
-
|
|
890
1222
|
/**
|
|
891
1223
|
* Indicates whether the viewer has been initialized.
|
|
892
1224
|
* @public
|