I've built this over and over in several of my modules (RockDevTools for Livereload, RockCalendar for creating events). Always a lot of work. Always a lot of boilerplate code. Always a lot of issues to fix. I think it's time to bring SSE (Server Sent Events) to everybody.
Simple example (Empty Trash):
Client-Side:
// create stream
const stream = ProcessWire.Sse.stream(
'ssedemo-empty-trash',
(event) => {
const textarea = document.querySelector('textarea[name="empty-trash-status"]');
try {
let json = JSON.parse(event.data);
stream.prepend(textarea, json.message, 100);
} catch (error) {
stream.prepend(textarea, event.data);
}
}
);
// update progress bar
const progressBar = document.querySelector('#empty-trash-progress');
stream.onProgress((progress) => {
progressBar.value = progress.percent;
});
// click on start button
document.querySelector('#empty-trash').addEventListener(
'click',
(e) => {
e.preventDefault();
stream.start();
});
// click on stop button
document.querySelector('#stop-empty-trash').addEventListener(
'click',
(e) => {
e.preventDefault();
stream.stop();
});
Server-Side:
public function __construct()
{
parent::__construct();
/** @var Sse $sse */
$sse = wire()->modules->get('Sse');
$sse->addStream('ssedemo-empty-trash', $this, 'emptyTrash');
}
public function emptyTrash(Sse $sse, Iterator $iterator)
{
$user = wire()->user;
if (!$user->isSuperuser()) die('no access');
$selector = [
'parent' => wire()->config->trashPageID,
'include' => 'all',
];
// first run
if ($iterator->num === 1) {
$iterator->max = wire()->pages->count($selector);
}
// trash one page at a time
$p = wire()->pages->get($selector);
if ($p->id) $p->delete(true);
else {
$sse->send('No more pages to delete');
return $sse->stop();
}
// send message and progress info
$sse->send(
$iterator->num . '/' . $iterator->max . ': deleted ' . $p->name,
$iterator
);
// no sleep to instantly run next iteration
$sse->sleep = 0;
}
Code + Readme: https://github.com/baumrock/SSE/tree/dev
What do you think? Would be nice if you could test it in your environments and let me know if you find any issues!