Skip to content

Commit 4f76898

Browse files
committed
feat(examples): add JavaScript execution and communication demo
- introduce js_execution example with Zig and JavaScript interop - implement advanced JS execution, data exchange, DOM manipulation, and raw data transfer - update C and Zig bindings for send_raw to use *const anyopaque for improved type safety
1 parent fd5a3ed commit 4f76898

File tree

4 files changed

+593
-4
lines changed

4 files changed

+593
-4
lines changed

examples/js_execution/index.html

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<script src="/webui.js"></script>
6+
<title>JavaScript Execution Example</title>
7+
<style>
8+
body {
9+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
11+
color: white;
12+
margin: 0;
13+
padding: 20px;
14+
min-height: 100vh;
15+
}
16+
.container {
17+
max-width: 900px;
18+
margin: 0 auto;
19+
}
20+
h1 {
21+
text-align: center;
22+
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
23+
margin-bottom: 30px;
24+
}
25+
.section {
26+
background: rgba(255,255,255,0.1);
27+
border-radius: 10px;
28+
padding: 20px;
29+
margin: 20px 0;
30+
backdrop-filter: blur(10px);
31+
}
32+
.controls {
33+
display: flex;
34+
flex-wrap: wrap;
35+
gap: 10px;
36+
align-items: center;
37+
}
38+
button {
39+
background: linear-gradient(45deg, #4CAF50, #45a049);
40+
color: white;
41+
border: none;
42+
padding: 10px 20px;
43+
border-radius: 20px;
44+
cursor: pointer;
45+
font-weight: bold;
46+
transition: all 0.3s ease;
47+
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
48+
}
49+
button:hover {
50+
background: linear-gradient(45deg, #45a049, #4CAF50);
51+
transform: translateY(-2px);
52+
}
53+
input, select, textarea {
54+
padding: 8px 12px;
55+
border: none;
56+
border-radius: 5px;
57+
margin: 5px;
58+
}
59+
.result-display {
60+
background: rgba(0,0,0,0.3);
61+
padding: 15px;
62+
border-radius: 8px;
63+
margin-top: 15px;
64+
font-family: monospace;
65+
white-space: pre-wrap;
66+
word-break: break-all;
67+
max-height: 200px;
68+
overflow-y: auto;
69+
}
70+
.data-display {
71+
background: rgba(0,255,0,0.1);
72+
padding: 10px;
73+
border-radius: 5px;
74+
margin-top: 10px;
75+
border: 1px solid rgba(0,255,0,0.3);
76+
}
77+
#dynamic-content {
78+
background: rgba(255,255,255,0.2);
79+
padding: 15px;
80+
border-radius: 8px;
81+
text-align: center;
82+
font-size: 18px;
83+
transition: background 0.3s ease;
84+
}
85+
</style>
86+
</head>
87+
<body>
88+
<div class="container">
89+
<h1>🚀 JavaScript Execution & Communication</h1>
90+
91+
<div class="section">
92+
<h3>Simple JavaScript Execution</h3>
93+
<button onclick="runSimple()">▶️ Run Simple JS</button>
94+
<div class="result-display" id="simple-result">Ready to execute JavaScript...</div>
95+
</div>
96+
97+
<div class="section">
98+
<h3>JavaScript with Response</h3>
99+
<div class="controls">
100+
<select id="operation">
101+
<option value="add">Addition</option>
102+
<option value="multiply">Multiplication</option>
103+
<option value="power">Power</option>
104+
</select>
105+
<input type="number" id="num1" value="5" style="width: 80px;">
106+
<input type="number" id="num2" value="3" style="width: 80px;">
107+
<button onclick="runWithResponse()">🧮 Calculate</button>
108+
</div>
109+
<div class="result-display" id="calc-result">Select operation and click Calculate...</div>
110+
</div>
111+
112+
<div class="section">
113+
<h3>Complex JavaScript Processing</h3>
114+
<div class="controls">
115+
<input type="text" id="text-input" value="Hello WebUI World" style="width: 200px;" placeholder="Enter text to process">
116+
<button onclick="runComplex()">🔄 Process Text</button>
117+
</div>
118+
<div class="result-display" id="complex-result">Enter text and click Process...</div>
119+
</div>
120+
121+
<div class="section">
122+
<h3>Send Data to JavaScript</h3>
123+
<div class="controls">
124+
<input type="text" id="message-input" value="Hello from Zig!" style="width: 150px;" placeholder="Message">
125+
<input type="number" id="value-input" value="42" style="width: 80px;" placeholder="Value">
126+
<button onclick="sendData()">📤 Send Data</button>
127+
</div>
128+
<div class="data-display" id="received-data">No data received yet...</div>
129+
</div>
130+
131+
<div class="section">
132+
<h3>Raw Binary Data</h3>
133+
<div class="controls">
134+
<input type="number" id="data-size" value="100" min="1" max="1024" style="width: 80px;">
135+
<span>bytes</span>
136+
<button onclick="sendRaw()">📊 Send Raw Data</button>
137+
</div>
138+
<div class="result-display" id="raw-result">Raw data display area...</div>
139+
</div>
140+
141+
<div class="section">
142+
<h3>Navigation</h3>
143+
<div class="controls">
144+
<input type="url" id="url-input" value="https://example.com" style="width: 250px;" placeholder="Enter URL">
145+
<button onclick="navigate()">🌐 Navigate</button>
146+
<button onclick="getPageInfo()">ℹ️ Get Page Info</button>
147+
</div>
148+
<div class="result-display" id="nav-result">Enter URL and navigate...</div>
149+
</div>
150+
151+
<div class="section">
152+
<h3>DOM Manipulation</h3>
153+
<div class="controls">
154+
<input type="text" id="new-content" value="Updated from Zig!" style="width: 200px;" placeholder="New content">
155+
<button onclick="updateContent()">✏️ Update Dynamic Content</button>
156+
</div>
157+
<div id="dynamic-content">This content can be updated from Zig</div>
158+
</div>
159+
160+
<div class="section">
161+
<h3>JSON Data Exchange</h3>
162+
<div class="controls">
163+
<textarea id="json-input" rows="3" style="width: 100%;" placeholder="Enter JSON data">{"name": "WebUI", "version": "2.5.0", "language": "Zig"}</textarea>
164+
<button onclick="sendJson()">📋 Send JSON</button>
165+
</div>
166+
<div class="result-display" id="json-result">JSON processing result will appear here...</div>
167+
</div>
168+
</div>
169+
170+
<script>
171+
// Functions called from Zig
172+
function receiveDataFromZig(data) {
173+
const display = document.getElementById('received-data');
174+
const parsed = typeof data === 'string' ? JSON.parse(data) : data;
175+
display.innerHTML = `
176+
<strong>Received from Zig:</strong><br>
177+
Message: ${parsed.message}<br>
178+
Value: ${parsed.value}<br>
179+
Timestamp: ${new Date(parsed.timestamp * 1000).toLocaleString()}
180+
`;
181+
console.log('Received data from Zig:', parsed);
182+
}
183+
184+
function receiveRawData(rawData) {
185+
const display = document.getElementById('raw-result');
186+
const view = new Uint8Array(rawData);
187+
const preview = Array.from(view.slice(0, 20))
188+
.map(b => b.toString(16).padStart(2, '0'))
189+
.join(' ');
190+
191+
display.innerHTML = `
192+
Received ${view.length} bytes of raw data
193+
Preview (first 20 bytes): ${preview}${view.length > 20 ? '...' : ''}
194+
`;
195+
console.log('Received raw data:', view);
196+
}
197+
198+
// UI event handlers
199+
function runSimple() {
200+
run_simple_js().then(result => {
201+
document.getElementById('simple-result').textContent = result;
202+
});
203+
}
204+
205+
function runWithResponse() {
206+
const operation = document.getElementById('operation').value;
207+
const num1 = parseInt(document.getElementById('num1').value);
208+
const num2 = parseInt(document.getElementById('num2').value);
209+
210+
run_js_with_response(operation, num1, num2).then(result => {
211+
document.getElementById('calc-result').textContent =
212+
`${operation}(${num1}, ${num2}) = ${result}`;
213+
});
214+
}
215+
216+
function runComplex() {
217+
const text = document.getElementById('text-input').value;
218+
219+
run_complex_js(text).then(result => {
220+
try {
221+
const parsed = JSON.parse(result);
222+
document.getElementById('complex-result').innerHTML = `
223+
<strong>Text Analysis:</strong><br>
224+
Original: ${parsed.original}<br>
225+
Length: ${parsed.length}<br>
226+
Uppercase: ${parsed.uppercase}<br>
227+
Word count: ${parsed.words}<br>
228+
Reversed: ${parsed.reversed}<br>
229+
Processed at: ${parsed.timestamp}
230+
`;
231+
} catch (e) {
232+
document.getElementById('complex-result').textContent = result;
233+
}
234+
});
235+
}
236+
237+
function sendData() {
238+
const message = document.getElementById('message-input').value;
239+
const value = parseInt(document.getElementById('value-input').value);
240+
241+
send_data_to_js(message, value).then(result => {
242+
console.log('Send data result:', result);
243+
});
244+
}
245+
246+
function sendRaw() {
247+
const size = parseInt(document.getElementById('data-size').value);
248+
249+
send_raw_data(size).then(result => {
250+
console.log('Send raw data result:', result);
251+
});
252+
}
253+
254+
function navigate() {
255+
const url = document.getElementById('url-input').value;
256+
257+
navigate_to_url(url).then(result => {
258+
document.getElementById('nav-result').textContent = result;
259+
});
260+
}
261+
262+
function getPageInfo() {
263+
get_page_content().then(result => {
264+
try {
265+
const parsed = JSON.parse(result);
266+
document.getElementById('nav-result').innerHTML = `
267+
<strong>Page Information:</strong><br>
268+
Title: ${parsed.title}<br>
269+
URL: ${parsed.url}<br>
270+
Elements: ${parsed.elements}<br>
271+
User Agent: ${parsed.userAgent.substring(0, 50)}...
272+
`;
273+
} catch (e) {
274+
document.getElementById('nav-result').textContent = result;
275+
}
276+
});
277+
}
278+
279+
function updateContent() {
280+
const newText = document.getElementById('new-content').value;
281+
282+
manipulate_dom('dynamic-content', newText).then(result => {
283+
console.log('DOM manipulation result:', result);
284+
});
285+
}
286+
287+
function sendJson() {
288+
const jsonText = document.getElementById('json-input').value;
289+
290+
try {
291+
// Validate JSON
292+
JSON.parse(jsonText);
293+
294+
handle_json_data(jsonText).then(result => {
295+
document.getElementById('json-result').textContent = result;
296+
});
297+
} catch (e) {
298+
document.getElementById('json-result').textContent = 'Invalid JSON: ' + e.message;
299+
}
300+
}
301+
302+
// Initialize page
303+
console.log('JavaScript Execution Example loaded');
304+
getPageInfo(); // Auto-load page info on start
305+
</script>
306+
</body>
307+
</html>

0 commit comments

Comments
 (0)