electrobun 0.0.19-beta.99 → 0.1.1
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/README.md +1 -1
- package/dist/api/browser/webviewtag.ts +54 -2
- package/dist/api/bun/ElectrobunConfig.ts +171 -0
- package/dist/api/bun/core/BrowserWindow.ts +4 -0
- package/dist/api/bun/core/Tray.ts +14 -0
- package/dist/api/bun/core/Updater.ts +4 -3
- package/dist/api/bun/index.ts +2 -0
- package/dist/api/bun/proc/native.ts +107 -5
- package/dist/main.js +5 -4
- package/package.json +4 -2
- package/src/cli/index.ts +621 -151
- package/templates/hello-world/bun.lock +164 -2
- package/templates/hello-world/electrobun.config.ts +28 -0
- package/templates/hello-world/src/bun/index.ts +2 -2
- package/templates/hello-world/src/mainview/index.html +5 -6
- package/templates/hello-world/src/mainview/index.ts +1 -5
- package/templates/interactive-playground/README.md +26 -0
- package/templates/interactive-playground/assets/tray-icon.png +0 -0
- package/templates/interactive-playground/electrobun.config.ts +36 -0
- package/templates/interactive-playground/package-lock.json +36 -0
- package/templates/interactive-playground/package.json +15 -0
- package/templates/interactive-playground/src/bun/demos/files.ts +70 -0
- package/templates/interactive-playground/src/bun/demos/menus.ts +139 -0
- package/templates/interactive-playground/src/bun/demos/rpc.ts +83 -0
- package/templates/interactive-playground/src/bun/demos/system.ts +72 -0
- package/templates/interactive-playground/src/bun/demos/updates.ts +105 -0
- package/templates/interactive-playground/src/bun/demos/windows.ts +90 -0
- package/templates/interactive-playground/src/bun/index.ts +124 -0
- package/templates/interactive-playground/src/bun/types/rpc.ts +109 -0
- package/templates/interactive-playground/src/mainview/components/EventLog.ts +107 -0
- package/templates/interactive-playground/src/mainview/components/Sidebar.ts +65 -0
- package/templates/interactive-playground/src/mainview/components/Toast.ts +57 -0
- package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +211 -0
- package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +102 -0
- package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +229 -0
- package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +132 -0
- package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +411 -0
- package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +207 -0
- package/templates/interactive-playground/src/mainview/index.css +538 -0
- package/templates/interactive-playground/src/mainview/index.html +103 -0
- package/templates/interactive-playground/src/mainview/index.ts +238 -0
- package/templates/multitab-browser/README.md +34 -0
- package/templates/multitab-browser/bun.lock +224 -0
- package/templates/multitab-browser/electrobun.config.ts +32 -0
- package/templates/multitab-browser/package-lock.json +20 -0
- package/templates/multitab-browser/package.json +12 -0
- package/templates/multitab-browser/src/bun/index.ts +144 -0
- package/templates/multitab-browser/src/bun/tabManager.ts +200 -0
- package/templates/multitab-browser/src/bun/types/rpc.ts +78 -0
- package/templates/multitab-browser/src/mainview/index.css +487 -0
- package/templates/multitab-browser/src/mainview/index.html +94 -0
- package/templates/multitab-browser/src/mainview/index.ts +634 -0
- package/templates/photo-booth/README.md +108 -0
- package/templates/photo-booth/bun.lock +239 -0
- package/templates/photo-booth/electrobun.config.ts +32 -0
- package/templates/photo-booth/package.json +17 -0
- package/templates/photo-booth/src/bun/index.ts +92 -0
- package/templates/photo-booth/src/mainview/index.css +465 -0
- package/templates/photo-booth/src/mainview/index.html +124 -0
- package/templates/photo-booth/src/mainview/index.ts +499 -0
- package/tests/bun.lock +14 -0
- package/tests/electrobun.config.ts +45 -0
- package/tests/package-lock.json +36 -0
- package/tests/package.json +13 -0
- package/tests/src/bun/index.ts +100 -0
- package/tests/src/bun/test-runner.ts +508 -0
- package/tests/src/mainview/index.html +110 -0
- package/tests/src/mainview/index.ts +458 -0
- package/tests/src/mainview/styles/main.css +451 -0
- package/tests/src/testviews/tray-test.html +57 -0
- package/tests/src/testviews/webview-mask.html +114 -0
- package/tests/src/testviews/webview-navigation.html +36 -0
- package/tests/src/testviews/window-create.html +17 -0
- package/tests/src/testviews/window-events.html +29 -0
- package/tests/src/testviews/window-focus.html +37 -0
- package/tests/src/webviewtag/index.ts +11 -0
- package/templates/hello-world/electrobun.config +0 -18
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export class TrayDemo {
|
|
2
|
+
private trays: Array<{ id: number; title: string }> = [];
|
|
3
|
+
private rpc: any;
|
|
4
|
+
|
|
5
|
+
render() {
|
|
6
|
+
return `
|
|
7
|
+
<div class="demo-section">
|
|
8
|
+
<div class="demo-header">
|
|
9
|
+
<span class="demo-icon">🔔</span>
|
|
10
|
+
<div>
|
|
11
|
+
<h2 class="demo-title">System Tray</h2>
|
|
12
|
+
<p class="demo-description">Create and manage system tray icons with menus</p>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="demo-controls">
|
|
17
|
+
<h3>Create System Tray</h3>
|
|
18
|
+
<div class="control-group">
|
|
19
|
+
<label class="control-label">Title:</label>
|
|
20
|
+
<input type="text" id="tray-title" class="control-input" value="My Tray Item" style="width: 200px;">
|
|
21
|
+
|
|
22
|
+
<button class="btn btn-primary" id="create-tray">Create Tray</button>
|
|
23
|
+
<button class="btn btn-danger" id="remove-all-trays">Remove All Trays</button>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div style="margin-top: 1rem; padding: 1rem; background: #f7fafc; border-radius: 0.5rem;">
|
|
27
|
+
<p style="color: #4a5568; font-size: 0.875rem;">
|
|
28
|
+
<strong>Note:</strong> System tray icons appear in your system's menu bar or notification area.
|
|
29
|
+
Click on the tray icon to see its menu. On macOS, look in the top-right menu bar.
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="demo-results">
|
|
35
|
+
<div class="results-header">Active Trays (<span id="tray-count">0</span>):</div>
|
|
36
|
+
<div id="tray-list" class="tray-list">
|
|
37
|
+
<div class="no-trays" style="text-align: center; color: #718096; padding: 2rem;">
|
|
38
|
+
No system tray items created yet.
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
initialize(rpc: any) {
|
|
47
|
+
this.rpc = rpc;
|
|
48
|
+
|
|
49
|
+
const createTrayBtn = document.getElementById('create-tray');
|
|
50
|
+
const removeAllTraysBtn = document.getElementById('remove-all-trays');
|
|
51
|
+
|
|
52
|
+
createTrayBtn?.addEventListener('click', async () => {
|
|
53
|
+
const title = (document.getElementById('tray-title') as HTMLInputElement).value;
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const result = await rpc.request.createTray({ title });
|
|
57
|
+
this.trays.push({ id: result.id, title });
|
|
58
|
+
this.updateTrayList();
|
|
59
|
+
console.log('Created tray:', result);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Error creating tray:', error);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
removeAllTraysBtn?.addEventListener('click', async () => {
|
|
66
|
+
for (const tray of this.trays) {
|
|
67
|
+
try {
|
|
68
|
+
await rpc.request.removeTray(tray.id);
|
|
69
|
+
console.log('Removed tray:', tray.id);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(`Error removing tray ${tray.id}:`, error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
this.trays = [];
|
|
75
|
+
this.updateTrayList();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private updateTrayList() {
|
|
80
|
+
const container = document.getElementById('tray-list');
|
|
81
|
+
const count = document.getElementById('tray-count');
|
|
82
|
+
|
|
83
|
+
if (!container || !count) return;
|
|
84
|
+
|
|
85
|
+
count.textContent = this.trays.length.toString();
|
|
86
|
+
|
|
87
|
+
if (this.trays.length === 0) {
|
|
88
|
+
container.innerHTML = `
|
|
89
|
+
<div class="no-trays" style="text-align: center; color: #718096; padding: 2rem;">
|
|
90
|
+
No system tray items created yet.
|
|
91
|
+
</div>
|
|
92
|
+
`;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
container.innerHTML = this.trays.map(tray => `
|
|
97
|
+
<div class="tray-item" style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.5rem; padding: 1rem; margin-bottom: 0.5rem;">
|
|
98
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
99
|
+
<div>
|
|
100
|
+
<strong>Tray ${tray.id}</strong>
|
|
101
|
+
<div style="color: #718096; font-size: 0.875rem;">${tray.title}</div>
|
|
102
|
+
<div style="color: #4299e1; font-size: 0.75rem; margin-top: 0.25rem;">
|
|
103
|
+
Click tray icon in menu bar to see menu
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<button class="btn btn-small btn-danger remove-tray" data-tray-id="${tray.id}">Remove</button>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
`).join('');
|
|
110
|
+
|
|
111
|
+
// Add remove button listeners
|
|
112
|
+
const removeButtons = document.querySelectorAll('.remove-tray');
|
|
113
|
+
removeButtons.forEach(btn => {
|
|
114
|
+
btn.addEventListener('click', async (e) => {
|
|
115
|
+
const id = parseInt((e.target as HTMLElement).getAttribute('data-tray-id') || '0');
|
|
116
|
+
try {
|
|
117
|
+
await this.rpc.request.removeTray(id);
|
|
118
|
+
console.log('Removed tray:', id);
|
|
119
|
+
this.trays = this.trays.filter(t => t.id !== id);
|
|
120
|
+
this.updateTrayList();
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error(`Error removing tray ${id}:`, error);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Handle events from the backend
|
|
129
|
+
onTrayClicked(data: { id: number; action: string }) {
|
|
130
|
+
console.log('Tray clicked:', data);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
export class WebViewDemo {
|
|
2
|
+
private rpc: any;
|
|
3
|
+
|
|
4
|
+
render() {
|
|
5
|
+
return `
|
|
6
|
+
<div class="demo-section">
|
|
7
|
+
<div class="demo-header">
|
|
8
|
+
<span class="demo-icon">🌐</span>
|
|
9
|
+
<div>
|
|
10
|
+
<h2 class="demo-title">WebView Browser</h2>
|
|
11
|
+
<p class="demo-description">Embedded browser with navigation, transparency, masking, and advanced features</p>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="demo-controls" style="padding: 1rem;">
|
|
16
|
+
<!-- Browser-like navigation bar -->
|
|
17
|
+
<div style="display: flex; gap: 0.5rem; align-items: center; padding: 0.5rem; background: #f7fafc; border: 1px solid #e2e8f0; border-radius: 0.5rem; margin-bottom: 1rem;">
|
|
18
|
+
<button class="btn btn-sm" id="webview-back" style="padding: 0.25rem 0.5rem;">←</button>
|
|
19
|
+
<button class="btn btn-sm" id="webview-forward" style="padding: 0.25rem 0.5rem;">→</button>
|
|
20
|
+
<button class="btn btn-sm" id="webview-reload" style="padding: 0.25rem 0.5rem;">🔄</button>
|
|
21
|
+
<input type="text" id="url-bar" class="control-input" style="flex: 1; padding: 0.25rem 0.5rem; font-size: 0.875rem;" placeholder="Enter URL or click quick nav buttons" />
|
|
22
|
+
<button class="btn btn-primary btn-sm" id="url-go" style="padding: 0.25rem 0.75rem;">Go</button>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- Quick navigation buttons -->
|
|
26
|
+
<div style="display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap;">
|
|
27
|
+
<button class="btn btn-sm" id="nav-eggbun">eggbun.sh</button>
|
|
28
|
+
<button class="btn btn-sm" id="nav-electrobun">electrobun.dev</button>
|
|
29
|
+
<button class="btn btn-sm" id="nav-github">GitHub</button>
|
|
30
|
+
<button class="btn btn-sm" id="nav-wikipedia">Wikipedia Random</button>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<!-- WebView control buttons -->
|
|
34
|
+
<div style="display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap;">
|
|
35
|
+
<button class="btn btn-secondary btn-sm" id="toggle-transparent">Toggle Transparent</button>
|
|
36
|
+
<button class="btn btn-secondary btn-sm" id="toggle-passthrough">Toggle Passthrough</button>
|
|
37
|
+
<button class="btn btn-secondary btn-sm" id="toggle-hidden">Toggle Hidden</button>
|
|
38
|
+
<button class="btn btn-secondary btn-sm" id="add-mask">Add Mask</button>
|
|
39
|
+
<button class="btn btn-secondary btn-sm" id="remove-mask">Remove Mask</button>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<!-- Draggable element for testing -->
|
|
43
|
+
<div style="display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap;">
|
|
44
|
+
<div id="draggable-test" draggable="true" style="padding: 10px; width: 120px; height: 80px; border: 3px dashed #4a5568; cursor: move; background: white; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 0.875rem; text-align: center;">
|
|
45
|
+
<div>Drag me over the webview</div>
|
|
46
|
+
<div id="drag-coords" style="font-size: 0.75rem; color: #4a5568; margin-top: 0.25rem;">x: 0, y: 0</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="demo-results" style="position: relative;">
|
|
53
|
+
<!-- Main webview container with mask overlay elements -->
|
|
54
|
+
<div style="position: relative; width: 100%; height: 500px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.5rem;">
|
|
55
|
+
|
|
56
|
+
<!-- Overlay squares for mask testing -->
|
|
57
|
+
<div class="element-to-mask" style="position: absolute; z-index: 10; top: -30px; right: 50px; width: 120px; height: 110px; background: black; color: white; padding: 10px; display: flex; align-items: center; justify-content: center; font-weight: bold; border: 10px solid firebrick">
|
|
58
|
+
Mask Layer 1
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div class="element-to-mask" style="position: absolute; z-index: 10; top: -20px; right: 160px; width: 120px; height: 130px; background: green; color: white; padding: 10px; display: flex; align-items: center; justify-content: center; font-weight: bold; border: 5px solid cadetblue;">
|
|
62
|
+
Mask Layer 2
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<!-- Main webview -->
|
|
66
|
+
<electrobun-webview
|
|
67
|
+
id="main-webview"
|
|
68
|
+
style="width: 100%; height: 100%;"
|
|
69
|
+
src="https://electrobun.dev"
|
|
70
|
+
preload=""
|
|
71
|
+
renderer="cef">
|
|
72
|
+
</electrobun-webview>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
<!-- Compact event log -->
|
|
78
|
+
<div style="margin-top: 1rem;">
|
|
79
|
+
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.5rem; padding: 0.5rem;">
|
|
80
|
+
<div style="font-weight: 500; padding: 0.25rem;">WebView Events Log</div>
|
|
81
|
+
<div id="webview-events" style="max-height: 150px; overflow-y: auto; margin-top: 0.5rem;">
|
|
82
|
+
<div class="no-events" style="text-align: center; color: #718096; font-size: 0.875rem;">
|
|
83
|
+
Events will appear here
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<!-- Additional webviews for testing partitions -->
|
|
90
|
+
<div style="margin-top: 1rem;">
|
|
91
|
+
<div style="font-weight: 500; padding: 0.5rem; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.5rem;">Session Partition Testing (Wikipedia)</div>
|
|
92
|
+
|
|
93
|
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-top: 0.5rem;">
|
|
94
|
+
<div style="border: 1px solid #e2e8f0; border-radius: 0.25rem; overflow: hidden;">
|
|
95
|
+
<div style="background: #f7fafc; padding: 0.25rem 0.5rem; font-size: 0.75rem;">
|
|
96
|
+
Shared (Default)
|
|
97
|
+
</div>
|
|
98
|
+
<electrobun-webview
|
|
99
|
+
id="partition-default"
|
|
100
|
+
style="width: 100%; height: 200px;"
|
|
101
|
+
src="https://en.wikipedia.org/wiki/Main_Page"
|
|
102
|
+
renderer="cef"
|
|
103
|
+
partition="">
|
|
104
|
+
</electrobun-webview>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div style="border: 1px solid #e2e8f0; border-radius: 0.25rem; overflow: hidden;">
|
|
108
|
+
<div style="background: #f7fafc; padding: 0.25rem 0.5rem; font-size: 0.75rem;">
|
|
109
|
+
Shared (Also Default)
|
|
110
|
+
</div>
|
|
111
|
+
<electrobun-webview
|
|
112
|
+
id="partition-default2"
|
|
113
|
+
style="width: 100%; height: 200px;"
|
|
114
|
+
src="https://en.wikipedia.org/wiki/Main_Page"
|
|
115
|
+
renderer="cef"
|
|
116
|
+
partition="">
|
|
117
|
+
</electrobun-webview>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div style="border: 1px solid #e2e8f0; border-radius: 0.25rem; overflow: hidden;">
|
|
121
|
+
<div style="background: #eff6ff; padding: 0.25rem 0.5rem; font-size: 0.75rem;">
|
|
122
|
+
Isolated (persist:user1)
|
|
123
|
+
</div>
|
|
124
|
+
<electrobun-webview
|
|
125
|
+
id="partition-user1"
|
|
126
|
+
style="width: 100%; height: 200px;"
|
|
127
|
+
src="https://en.wikipedia.org/wiki/Main_Page"
|
|
128
|
+
renderer="cef"
|
|
129
|
+
partition="persist:user1">
|
|
130
|
+
</electrobun-webview>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div style="border: 1px solid #e2e8f0; border-radius: 0.25rem; overflow: hidden;">
|
|
134
|
+
<div style="background: #f0fdf4; padding: 0.25rem 0.5rem; font-size: 0.75rem;">
|
|
135
|
+
Isolated (persist:user2)
|
|
136
|
+
</div>
|
|
137
|
+
<electrobun-webview
|
|
138
|
+
id="partition-user2"
|
|
139
|
+
style="width: 100%; height: 200px;"
|
|
140
|
+
src="https://en.wikipedia.org/wiki/Main_Page"
|
|
141
|
+
renderer="cef"
|
|
142
|
+
partition="persist:user2">
|
|
143
|
+
</electrobun-webview>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div style="margin-top: 0.5rem; padding: 0.5rem; background: #ebf8ff; border: 1px solid #90cdf4; border-radius: 0.25rem; font-size: 0.75rem; color: #2b6cb0;">
|
|
148
|
+
<strong>How to test partitions:</strong> Click on any Wikipedia link in one webview. The two "Shared" webviews will both show visited links in purple, while the "Isolated" webviews maintain separate browsing history. Try logging in or changing settings - shared partitions share everything, isolated ones are independent.
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<!-- HTML content test -->
|
|
153
|
+
<div style="margin-top: 1rem;">
|
|
154
|
+
<div style="font-weight: 500; padding: 0.5rem; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.5rem;">Inline HTML WebView</div>
|
|
155
|
+
<div style="margin-top: 0.5rem; border: 1px solid #e2e8f0; border-radius: 0.25rem; overflow: hidden;">
|
|
156
|
+
<electrobun-webview
|
|
157
|
+
style="width: 100%; height: 150px;"
|
|
158
|
+
preload="window.onload = () => {document.body.innerHTML += '<br>Hello from preload script!';}"
|
|
159
|
+
html="<html><body style='padding: 20px; font-family: system-ui;'><h2>WebView with inline HTML</h2><p>This webview is rendered from HTML string instead of URL.</p></body></html>">
|
|
160
|
+
</electrobun-webview>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
initialize(rpc: any) {
|
|
169
|
+
this.rpc = rpc;
|
|
170
|
+
this.setupEventListeners();
|
|
171
|
+
this.setupWebViewEvents();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private setupEventListeners() {
|
|
175
|
+
const webview = document.getElementById('main-webview') as any;
|
|
176
|
+
const urlBar = document.getElementById('url-bar') as HTMLInputElement;
|
|
177
|
+
|
|
178
|
+
// Safety check: If webview doesn't exist, don't set up listeners
|
|
179
|
+
if (!webview) {
|
|
180
|
+
console.warn('WebView element not found during event listener setup');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Navigation controls
|
|
185
|
+
document.getElementById('webview-back')?.addEventListener('click', () => {
|
|
186
|
+
if (webview && typeof webview.goBack === 'function') {
|
|
187
|
+
webview.goBack();
|
|
188
|
+
this.addWebViewEvent('← Back');
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
document.getElementById('webview-forward')?.addEventListener('click', () => {
|
|
193
|
+
if (webview && typeof webview.goForward === 'function') {
|
|
194
|
+
webview.goForward();
|
|
195
|
+
this.addWebViewEvent('→ Forward');
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
document.getElementById('webview-reload')?.addEventListener('click', () => {
|
|
200
|
+
if (webview && typeof webview.reload === 'function') {
|
|
201
|
+
webview.reload();
|
|
202
|
+
this.addWebViewEvent('🔄 Reload');
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// URL bar navigation
|
|
207
|
+
const navigateToUrl = () => {
|
|
208
|
+
const url = urlBar?.value?.trim();
|
|
209
|
+
if (url && webview && typeof webview.setAttribute === 'function') {
|
|
210
|
+
// Add protocol if missing
|
|
211
|
+
const finalUrl = url.startsWith('http://') || url.startsWith('https://')
|
|
212
|
+
? url
|
|
213
|
+
: `https://${url}`;
|
|
214
|
+
webview.setAttribute('src', finalUrl);
|
|
215
|
+
this.addWebViewEvent(`Navigate: ${finalUrl}`);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
document.getElementById('url-go')?.addEventListener('click', navigateToUrl);
|
|
220
|
+
urlBar?.addEventListener('keypress', (e) => {
|
|
221
|
+
if (e.key === 'Enter') {
|
|
222
|
+
navigateToUrl();
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Quick navigation
|
|
227
|
+
document.getElementById('nav-eggbun')?.addEventListener('click', () => {
|
|
228
|
+
if (webview && typeof webview.setAttribute === 'function' && urlBar) {
|
|
229
|
+
webview.setAttribute('src', 'https://eggbun.sh');
|
|
230
|
+
urlBar.value = 'https://eggbun.sh';
|
|
231
|
+
this.addWebViewEvent('Nav: eggbun.sh');
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
document.getElementById('nav-electrobun')?.addEventListener('click', () => {
|
|
236
|
+
if (webview && typeof webview.setAttribute === 'function' && urlBar) {
|
|
237
|
+
webview.setAttribute('src', 'https://electrobun.dev');
|
|
238
|
+
urlBar.value = 'https://electrobun.dev';
|
|
239
|
+
this.addWebViewEvent('Nav: electrobun.dev');
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
document.getElementById('nav-github')?.addEventListener('click', () => {
|
|
244
|
+
if (webview && typeof webview.setAttribute === 'function' && urlBar) {
|
|
245
|
+
webview.setAttribute('src', 'https://github.com/blackboardsh/electrobun');
|
|
246
|
+
urlBar.value = 'https://github.com/blackboardsh/electrobun';
|
|
247
|
+
this.addWebViewEvent('Nav: GitHub');
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
document.getElementById('nav-wikipedia')?.addEventListener('click', () => {
|
|
252
|
+
if (webview && typeof webview.setAttribute === 'function' && urlBar) {
|
|
253
|
+
webview.setAttribute('src', 'https://en.wikipedia.org/wiki/Special:Random');
|
|
254
|
+
urlBar.value = 'https://en.wikipedia.org/wiki/Special:Random';
|
|
255
|
+
this.addWebViewEvent('Nav: Wikipedia Random');
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// WebView effects
|
|
260
|
+
let isTransparent = false;
|
|
261
|
+
let isPassthrough = false;
|
|
262
|
+
let isHidden = false;
|
|
263
|
+
|
|
264
|
+
document.getElementById('toggle-transparent')?.addEventListener('click', () => {
|
|
265
|
+
if (webview && typeof webview.toggleTransparent === 'function') {
|
|
266
|
+
webview.toggleTransparent();
|
|
267
|
+
isTransparent = !isTransparent;
|
|
268
|
+
this.addWebViewEvent(`Transparent: ${isTransparent ? 'ON' : 'OFF'}`);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
document.getElementById('toggle-passthrough')?.addEventListener('click', () => {
|
|
273
|
+
if (webview && typeof webview.togglePassthrough === 'function') {
|
|
274
|
+
webview.togglePassthrough();
|
|
275
|
+
isPassthrough = !isPassthrough;
|
|
276
|
+
this.addWebViewEvent(`Passthrough: ${isPassthrough ? 'ON' : 'OFF'}`);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
document.getElementById('toggle-hidden')?.addEventListener('click', () => {
|
|
281
|
+
if (webview && typeof webview.toggleHidden === 'function') {
|
|
282
|
+
webview.toggleHidden();
|
|
283
|
+
isHidden = !isHidden;
|
|
284
|
+
this.addWebViewEvent(`Hidden: ${isHidden ? 'ON' : 'OFF'}`);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Element masking
|
|
289
|
+
let maskActive = false;
|
|
290
|
+
document.getElementById('add-mask')?.addEventListener('click', () => {
|
|
291
|
+
if (webview && typeof webview.addMaskSelector === 'function') {
|
|
292
|
+
webview.addMaskSelector('.element-to-mask');
|
|
293
|
+
maskActive = true;
|
|
294
|
+
this.addWebViewEvent('Mask added: .element-to-mask');
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
document.getElementById('remove-mask')?.addEventListener('click', () => {
|
|
299
|
+
if (webview && typeof webview.removeMaskSelector === 'function') {
|
|
300
|
+
webview.removeMaskSelector('.element-to-mask');
|
|
301
|
+
maskActive = false;
|
|
302
|
+
this.addWebViewEvent('Mask removed: .element-to-mask');
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Draggable element position tracking
|
|
307
|
+
const draggable = document.getElementById('draggable-test');
|
|
308
|
+
const dragCoords = document.getElementById('drag-coords');
|
|
309
|
+
|
|
310
|
+
if (draggable && dragCoords) {
|
|
311
|
+
draggable.addEventListener('dragstart', (e: DragEvent) => {
|
|
312
|
+
// Store initial offset
|
|
313
|
+
const rect = draggable.getBoundingClientRect();
|
|
314
|
+
(e.dataTransfer as any).effectAllowed = 'move';
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Update coordinates during drag
|
|
318
|
+
document.addEventListener('dragover', (e: DragEvent) => {
|
|
319
|
+
e.preventDefault();
|
|
320
|
+
if (dragCoords) {
|
|
321
|
+
dragCoords.textContent = `x: ${e.clientX}, y: ${e.clientY}`;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
draggable.addEventListener('dragend', (e: DragEvent) => {
|
|
326
|
+
if (dragCoords) {
|
|
327
|
+
dragCoords.textContent = `x: ${e.clientX}, y: ${e.clientY}`;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Add mask selectors to all webviews (with safety checks)
|
|
333
|
+
document.querySelectorAll('electrobun-webview').forEach((w: any) => {
|
|
334
|
+
if (w && typeof w.addMaskSelector === 'function') {
|
|
335
|
+
w.addMaskSelector("header");
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private setupWebViewEvents() {
|
|
342
|
+
const webview = document.getElementById('main-webview') as any;
|
|
343
|
+
const urlBar = document.getElementById('url-bar') as HTMLInputElement;
|
|
344
|
+
|
|
345
|
+
if (webview && typeof webview.on === 'function') {
|
|
346
|
+
// Use the on() method as shown in the old playground
|
|
347
|
+
webview.on('did-navigate', (e: any) => {
|
|
348
|
+
const url = e.detail?.url || 'unknown';
|
|
349
|
+
if (urlBar) {
|
|
350
|
+
urlBar.value = url;
|
|
351
|
+
}
|
|
352
|
+
this.addWebViewEvent(`did-navigate: ${url}`);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
webview.on('did-navigate-in-page', (e: any) => {
|
|
356
|
+
this.addWebViewEvent(`in-page-nav: ${e.detail?.url || 'unknown'}`);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
webview.on('did-commit-navigation', (e: any) => {
|
|
360
|
+
this.addWebViewEvent(`commit-nav: ${e.detail?.url || 'unknown'}`);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
webview.on('dom-ready', () => {
|
|
364
|
+
this.addWebViewEvent(`DOM ready`);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
webview.on('new-window-open', (e: any) => {
|
|
368
|
+
this.addWebViewEvent(`new-window: ${e.detail?.url || 'unknown'}`);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Also try addEventListener for compatibility
|
|
372
|
+
if (typeof webview.addEventListener === 'function') {
|
|
373
|
+
webview.addEventListener('did-navigate', (e: any) => {
|
|
374
|
+
const url = e.detail?.url || 'unknown';
|
|
375
|
+
if (urlBar) {
|
|
376
|
+
urlBar.value = url;
|
|
377
|
+
}
|
|
378
|
+
this.addWebViewEvent(`did-navigate: ${url}`);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private addWebViewEvent(event: string) {
|
|
385
|
+
const container = document.getElementById('webview-events');
|
|
386
|
+
if (!container) return;
|
|
387
|
+
|
|
388
|
+
const time = new Date().toLocaleTimeString();
|
|
389
|
+
const eventHtml = `
|
|
390
|
+
<div style="border-left: 2px solid #0ea5e9; padding: 0.25rem 0.5rem; margin-bottom: 0.25rem; font-size: 0.75rem;">
|
|
391
|
+
<span style="color: #64748b;">${time}</span>
|
|
392
|
+
<span style="color: #0369a1; margin-left: 0.5rem;">${event}</span>
|
|
393
|
+
</div>
|
|
394
|
+
`;
|
|
395
|
+
|
|
396
|
+
// Remove "no events" message if it exists
|
|
397
|
+
const noEvents = container.querySelector('.no-events');
|
|
398
|
+
if (noEvents) {
|
|
399
|
+
container.innerHTML = '';
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Add new event at the top
|
|
403
|
+
container.insertAdjacentHTML('afterbegin', eventHtml);
|
|
404
|
+
|
|
405
|
+
// Keep only last 10 events
|
|
406
|
+
const events = container.children;
|
|
407
|
+
while (events.length > 10) {
|
|
408
|
+
container.removeChild(events[events.length - 1]);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|