'use strict'; /** * GPS Navigator — Qt WebChannel bridge. * * qwebchannel.js is injected by PyQt5 at DocumentCreation time (before any * page script runs), so QWebChannel is always available here. * * Exposes: * window._py(method, arg1, ...) → Promise that resolves with the return value * window.py → the registered bridge object (set after init) */ (function () { // _py('method', arg1, arg2, ...) → Promise // Works for both void slots (resolves undefined) and value-returning slots. window._py = function (method) { var args = Array.prototype.slice.call(arguments, 1); return new Promise(function (resolve) { window.py[method].apply(window.py, args.concat([resolve])); }); }; function _initChannel() { if (typeof QWebChannel === 'undefined' || typeof qt === 'undefined') { // Running in a plain browser (dev mode) — no bridge available. console.warn('[bridge] QWebChannel not available — dev mode, no GPS bridge'); window.py = null; // Let the app start anyway (it will show "no GPS" state) if (typeof window.bootApp === 'function') window.bootApp(); return; } new QWebChannel(qt.webChannelTransport, function (channel) { window.py = channel.objects.py; // ── GPS messages: Python signal → JS handler ──────────────────────── // Qt queues this signal delivery from the NMEA reader thread to the // main thread, so it always arrives in the JS event loop safely. window.py.gpsMessage.connect(function (json_str) { try { var msg = JSON.parse(json_str); if (typeof window.handleGPSMsg === 'function') { window.handleGPSMsg(msg); } } catch (e) { console.error('[bridge] gpsMessage parse error:', e, json_str); } }); // ── Start GPS autodetect (signal handler is now connected) ─────────── window.py.autodetect_and_start(); // ── Boot the application ───────────────────────────────────────────── if (typeof window.bootApp === 'function') { window.bootApp(); } }); } // Run after DOM + all other scripts are loaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', _initChannel); } else { _initChannel(); } })();