becomap 1.5.72 → 1.5.73
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/lib/becomap.js +1 -1
- package/lib/index.d.ts +6 -10
- package/package.json +1 -1
- package/public/index.html +154 -744
- package/public/README.md +0 -902
package/public/index.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
4
|
<head>
|
|
@@ -22,182 +22,43 @@
|
|
|
22
22
|
|
|
23
23
|
<body>
|
|
24
24
|
<div id="mapContainer"></div>
|
|
25
|
+
|
|
26
|
+
<!-- External libs -->
|
|
25
27
|
<script src="https://unpkg.com/maplibre-gl@4.4.1/dist/maplibre-gl.js"></script>
|
|
26
28
|
<script src="https://unpkg.com/@turf/turf@7.1.0/turf.min.js"></script>
|
|
27
|
-
|
|
29
|
+
|
|
30
|
+
<!-- Core Map SDK Integration -->
|
|
31
|
+
<script>
|
|
32
|
+
// ============================================================================
|
|
28
33
|
// GLOBAL VARIABLES
|
|
29
34
|
// ============================================================================
|
|
30
35
|
window._mapView = null;
|
|
31
36
|
window._site = null;
|
|
32
37
|
window._eventListeners = new Map();
|
|
33
|
-
window._bridgeHealth = {
|
|
34
|
-
isConnected: false,
|
|
35
|
-
lastHeartbeat: null,
|
|
36
|
-
connectionAttempts: 0,
|
|
37
|
-
maxRetries: 3
|
|
38
|
-
};
|
|
39
|
-
window._operationQueue = [];
|
|
40
|
-
window._isProcessingQueue = false;
|
|
41
|
-
window._appState = 'initializing'; // 'initializing', 'ready', 'error', 'destroyed'
|
|
42
38
|
|
|
43
39
|
// ============================================================================
|
|
44
40
|
// UTILITY FUNCTIONS
|
|
45
41
|
// ============================================================================
|
|
46
42
|
|
|
47
43
|
/**
|
|
48
|
-
*
|
|
49
|
-
* @returns {boolean} - True if native bridge is available
|
|
50
|
-
*/
|
|
51
|
-
function isNativeBridgeAvailable() {
|
|
52
|
-
return !!(window.webkit?.messageHandlers?.jsHandler || window.jsHandler?.postMessage);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Updates bridge health status
|
|
57
|
-
* @param {boolean} isConnected - Connection status
|
|
58
|
-
*/
|
|
59
|
-
function updateBridgeHealth(isConnected) {
|
|
60
|
-
window._bridgeHealth.isConnected = isConnected;
|
|
61
|
-
window._bridgeHealth.lastHeartbeat = Date.now();
|
|
62
|
-
|
|
63
|
-
if (isConnected) {
|
|
64
|
-
window._bridgeHealth.connectionAttempts = 0;
|
|
65
|
-
processOperationQueue();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Sends messages to native platform with retry mechanism
|
|
44
|
+
* Sends messages to native platform (iOS/Android)
|
|
71
45
|
* @param {string} type - Message type
|
|
72
46
|
* @param {any} payload - Message payload
|
|
73
|
-
* @param {boolean} skipQueue - Skip queue and send immediately
|
|
74
|
-
*/
|
|
75
|
-
function notifyNative(type, payload = null, skipQueue = false) {
|
|
76
|
-
const message = { type, payload, timestamp: Date.now() };
|
|
77
|
-
|
|
78
|
-
if (!isNativeBridgeAvailable()) {
|
|
79
|
-
console.warn("Native handler not available:", message);
|
|
80
|
-
|
|
81
|
-
if (!skipQueue && window._bridgeHealth.connectionAttempts < window._bridgeHealth.maxRetries) {
|
|
82
|
-
queueOperation(() => notifyNative(type, payload, true));
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Fallback: store in localStorage for debugging
|
|
87
|
-
try {
|
|
88
|
-
const failedMessages = JSON.parse(localStorage.getItem('becomap_failed_messages') || '[]');
|
|
89
|
-
failedMessages.push(message);
|
|
90
|
-
localStorage.setItem('becomap_failed_messages', JSON.stringify(failedMessages.slice(-50))); // Keep last 50
|
|
91
|
-
} catch (e) {
|
|
92
|
-
console.warn('Failed to store message in localStorage:', e);
|
|
93
|
-
}
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
const messageStr = JSON.stringify(message);
|
|
99
|
-
|
|
100
|
-
if (window.webkit?.messageHandlers?.jsHandler) {
|
|
101
|
-
// iOS
|
|
102
|
-
window.webkit.messageHandlers.jsHandler.postMessage(messageStr);
|
|
103
|
-
} else if (window.jsHandler?.postMessage) {
|
|
104
|
-
// Android
|
|
105
|
-
window.jsHandler.postMessage(messageStr);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
updateBridgeHealth(true);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error('Failed to send message to native:', error, message);
|
|
111
|
-
updateBridgeHealth(false);
|
|
112
|
-
|
|
113
|
-
if (!skipQueue) {
|
|
114
|
-
queueOperation(() => notifyNative(type, payload, true));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Queues an operation for later execution
|
|
121
|
-
* @param {Function} operation - Operation to queue
|
|
122
|
-
*/
|
|
123
|
-
function queueOperation(operation) {
|
|
124
|
-
window._operationQueue.push({
|
|
125
|
-
operation,
|
|
126
|
-
timestamp: Date.now(),
|
|
127
|
-
retries: 0
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Process queue after a short delay
|
|
131
|
-
setTimeout(processOperationQueue, 100);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Processes queued operations
|
|
136
47
|
*/
|
|
137
|
-
function
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// Remove expired operations
|
|
149
|
-
window._operationQueue = window._operationQueue.filter(item =>
|
|
150
|
-
now - item.timestamp < maxAge
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
// Process remaining operations
|
|
154
|
-
while (window._operationQueue.length > 0 && isNativeBridgeAvailable()) {
|
|
155
|
-
const item = window._operationQueue.shift();
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
item.operation();
|
|
159
|
-
} catch (error) {
|
|
160
|
-
console.error('Error processing queued operation:', error);
|
|
161
|
-
|
|
162
|
-
// Retry failed operations up to 3 times
|
|
163
|
-
if (item.retries < 3) {
|
|
164
|
-
item.retries++;
|
|
165
|
-
window._operationQueue.unshift(item);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
} finally {
|
|
171
|
-
window._isProcessingQueue = false;
|
|
48
|
+
function notifyNative(type, payload = null) {
|
|
49
|
+
const message = JSON.stringify({ type, payload });
|
|
50
|
+
|
|
51
|
+
if (window.webkit?.messageHandlers?.jsHandler) {
|
|
52
|
+
// iOS
|
|
53
|
+
window.webkit.messageHandlers.jsHandler.postMessage(message);
|
|
54
|
+
} else if (window.jsHandler?.postMessage) {
|
|
55
|
+
// Android
|
|
56
|
+
window.jsHandler.postMessage(message);
|
|
57
|
+
} else {
|
|
58
|
+
console.log("Native handler not available:", message);
|
|
172
59
|
}
|
|
173
60
|
}
|
|
174
61
|
|
|
175
|
-
/**
|
|
176
|
-
* Throttle function to prevent event flooding
|
|
177
|
-
* @param {Function} func - Function to throttle
|
|
178
|
-
* @param {number} delay - Delay in milliseconds
|
|
179
|
-
* @returns {Function} - Throttled function
|
|
180
|
-
*/
|
|
181
|
-
function throttle(func, delay) {
|
|
182
|
-
let timeoutId;
|
|
183
|
-
let lastExecTime = 0;
|
|
184
|
-
|
|
185
|
-
return function (...args) {
|
|
186
|
-
const currentTime = Date.now();
|
|
187
|
-
|
|
188
|
-
if (currentTime - lastExecTime > delay) {
|
|
189
|
-
func.apply(this, args);
|
|
190
|
-
lastExecTime = currentTime;
|
|
191
|
-
} else {
|
|
192
|
-
clearTimeout(timeoutId);
|
|
193
|
-
timeoutId = setTimeout(() => {
|
|
194
|
-
func.apply(this, args);
|
|
195
|
-
lastExecTime = Date.now();
|
|
196
|
-
}, delay - (currentTime - lastExecTime));
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
62
|
/**
|
|
202
63
|
* Safely converts objects to JSON with error handling
|
|
203
64
|
* @param {any} obj - Object to convert
|
|
@@ -213,97 +74,20 @@
|
|
|
213
74
|
}
|
|
214
75
|
|
|
215
76
|
/**
|
|
216
|
-
* Executes function with
|
|
77
|
+
* Executes function with error handling and native notification
|
|
217
78
|
* @param {Function} fn - Function to execute
|
|
218
79
|
* @param {string} errorType - Error type for native notification
|
|
219
|
-
* @param {any} errorDetails - Additional error details to include in the payload
|
|
220
80
|
* @param {any} fallbackValue - Fallback value if function fails
|
|
221
|
-
* @param {number} timeout - Timeout in milliseconds (default: 5000)
|
|
222
|
-
* @param {number} maxRetries - Maximum retry attempts (default: 0)
|
|
223
|
-
*/
|
|
224
|
-
function executeWithErrorHandling(fn, errorType, errorDetails = null, fallbackValue = null, timeout = 5000, maxRetries = 0) {
|
|
225
|
-
return new Promise((resolve) => {
|
|
226
|
-
let retryCount = 0;
|
|
227
|
-
|
|
228
|
-
function attemptExecution() {
|
|
229
|
-
try {
|
|
230
|
-
// Validate pre-conditions
|
|
231
|
-
if (window._appState === 'destroyed') {
|
|
232
|
-
throw new Error('Application has been destroyed');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (!window._mapView && errorDetails?.operation !== 'init') {
|
|
236
|
-
throw new Error('MapView not initialized');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Set up timeout
|
|
240
|
-
const timeoutId = setTimeout(() => {
|
|
241
|
-
throw new Error(`Operation timed out after ${timeout}ms`);
|
|
242
|
-
}, timeout);
|
|
243
|
-
|
|
244
|
-
const result = fn();
|
|
245
|
-
clearTimeout(timeoutId);
|
|
246
|
-
|
|
247
|
-
// Handle promises
|
|
248
|
-
if (result && typeof result.then === 'function') {
|
|
249
|
-
result
|
|
250
|
-
.then(res => resolve(res !== undefined ? res : fallbackValue))
|
|
251
|
-
.catch(handleError);
|
|
252
|
-
} else {
|
|
253
|
-
resolve(result !== undefined ? result : fallbackValue);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
} catch (error) {
|
|
257
|
-
handleError(error);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function handleError(error) {
|
|
262
|
-
console.error(`${errorType} error (attempt ${retryCount + 1}):`, error);
|
|
263
|
-
|
|
264
|
-
const errorPayload = {
|
|
265
|
-
message: error.message,
|
|
266
|
-
stack: error.stack,
|
|
267
|
-
timestamp: Date.now(),
|
|
268
|
-
attempt: retryCount + 1,
|
|
269
|
-
maxRetries: maxRetries + 1,
|
|
270
|
-
appState: window._appState,
|
|
271
|
-
bridgeHealth: { ...window._bridgeHealth },
|
|
272
|
-
...errorDetails
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// Retry logic for transient errors
|
|
276
|
-
if (retryCount < maxRetries && isRetriableError(error)) {
|
|
277
|
-
retryCount++;
|
|
278
|
-
const delay = Math.min(1000 * Math.pow(2, retryCount - 1), 5000); // Exponential backoff
|
|
279
|
-
setTimeout(attemptExecution, delay);
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
notifyNative(errorType, errorPayload);
|
|
284
|
-
resolve(fallbackValue);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
attemptExecution();
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Determines if an error is retriable
|
|
293
|
-
* @param {Error} error - The error to check
|
|
294
|
-
* @returns {boolean} - True if error is retriable
|
|
295
81
|
*/
|
|
296
|
-
function
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
error.message.toLowerCase().includes(msg)
|
|
306
|
-
);
|
|
82
|
+
function executeWithErrorHandling(fn, errorType, fallbackValue = null) {
|
|
83
|
+
try {
|
|
84
|
+
const result = fn();
|
|
85
|
+
return result !== undefined ? result : fallbackValue;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error(`${errorType} error:`, error);
|
|
88
|
+
notifyNative(errorType, { message: error.message });
|
|
89
|
+
return fallbackValue;
|
|
90
|
+
}
|
|
307
91
|
}
|
|
308
92
|
|
|
309
93
|
// ============================================================================
|
|
@@ -325,100 +109,44 @@
|
|
|
325
109
|
|
|
326
110
|
// Map load event
|
|
327
111
|
const loadListenerId = mapView.eventsHandler.on('load', () => {
|
|
328
|
-
|
|
329
|
-
window._appState = 'ready';
|
|
330
|
-
notifyNative("onRenderComplete", {
|
|
331
|
-
site: safeToJSON(window._site),
|
|
332
|
-
timestamp: Date.now(),
|
|
333
|
-
appState: window._appState
|
|
334
|
-
});
|
|
335
|
-
} catch (error) {
|
|
336
|
-
console.error('Error in load event handler:', error);
|
|
337
|
-
notifyNative("onError", {
|
|
338
|
-
message: error.message,
|
|
339
|
-
event: 'load',
|
|
340
|
-
timestamp: Date.now()
|
|
341
|
-
});
|
|
342
|
-
}
|
|
112
|
+
notifyNative("mapLoad", { timestamp: Date.now() });
|
|
343
113
|
});
|
|
344
114
|
|
|
345
|
-
// View change event
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
} catch (error) {
|
|
353
|
-
console.error('Error in viewChange event handler:', error);
|
|
354
|
-
}
|
|
355
|
-
}, 100); // Throttle to max 10 events per second
|
|
356
|
-
|
|
357
|
-
const viewChangeListenerId = mapView.eventsHandler.on('viewChange', throttledViewChange);
|
|
115
|
+
// View change event
|
|
116
|
+
const viewChangeListenerId = mapView.eventsHandler.on('viewChange', (args) => {
|
|
117
|
+
notifyNative("viewChange", {
|
|
118
|
+
viewOptions: safeToJSON(args.viewOptions),
|
|
119
|
+
timestamp: Date.now()
|
|
120
|
+
});
|
|
121
|
+
});
|
|
358
122
|
|
|
359
123
|
// Location selection event
|
|
360
124
|
const selectListenerId = mapView.eventsHandler.on('select', (args) => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
});
|
|
366
|
-
} catch (error) {
|
|
367
|
-
console.error('Error in select event handler:', error);
|
|
368
|
-
notifyNative("onError", {
|
|
369
|
-
message: error.message,
|
|
370
|
-
event: 'select',
|
|
371
|
-
timestamp: Date.now()
|
|
372
|
-
});
|
|
373
|
-
}
|
|
125
|
+
notifyNative("locationSelect", {
|
|
126
|
+
locations: args.locations?.map(loc => safeToJSON(loc)) || [],
|
|
127
|
+
timestamp: Date.now()
|
|
128
|
+
});
|
|
374
129
|
});
|
|
375
130
|
|
|
376
131
|
// Floor switch event
|
|
377
132
|
const switchToFloorListenerId = mapView.eventsHandler.on('switchToFloor', (args) => {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
});
|
|
383
|
-
} catch (error) {
|
|
384
|
-
console.error('Error in switchToFloor event handler:', error);
|
|
385
|
-
notifyNative("onError", {
|
|
386
|
-
message: error.message,
|
|
387
|
-
event: 'switchToFloor',
|
|
388
|
-
timestamp: Date.now()
|
|
389
|
-
});
|
|
390
|
-
}
|
|
133
|
+
notifyNative("floorSwitch", {
|
|
134
|
+
floor: safeToJSON(args.floor),
|
|
135
|
+
timestamp: Date.now()
|
|
136
|
+
});
|
|
391
137
|
});
|
|
392
138
|
|
|
393
139
|
// Route step load event
|
|
394
140
|
const stepLoadListenerId = mapView.eventsHandler.on('stepLoad', (args) => {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
});
|
|
400
|
-
} catch (error) {
|
|
401
|
-
console.error('Error in stepLoad event handler:', error);
|
|
402
|
-
notifyNative("onError", {
|
|
403
|
-
message: error.message,
|
|
404
|
-
event: 'stepLoad',
|
|
405
|
-
timestamp: Date.now()
|
|
406
|
-
});
|
|
407
|
-
}
|
|
141
|
+
notifyNative("stepLoad", {
|
|
142
|
+
step: safeToJSON(args.step),
|
|
143
|
+
timestamp: Date.now()
|
|
144
|
+
});
|
|
408
145
|
});
|
|
409
146
|
|
|
410
147
|
// Walkthrough end event
|
|
411
148
|
const walkthroughEndListenerId = mapView.eventsHandler.on('walkthroughEnd', () => {
|
|
412
|
-
|
|
413
|
-
notifyNative("onWalkthroughEnd", { timestamp: Date.now() });
|
|
414
|
-
} catch (error) {
|
|
415
|
-
console.error('Error in walkthroughEnd event handler:', error);
|
|
416
|
-
notifyNative("onError", {
|
|
417
|
-
message: error.message,
|
|
418
|
-
event: 'walkthroughEnd',
|
|
419
|
-
timestamp: Date.now()
|
|
420
|
-
});
|
|
421
|
-
}
|
|
149
|
+
notifyNative("walkthroughEnd", { timestamp: Date.now() });
|
|
422
150
|
});
|
|
423
151
|
|
|
424
152
|
// Store listener IDs for cleanup
|
|
@@ -454,135 +182,36 @@
|
|
|
454
182
|
// ============================================================================
|
|
455
183
|
|
|
456
184
|
/**
|
|
457
|
-
* Initializes the map with site options
|
|
185
|
+
* Initializes the map with site options
|
|
458
186
|
* @param {Object} siteOptions - Site configuration options
|
|
459
187
|
*/
|
|
460
|
-
function init(siteOptions) {
|
|
461
|
-
// Validate input parameters
|
|
462
|
-
if (!siteOptions || typeof siteOptions !== 'object') {
|
|
463
|
-
const error = new Error('Invalid siteOptions provided');
|
|
464
|
-
notifyNative("onError", {
|
|
465
|
-
message: error.message,
|
|
466
|
-
timestamp: Date.now(),
|
|
467
|
-
operation: "init",
|
|
468
|
-
siteOptions: siteOptions
|
|
469
|
-
});
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// Check if already initialized
|
|
474
|
-
if (window._appState === 'ready' && window._mapView) {
|
|
475
|
-
console.warn('Map already initialized');
|
|
476
|
-
notifyNative("onRenderComplete", {
|
|
477
|
-
site: safeToJSON(window._site),
|
|
478
|
-
timestamp: Date.now(),
|
|
479
|
-
appState: window._appState
|
|
480
|
-
});
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
window._appState = 'initializing';
|
|
485
|
-
|
|
188
|
+
async function init(siteOptions) {
|
|
486
189
|
try {
|
|
487
190
|
const container = document.getElementById('mapContainer');
|
|
488
191
|
if (!container) {
|
|
489
192
|
throw new Error('Map container not found');
|
|
490
193
|
}
|
|
491
194
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
attempts++;
|
|
500
|
-
|
|
501
|
-
if (window.becomap?.getSite && window.becomap?.getMapView) {
|
|
502
|
-
clearInterval(checkInterval);
|
|
503
|
-
resolve();
|
|
504
|
-
} else if (attempts >= maxAttempts) {
|
|
505
|
-
clearInterval(checkInterval);
|
|
506
|
-
reject(new Error('Becomap UMD failed to load within timeout'));
|
|
507
|
-
}
|
|
508
|
-
}, 100);
|
|
509
|
-
});
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
// Initialize with proper error handling and timeouts
|
|
513
|
-
checkBecomapLoaded()
|
|
514
|
-
.then(() => {
|
|
515
|
-
const mapOptions = { zoom: 18.5 };
|
|
516
|
-
|
|
517
|
-
// Add timeout to getSite
|
|
518
|
-
const getSiteWithTimeout = Promise.race([
|
|
519
|
-
window.becomap.getSite(siteOptions),
|
|
520
|
-
new Promise((_, reject) =>
|
|
521
|
-
setTimeout(() => reject(new Error('getSite timeout')), 10000)
|
|
522
|
-
)
|
|
523
|
-
]);
|
|
524
|
-
|
|
525
|
-
return getSiteWithTimeout;
|
|
526
|
-
})
|
|
527
|
-
.then(site => {
|
|
528
|
-
if (!site) {
|
|
529
|
-
throw new Error('Failed to load site data');
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
window._site = site;
|
|
533
|
-
|
|
534
|
-
// Add timeout to getMapView
|
|
535
|
-
const getMapViewWithTimeout = Promise.race([
|
|
536
|
-
window.becomap.getMapView(container, site, { zoom: 18.5 }),
|
|
537
|
-
new Promise((_, reject) =>
|
|
538
|
-
setTimeout(() => reject(new Error('getMapView timeout')), 15000)
|
|
539
|
-
)
|
|
540
|
-
]);
|
|
541
|
-
|
|
542
|
-
return getMapViewWithTimeout;
|
|
543
|
-
})
|
|
544
|
-
.then(mapView => {
|
|
545
|
-
if (!mapView) {
|
|
546
|
-
throw new Error('Failed to create map view');
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
window._mapView = mapView;
|
|
550
|
-
|
|
551
|
-
// Setup event listeners
|
|
552
|
-
setupMapViewEventListeners(mapView);
|
|
553
|
-
|
|
554
|
-
// Initialize bridge health monitoring
|
|
555
|
-
updateBridgeHealth(isNativeBridgeAvailable());
|
|
556
|
-
|
|
557
|
-
console.log('Map initialization completed successfully');
|
|
558
|
-
})
|
|
559
|
-
.catch(err => {
|
|
560
|
-
window._appState = 'error';
|
|
561
|
-
console.error('Init error:', err);
|
|
562
|
-
|
|
563
|
-
notifyNative("onError", {
|
|
564
|
-
message: err.message,
|
|
565
|
-
stack: err.stack,
|
|
566
|
-
timestamp: Date.now(),
|
|
567
|
-
operation: "init",
|
|
568
|
-
siteOptions,
|
|
569
|
-
appState: window._appState,
|
|
570
|
-
containerExists: !!document.getElementById('mapContainer'),
|
|
571
|
-
becomapLoaded: !!(window.becomap?.getSite && window.becomap?.getMapView)
|
|
572
|
-
});
|
|
573
|
-
});
|
|
195
|
+
if (!window.becomap?.getSite || !window.becomap?.getMapView) {
|
|
196
|
+
throw new Error('Becomap UMD not loaded');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const mapOptions = { zoom: 18.5 };
|
|
200
|
+
window._site = await window.becomap.getSite(siteOptions);
|
|
201
|
+
window._mapView = await window.becomap.getMapView(container, window._site, mapOptions);
|
|
574
202
|
|
|
575
|
-
|
|
576
|
-
window.
|
|
577
|
-
console.error('Init synchronous error:', err);
|
|
203
|
+
// Setup event listeners
|
|
204
|
+
setupMapViewEventListeners(window._mapView);
|
|
578
205
|
|
|
579
|
-
notifyNative("
|
|
206
|
+
notifyNative("onRenderComplete", {
|
|
207
|
+
site: safeToJSON(window._site),
|
|
208
|
+
timestamp: Date.now()
|
|
209
|
+
});
|
|
210
|
+
} catch (err) {
|
|
211
|
+
console.error('Init error:', err);
|
|
212
|
+
notifyNative("initError", {
|
|
580
213
|
message: err.message,
|
|
581
|
-
|
|
582
|
-
timestamp: Date.now(),
|
|
583
|
-
operation: "init",
|
|
584
|
-
siteOptions,
|
|
585
|
-
appState: window._appState
|
|
214
|
+
timestamp: Date.now()
|
|
586
215
|
});
|
|
587
216
|
}
|
|
588
217
|
}
|
|
@@ -593,104 +222,68 @@
|
|
|
593
222
|
|
|
594
223
|
// Floor and Location Methods
|
|
595
224
|
globalThis.getCurrentFloor = () => {
|
|
596
|
-
executeWithErrorHandling(
|
|
225
|
+
const floor = executeWithErrorHandling(
|
|
597
226
|
() => window._mapView?.currentFloor,
|
|
598
|
-
"
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
notifyNative("onGetCurrentFloor", safeToJSON(floor));
|
|
602
|
-
}).catch(error => {
|
|
603
|
-
console.error('Error in getCurrentFloor:', error);
|
|
604
|
-
notifyNative("onGetCurrentFloor", null);
|
|
605
|
-
});
|
|
227
|
+
"getCurrentFloorError"
|
|
228
|
+
);
|
|
229
|
+
notifyNative("getCurrentFloor", safeToJSON(floor));
|
|
606
230
|
};
|
|
607
231
|
|
|
608
232
|
globalThis.selectFloorWithId = (floor) => {
|
|
609
233
|
executeWithErrorHandling(
|
|
610
234
|
() => window._mapView?.selectFloorWithId(floor),
|
|
611
|
-
"
|
|
612
|
-
{ operation: "selectFloorWithId", floor }
|
|
235
|
+
"selectFloorError"
|
|
613
236
|
);
|
|
614
237
|
};
|
|
615
238
|
|
|
616
239
|
globalThis.selectLocationWithId = (location) => {
|
|
617
240
|
executeWithErrorHandling(
|
|
618
241
|
() => window._mapView?.selectLocationWithId(location),
|
|
619
|
-
"
|
|
620
|
-
{ operation: "selectLocationWithId", location }
|
|
242
|
+
"selectLocationError"
|
|
621
243
|
);
|
|
622
244
|
};
|
|
623
245
|
|
|
624
246
|
// Data Retrieval Methods
|
|
625
247
|
globalThis.getCategories = () => {
|
|
626
|
-
executeWithErrorHandling(
|
|
248
|
+
const categories = executeWithErrorHandling(
|
|
627
249
|
() => window._mapView?.getCategories(),
|
|
628
|
-
"
|
|
629
|
-
{ operation: "getCategories" },
|
|
250
|
+
"getCategoriesError",
|
|
630
251
|
[]
|
|
631
|
-
)
|
|
632
|
-
|
|
633
|
-
const categoriesArray = Array.isArray(categories) ? categories : [];
|
|
634
|
-
notifyNative("onGetCategories", categoriesArray.map(cat => safeToJSON(cat)));
|
|
635
|
-
}).catch(error => {
|
|
636
|
-
console.error('Error in getCategories:', error);
|
|
637
|
-
notifyNative("onGetCategories", []);
|
|
638
|
-
});
|
|
252
|
+
);
|
|
253
|
+
notifyNative("getCategories", categories?.map(cat => safeToJSON(cat)) || []);
|
|
639
254
|
};
|
|
640
255
|
|
|
641
256
|
globalThis.getLocations = () => {
|
|
642
|
-
executeWithErrorHandling(
|
|
257
|
+
const locations = executeWithErrorHandling(
|
|
643
258
|
() => window._mapView?.getLocations(),
|
|
644
|
-
"
|
|
645
|
-
{ operation: "getLocations" },
|
|
259
|
+
"getLocationsError",
|
|
646
260
|
[]
|
|
647
|
-
)
|
|
648
|
-
|
|
649
|
-
const locationsArray = Array.isArray(locations) ? locations : [];
|
|
650
|
-
notifyNative("onGetLocations", locationsArray.map(loc => safeToJSON(loc)));
|
|
651
|
-
}).catch(error => {
|
|
652
|
-
console.error('Error in getLocations:', error);
|
|
653
|
-
notifyNative("onGetLocations", []);
|
|
654
|
-
});
|
|
261
|
+
);
|
|
262
|
+
notifyNative("getLocations", locations?.map(loc => safeToJSON(loc)) || []);
|
|
655
263
|
};
|
|
656
264
|
|
|
657
|
-
globalThis.
|
|
658
|
-
executeWithErrorHandling(
|
|
265
|
+
globalThis.getAllAmenities = () => {
|
|
266
|
+
const amenities = executeWithErrorHandling(
|
|
659
267
|
() => window._mapView?.getAllAminityLocations(),
|
|
660
|
-
"
|
|
661
|
-
{ operation: "getAmenities" },
|
|
268
|
+
"getAllAmenitiesError",
|
|
662
269
|
[]
|
|
663
|
-
)
|
|
664
|
-
|
|
665
|
-
const amenitiesArray = Array.isArray(amenities) ? amenities : [];
|
|
666
|
-
notifyNative("onGetAmenities", amenitiesArray.map(amenity => safeToJSON(amenity)));
|
|
667
|
-
}).catch(error => {
|
|
668
|
-
console.error('Error in getAmenities:', error);
|
|
669
|
-
notifyNative("onGetAmenities", []);
|
|
670
|
-
});
|
|
270
|
+
);
|
|
271
|
+
notifyNative("getAllAmenities", amenities?.map(amenity => safeToJSON(amenity)) || []);
|
|
671
272
|
};
|
|
672
273
|
|
|
673
|
-
globalThis.
|
|
674
|
-
executeWithErrorHandling(
|
|
274
|
+
globalThis.getAmenities = () => {
|
|
275
|
+
const amenities = executeWithErrorHandling(
|
|
675
276
|
() => window._mapView?.getAmenities(),
|
|
676
|
-
"
|
|
677
|
-
{ operation: "getAmenityTypes" },
|
|
277
|
+
"getAmenitiesError",
|
|
678
278
|
[]
|
|
679
|
-
)
|
|
680
|
-
|
|
681
|
-
const amenitiesArray = Array.isArray(amenities) ? amenities : [];
|
|
682
|
-
notifyNative("onGetAmenityTypes", amenitiesArray.map(amenity => safeToJSON(amenity)));
|
|
683
|
-
}).catch(error => {
|
|
684
|
-
console.error('Error in getAmenityTypes:', error);
|
|
685
|
-
notifyNative("onGetAmenityTypes", []);
|
|
686
|
-
});
|
|
279
|
+
);
|
|
280
|
+
notifyNative("getAmenities", amenities?.map(amenity => safeToJSON(amenity)) || []);
|
|
687
281
|
};
|
|
688
282
|
|
|
689
283
|
globalThis.selectAmenities = (type) => {
|
|
690
284
|
executeWithErrorHandling(
|
|
691
285
|
() => window._mapView?.selectAmenities(type),
|
|
692
|
-
"
|
|
693
|
-
{ operation: "selectAmenities", type }
|
|
286
|
+
"selectAmenitiesError"
|
|
694
287
|
);
|
|
695
288
|
};
|
|
696
289
|
|
|
@@ -698,43 +291,41 @@
|
|
|
698
291
|
globalThis.getSessionId = async () => {
|
|
699
292
|
try {
|
|
700
293
|
const sessionId = await window._mapView?.getSessionId();
|
|
701
|
-
notifyNative("
|
|
294
|
+
notifyNative("getSessionId", sessionId);
|
|
702
295
|
} catch (err) {
|
|
703
|
-
notifyNative("
|
|
296
|
+
notifyNative("getSessionIdError", {
|
|
704
297
|
message: err.message,
|
|
705
|
-
timestamp: Date.now()
|
|
706
|
-
operation: "getSessionId"
|
|
298
|
+
timestamp: Date.now()
|
|
707
299
|
});
|
|
708
300
|
}
|
|
709
301
|
};
|
|
710
302
|
|
|
303
|
+
globalThis.getQuestions = () => {
|
|
304
|
+
const questions = executeWithErrorHandling(
|
|
305
|
+
() => window._mapView?.getQuestions(),
|
|
306
|
+
"getQuestionsError",
|
|
307
|
+
[]
|
|
308
|
+
);
|
|
309
|
+
notifyNative("getQuestions", questions?.map(q => safeToJSON(q)) || []);
|
|
310
|
+
};
|
|
311
|
+
|
|
711
312
|
globalThis.getHappenings = (type) => {
|
|
712
|
-
executeWithErrorHandling(
|
|
313
|
+
const happenings = executeWithErrorHandling(
|
|
713
314
|
() => window._mapView?.getHappenings(type),
|
|
714
|
-
"
|
|
715
|
-
{ operation: "getHappenings", type },
|
|
315
|
+
"getHappeningsError",
|
|
716
316
|
[]
|
|
717
|
-
)
|
|
718
|
-
|
|
719
|
-
const happeningsArray = Array.isArray(happenings) ? happenings : [];
|
|
720
|
-
notifyNative("onGetHappenings", happeningsArray.map(h => safeToJSON(h)));
|
|
721
|
-
}).catch(error => {
|
|
722
|
-
console.error('Error in getHappenings:', error);
|
|
723
|
-
notifyNative("onGetHappenings", []);
|
|
724
|
-
});
|
|
317
|
+
);
|
|
318
|
+
notifyNative("getHappenings", happenings?.map(h => safeToJSON(h)) || []);
|
|
725
319
|
};
|
|
726
320
|
|
|
727
321
|
globalThis.getEventSuggestions = async (sessionId, answers) => {
|
|
728
322
|
try {
|
|
729
323
|
const suggestions = await window._mapView?.getEventSuggestions(sessionId, answers);
|
|
730
|
-
notifyNative("
|
|
324
|
+
notifyNative("getEventSuggestions", suggestions?.map(s => safeToJSON(s)) || []);
|
|
731
325
|
} catch (err) {
|
|
732
|
-
notifyNative("
|
|
326
|
+
notifyNative("getEventSuggestionsError", {
|
|
733
327
|
message: err.message,
|
|
734
|
-
timestamp: Date.now()
|
|
735
|
-
operation: "getEventSuggestions",
|
|
736
|
-
sessionId,
|
|
737
|
-
answers
|
|
328
|
+
timestamp: Date.now()
|
|
738
329
|
});
|
|
739
330
|
}
|
|
740
331
|
};
|
|
@@ -743,79 +334,70 @@
|
|
|
743
334
|
globalThis.focusTo = (location, zoom, bearing, pitch) => {
|
|
744
335
|
executeWithErrorHandling(
|
|
745
336
|
() => window._mapView?.focusTo(location, zoom, bearing, pitch),
|
|
746
|
-
"
|
|
747
|
-
{ operation: "focusTo", location, zoom, bearing, pitch }
|
|
337
|
+
"focusToError"
|
|
748
338
|
);
|
|
749
339
|
};
|
|
750
340
|
|
|
751
341
|
globalThis.clearSelection = () => {
|
|
752
342
|
executeWithErrorHandling(
|
|
753
343
|
() => window._mapView?.clearSelection(),
|
|
754
|
-
"
|
|
755
|
-
{ operation: "clearSelection" }
|
|
344
|
+
"clearSelectionError"
|
|
756
345
|
);
|
|
757
346
|
};
|
|
758
347
|
|
|
759
348
|
globalThis.updateZoom = (zoom) => {
|
|
760
349
|
executeWithErrorHandling(
|
|
761
350
|
() => window._mapView?.updateZoom(zoom),
|
|
762
|
-
"
|
|
763
|
-
{ operation: "updateZoom", zoom }
|
|
351
|
+
"updateZoomError"
|
|
764
352
|
);
|
|
765
353
|
};
|
|
766
354
|
|
|
767
355
|
globalThis.updatePitch = (pitch) => {
|
|
768
356
|
executeWithErrorHandling(
|
|
769
357
|
() => window._mapView?.updatePitch(pitch),
|
|
770
|
-
"
|
|
771
|
-
{ operation: "updatePitch", pitch }
|
|
358
|
+
"updatePitchError"
|
|
772
359
|
);
|
|
773
360
|
};
|
|
774
361
|
|
|
775
362
|
globalThis.updateBearing = (bearing) => {
|
|
776
363
|
executeWithErrorHandling(
|
|
777
364
|
() => window._mapView?.updateBearing(bearing),
|
|
778
|
-
"
|
|
779
|
-
{ operation: "updateBearing", bearing }
|
|
365
|
+
"updateBearingError"
|
|
780
366
|
);
|
|
781
367
|
};
|
|
782
368
|
|
|
783
369
|
globalThis.enableMultiSelection = (val) => {
|
|
784
370
|
executeWithErrorHandling(
|
|
785
371
|
() => window._mapView?.enableMultiSelection(val),
|
|
786
|
-
"
|
|
787
|
-
{ operation: "enableMultiSelection", value: val }
|
|
372
|
+
"enableMultiSelectionError"
|
|
788
373
|
);
|
|
789
374
|
};
|
|
790
375
|
|
|
791
376
|
globalThis.setBounds = (sw, ne) => {
|
|
792
377
|
executeWithErrorHandling(
|
|
793
378
|
() => window._mapView?.setBounds(sw, ne),
|
|
794
|
-
"
|
|
795
|
-
{ operation: "setBounds", southwest: sw, northeast: ne }
|
|
379
|
+
"setBoundsError"
|
|
796
380
|
);
|
|
797
381
|
};
|
|
798
382
|
|
|
799
383
|
globalThis.setViewport = (options) => {
|
|
800
384
|
executeWithErrorHandling(
|
|
801
385
|
() => window._mapView?.setViewport(options),
|
|
802
|
-
"
|
|
803
|
-
{ operation: "setViewport", options }
|
|
386
|
+
"setViewportError"
|
|
804
387
|
);
|
|
805
388
|
};
|
|
806
389
|
|
|
807
390
|
globalThis.resetDefaultViewport = (options) => {
|
|
808
391
|
executeWithErrorHandling(
|
|
809
392
|
() => window._mapView?.resetDefaultViewport(options),
|
|
810
|
-
"
|
|
811
|
-
{ operation: "resetDefaultViewport", options }
|
|
393
|
+
"resetDefaultViewportError"
|
|
812
394
|
);
|
|
813
395
|
};
|
|
814
396
|
|
|
815
397
|
// Search Methods
|
|
816
398
|
globalThis.searchForLocations = (q, callbackId) => {
|
|
817
399
|
if (!window._mapView?.searchForLocations) {
|
|
818
|
-
notifyNative("
|
|
400
|
+
notifyNative("searchForLocations", {
|
|
819
401
|
callbackId,
|
|
820
402
|
results: [],
|
|
821
403
|
error: "Search method not available"
|
|
@@ -824,7 +406,7 @@
|
|
|
824
406
|
}
|
|
825
407
|
|
|
826
408
|
window._mapView.searchForLocations(q, (matches) => {
|
|
827
|
-
notifyNative("
|
|
409
|
+
notifyNative("searchForLocations", {
|
|
828
410
|
callbackId,
|
|
829
411
|
results: matches?.map(m => safeToJSON(m)) || []
|
|
830
412
|
});
|
|
@@ -833,7 +415,7 @@
|
|
|
833
415
|
|
|
834
416
|
globalThis.searchForCategories = (q, callbackId) => {
|
|
835
417
|
if (!window._mapView?.searchForCategories) {
|
|
836
|
-
notifyNative("
|
|
418
|
+
notifyNative("searchForCategories", {
|
|
837
419
|
callbackId,
|
|
838
420
|
results: [],
|
|
839
421
|
error: "Search method not available"
|
|
@@ -842,7 +424,7 @@
|
|
|
842
424
|
}
|
|
843
425
|
|
|
844
426
|
window._mapView.searchForCategories(q, (matches) => {
|
|
845
|
-
notifyNative("
|
|
427
|
+
notifyNative("searchForCategories", {
|
|
846
428
|
callbackId,
|
|
847
429
|
results: matches?.map(m => safeToJSON(m)) || []
|
|
848
430
|
});
|
|
@@ -856,53 +438,33 @@
|
|
|
856
438
|
globalThis.getRoute = (startID, goalID, waypoints = [], routeOptions) => {
|
|
857
439
|
try {
|
|
858
440
|
const routes = window.becomap.getRouteById(startID, goalID, waypoints, routeOptions);
|
|
859
|
-
notifyNative("
|
|
441
|
+
notifyNative("getRoute", routes?.map(route => safeToJSON(route)) || []);
|
|
860
442
|
} catch (error) {
|
|
861
|
-
notifyNative("
|
|
443
|
+
notifyNative("getRouteError", {
|
|
862
444
|
message: error.message,
|
|
863
|
-
timestamp: Date.now()
|
|
864
|
-
operation: "getRoute",
|
|
865
|
-
startID,
|
|
866
|
-
goalID,
|
|
867
|
-
waypoints,
|
|
868
|
-
routeOptions
|
|
445
|
+
timestamp: Date.now()
|
|
869
446
|
});
|
|
870
447
|
}
|
|
871
448
|
};
|
|
872
449
|
|
|
873
|
-
globalThis.showRoute = (
|
|
450
|
+
globalThis.showRoute = () => {
|
|
874
451
|
executeWithErrorHandling(
|
|
875
|
-
() =>
|
|
876
|
-
|
|
877
|
-
if (!routeController) return;
|
|
878
|
-
|
|
879
|
-
if (segmentOrderIndex !== undefined) {
|
|
880
|
-
routeController.showSegmentByOrderIndex(segmentOrderIndex);
|
|
881
|
-
} else {
|
|
882
|
-
const segments = routeController.segments;
|
|
883
|
-
if (segments && segments.length > 0) {
|
|
884
|
-
routeController.showRoute(segments);
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
},
|
|
888
|
-
"onError",
|
|
889
|
-
{ operation: "showRoute", segmentOrderIndex }
|
|
452
|
+
() => window._mapView?.routeController?.showSavedRoute(),
|
|
453
|
+
"showRouteError"
|
|
890
454
|
);
|
|
891
455
|
};
|
|
892
456
|
|
|
893
457
|
globalThis.showStep = (step) => {
|
|
894
458
|
executeWithErrorHandling(
|
|
895
459
|
() => window._mapView?.routeController?.showStepByOrderIndex(step),
|
|
896
|
-
"
|
|
897
|
-
{ operation: "showStep", step }
|
|
460
|
+
"showStepError"
|
|
898
461
|
);
|
|
899
462
|
};
|
|
900
463
|
|
|
901
464
|
globalThis.clearAllRoutes = () => {
|
|
902
465
|
executeWithErrorHandling(
|
|
903
466
|
() => window._mapView?.routeController?.clearAllRoutes(),
|
|
904
|
-
"
|
|
905
|
-
{ operation: "clearAllRoutes" }
|
|
467
|
+
"clearAllRoutesError"
|
|
906
468
|
);
|
|
907
469
|
};
|
|
908
470
|
|
|
@@ -911,180 +473,28 @@
|
|
|
911
473
|
// ============================================================================
|
|
912
474
|
|
|
913
475
|
/**
|
|
914
|
-
*
|
|
476
|
+
* Cleanup function to be called when the webview is destroyed
|
|
915
477
|
*/
|
|
916
478
|
globalThis.cleanup = () => {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
// Clear event listeners
|
|
922
|
-
clearMapViewEventListeners();
|
|
923
|
-
|
|
924
|
-
// Clear operation queue
|
|
925
|
-
window._operationQueue = [];
|
|
926
|
-
window._isProcessingQueue = false;
|
|
927
|
-
|
|
928
|
-
// Reset bridge health
|
|
929
|
-
window._bridgeHealth = {
|
|
930
|
-
isConnected: false,
|
|
931
|
-
lastHeartbeat: null,
|
|
932
|
-
connectionAttempts: 0,
|
|
933
|
-
maxRetries: 3
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
// Cleanup map view
|
|
937
|
-
if (window._mapView && typeof window._mapView.destroy === 'function') {
|
|
938
|
-
window._mapView.destroy();
|
|
939
|
-
}
|
|
940
|
-
window._mapView = null;
|
|
941
|
-
|
|
942
|
-
// Clear site data
|
|
943
|
-
window._site = null;
|
|
944
|
-
|
|
945
|
-
// Clear any stored failed messages
|
|
946
|
-
try {
|
|
947
|
-
localStorage.removeItem('becomap_failed_messages');
|
|
948
|
-
} catch (e) {
|
|
949
|
-
console.warn('Failed to clear localStorage:', e);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
console.log('Cleanup completed successfully');
|
|
953
|
-
|
|
954
|
-
// Final notification to native
|
|
955
|
-
notifyNative("onCleanupComplete", {
|
|
956
|
-
timestamp: Date.now(),
|
|
957
|
-
appState: window._appState
|
|
958
|
-
}, true); // Skip queue for final message
|
|
959
|
-
|
|
960
|
-
} catch (error) {
|
|
961
|
-
console.error('Error during cleanup:', error);
|
|
962
|
-
notifyNative("onError", {
|
|
963
|
-
message: error.message,
|
|
964
|
-
operation: "cleanup",
|
|
965
|
-
timestamp: Date.now()
|
|
966
|
-
}, true);
|
|
967
|
-
}
|
|
968
|
-
};
|
|
969
|
-
|
|
970
|
-
/**
|
|
971
|
-
* Application state management
|
|
972
|
-
*/
|
|
973
|
-
globalThis.getAppState = () => {
|
|
974
|
-
const state = {
|
|
975
|
-
appState: window._appState,
|
|
976
|
-
bridgeHealth: { ...window._bridgeHealth },
|
|
977
|
-
queueLength: window._operationQueue.length,
|
|
978
|
-
hasMapView: !!window._mapView,
|
|
979
|
-
hasSite: !!window._site,
|
|
980
|
-
timestamp: Date.now()
|
|
981
|
-
};
|
|
982
|
-
|
|
983
|
-
notifyNative("onGetAppState", state);
|
|
984
|
-
return state;
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
/**
|
|
988
|
-
* Health check function for native to verify bridge connectivity
|
|
989
|
-
*/
|
|
990
|
-
globalThis.healthCheck = () => {
|
|
991
|
-
const healthData = {
|
|
992
|
-
timestamp: Date.now(),
|
|
993
|
-
appState: window._appState,
|
|
994
|
-
bridgeConnected: isNativeBridgeAvailable(),
|
|
995
|
-
mapViewReady: !!window._mapView,
|
|
996
|
-
siteLoaded: !!window._site,
|
|
997
|
-
queueLength: window._operationQueue.length,
|
|
998
|
-
lastHeartbeat: window._bridgeHealth.lastHeartbeat
|
|
999
|
-
};
|
|
1000
|
-
|
|
1001
|
-
updateBridgeHealth(true); // Update heartbeat
|
|
1002
|
-
notifyNative("onHealthCheck", healthData);
|
|
1003
|
-
|
|
1004
|
-
return healthData;
|
|
1005
|
-
};
|
|
1006
|
-
|
|
1007
|
-
/**
|
|
1008
|
-
* Error recovery function
|
|
1009
|
-
*/
|
|
1010
|
-
globalThis.recoverFromError = () => {
|
|
1011
|
-
try {
|
|
1012
|
-
console.log('Attempting error recovery...');
|
|
1013
|
-
|
|
1014
|
-
// Reset app state if in error
|
|
1015
|
-
if (window._appState === 'error') {
|
|
1016
|
-
window._appState = 'initializing';
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
// Clear failed operations
|
|
1020
|
-
window._operationQueue = [];
|
|
1021
|
-
window._isProcessingQueue = false;
|
|
1022
|
-
|
|
1023
|
-
// Reset bridge health
|
|
1024
|
-
updateBridgeHealth(isNativeBridgeAvailable());
|
|
1025
|
-
|
|
1026
|
-
// Process any pending operations
|
|
1027
|
-
processOperationQueue();
|
|
1028
|
-
|
|
1029
|
-
notifyNative("onErrorRecovery", {
|
|
1030
|
-
timestamp: Date.now(),
|
|
1031
|
-
appState: window._appState,
|
|
1032
|
-
bridgeHealth: { ...window._bridgeHealth }
|
|
1033
|
-
});
|
|
1034
|
-
|
|
1035
|
-
console.log('Error recovery completed');
|
|
1036
|
-
|
|
1037
|
-
} catch (error) {
|
|
1038
|
-
console.error('Error during recovery:', error);
|
|
1039
|
-
notifyNative("onError", {
|
|
1040
|
-
message: error.message,
|
|
1041
|
-
operation: "recoverFromError",
|
|
1042
|
-
timestamp: Date.now()
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
|
|
1047
|
-
/**
|
|
1048
|
-
* Debug information function
|
|
1049
|
-
*/
|
|
1050
|
-
globalThis.getDebugInfo = () => {
|
|
1051
|
-
const debugInfo = {
|
|
1052
|
-
timestamp: Date.now(),
|
|
1053
|
-
appState: window._appState,
|
|
1054
|
-
bridgeHealth: { ...window._bridgeHealth },
|
|
1055
|
-
queueLength: window._operationQueue.length,
|
|
1056
|
-
hasMapView: !!window._mapView,
|
|
1057
|
-
hasSite: !!window._site,
|
|
1058
|
-
eventListeners: window._eventListeners.size,
|
|
1059
|
-
userAgent: navigator.userAgent,
|
|
1060
|
-
url: window.location.href,
|
|
1061
|
-
becomapLoaded: !!(window.becomap?.getSite && window.becomap?.getMapView),
|
|
1062
|
-
containerExists: !!document.getElementById('mapContainer')
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
// Get failed messages from localStorage
|
|
1066
|
-
try {
|
|
1067
|
-
const failedMessages = JSON.parse(localStorage.getItem('becomap_failed_messages') || '[]');
|
|
1068
|
-
debugInfo.failedMessagesCount = failedMessages.length;
|
|
1069
|
-
debugInfo.lastFailedMessage = failedMessages[failedMessages.length - 1];
|
|
1070
|
-
} catch (e) {
|
|
1071
|
-
debugInfo.failedMessagesError = e.message;
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
notifyNative("onGetDebugInfo", debugInfo);
|
|
1075
|
-
return debugInfo;
|
|
479
|
+
clearMapViewEventListeners();
|
|
480
|
+
window._mapView = null;
|
|
481
|
+
window._site = null;
|
|
1076
482
|
};
|
|
1077
483
|
|
|
1078
|
-
// Initialize bridge health monitoring
|
|
1079
|
-
updateBridgeHealth(isNativeBridgeAvailable());
|
|
1080
|
-
|
|
1081
|
-
// Set up periodic health checks
|
|
1082
|
-
setInterval(() => {
|
|
1083
|
-
if (window._appState !== 'destroyed') {
|
|
1084
|
-
updateBridgeHealth(isNativeBridgeAvailable());
|
|
1085
|
-
}
|
|
1086
|
-
}, 5000); // Check every 5 seconds
|
|
1087
|
-
|
|
1088
484
|
// Export init function
|
|
1089
|
-
globalThis.init = init
|
|
1090
|
-
</
|
|
485
|
+
globalThis.init = init;
|
|
486
|
+
</script>
|
|
487
|
+
|
|
488
|
+
<!-- <script>
|
|
489
|
+
const siteOptions = {
|
|
490
|
+
clientId: "c079dfa3a77dad13351cfacd95841c2c2780fe08",
|
|
491
|
+
clientSecret: "f62a59675b2a47ddb75f1f994d88e653",
|
|
492
|
+
siteIdentifier: "67dcf5dd2f21c64e3225254f"
|
|
493
|
+
};
|
|
494
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
495
|
+
init(siteOptions);
|
|
496
|
+
});
|
|
497
|
+
</script> -->
|
|
498
|
+
</body>
|
|
499
|
+
|
|
500
|
+
</html>
|