sparkbun 0.1.3 → 0.1.5
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.
|
Binary file
|
package/package.json
CHANGED
package/src/bun/proc/native.ts
CHANGED
|
@@ -2595,7 +2595,10 @@ export const Session = {
|
|
|
2595
2595
|
|
|
2596
2596
|
// Stub: native side accepts this parameter but never calls it.
|
|
2597
2597
|
// Remove when native wrappers are recompiled without it.
|
|
2598
|
-
const webviewDecideNavigation =
|
|
2598
|
+
const webviewDecideNavigation = new JSCallback(
|
|
2599
|
+
() => 1,
|
|
2600
|
+
{ args: [FFIType.u32, FFIType.cstring], returns: FFIType.u32 },
|
|
2601
|
+
);
|
|
2599
2602
|
|
|
2600
2603
|
const webviewEventHandler = (id: number, eventName: string, detail: string) => {
|
|
2601
2604
|
BrowserView.ensureWrapped(id);
|
package/src/cli/index.ts
CHANGED
|
@@ -136,8 +136,6 @@ function getPlatformPaths(
|
|
|
136
136
|
CEF_HELPER_LINUX: join(platformDistDir, "process_helper"),
|
|
137
137
|
CEF_DIR: join(platformDistDir, "cef"),
|
|
138
138
|
|
|
139
|
-
PRELOAD_FULL_JS: join(platformDistDir, "preload-full.js"),
|
|
140
|
-
PRELOAD_SANDBOXED_JS: join(platformDistDir, "preload-sandboxed.js"),
|
|
141
139
|
};
|
|
142
140
|
}
|
|
143
141
|
|
|
@@ -2086,31 +2084,39 @@ usageDescriptions : ""}${urlTypes ? "\n" + urlTypes : ""}${documentTypes ?
|
|
|
2086
2084
|
};
|
|
2087
2085
|
|
|
2088
2086
|
if (targetOS === "win") {
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
:
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2087
|
+
if (OS !== "win") {
|
|
2088
|
+
console.warn(
|
|
2089
|
+
`\n⚠️ Cross-compiling for Windows: icon, hideConsole, and PE metadata (title, version, publisher, etc.) will be ignored.\n` +
|
|
2090
|
+
` Bun's Windows-specific compile options require building on a Windows host.\n` +
|
|
2091
|
+
` See: https://bun.com/docs/bundler/executables#windows-specific-flags\n`
|
|
2092
|
+
);
|
|
2093
|
+
} else {
|
|
2094
|
+
let icoPath: string | undefined;
|
|
2095
|
+
if (config.build.win?.icon) {
|
|
2096
|
+
const iconSrc = config.build.win.icon.startsWith("/") || config.build.win.icon.match(/^[a-zA-Z]:/)
|
|
2097
|
+
? config.build.win.icon
|
|
2098
|
+
: join(projectRoot, config.build.win.icon);
|
|
2099
|
+
if (existsSync(iconSrc)) {
|
|
2100
|
+
icoPath = iconSrc;
|
|
2101
|
+
if (iconSrc.toLowerCase().endsWith(".png")) {
|
|
2102
|
+
const pngToIco = (await import("png-to-ico")).default;
|
|
2103
|
+
const tempIcoPath = join(buildFolder, "temp-launcher-icon.ico");
|
|
2104
|
+
const icoBuffer = await pngToIco(iconSrc);
|
|
2105
|
+
writeFileSync(tempIcoPath, new Uint8Array(icoBuffer));
|
|
2106
|
+
icoPath = tempIcoPath;
|
|
2107
|
+
}
|
|
2102
2108
|
}
|
|
2103
2109
|
}
|
|
2110
|
+
compileOptions.windows = {
|
|
2111
|
+
hideConsole: true,
|
|
2112
|
+
...(icoPath && { icon: icoPath }),
|
|
2113
|
+
title: config.app.name,
|
|
2114
|
+
version: config.app.version,
|
|
2115
|
+
description: config.app.name,
|
|
2116
|
+
publisher: config.app.publisher || " ",
|
|
2117
|
+
copyright: config.app.copyright || " ",
|
|
2118
|
+
};
|
|
2104
2119
|
}
|
|
2105
|
-
compileOptions.windows = {
|
|
2106
|
-
hideConsole: true,
|
|
2107
|
-
...(icoPath && { icon: icoPath }),
|
|
2108
|
-
title: config.app.name,
|
|
2109
|
-
version: config.app.version,
|
|
2110
|
-
description: config.app.name,
|
|
2111
|
-
publisher: config.app.publisher || " ",
|
|
2112
|
-
copyright: config.app.copyright || " ",
|
|
2113
|
-
};
|
|
2114
2120
|
}
|
|
2115
2121
|
|
|
2116
2122
|
console.log(`Compiling launcher with Bun.build()...`);
|
|
@@ -2128,16 +2134,6 @@ usageDescriptions : ""}${urlTypes ? "\n" + urlTypes : ""}${documentTypes ?
|
|
|
2128
2134
|
patchPeSubsystem(bunCliLauncherDestination);
|
|
2129
2135
|
}
|
|
2130
2136
|
|
|
2131
|
-
cpSync(targetPaths.PRELOAD_FULL_JS, join(appBundleFolderResourcesPath, "preload-full.js"), {
|
|
2132
|
-
dereference: true,
|
|
2133
|
-
});
|
|
2134
|
-
cpSync(
|
|
2135
|
-
targetPaths.PRELOAD_SANDBOXED_JS,
|
|
2136
|
-
join(appBundleFolderResourcesPath, "preload-sandboxed.js"),
|
|
2137
|
-
{
|
|
2138
|
-
dereference: true,
|
|
2139
|
-
},
|
|
2140
|
-
);
|
|
2141
2137
|
|
|
2142
2138
|
|
|
2143
2139
|
// copy native wrapper dynamic library
|
|
@@ -1,885 +0,0 @@
|
|
|
1
|
-
(function(){// src/bun/preload/encryption.ts
|
|
2
|
-
function base64ToUint8Array(base64) {
|
|
3
|
-
return new Uint8Array(atob(base64).split("").map((char) => char.charCodeAt(0)));
|
|
4
|
-
}
|
|
5
|
-
function uint8ArrayToBase64(uint8Array) {
|
|
6
|
-
let binary = "";
|
|
7
|
-
for (let i = 0;i < uint8Array.length; i++) {
|
|
8
|
-
binary += String.fromCharCode(uint8Array[i]);
|
|
9
|
-
}
|
|
10
|
-
return btoa(binary);
|
|
11
|
-
}
|
|
12
|
-
async function generateKeyFromBytes(rawKey) {
|
|
13
|
-
return await window.crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM" }, true, ["encrypt", "decrypt"]);
|
|
14
|
-
}
|
|
15
|
-
async function initEncryption() {
|
|
16
|
-
const secretKey = await generateKeyFromBytes(new Uint8Array(window.__electrobunSecretKeyBytes));
|
|
17
|
-
const encryptString = async (plaintext) => {
|
|
18
|
-
const encoder = new TextEncoder;
|
|
19
|
-
const encodedText = encoder.encode(plaintext);
|
|
20
|
-
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
|
21
|
-
const encryptedBuffer = await window.crypto.subtle.encrypt({ name: "AES-GCM", iv }, secretKey, encodedText);
|
|
22
|
-
const encryptedData = new Uint8Array(encryptedBuffer.slice(0, -16));
|
|
23
|
-
const tag = new Uint8Array(encryptedBuffer.slice(-16));
|
|
24
|
-
return {
|
|
25
|
-
encryptedData: uint8ArrayToBase64(encryptedData),
|
|
26
|
-
iv: uint8ArrayToBase64(iv),
|
|
27
|
-
tag: uint8ArrayToBase64(tag)
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
const decryptString = async (encryptedDataB64, ivB64, tagB64) => {
|
|
31
|
-
const encryptedData = base64ToUint8Array(encryptedDataB64);
|
|
32
|
-
const iv = base64ToUint8Array(ivB64);
|
|
33
|
-
const tag = base64ToUint8Array(tagB64);
|
|
34
|
-
const combinedData = new Uint8Array(encryptedData.length + tag.length);
|
|
35
|
-
combinedData.set(encryptedData);
|
|
36
|
-
combinedData.set(tag, encryptedData.length);
|
|
37
|
-
const decryptedBuffer = await window.crypto.subtle.decrypt({ name: "AES-GCM", iv }, secretKey, combinedData);
|
|
38
|
-
const decoder = new TextDecoder;
|
|
39
|
-
return decoder.decode(decryptedBuffer);
|
|
40
|
-
};
|
|
41
|
-
window.__electrobun_encrypt = encryptString;
|
|
42
|
-
window.__electrobun_decrypt = decryptString;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// src/bun/preload/internalRpc.ts
|
|
46
|
-
var pendingRequests = {};
|
|
47
|
-
var requestId = 0;
|
|
48
|
-
var isProcessingQueue = false;
|
|
49
|
-
var sendQueue = [];
|
|
50
|
-
function processQueue() {
|
|
51
|
-
if (isProcessingQueue) {
|
|
52
|
-
setTimeout(processQueue);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
if (sendQueue.length === 0)
|
|
56
|
-
return;
|
|
57
|
-
isProcessingQueue = true;
|
|
58
|
-
const batch = JSON.stringify(sendQueue);
|
|
59
|
-
sendQueue.length = 0;
|
|
60
|
-
window.__electrobunInternalBridge?.postMessage(batch);
|
|
61
|
-
setTimeout(() => {
|
|
62
|
-
isProcessingQueue = false;
|
|
63
|
-
}, 2);
|
|
64
|
-
}
|
|
65
|
-
function send(type, payload) {
|
|
66
|
-
sendQueue.push(JSON.stringify({ type: "message", id: type, payload }));
|
|
67
|
-
processQueue();
|
|
68
|
-
}
|
|
69
|
-
function request(type, payload) {
|
|
70
|
-
return new Promise((resolve, reject) => {
|
|
71
|
-
const id = `req_${++requestId}_${Date.now()}`;
|
|
72
|
-
pendingRequests[id] = { resolve, reject };
|
|
73
|
-
sendQueue.push(JSON.stringify({
|
|
74
|
-
type: "request",
|
|
75
|
-
method: type,
|
|
76
|
-
id,
|
|
77
|
-
params: payload,
|
|
78
|
-
hostWebviewId: window.__electrobunWebviewId
|
|
79
|
-
}));
|
|
80
|
-
processQueue();
|
|
81
|
-
setTimeout(() => {
|
|
82
|
-
if (pendingRequests[id]) {
|
|
83
|
-
delete pendingRequests[id];
|
|
84
|
-
reject(new Error(`Request timeout: ${type}`));
|
|
85
|
-
}
|
|
86
|
-
}, 1e4);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
function handleResponse(msg) {
|
|
90
|
-
if (msg && msg.type === "response" && msg.id) {
|
|
91
|
-
const pending = pendingRequests[msg.id];
|
|
92
|
-
if (pending) {
|
|
93
|
-
delete pendingRequests[msg.id];
|
|
94
|
-
if (msg.success)
|
|
95
|
-
pending.resolve(msg.payload);
|
|
96
|
-
else
|
|
97
|
-
pending.reject(msg.payload);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// src/bun/preload/dragRegions.ts
|
|
103
|
-
function isAppRegionDrag(e) {
|
|
104
|
-
const target = e.target;
|
|
105
|
-
if (!target || !target.closest)
|
|
106
|
-
return false;
|
|
107
|
-
if (target.closest(".electrobun-webkit-app-region-no-drag") || target.closest('[style*="app-region"][style*="no-drag"]')) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
const draggableByStyle = target.closest('[style*="app-region"][style*="drag"]');
|
|
111
|
-
const draggableByClass = target.closest(".electrobun-webkit-app-region-drag");
|
|
112
|
-
return !!(draggableByStyle || draggableByClass);
|
|
113
|
-
}
|
|
114
|
-
function initDragRegions() {
|
|
115
|
-
document.addEventListener("mousedown", (e) => {
|
|
116
|
-
if (isAppRegionDrag(e)) {
|
|
117
|
-
send("startWindowMove", { id: window.__electrobunWindowId });
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
document.addEventListener("mouseup", (e) => {
|
|
121
|
-
if (isAppRegionDrag(e)) {
|
|
122
|
-
send("stopWindowMove", { id: window.__electrobunWindowId });
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// src/bun/preload/overlaySync.ts
|
|
128
|
-
class OverlaySyncController {
|
|
129
|
-
element;
|
|
130
|
-
options;
|
|
131
|
-
lastRect = { x: 0, y: 0, width: 0, height: 0 };
|
|
132
|
-
resizeObserver = null;
|
|
133
|
-
positionLoop = null;
|
|
134
|
-
resizeHandler = null;
|
|
135
|
-
burstUntil = 0;
|
|
136
|
-
constructor(element, options) {
|
|
137
|
-
this.element = element;
|
|
138
|
-
this.options = {
|
|
139
|
-
onSync: options.onSync,
|
|
140
|
-
getMasks: options.getMasks ?? (() => []),
|
|
141
|
-
burstIntervalMs: options.burstIntervalMs ?? 50,
|
|
142
|
-
baseIntervalMs: options.baseIntervalMs ?? 100,
|
|
143
|
-
burstDurationMs: options.burstDurationMs ?? 500
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
start() {
|
|
147
|
-
this.resizeObserver = new ResizeObserver(() => this.sync());
|
|
148
|
-
this.resizeObserver.observe(this.element);
|
|
149
|
-
const loop = () => {
|
|
150
|
-
this.sync();
|
|
151
|
-
const now = performance.now();
|
|
152
|
-
const interval = now < this.burstUntil ? this.options.burstIntervalMs : this.options.baseIntervalMs;
|
|
153
|
-
this.positionLoop = setTimeout(loop, interval);
|
|
154
|
-
};
|
|
155
|
-
this.positionLoop = setTimeout(loop, this.options.baseIntervalMs);
|
|
156
|
-
this.resizeHandler = () => this.sync(true);
|
|
157
|
-
window.addEventListener("resize", this.resizeHandler);
|
|
158
|
-
}
|
|
159
|
-
stop() {
|
|
160
|
-
if (this.resizeObserver)
|
|
161
|
-
this.resizeObserver.disconnect();
|
|
162
|
-
if (this.positionLoop)
|
|
163
|
-
clearTimeout(this.positionLoop);
|
|
164
|
-
if (this.resizeHandler) {
|
|
165
|
-
window.removeEventListener("resize", this.resizeHandler);
|
|
166
|
-
}
|
|
167
|
-
this.resizeObserver = null;
|
|
168
|
-
this.positionLoop = null;
|
|
169
|
-
this.resizeHandler = null;
|
|
170
|
-
}
|
|
171
|
-
forceSync() {
|
|
172
|
-
this.sync(true);
|
|
173
|
-
}
|
|
174
|
-
setLastRect(rect) {
|
|
175
|
-
this.lastRect = rect;
|
|
176
|
-
}
|
|
177
|
-
sync(force = false) {
|
|
178
|
-
const rect = this.element.getBoundingClientRect();
|
|
179
|
-
const newRect = {
|
|
180
|
-
x: rect.x,
|
|
181
|
-
y: rect.y,
|
|
182
|
-
width: rect.width,
|
|
183
|
-
height: rect.height
|
|
184
|
-
};
|
|
185
|
-
if (newRect.width === 0 && newRect.height === 0) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
if (!force && newRect.x === this.lastRect.x && newRect.y === this.lastRect.y && newRect.width === this.lastRect.width && newRect.height === this.lastRect.height) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
this.burstUntil = performance.now() + this.options.burstDurationMs;
|
|
192
|
-
this.lastRect = newRect;
|
|
193
|
-
const masks = this.options.getMasks();
|
|
194
|
-
this.options.onSync(newRect, JSON.stringify(masks));
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// src/bun/preload/webviewTag.ts
|
|
199
|
-
var webviewRegistry = {};
|
|
200
|
-
|
|
201
|
-
class ElectrobunWebviewTag extends HTMLElement {
|
|
202
|
-
webviewId = null;
|
|
203
|
-
maskSelectors = new Set;
|
|
204
|
-
_sync = null;
|
|
205
|
-
transparent = false;
|
|
206
|
-
passthroughEnabled = false;
|
|
207
|
-
hidden = false;
|
|
208
|
-
sandboxed = false;
|
|
209
|
-
_eventListeners = {};
|
|
210
|
-
static get observedAttributes() {
|
|
211
|
-
return ["src", "html"];
|
|
212
|
-
}
|
|
213
|
-
constructor() {
|
|
214
|
-
super();
|
|
215
|
-
}
|
|
216
|
-
connectedCallback() {
|
|
217
|
-
requestAnimationFrame(() => this.initWebview());
|
|
218
|
-
}
|
|
219
|
-
attributeChangedCallback(name, oldValue, newValue) {
|
|
220
|
-
if (oldValue === newValue)
|
|
221
|
-
return;
|
|
222
|
-
if (newValue === null)
|
|
223
|
-
return;
|
|
224
|
-
if (this.webviewId === null)
|
|
225
|
-
return;
|
|
226
|
-
if (name === "src")
|
|
227
|
-
this.loadURL(newValue);
|
|
228
|
-
else if (name === "html")
|
|
229
|
-
this.loadHTML(newValue);
|
|
230
|
-
}
|
|
231
|
-
disconnectedCallback() {
|
|
232
|
-
if (this.webviewId !== null) {
|
|
233
|
-
send("webviewTagRemove", { id: this.webviewId });
|
|
234
|
-
delete webviewRegistry[this.webviewId];
|
|
235
|
-
}
|
|
236
|
-
if (this._sync)
|
|
237
|
-
this._sync.stop();
|
|
238
|
-
}
|
|
239
|
-
async initWebview() {
|
|
240
|
-
const rect = this.getBoundingClientRect();
|
|
241
|
-
const initialRect = {
|
|
242
|
-
x: rect.x,
|
|
243
|
-
y: rect.y,
|
|
244
|
-
width: rect.width,
|
|
245
|
-
height: rect.height
|
|
246
|
-
};
|
|
247
|
-
const url = this.getAttribute("src");
|
|
248
|
-
const html = this.getAttribute("html");
|
|
249
|
-
const preload = this.getAttribute("preload");
|
|
250
|
-
const partition = this.getAttribute("partition");
|
|
251
|
-
const renderer = this.getAttribute("renderer") || "native";
|
|
252
|
-
const masks = this.getAttribute("masks");
|
|
253
|
-
const sandbox = this.hasAttribute("sandbox");
|
|
254
|
-
this.sandboxed = sandbox;
|
|
255
|
-
const transparent = this.hasAttribute("transparent");
|
|
256
|
-
const passthrough = this.hasAttribute("passthrough");
|
|
257
|
-
this.transparent = transparent;
|
|
258
|
-
this.passthroughEnabled = passthrough;
|
|
259
|
-
if (transparent)
|
|
260
|
-
this.style.opacity = "0";
|
|
261
|
-
if (passthrough)
|
|
262
|
-
this.style.pointerEvents = "none";
|
|
263
|
-
if (masks) {
|
|
264
|
-
masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
|
|
265
|
-
}
|
|
266
|
-
try {
|
|
267
|
-
const webviewId = await request("webviewTagInit", {
|
|
268
|
-
hostWebviewId: window.__electrobunWebviewId,
|
|
269
|
-
windowId: window.__electrobunWindowId,
|
|
270
|
-
renderer,
|
|
271
|
-
url,
|
|
272
|
-
html,
|
|
273
|
-
preload,
|
|
274
|
-
partition,
|
|
275
|
-
frame: {
|
|
276
|
-
width: rect.width,
|
|
277
|
-
height: rect.height,
|
|
278
|
-
x: rect.x,
|
|
279
|
-
y: rect.y
|
|
280
|
-
},
|
|
281
|
-
navigationRules: null,
|
|
282
|
-
sandbox,
|
|
283
|
-
transparent,
|
|
284
|
-
passthrough
|
|
285
|
-
});
|
|
286
|
-
this.webviewId = webviewId;
|
|
287
|
-
this.id = `electrobun-webview-${webviewId}`;
|
|
288
|
-
webviewRegistry[webviewId] = this;
|
|
289
|
-
this.setupObservers(initialRect);
|
|
290
|
-
this.syncDimensions(true);
|
|
291
|
-
requestAnimationFrame(() => {
|
|
292
|
-
Object.values(webviewRegistry).forEach((webview) => {
|
|
293
|
-
if (webview !== this && webview.webviewId !== null) {
|
|
294
|
-
webview.syncDimensions(true);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
} catch (err) {
|
|
299
|
-
console.error("Failed to init webview:", err);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
setupObservers(initialRect) {
|
|
303
|
-
const getMasks = () => {
|
|
304
|
-
const rect = this.getBoundingClientRect();
|
|
305
|
-
const masks = [];
|
|
306
|
-
this.maskSelectors.forEach((selector) => {
|
|
307
|
-
try {
|
|
308
|
-
document.querySelectorAll(selector).forEach((el) => {
|
|
309
|
-
const mr = el.getBoundingClientRect();
|
|
310
|
-
masks.push({
|
|
311
|
-
x: mr.x - rect.x,
|
|
312
|
-
y: mr.y - rect.y,
|
|
313
|
-
width: mr.width,
|
|
314
|
-
height: mr.height
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
} catch (_e) {}
|
|
318
|
-
});
|
|
319
|
-
return masks;
|
|
320
|
-
};
|
|
321
|
-
this._sync = new OverlaySyncController(this, {
|
|
322
|
-
onSync: (rect, masksJson) => {
|
|
323
|
-
if (this.webviewId === null)
|
|
324
|
-
return;
|
|
325
|
-
send("webviewTagResize", {
|
|
326
|
-
id: this.webviewId,
|
|
327
|
-
frame: rect,
|
|
328
|
-
masks: masksJson
|
|
329
|
-
});
|
|
330
|
-
},
|
|
331
|
-
getMasks,
|
|
332
|
-
burstIntervalMs: 10,
|
|
333
|
-
baseIntervalMs: 100,
|
|
334
|
-
burstDurationMs: 50
|
|
335
|
-
});
|
|
336
|
-
this._sync.setLastRect(initialRect);
|
|
337
|
-
this._sync.start();
|
|
338
|
-
}
|
|
339
|
-
syncDimensions(force = false) {
|
|
340
|
-
if (!this._sync)
|
|
341
|
-
return;
|
|
342
|
-
if (force) {
|
|
343
|
-
this._sync.forceSync();
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
loadURL(url) {
|
|
347
|
-
if (this.webviewId === null)
|
|
348
|
-
return;
|
|
349
|
-
this.setAttribute("src", url);
|
|
350
|
-
send("webviewTagUpdateSrc", { id: this.webviewId, url });
|
|
351
|
-
}
|
|
352
|
-
loadHTML(html) {
|
|
353
|
-
if (this.webviewId === null)
|
|
354
|
-
return;
|
|
355
|
-
send("webviewTagUpdateHtml", { id: this.webviewId, html });
|
|
356
|
-
}
|
|
357
|
-
reload() {
|
|
358
|
-
if (this.webviewId !== null)
|
|
359
|
-
send("webviewTagReload", { id: this.webviewId });
|
|
360
|
-
}
|
|
361
|
-
goBack() {
|
|
362
|
-
if (this.webviewId !== null)
|
|
363
|
-
send("webviewTagGoBack", { id: this.webviewId });
|
|
364
|
-
}
|
|
365
|
-
goForward() {
|
|
366
|
-
if (this.webviewId !== null)
|
|
367
|
-
send("webviewTagGoForward", { id: this.webviewId });
|
|
368
|
-
}
|
|
369
|
-
async canGoBack() {
|
|
370
|
-
if (this.webviewId === null)
|
|
371
|
-
return false;
|
|
372
|
-
return await request("webviewTagCanGoBack", {
|
|
373
|
-
id: this.webviewId
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
async canGoForward() {
|
|
377
|
-
if (this.webviewId === null)
|
|
378
|
-
return false;
|
|
379
|
-
return await request("webviewTagCanGoForward", {
|
|
380
|
-
id: this.webviewId
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
toggleTransparent(value) {
|
|
384
|
-
if (this.webviewId === null)
|
|
385
|
-
return;
|
|
386
|
-
this.transparent = value !== undefined ? value : !this.transparent;
|
|
387
|
-
this.style.opacity = this.transparent ? "0" : "";
|
|
388
|
-
send("webviewTagSetTransparent", {
|
|
389
|
-
id: this.webviewId,
|
|
390
|
-
transparent: this.transparent
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
togglePassthrough(value) {
|
|
394
|
-
if (this.webviewId === null)
|
|
395
|
-
return;
|
|
396
|
-
this.passthroughEnabled = value !== undefined ? value : !this.passthroughEnabled;
|
|
397
|
-
this.style.pointerEvents = this.passthroughEnabled ? "none" : "";
|
|
398
|
-
send("webviewTagSetPassthrough", {
|
|
399
|
-
id: this.webviewId,
|
|
400
|
-
enablePassthrough: this.passthroughEnabled
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
toggleHidden(value) {
|
|
404
|
-
if (this.webviewId === null)
|
|
405
|
-
return;
|
|
406
|
-
this.hidden = value !== undefined ? value : !this.hidden;
|
|
407
|
-
send("webviewTagSetHidden", { id: this.webviewId, hidden: this.hidden });
|
|
408
|
-
}
|
|
409
|
-
addMaskSelector(selector) {
|
|
410
|
-
this.maskSelectors.add(selector);
|
|
411
|
-
this.syncDimensions(true);
|
|
412
|
-
}
|
|
413
|
-
removeMaskSelector(selector) {
|
|
414
|
-
this.maskSelectors.delete(selector);
|
|
415
|
-
this.syncDimensions(true);
|
|
416
|
-
}
|
|
417
|
-
setNavigationRules(rules) {
|
|
418
|
-
if (this.webviewId !== null) {
|
|
419
|
-
send("webviewTagSetNavigationRules", { id: this.webviewId, rules });
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
findInPage(searchText, options) {
|
|
423
|
-
if (this.webviewId === null)
|
|
424
|
-
return;
|
|
425
|
-
const forward = options?.forward !== false;
|
|
426
|
-
const matchCase = options?.matchCase || false;
|
|
427
|
-
send("webviewTagFindInPage", {
|
|
428
|
-
id: this.webviewId,
|
|
429
|
-
searchText,
|
|
430
|
-
forward,
|
|
431
|
-
matchCase
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
stopFindInPage() {
|
|
435
|
-
if (this.webviewId !== null)
|
|
436
|
-
send("webviewTagStopFind", { id: this.webviewId });
|
|
437
|
-
}
|
|
438
|
-
openDevTools() {
|
|
439
|
-
if (this.webviewId !== null)
|
|
440
|
-
send("webviewTagOpenDevTools", { id: this.webviewId });
|
|
441
|
-
}
|
|
442
|
-
closeDevTools() {
|
|
443
|
-
if (this.webviewId !== null)
|
|
444
|
-
send("webviewTagCloseDevTools", { id: this.webviewId });
|
|
445
|
-
}
|
|
446
|
-
toggleDevTools() {
|
|
447
|
-
if (this.webviewId !== null)
|
|
448
|
-
send("webviewTagToggleDevTools", { id: this.webviewId });
|
|
449
|
-
}
|
|
450
|
-
executeJavascript(js) {
|
|
451
|
-
if (this.webviewId === null)
|
|
452
|
-
return;
|
|
453
|
-
send("webviewTagExecuteJavascript", { id: this.webviewId, js });
|
|
454
|
-
}
|
|
455
|
-
on(event, listener) {
|
|
456
|
-
if (!this._eventListeners[event])
|
|
457
|
-
this._eventListeners[event] = [];
|
|
458
|
-
this._eventListeners[event].push(listener);
|
|
459
|
-
}
|
|
460
|
-
off(event, listener) {
|
|
461
|
-
if (!this._eventListeners[event])
|
|
462
|
-
return;
|
|
463
|
-
const idx = this._eventListeners[event].indexOf(listener);
|
|
464
|
-
if (idx !== -1)
|
|
465
|
-
this._eventListeners[event].splice(idx, 1);
|
|
466
|
-
}
|
|
467
|
-
emit(event, detail) {
|
|
468
|
-
const listeners = this._eventListeners[event];
|
|
469
|
-
if (listeners) {
|
|
470
|
-
const customEvent = new CustomEvent(event, { detail });
|
|
471
|
-
listeners.forEach((fn) => fn(customEvent));
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
get src() {
|
|
475
|
-
return this.getAttribute("src");
|
|
476
|
-
}
|
|
477
|
-
set src(value) {
|
|
478
|
-
if (value) {
|
|
479
|
-
this.setAttribute("src", value);
|
|
480
|
-
} else {
|
|
481
|
-
this.removeAttribute("src");
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
get html() {
|
|
485
|
-
return this.getAttribute("html");
|
|
486
|
-
}
|
|
487
|
-
set html(value) {
|
|
488
|
-
if (value) {
|
|
489
|
-
this.setAttribute("html", value);
|
|
490
|
-
} else {
|
|
491
|
-
this.removeAttribute("html");
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
get preload() {
|
|
495
|
-
return this.getAttribute("preload");
|
|
496
|
-
}
|
|
497
|
-
set preload(value) {
|
|
498
|
-
if (value)
|
|
499
|
-
this.setAttribute("preload", value);
|
|
500
|
-
else
|
|
501
|
-
this.removeAttribute("preload");
|
|
502
|
-
}
|
|
503
|
-
get renderer() {
|
|
504
|
-
return this.getAttribute("renderer") || "native";
|
|
505
|
-
}
|
|
506
|
-
set renderer(value) {
|
|
507
|
-
this.setAttribute("renderer", value);
|
|
508
|
-
}
|
|
509
|
-
get sandbox() {
|
|
510
|
-
return this.sandboxed;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
function initWebviewTag() {
|
|
514
|
-
if (!customElements.get("electrobun-webview")) {
|
|
515
|
-
customElements.define("electrobun-webview", ElectrobunWebviewTag);
|
|
516
|
-
}
|
|
517
|
-
const injectStyles = () => {
|
|
518
|
-
const style = document.createElement("style");
|
|
519
|
-
style.textContent = `
|
|
520
|
-
electrobun-webview {
|
|
521
|
-
display: block;
|
|
522
|
-
width: 800px;
|
|
523
|
-
height: 300px;
|
|
524
|
-
background: #fff;
|
|
525
|
-
background-repeat: no-repeat !important;
|
|
526
|
-
overflow: hidden;
|
|
527
|
-
}
|
|
528
|
-
`;
|
|
529
|
-
if (document.head?.firstChild) {
|
|
530
|
-
document.head.insertBefore(style, document.head.firstChild);
|
|
531
|
-
} else if (document.head) {
|
|
532
|
-
document.head.appendChild(style);
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
if (document.head) {
|
|
536
|
-
injectStyles();
|
|
537
|
-
} else {
|
|
538
|
-
document.addEventListener("DOMContentLoaded", injectStyles);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// src/bun/preload/wgpuTag.ts
|
|
543
|
-
var wgpuTagRegistry = {};
|
|
544
|
-
|
|
545
|
-
class ElectrobunWgpuTag extends HTMLElement {
|
|
546
|
-
wgpuViewId = null;
|
|
547
|
-
maskSelectors = new Set;
|
|
548
|
-
_sync = null;
|
|
549
|
-
transparent = false;
|
|
550
|
-
passthroughEnabled = false;
|
|
551
|
-
hidden = false;
|
|
552
|
-
_eventListeners = {};
|
|
553
|
-
constructor() {
|
|
554
|
-
super();
|
|
555
|
-
}
|
|
556
|
-
connectedCallback() {
|
|
557
|
-
requestAnimationFrame(() => this.initWgpuView());
|
|
558
|
-
}
|
|
559
|
-
disconnectedCallback() {
|
|
560
|
-
if (this.wgpuViewId !== null) {
|
|
561
|
-
send("wgpuTagRemove", { id: this.wgpuViewId });
|
|
562
|
-
delete wgpuTagRegistry[this.wgpuViewId];
|
|
563
|
-
}
|
|
564
|
-
if (this._sync)
|
|
565
|
-
this._sync.stop();
|
|
566
|
-
}
|
|
567
|
-
async initWgpuView() {
|
|
568
|
-
const rect = this.getBoundingClientRect();
|
|
569
|
-
const initialRect = {
|
|
570
|
-
x: rect.x,
|
|
571
|
-
y: rect.y,
|
|
572
|
-
width: rect.width,
|
|
573
|
-
height: rect.height
|
|
574
|
-
};
|
|
575
|
-
const transparent = this.hasAttribute("transparent");
|
|
576
|
-
const passthrough = this.hasAttribute("passthrough");
|
|
577
|
-
const hidden = this.hasAttribute("hidden");
|
|
578
|
-
const masks = this.getAttribute("masks");
|
|
579
|
-
this.transparent = transparent;
|
|
580
|
-
this.passthroughEnabled = passthrough;
|
|
581
|
-
this.hidden = hidden;
|
|
582
|
-
if (masks) {
|
|
583
|
-
masks.split(",").forEach((s) => this.maskSelectors.add(s.trim()));
|
|
584
|
-
}
|
|
585
|
-
if (transparent)
|
|
586
|
-
this.style.opacity = "0";
|
|
587
|
-
if (passthrough)
|
|
588
|
-
this.style.pointerEvents = "none";
|
|
589
|
-
try {
|
|
590
|
-
const wgpuViewId = await request("wgpuTagInit", {
|
|
591
|
-
windowId: window.__electrobunWindowId,
|
|
592
|
-
frame: {
|
|
593
|
-
width: rect.width,
|
|
594
|
-
height: rect.height,
|
|
595
|
-
x: rect.x,
|
|
596
|
-
y: rect.y
|
|
597
|
-
},
|
|
598
|
-
transparent,
|
|
599
|
-
passthrough
|
|
600
|
-
});
|
|
601
|
-
this.wgpuViewId = wgpuViewId;
|
|
602
|
-
this.id = `electrobun-wgpu-${wgpuViewId}`;
|
|
603
|
-
wgpuTagRegistry[wgpuViewId] = this;
|
|
604
|
-
this.setupObservers(initialRect);
|
|
605
|
-
this.syncDimensions(true);
|
|
606
|
-
if (hidden) {
|
|
607
|
-
this.toggleHidden(true);
|
|
608
|
-
}
|
|
609
|
-
requestAnimationFrame(() => {
|
|
610
|
-
Object.values(wgpuTagRegistry).forEach((view) => {
|
|
611
|
-
if (view !== this && view.wgpuViewId !== null) {
|
|
612
|
-
view.syncDimensions(true);
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
});
|
|
616
|
-
this.emit("ready", { id: wgpuViewId });
|
|
617
|
-
} catch (err) {
|
|
618
|
-
console.error("Failed to init WGPU view:", err);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
setupObservers(initialRect) {
|
|
622
|
-
const getMasks = () => {
|
|
623
|
-
const rect = this.getBoundingClientRect();
|
|
624
|
-
const masks = [];
|
|
625
|
-
this.maskSelectors.forEach((selector) => {
|
|
626
|
-
try {
|
|
627
|
-
document.querySelectorAll(selector).forEach((el) => {
|
|
628
|
-
const mr = el.getBoundingClientRect();
|
|
629
|
-
masks.push({
|
|
630
|
-
x: mr.x - rect.x,
|
|
631
|
-
y: mr.y - rect.y,
|
|
632
|
-
width: mr.width,
|
|
633
|
-
height: mr.height
|
|
634
|
-
});
|
|
635
|
-
});
|
|
636
|
-
} catch (_e) {}
|
|
637
|
-
});
|
|
638
|
-
return masks;
|
|
639
|
-
};
|
|
640
|
-
this._sync = new OverlaySyncController(this, {
|
|
641
|
-
onSync: (rect, masksJson) => {
|
|
642
|
-
if (this.wgpuViewId === null)
|
|
643
|
-
return;
|
|
644
|
-
send("wgpuTagResize", {
|
|
645
|
-
id: this.wgpuViewId,
|
|
646
|
-
frame: rect,
|
|
647
|
-
masks: masksJson
|
|
648
|
-
});
|
|
649
|
-
},
|
|
650
|
-
getMasks,
|
|
651
|
-
burstIntervalMs: 10,
|
|
652
|
-
baseIntervalMs: 100,
|
|
653
|
-
burstDurationMs: 50
|
|
654
|
-
});
|
|
655
|
-
this._sync.setLastRect(initialRect);
|
|
656
|
-
this._sync.start();
|
|
657
|
-
}
|
|
658
|
-
syncDimensions(force = false) {
|
|
659
|
-
if (!this._sync)
|
|
660
|
-
return;
|
|
661
|
-
if (force) {
|
|
662
|
-
this._sync.forceSync();
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
toggleTransparent(value) {
|
|
666
|
-
if (this.wgpuViewId === null)
|
|
667
|
-
return;
|
|
668
|
-
this.transparent = value !== undefined ? value : !this.transparent;
|
|
669
|
-
this.style.opacity = this.transparent ? "0" : "";
|
|
670
|
-
send("wgpuTagSetTransparent", {
|
|
671
|
-
id: this.wgpuViewId,
|
|
672
|
-
transparent: this.transparent
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
togglePassthrough(value) {
|
|
676
|
-
if (this.wgpuViewId === null)
|
|
677
|
-
return;
|
|
678
|
-
this.passthroughEnabled = value !== undefined ? value : !this.passthroughEnabled;
|
|
679
|
-
this.style.pointerEvents = this.passthroughEnabled ? "none" : "";
|
|
680
|
-
send("wgpuTagSetPassthrough", {
|
|
681
|
-
id: this.wgpuViewId,
|
|
682
|
-
passthrough: this.passthroughEnabled
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
toggleHidden(value) {
|
|
686
|
-
if (this.wgpuViewId === null)
|
|
687
|
-
return;
|
|
688
|
-
this.hidden = value !== undefined ? value : !this.hidden;
|
|
689
|
-
send("wgpuTagSetHidden", { id: this.wgpuViewId, hidden: this.hidden });
|
|
690
|
-
}
|
|
691
|
-
runTest() {
|
|
692
|
-
if (this.wgpuViewId === null)
|
|
693
|
-
return;
|
|
694
|
-
send("wgpuTagRunTest", { id: this.wgpuViewId });
|
|
695
|
-
}
|
|
696
|
-
addMaskSelector(selector) {
|
|
697
|
-
this.maskSelectors.add(selector);
|
|
698
|
-
this.syncDimensions(true);
|
|
699
|
-
}
|
|
700
|
-
removeMaskSelector(selector) {
|
|
701
|
-
this.maskSelectors.delete(selector);
|
|
702
|
-
this.syncDimensions(true);
|
|
703
|
-
}
|
|
704
|
-
on(event, listener) {
|
|
705
|
-
if (!this._eventListeners[event])
|
|
706
|
-
this._eventListeners[event] = [];
|
|
707
|
-
this._eventListeners[event].push(listener);
|
|
708
|
-
}
|
|
709
|
-
off(event, listener) {
|
|
710
|
-
if (!this._eventListeners[event])
|
|
711
|
-
return;
|
|
712
|
-
const idx = this._eventListeners[event].indexOf(listener);
|
|
713
|
-
if (idx !== -1)
|
|
714
|
-
this._eventListeners[event].splice(idx, 1);
|
|
715
|
-
}
|
|
716
|
-
emit(event, detail) {
|
|
717
|
-
const listeners = this._eventListeners[event];
|
|
718
|
-
if (listeners) {
|
|
719
|
-
const customEvent = new CustomEvent(event, { detail });
|
|
720
|
-
listeners.forEach((fn) => fn(customEvent));
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
function initWgpuTag() {
|
|
725
|
-
if (!customElements.get("electrobun-wgpu")) {
|
|
726
|
-
customElements.define("electrobun-wgpu", ElectrobunWgpuTag);
|
|
727
|
-
}
|
|
728
|
-
const injectStyles = () => {
|
|
729
|
-
const style = document.createElement("style");
|
|
730
|
-
style.textContent = `
|
|
731
|
-
electrobun-wgpu {
|
|
732
|
-
display: block;
|
|
733
|
-
width: 800px;
|
|
734
|
-
height: 300px;
|
|
735
|
-
background: #000;
|
|
736
|
-
overflow: hidden;
|
|
737
|
-
}
|
|
738
|
-
`;
|
|
739
|
-
if (document.head?.firstChild) {
|
|
740
|
-
document.head.insertBefore(style, document.head.firstChild);
|
|
741
|
-
} else if (document.head) {
|
|
742
|
-
document.head.appendChild(style);
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
if (document.head) {
|
|
746
|
-
injectStyles();
|
|
747
|
-
} else {
|
|
748
|
-
document.addEventListener("DOMContentLoaded", injectStyles);
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// src/bun/preload/events.ts
|
|
753
|
-
function emitWebviewEvent(eventName, detail) {
|
|
754
|
-
setTimeout(() => {
|
|
755
|
-
const bridge = window.__electrobunEventBridge || window.__electrobunInternalBridge;
|
|
756
|
-
bridge?.postMessage(JSON.stringify({
|
|
757
|
-
id: "webviewEvent",
|
|
758
|
-
type: "message",
|
|
759
|
-
payload: {
|
|
760
|
-
id: window.__electrobunWebviewId,
|
|
761
|
-
eventName,
|
|
762
|
-
detail
|
|
763
|
-
}
|
|
764
|
-
}));
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
function initLifecycleEvents() {
|
|
768
|
-
window.addEventListener("load", () => {
|
|
769
|
-
if (window === window.top) {
|
|
770
|
-
emitWebviewEvent("dom-ready", document.location.href);
|
|
771
|
-
}
|
|
772
|
-
});
|
|
773
|
-
window.addEventListener("popstate", () => {
|
|
774
|
-
emitWebviewEvent("did-navigate-in-page", window.location.href);
|
|
775
|
-
});
|
|
776
|
-
window.addEventListener("hashchange", () => {
|
|
777
|
-
emitWebviewEvent("did-navigate-in-page", window.location.href);
|
|
778
|
-
});
|
|
779
|
-
}
|
|
780
|
-
var cmdKeyHeld = false;
|
|
781
|
-
var cmdKeyTimestamp = 0;
|
|
782
|
-
var CMD_KEY_THRESHOLD_MS = 500;
|
|
783
|
-
function isCmdHeld() {
|
|
784
|
-
if (cmdKeyHeld)
|
|
785
|
-
return true;
|
|
786
|
-
return Date.now() - cmdKeyTimestamp < CMD_KEY_THRESHOLD_MS && cmdKeyTimestamp > 0;
|
|
787
|
-
}
|
|
788
|
-
function initCmdClickHandling() {
|
|
789
|
-
window.addEventListener("keydown", (event) => {
|
|
790
|
-
if (event.key === "Meta" || event.metaKey) {
|
|
791
|
-
cmdKeyHeld = true;
|
|
792
|
-
cmdKeyTimestamp = Date.now();
|
|
793
|
-
}
|
|
794
|
-
}, true);
|
|
795
|
-
window.addEventListener("keyup", (event) => {
|
|
796
|
-
if (event.key === "Meta") {
|
|
797
|
-
cmdKeyHeld = false;
|
|
798
|
-
cmdKeyTimestamp = Date.now();
|
|
799
|
-
}
|
|
800
|
-
}, true);
|
|
801
|
-
window.addEventListener("blur", () => {
|
|
802
|
-
cmdKeyHeld = false;
|
|
803
|
-
});
|
|
804
|
-
window.addEventListener("click", (event) => {
|
|
805
|
-
if (event.metaKey || event.ctrlKey) {
|
|
806
|
-
const anchor = event.target?.closest?.("a");
|
|
807
|
-
if (anchor && anchor.href) {
|
|
808
|
-
event.preventDefault();
|
|
809
|
-
event.stopPropagation();
|
|
810
|
-
event.stopImmediatePropagation();
|
|
811
|
-
emitWebviewEvent("new-window-open", JSON.stringify({
|
|
812
|
-
url: anchor.href,
|
|
813
|
-
isCmdClick: true,
|
|
814
|
-
isSPANavigation: false
|
|
815
|
-
}));
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}, true);
|
|
819
|
-
}
|
|
820
|
-
function initSPANavigationInterception() {
|
|
821
|
-
const originalPushState = history.pushState;
|
|
822
|
-
const originalReplaceState = history.replaceState;
|
|
823
|
-
history.pushState = function(state, title, url) {
|
|
824
|
-
if (isCmdHeld() && url) {
|
|
825
|
-
const resolvedUrl = new URL(String(url), window.location.href).href;
|
|
826
|
-
emitWebviewEvent("new-window-open", JSON.stringify({
|
|
827
|
-
url: resolvedUrl,
|
|
828
|
-
isCmdClick: true,
|
|
829
|
-
isSPANavigation: true
|
|
830
|
-
}));
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
return originalPushState.apply(this, [state, title, url]);
|
|
834
|
-
};
|
|
835
|
-
history.replaceState = function(state, title, url) {
|
|
836
|
-
if (isCmdHeld() && url) {
|
|
837
|
-
const resolvedUrl = new URL(String(url), window.location.href).href;
|
|
838
|
-
emitWebviewEvent("new-window-open", JSON.stringify({
|
|
839
|
-
url: resolvedUrl,
|
|
840
|
-
isCmdClick: true,
|
|
841
|
-
isSPANavigation: true
|
|
842
|
-
}));
|
|
843
|
-
return;
|
|
844
|
-
}
|
|
845
|
-
return originalReplaceState.apply(this, [state, title, url]);
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
function initOverscrollPrevention() {
|
|
849
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
850
|
-
const style = document.createElement("style");
|
|
851
|
-
style.type = "text/css";
|
|
852
|
-
style.appendChild(document.createTextNode("html, body { overscroll-behavior: none; }"));
|
|
853
|
-
document.head.appendChild(style);
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// src/bun/preload/index.ts
|
|
858
|
-
initEncryption().catch((err) => console.error("Failed to initialize encryption:", err));
|
|
859
|
-
var internalMessageHandler = (msg) => {
|
|
860
|
-
handleResponse(msg);
|
|
861
|
-
};
|
|
862
|
-
if (!window.__electrobun) {
|
|
863
|
-
window.__electrobun = {
|
|
864
|
-
receiveInternalMessageFromBun: internalMessageHandler,
|
|
865
|
-
receiveMessageFromBun: (msg) => {
|
|
866
|
-
console.log("receiveMessageFromBun (no handler):", msg);
|
|
867
|
-
}
|
|
868
|
-
};
|
|
869
|
-
} else {
|
|
870
|
-
window.__electrobun.receiveInternalMessageFromBun = internalMessageHandler;
|
|
871
|
-
window.__electrobun.receiveMessageFromBun = (msg) => {
|
|
872
|
-
console.log("receiveMessageFromBun (no handler):", msg);
|
|
873
|
-
};
|
|
874
|
-
}
|
|
875
|
-
window.__electrobunSendToHost = (message) => {
|
|
876
|
-
emitWebviewEvent("host-message", JSON.stringify(message));
|
|
877
|
-
};
|
|
878
|
-
initLifecycleEvents();
|
|
879
|
-
initCmdClickHandling();
|
|
880
|
-
initSPANavigationInterception();
|
|
881
|
-
initOverscrollPrevention();
|
|
882
|
-
initDragRegions();
|
|
883
|
-
initWebviewTag();
|
|
884
|
-
initWgpuTag();
|
|
885
|
-
})();
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
(function(){// src/bun/preload/events.ts
|
|
2
|
-
function emitWebviewEvent(eventName, detail) {
|
|
3
|
-
setTimeout(() => {
|
|
4
|
-
const bridge = window.__electrobunEventBridge || window.__electrobunInternalBridge;
|
|
5
|
-
bridge?.postMessage(JSON.stringify({
|
|
6
|
-
id: "webviewEvent",
|
|
7
|
-
type: "message",
|
|
8
|
-
payload: {
|
|
9
|
-
id: window.__electrobunWebviewId,
|
|
10
|
-
eventName,
|
|
11
|
-
detail
|
|
12
|
-
}
|
|
13
|
-
}));
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
function initLifecycleEvents() {
|
|
17
|
-
window.addEventListener("load", () => {
|
|
18
|
-
if (window === window.top) {
|
|
19
|
-
emitWebviewEvent("dom-ready", document.location.href);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
window.addEventListener("popstate", () => {
|
|
23
|
-
emitWebviewEvent("did-navigate-in-page", window.location.href);
|
|
24
|
-
});
|
|
25
|
-
window.addEventListener("hashchange", () => {
|
|
26
|
-
emitWebviewEvent("did-navigate-in-page", window.location.href);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
var cmdKeyHeld = false;
|
|
30
|
-
var cmdKeyTimestamp = 0;
|
|
31
|
-
var CMD_KEY_THRESHOLD_MS = 500;
|
|
32
|
-
function isCmdHeld() {
|
|
33
|
-
if (cmdKeyHeld)
|
|
34
|
-
return true;
|
|
35
|
-
return Date.now() - cmdKeyTimestamp < CMD_KEY_THRESHOLD_MS && cmdKeyTimestamp > 0;
|
|
36
|
-
}
|
|
37
|
-
function initCmdClickHandling() {
|
|
38
|
-
window.addEventListener("keydown", (event) => {
|
|
39
|
-
if (event.key === "Meta" || event.metaKey) {
|
|
40
|
-
cmdKeyHeld = true;
|
|
41
|
-
cmdKeyTimestamp = Date.now();
|
|
42
|
-
}
|
|
43
|
-
}, true);
|
|
44
|
-
window.addEventListener("keyup", (event) => {
|
|
45
|
-
if (event.key === "Meta") {
|
|
46
|
-
cmdKeyHeld = false;
|
|
47
|
-
cmdKeyTimestamp = Date.now();
|
|
48
|
-
}
|
|
49
|
-
}, true);
|
|
50
|
-
window.addEventListener("blur", () => {
|
|
51
|
-
cmdKeyHeld = false;
|
|
52
|
-
});
|
|
53
|
-
window.addEventListener("click", (event) => {
|
|
54
|
-
if (event.metaKey || event.ctrlKey) {
|
|
55
|
-
const anchor = event.target?.closest?.("a");
|
|
56
|
-
if (anchor && anchor.href) {
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
event.stopPropagation();
|
|
59
|
-
event.stopImmediatePropagation();
|
|
60
|
-
emitWebviewEvent("new-window-open", JSON.stringify({
|
|
61
|
-
url: anchor.href,
|
|
62
|
-
isCmdClick: true,
|
|
63
|
-
isSPANavigation: false
|
|
64
|
-
}));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}, true);
|
|
68
|
-
}
|
|
69
|
-
function initSPANavigationInterception() {
|
|
70
|
-
const originalPushState = history.pushState;
|
|
71
|
-
const originalReplaceState = history.replaceState;
|
|
72
|
-
history.pushState = function(state, title, url) {
|
|
73
|
-
if (isCmdHeld() && url) {
|
|
74
|
-
const resolvedUrl = new URL(String(url), window.location.href).href;
|
|
75
|
-
emitWebviewEvent("new-window-open", JSON.stringify({
|
|
76
|
-
url: resolvedUrl,
|
|
77
|
-
isCmdClick: true,
|
|
78
|
-
isSPANavigation: true
|
|
79
|
-
}));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
return originalPushState.apply(this, [state, title, url]);
|
|
83
|
-
};
|
|
84
|
-
history.replaceState = function(state, title, url) {
|
|
85
|
-
if (isCmdHeld() && url) {
|
|
86
|
-
const resolvedUrl = new URL(String(url), window.location.href).href;
|
|
87
|
-
emitWebviewEvent("new-window-open", JSON.stringify({
|
|
88
|
-
url: resolvedUrl,
|
|
89
|
-
isCmdClick: true,
|
|
90
|
-
isSPANavigation: true
|
|
91
|
-
}));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
return originalReplaceState.apply(this, [state, title, url]);
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
function initOverscrollPrevention() {
|
|
98
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
99
|
-
const style = document.createElement("style");
|
|
100
|
-
style.type = "text/css";
|
|
101
|
-
style.appendChild(document.createTextNode("html, body { overscroll-behavior: none; }"));
|
|
102
|
-
document.head.appendChild(style);
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// src/bun/preload/index-sandboxed.ts
|
|
107
|
-
initLifecycleEvents();
|
|
108
|
-
initCmdClickHandling();
|
|
109
|
-
initSPANavigationInterception();
|
|
110
|
-
initOverscrollPrevention();
|
|
111
|
-
})();
|