Skip to content
121 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

preparing for cloud work1// The desktop bridge: what the site finds at `window.g1tDesktop`, run at
2// the start of every page the window loads (bridge.rs puts it there). The
3// site's lib/notify-client.ts describes the contract from its side; when
4// the bridge is there, notifications go to the system, the badge to the
5// icon, links out to the browser, and g1t:// links arrive as `onNavigate`.
6// Each call is a command in bridge.rs, which only answers the server's
7// pages; on any other page the calls fail quietly.
8(function () {
9 if (window.g1tDesktop) return;
10 var VERSION = "__VERSION__";
11 var PLATFORM = "__PLATFORM__";
12
13 function invoke(command, args) {
14 var core = window.__TAURI__ && window.__TAURI__.core;
15 if (core && typeof core.invoke === "function") return core.invoke(command, args || {});
16 var internals = window.__TAURI_INTERNALS__;
17 if (internals && typeof internals.invoke === "function") return internals.invoke(command, args || {});
18 return Promise.reject(new Error("g1t desktop: this page cannot reach the app"));
19 }
20
21 function quietly(promise) {
22 promise.catch(function (error) {
23 console.warn("g1t desktop:", error && error.message ? error.message : error);
24 });
25 }
26
27 var listeners = [];
28 var listening = false;
29 function listen() {
30 if (listening) return;
31 listening = true;
32 var events = window.__TAURI__ && window.__TAURI__.event;
33 if (!events || typeof events.listen !== "function") return;
34 events
35 .listen("g1t-navigate", function (event) {
36 var href = event && event.payload;
37 if (typeof href !== "string") return;
38 listeners.slice().forEach(function (listener) {
39 try {
40 listener(href);
41 } catch (error) {
42 console.warn("g1t desktop: a navigate listener failed", error);
43 }
44 });
45 })
46 .catch(function () {});
47 }
48
49 var bridge = {
50 version: VERSION,
51 platform: PLATFORM,
52 // A native notification, for a message to the person while the window is behind another.
53 notify: function (notification) {
54 quietly(invoke("notify", { title: String(notification.title || "g1t"), body: String(notification.body || "") }));
55 },
56 // What needs the person, on the icon and the tray; 0 clears it.
57 setBadge: function (count) {
58 quietly(invoke("set_badge", { count: Math.max(0, Math.floor(Number(count) || 0)) }));
59 },
60 // A link to somewhere else, in the browser the system uses.
61 openUrl: function (url) {
62 quietly(invoke("open_url", { url: String(url) }));
63 },
64 // g1t:// links, as site paths such as "/acme/-/chat/dm/chn_1".
65 onNavigate: function (listener) {
66 listeners.push(listener);
67 listen();
68 return function () {
69 var at = listeners.indexOf(listener);
70 if (at >= 0) listeners.splice(at, 1);
71 };
72 },
73 // Looks for an update now: "current", "ready:<version>", or rejects with why.
74 checkForUpdates: function () {
75 return invoke("check_for_updates");
76 },
77 };
78 Object.defineProperty(window, "g1tDesktop", { value: Object.freeze(bridge), writable: false, configurable: false });
79
80 // Links out. A link to another site opens in the system's browser, and
81 // the window stays on g1t; a link that asks for a new tab, or a click
82 // with Ctrl or Cmd held, goes on in this window, which has no tabs.
83 function destination(href) {
84 try {
85 var url = new URL(href, location.href);
86 return /^https?:$/.test(url.protocol) ? url : null;
87 } catch (error) {
88 return null;
89 }
90 }
91 document.addEventListener(
92 "click",
93 function (event) {
94 if (event.defaultPrevented || event.button !== 0) return;
95 var anchor = event.target && event.target.closest ? event.target.closest("a[href]") : null;
96 if (!anchor || anchor.hasAttribute("download")) return;
97 var url = destination(anchor.getAttribute("href"));
98 if (!url) return;
99 if (url.origin !== location.origin) {
100 event.preventDefault();
101 event.stopImmediatePropagation();
102 bridge.openUrl(url.href);
103 } else if (anchor.target === "_blank" || event.metaKey || event.ctrlKey) {
104 event.preventDefault();
105 event.stopImmediatePropagation();
106 location.assign(url.href);
107 }
108 },
109 true,
110 );
111 var open = window.open;
112 window.open = function (href, target, features) {
113 var url = destination(href);
114 if (url) {
115 if (url.origin === location.origin) location.assign(url.href);
116 else bridge.openUrl(url.href);
117 return null;
118 }
119 return typeof open === "function" ? open.call(window, href, target, features) : null;
120 };
121})();