@preference-sl/pref-viewer 2.2.0 → 2.3.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +57 -37
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "license": "MIT",
package/src/index.js CHANGED
@@ -71,6 +71,7 @@ class PrefViewer extends HTMLElement {
71
71
  // modelUrl might be provided via attribute before connectedCallback
72
72
  this.modelUrl = null;
73
73
  this._hasInitialized = false;
74
+ this._pluginHookSetup = false; // Track if we've already set up the plugin hook
74
75
  }
75
76
 
76
77
  static get observedAttributes() {
@@ -91,6 +92,13 @@ class PrefViewer extends HTMLElement {
91
92
 
92
93
  connectedCallback() {
93
94
  console.log("PrefViewer: connectedCallback");
95
+
96
+ // Set up the plugin hook ONCE globally before any other initialization
97
+ if (!this._pluginHookSetup) {
98
+ this._setupUrlPreprocessing();
99
+ this._pluginHookSetup = true;
100
+ }
101
+
94
102
  // 1) Determine modelUrl now that element is connected
95
103
  if (!this.hasAttribute("model")) {
96
104
  this.modelUrl = new URL("./models/window.gltf", import.meta.url).href;
@@ -113,7 +121,47 @@ class PrefViewer extends HTMLElement {
113
121
  disconnectedCallback() {
114
122
  console.log("PrefViewer: disconnectedCallback - disposing engine");
115
123
  this._disposeEngine();
116
- window.removeEventListener("resize", this._onWindowResize);
124
+ if (this._onWindowResize) {
125
+ window.removeEventListener("resize", this._onWindowResize);
126
+ }
127
+ }
128
+
129
+ // ====== URL Preprocessing Setup ======
130
+ _setupUrlPreprocessing() {
131
+ console.log("PrefViewer: Setting up URL preprocessing hook");
132
+
133
+ const transformUrl = (url) => {
134
+ // a) If the loader already prepended "blob:…", strip it out.
135
+ const stripped = url.replace(
136
+ /^blob:(?:http|https|file):\/\/[^\/]+\/(.+)/i,
137
+ "$1"
138
+ );
139
+ // b) Normalize backslashes "\" → forward slashes "/"
140
+ const fixedSlashes = stripped.replace(/\\/g, "/");
141
+ console.log(
142
+ `PrefViewer: preprocessUrl received "${url}", stripped to "${stripped}", normalized to "${fixedSlashes}"`
143
+ );
144
+ // c) If it now starts with "http://" or "https://", return it as an absolute URL:
145
+ if (/^https?:\/\//i.test(fixedSlashes)) {
146
+ console.log(`PrefViewer: preprocessUrl returning absolute URL "${fixedSlashes}"`);
147
+ return fixedSlashes;
148
+ }
149
+ // d) Otherwise, return the relative path
150
+ console.log(`PrefViewer: preprocessUrl returning relative URL "${fixedSlashes}"`);
151
+ return fixedSlashes;
152
+ };
153
+
154
+ SceneLoader.OnPluginActivatedObservable.add((plugin) => {
155
+ console.log(`PrefViewer: Plugin activated - ${plugin.name}`);
156
+ if (plugin.name === "gltf" || plugin.name === "gltf2") {
157
+ // Support both sync and async preprocessing
158
+ plugin.preprocessUrl = transformUrl;
159
+ if (typeof plugin.preprocessUrlAsync === 'function' || plugin.preprocessUrlAsync === undefined) {
160
+ plugin.preprocessUrlAsync = (url) => Promise.resolve(transformUrl(url));
161
+ }
162
+ console.log("PrefViewer: URL preprocessing hooks set up for GLTF plugin");
163
+ }
164
+ });
117
165
  }
118
166
 
119
167
  // ====== Private setup methods ======
@@ -147,56 +195,28 @@ class PrefViewer extends HTMLElement {
147
195
  this.scene = new Scene(this.engine);
148
196
  this.scene.clearColor = new Color4(1, 1, 1, 1);
149
197
 
150
- // 2) Hook into Babylon’s GLTF loader so that any URIs starting with "blob:…"
151
- // get stripped off before we check for an absolute "https://".
152
- console.log("PrefViewer: Adding preprocessUrl hook");
153
- SceneLoader.OnPluginActivatedObservable.add((plugin) => {
154
- console.log(`PrefViewer: Plugin activated - ${plugin.name}`);
155
- if (plugin.name === "gltf" || plugin.name === "gltf2") {
156
- plugin.preprocessUrl = (url) => {
157
- // a) If the loader already prepended "blob:…", strip it out.
158
- // Regex explanation: ^blob:(?:file|https?|ftp):\/\/[^\/]+\/(.*)
159
- // basically removes the entire "blob:http://localhost:3000/" prefix.
160
- const stripped = url.replace(
161
- /^blob:(?:http|https|file):\/\/[^\/]+\/(.+)/i,
162
- "$1"
163
- );
164
- // b) Normalize backslashes "\" → forward slashes "/"
165
- const fixedSlashes = stripped.replace(/\\/g, "/");
166
- console.log(
167
- `PrefViewer: preprocessUrl received "${url}", stripped to "${stripped}", normalized to "${fixedSlashes}"`
168
- );
169
- // c) If it now starts with "http://" or "https://", return it as an absolute URL:
170
- if (/^https?:\/\//i.test(fixedSlashes)) {
171
- console.log(`PrefViewer: preprocessUrl returning absolute URL "${fixedSlashes}"`);
172
- return fixedSlashes;
173
- }
174
- // d) Otherwise, return the relative path (Babylon will resolve it relative to the blob if needed)
175
- console.log(`PrefViewer: preprocessUrl returning relative URL "${fixedSlashes}"`);
176
- return fixedSlashes;
177
- };
178
- }
179
- });
180
-
181
- // 3) Create camera and lights
198
+ // 2) Create camera and lights
182
199
  console.log("PrefViewer: _createCamera and _createLights");
183
200
  this._createCamera();
184
201
  this._createLights();
185
202
 
186
- // 4) Hook up input/event handlers (e.g. wheel-to-zoom)
203
+ // 3) Hook up input/event handlers (e.g. wheel-to-zoom)
187
204
  console.log("PrefViewer: _setupEventListeners");
188
205
  this._setupEventListeners();
189
206
 
190
- // 5) Start Babylons render loop
207
+ // 4) Start Babylon's render loop
191
208
  console.log("PrefViewer: Starting render loop");
192
209
  this.engine.runRenderLoop(() => {
193
210
  if (this.scene) {
194
211
  this.scene.render();
195
212
  }
196
213
  });
214
+
197
215
  this._onWindowResize = () => {
198
216
  console.log("PrefViewer: Window resized - calling engine.resize()");
199
- this.engine.resize();
217
+ if (this.engine) {
218
+ this.engine.resize();
219
+ }
200
220
  };
201
221
  window.addEventListener("resize", this._onWindowResize);
202
222
  }
@@ -260,7 +280,7 @@ class PrefViewer extends HTMLElement {
260
280
  return;
261
281
  }
262
282
 
263
- // Dispose previous meshes so we dont accumulate them
283
+ // Dispose previous meshes so we don't accumulate them
264
284
  this._disposePreviousMeshes();
265
285
 
266
286
  try {