Skip to content

Commit a803854

Browse files
Sascha Nowakclue
authored andcommitted
Add chat example
Originally by @nlx-sascha, squashed by @clue
1 parent 3956bbf commit a803854

3 files changed

Lines changed: 260 additions & 0 deletions

File tree

examples/10-eventsource.html

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<title>EventSource example</title>
6+
<script>
7+
var es = new EventSource('demo'), username = '';
8+
es.addEventListener('message', function(event) {
9+
var data = JSON.parse(event.data);
10+
var $messages = document.querySelectorAll('.chat-messages')[0];
11+
var message = document.createElement('div');
12+
if (data.username !== '') {
13+
message.innerHTML = `<strong>${data.username}:</strong> ${data.message}`;
14+
} else {
15+
message.innerHTML = data.message;
16+
}
17+
message.classList.add('chat-message');
18+
if ($messages.childNodes.length !== 0) {
19+
$messages.insertBefore(message, $messages.firstChild);
20+
} else {
21+
$messages.appendChild(message);
22+
}
23+
});
24+
25+
document.addEventListener('DOMContentLoaded', function() {
26+
var $chatForm = document.querySelectorAll('.chat-form')[0];
27+
$chatForm.addEventListener('submit', function($event) {
28+
$event.preventDefault();
29+
var $input = document.querySelectorAll('.chat-form input')[0];
30+
if ($input.value.length) {
31+
fetch(`/message?message=${$input.value}&username=${username}`).then(function() {
32+
$input.value = '';
33+
});
34+
}
35+
});
36+
});
37+
38+
document.addEventListener('DOMContentLoaded', function() {
39+
var $chatForm = document.querySelectorAll('.username-form')[0];
40+
$chatForm.addEventListener('submit', function($event) {
41+
$event.preventDefault();
42+
var $input = document.querySelectorAll('.username-form input')[0];
43+
if ($input.value.length > 3) {
44+
document.activeElement.blur();
45+
username = $input.value;
46+
document.querySelectorAll('.chat-header')[0].innerHTML = username;
47+
document.body.classList.add('hide-username');
48+
setTimeout(function() {
49+
document.querySelectorAll('.username-form-container')[0].style.display = 'none';
50+
document.querySelectorAll('.chat-form input')[0].focus();
51+
}, 800);
52+
}
53+
});
54+
});
55+
</script>
56+
57+
<link href="styles.css" media="all" rel="stylesheet"/>
58+
</head>
59+
<body>
60+
<div class="chat">
61+
<div class="chat-header"></div>
62+
<div class="chat-messages"></div>
63+
<div class="chat-footer">
64+
<form class="chat-form">
65+
<input type="text" placeholder="Enter chat message">
66+
<button type="submit">Send</button>
67+
</form>
68+
</div>
69+
</div>
70+
<div class="username-form-container">
71+
<form class="username-form">
72+
<input type="text" placeholder="Enter username" autofocus="">
73+
<button type="submit">Enter</button>
74+
</form>
75+
</div>
76+
</body>
77+
</html>

examples/10-styles.css

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
* {
2+
box-sizing: border-box;
3+
}
4+
5+
html {
6+
font-family: sans-serif;
7+
-ms-text-size-adjust: 100%;
8+
-webkit-text-size-adjust: 100%;
9+
}
10+
11+
body {
12+
margin: 10vh 10vw;
13+
background: linear-gradient(#2699e3, #2699e3 25vh, #e9e9e9 25vh, #e9e9e9);
14+
}
15+
16+
button {
17+
border: 0 none;
18+
padding: 0.5rem 1.5rem;
19+
background: #1188d4;
20+
color: #ffffff;
21+
text-transform: uppercase;
22+
}
23+
24+
button:focus {
25+
text-decoration: none;
26+
outline: 0 none;
27+
}
28+
29+
input {
30+
border: 0 none;
31+
padding: 0.5rem 1rem;
32+
}
33+
34+
input:focus {
35+
outline: 0 none;
36+
}
37+
38+
form {
39+
width: 100%;
40+
display: flex;
41+
flex-direction: row;
42+
}
43+
44+
form input {
45+
transition: all 0.5s;
46+
flex: 1
47+
}
48+
49+
.chat {
50+
max-width: 1100px;
51+
margin: 0 auto;
52+
}
53+
54+
.chat-header,
55+
.chat-footer {
56+
padding: 2rem;
57+
height: 10vh;
58+
background: #f7f7f7;
59+
display: flex;
60+
align-items: center;
61+
}
62+
63+
.chat-messages {
64+
height: 60vh;
65+
background: #ffffff;
66+
padding: 1rem 5rem;
67+
overflow: hidden;
68+
}
69+
70+
.chat-message {
71+
padding: 1rem 0 1rem 2.5rem;
72+
position: relative;
73+
min-height: 24px;
74+
}
75+
76+
.chat-message:before {
77+
content: '';
78+
background: url(data:image/svg+xml,%3Csvg%20fill%3D%22%23000000%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M9%2011.75c-.69%200-1.25.56-1.25%201.25s.56%201.25%201.25%201.25%201.25-.56%201.25-1.25-.56-1.25-1.25-1.25zm6%200c-.69%200-1.25.56-1.25%201.25s.56%201.25%201.25%201.25%201.25-.56%201.25-1.25-.56-1.25-1.25-1.25zM12%202C6.48%202%202%206.48%202%2012s4.48%2010%2010%2010%2010-4.48%2010-10S17.52%202%2012%202zm0%2018c-4.41%200-8-3.59-8-8%200-.29.02-.58.05-.86%202.36-1.05%204.23-2.98%205.21-5.37C11.07%208.33%2014.05%2010%2017.42%2010c.78%200%201.53-.09%202.25-.26.21.71.33%201.47.33%202.26%200%204.41-3.59%208-8%208z%22/%3E%0A%20%20%20%20%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22/%3E%0A%3C/svg%3E);
79+
position: absolute;
80+
top: calc(50% - 12px);
81+
left: 0;
82+
width: 24px;
83+
height: 24px;
84+
}
85+
86+
.chat-message:not(:first-child) {
87+
border-top: 1px solid #e9e9e9;
88+
}
89+
90+
.username-form-container {
91+
transition: opacity 0.15s linear 0.55s;
92+
position: absolute;
93+
top: 0;
94+
left: 0;
95+
right: 0;
96+
bottom: 0;
97+
display: flex;
98+
align-items: center;
99+
justify-content: center;
100+
background: rgba(255, 255, 255, 0.95);
101+
}
102+
103+
.username-form-container .username-form {
104+
transition: transform 0.5s;
105+
width: calc(100% - 20vw - 4rem);
106+
max-width: calc(1100px - 4rem);
107+
}
108+
109+
.hide-username .username-form-container {
110+
opacity: 0;
111+
}
112+
113+
.hide-username .username-form {
114+
transform: translate3d(0, -35vh, 0);
115+
}
116+
117+
.hide-username .username-form input {
118+
padding: 0;
119+
height: 1rem;
120+
font-size: 1rem;
121+
background: transparent;
122+
}
123+
124+
.hide-username .username-form button {
125+
display: none;
126+
}

examples/11-chat.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
use Clue\React\Sse\BufferedChannel;
6+
use React\Http\Request;
7+
use React\Http\Response;
8+
9+
$loop = React\EventLoop\Factory::create();
10+
$socket = new React\Socket\Server($loop);
11+
12+
$channel = new BufferedChannel();
13+
14+
$http = new React\Http\Server($socket);
15+
$http->on('request', function (Request $request, Response $response) use ($channel) {
16+
17+
switch ($request->getPath()) {
18+
case '/':
19+
$response->writeHead('200', array('Content-Type' => 'text/html'));
20+
$response->end(file_get_contents(__DIR__ . '/10-eventsource.html'));
21+
$message = array('message' => 'New person connected from '. $request->remoteAddress, 'username' => '');
22+
$channel->writeMessage(json_encode($message));
23+
return;
24+
case '/styles.css':
25+
$response->writeHead('200', array('Content-Type' => 'text/css'));
26+
$response->end(file_get_contents(__DIR__ . '/10-styles.css'));
27+
return;
28+
case '/message':
29+
$query = $request->getQuery();
30+
if (array_key_exists('message', $query)) {
31+
$message = array('message' => htmlspecialchars($query['message']), 'username' => htmlspecialchars($query['username']));
32+
$channel->writeMessage(json_encode($message));
33+
}
34+
$response->writeHead('201', array('Content-Type' => 'text/json'));
35+
$response->end();
36+
return;
37+
}
38+
39+
echo $request->remoteAddress . ' connected' . PHP_EOL;
40+
41+
$headers = $request->getHeaders();
42+
$id = isset($headers['Last-Event-ID']) ? $headers['Last-Event-ID'] : null;
43+
44+
$response->writeHead(200, array('Content-Type' => 'text/event-stream'));
45+
$channel->connect($response, $id);
46+
47+
$response->on('close', function () use ($response, $channel, $request) {
48+
echo $request->remoteAddress . 'disconnected' . PHP_EOL;
49+
$channel->disconnect($response);
50+
});
51+
});
52+
53+
$socket->listen(isset($argv[1]) ? $argv[1] : 0, '0.0.0.0');
54+
55+
echo 'Server now listening on http://localhost:' . $socket->getPort() . ' (port is first parameter)' . PHP_EOL;
56+
57+
$loop->run();

0 commit comments

Comments
 (0)