Skip to content

Commit ae6b923

Browse files
committed
add web_app_multi_client example
1 parent 9390902 commit ae6b923

File tree

2 files changed

+256
-0
lines changed

2 files changed

+256
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>WebUI - Web App Multi-Client Example</title>
6+
<style>
7+
body {
8+
font-family: 'Arial', sans-serif;
9+
color: white;
10+
background: linear-gradient(to right, #507d91, #1c596f, #022737);
11+
text-align: center;
12+
font-size: 18px;
13+
}
14+
button,
15+
input {
16+
padding: 10px;
17+
border-radius: 3px;
18+
border: 1px solid #ccc;
19+
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1);
20+
transition: 0.2s;
21+
}
22+
button {
23+
background: #3498db;
24+
color: #fff;
25+
cursor: pointer;
26+
font-size: 16px;
27+
}
28+
h1 {
29+
text-shadow: -7px 10px 7px rgb(67 57 57 / 76%);
30+
}
31+
button:hover {
32+
background: #c9913d;
33+
}
34+
input:focus {
35+
outline: none;
36+
border-color: #3498db;
37+
}
38+
39+
a:link {
40+
color: #fd5723;
41+
}
42+
a:active {
43+
color: #fd5723;
44+
}
45+
a:visited {
46+
color: #fd5723;
47+
}
48+
a:hover {
49+
color: #f0bcac;
50+
}
51+
span {
52+
color:#d69d48;
53+
font-size: larger;
54+
}
55+
</style>
56+
</head>
57+
<body>
58+
<h3>Web App Multi-Client Example</h3>
59+
<br />
60+
<span id="status">Connecting...</span>
61+
<br />
62+
<br />
63+
You are user number <span id="userNumber">0</span>
64+
<br />
65+
<br />
66+
Your connection numer is <span id="connectionNumber">0</span>
67+
<br />
68+
<br />
69+
There are <span id="userCount">0</span> users connected, and <span id="tabCount">0</span> tabs opened.
70+
<br />
71+
<br />
72+
Current user input: <input id="privateInput"></input> <button OnClick="save(document.getElementById('privateInput').value)">Save</button> <a href="">Reload This Page</a>
73+
<br />
74+
<br />
75+
All users input: <input id="publicInput"></input> <button OnClick="saveAll(document.getElementById('publicInput').value);">Update All Users</button>
76+
<br />
77+
<br />
78+
<a href="" target="_blank">Open New Tab</a>
79+
<br />
80+
<br />
81+
<button OnClick="exit_app();">Exit</button>
82+
<br />
83+
<br />
84+
<br />
85+
Note: <br /><em>Copy URL, and open it in a private window, or another web browser to create new users.</em>
86+
</body>
87+
88+
<!-- Connect this window to the background app -->
89+
<script src="/webui.js"></script>
90+
91+
<script>
92+
// JavaScript Example
93+
/*
94+
document.addEventListener('DOMContentLoaded', function() {
95+
// DOM is loaded. Check if `webui` object is available
96+
if (typeof webui !== 'undefined') {
97+
// Set events callback
98+
webui.setEventCallback((e) => {
99+
if (e == webui.event.CONNECTED) {
100+
// Connection to the backend is established
101+
console.log('Connected.');
102+
webuiTest();
103+
} else if (e == webui.event.DISCONNECTED) {
104+
// Connection to the backend is lost
105+
console.log('Disconnected.');
106+
}
107+
});
108+
} else {
109+
// The virtual file `webui.js` is not included
110+
alert('Please add webui.js to your HTML.');
111+
}
112+
});
113+
114+
function webuiTest() {
115+
// Call a backend function
116+
if (webui.isConnected()) {
117+
118+
// When you bind a func in the backend
119+
// webui will create the `func` object
120+
// in three places:
121+
//
122+
// Global : func(...)
123+
// Property : webui.func(...)
124+
// Method : webui.call('func', ...)
125+
//
126+
// [!] Note: Objects creation fails when
127+
// a similar object already exist.
128+
129+
const foo = 'Hello';
130+
const bar = 123456;
131+
132+
// Calling as global object
133+
myBackendFunction(foo, bar).then((response) => {
134+
// Do something with `response`
135+
});
136+
137+
// Calling as property of `webui.` object
138+
webui.myBackendFunction(foo, bar).then((response) => {
139+
// Do something with `response`
140+
});
141+
142+
// Calling using the method `webui.call()`
143+
webui.call('myBackendFunction', foo, bar).then((response) => {
144+
// Do something with `response`
145+
});
146+
147+
// Using await
148+
// const response = await myBackendFunction(foo, bar);
149+
// const response = await webui.myBackendFunction(foo, bar);
150+
// const response = await webui.call('myBackendFunction', foo, bar);
151+
}
152+
}
153+
*/
154+
</script>
155+
</html>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import std/strformat
2+
3+
import webui
4+
5+
# Arrays to hold permanent data
6+
var
7+
privateInput: array[256, string] # One for each user
8+
publicInput: string # One for all users
9+
usersCount: int
10+
tabCount: int
11+
12+
proc save(e: Event) =
13+
# Get input value and save it in the array
14+
privateInput[e.clientId] = e.getString()
15+
16+
proc saveAll(e: Event) =
17+
# Get input value and save it in the array
18+
publicInput = e.getString()
19+
20+
# Update all users
21+
e.window.run(fmt"document.getElementById('publicInput').value = '{publicInput}';")
22+
23+
proc events(e: Event) =
24+
# This function gets called every time there is an event
25+
26+
# Get full web browser cookies
27+
# this is a port of the C example, which declares,
28+
# but doesnt use the `cookies` variable
29+
let cookies {.used.} = e.cookies
30+
31+
# Static client (Based on web browser cookies)
32+
let clientId = e.clientId
33+
34+
# Dynamic client connection ID (Changes on connect/disconnect events)
35+
let connectionId = e.connectionId
36+
37+
case e.eventType
38+
of weConnected: # New connection
39+
if users_count < (client_id + 1): # +1 because it starts from 0
40+
users_count = client_id + 1
41+
42+
inc tabCount
43+
of weDisconnected: # Disconnection
44+
if tab_count > 0:
45+
dec tab_count
46+
else:
47+
discard
48+
49+
# --- Update this current user only
50+
51+
# status
52+
e.runClient("document.getElementById('status').innerText = 'Connected!';")
53+
54+
# userNumber
55+
e.runClient(fmt"document.getElementById('userNumber').innerText = '{clientId}';")
56+
57+
# connectionId
58+
e.runClient(fmt"document.getElementById('connectionNumber').innerText = '{connectionId}';")
59+
60+
# privateInput
61+
e.runClient(fmt"document.getElementById('privateInput').value = '{privateInput[clientId]}';")
62+
63+
# publicInput
64+
e.runClient(fmt"document.getElementById('publicInput').value = '{publicInput}';")
65+
66+
# --- Update all connected users
67+
68+
# userCount
69+
e.runClient(fmt"document.getElementById('userCount').innerText = '{usersCount}';")
70+
71+
# tabCount
72+
e.runClient(fmt"document.getElementById('tabCount').innerText = '{tabCount}';")
73+
74+
proc main() =
75+
# Allow multi-user connection and cookies
76+
setConfig({wcMultiClient, wcUseCookies}, true)
77+
78+
# Create new window
79+
let window = newWindow()
80+
81+
# Bind HTML with Nim functions
82+
window.bind("save", save)
83+
window.bind("saveAll", saveAll)
84+
window.bind("exit_app", exit)
85+
86+
# Bind all events
87+
window.bind("", events)
88+
89+
# Start server only
90+
let url = window.startServer("index.html")
91+
92+
# Open a new page in the default native web browser
93+
openUrl(url)
94+
95+
# Wait until all windows get closed
96+
wait()
97+
98+
# Free all memory resources (Optional)
99+
clean()
100+
101+
main()

0 commit comments

Comments
 (0)