app: origin-aware nav handler for URL-origin apps (keep the app in-view)
lantern-run installed default-nav-handler unconditionally, which returns 'external for any non-lantern:/about:/data:/blob: URI. For a URL-origin app (assets: an http(s) URL) that externalizes the app's OWN first load — the page opens in the system browser instead of the webview. The is-url path loaded a URL but never kept it in-view, so it was never actually usable.
Add make-url-nav-handler (allow the app's own origin + lantern:/about:/data:/blob:, externalize only genuinely different origins) + url-origin, and select it in lantern-run when is-url. This is the pivot-required "the Shell renders the node's origin" behavior: slate-shell --url http://localhost:<port> now renders the node PWA in the native window and only sends off-origin links to the browser.
lantern/src/lantern/app.sgl | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)lantern/src/lantern/app.sglmodified
(starts-with? assets "https://") (starts-with? assets "file://")))) ;; The origin (scheme://host[:port], no path) of a URL — everything up to the ;; first '/' after the "scheme://". For a URL-origin app this is the string a ;; same-origin navigation shares as a prefix. (define (url-origin url) (let ((sep (find-substring url "://"))) (if (not sep) url (let ((rest-start (+ sep 3))) (let loop ((i rest-start)) (cond ((>= i (string-length url)) url) ((char=? (string-ref url i) #\/) (substring url 0 i)) (else (loop (+ i 1))))))))) (define (find-substring s sub) (let ((n (string-length s)) (m (string-length sub))) (let loop ((i 0)) (cond ((> (+ i m) n) #f) ((string=? (substring s i (+ i m)) sub) i) (else (loop (+ i 1))))))) ;; The nav handler for a URL-ORIGIN app (assets: an http(s)/file URL). The ;; default handler externalizes every non-lantern:/about:/data:/blob: URI — ;; which, for a URL app, wrongly sends the app's OWN first load to the system ;; browser (a node-origin Slate would open in the user's browser instead of ;; the window). This keeps the app's own origin (and its in-page navigations) ;; in the view, and externalizes only genuinely different origins — the ;; pivot's "the Shell renders the node's origin" behavior. (define (make-url-nav-handler app-url) (let ((origin (url-origin app-url))) (lambda (uri) (if (or (starts-with? uri "lantern:") (starts-with? uri "about:") (starts-with? uri "data:") (starts-with? uri "blob:") (= (string-length uri) 0) (starts-with? uri origin)) 'allow 'external)))) ;; ---- the runner ------------------------------------------------------- (define (lantern-run app (keys: (title #f) (width 1024) (height 768) (when (procedure? init) (init app)))) (dict-ref app plugins: (list))) ;; Origin gate + load + show. (webview-set-nav-handler wv win default-nav-handler) ;; Origin gate + load + show. A URL-origin app keeps its OWN origin in ;; the view (make-url-nav-handler); the embedded lantern://app case uses ;; the default handler (external http links open in the browser). (webview-set-nav-handler wv win (if is-url (make-url-nav-handler assets) default-nav-handler)) ;; Opt-in page-driven close: hand a WM close-request to the page (an ;; `app.close-requested` event) and VETO the immediate close, so the page