Chat Room
div#bob
alice says:
on 1 Jan. 1970 and 0 ms
I love you Bob
div#alice
you say:
on 1 Jan. 1970 and 0 ms
I love you Bob
IO streams effectively channel interactions between isolated components.
let _r = __.record(),
IO = dom.IO;
// : Model
let M = {
user: 'alice',
msgs: [],
input: ''
}
// read : Model -> [Msg]
let read = M => M.msgs
.map(_r.set('user', M.user));
// send : Model -> Msg
let send = M => ({
sender: M.user,
date: Date.now(),
body: M.input
});
//------ Server ------
let server = {};
// .msgs : [Msg]
server.msgs = [{
sender: 'alice',
date: 0,
body: 'I love you Bob'
}];
// .clients : [IO(e)]
server.clients = [];
// .post : Msg -> ServerEffect
server.post = msg => {
server.msgs.push(msg);
server.clients.forEach(
io => io.channel('msg', msg)
);
}
// .join : User -> ServerEffect
server.join = user => server.clients.push(
client(user, server)
);
//------ Client ------
// client : (User, Server) -> IO(e)
let client = (user, server) =>
client.app.start({
user,
msgs: server.msgs,
input: ''
});
// .app : e -> State(Model, IO(e))
client.app = dom.app()
.on('start', st => st
.reads(IO.put(view.main))
)
.on('input', (st, text) => st
.set('input', text)
.return(IO())
)
.on('msg', (st, msg) => st
.streamline({msgs: M => [...M.msgs, msg]})
.reads(read)
.push(IO.map(view.msg).put([-1]))
)
.on('send', st => st
.set('input', '')
.reads(IO.replace(view.input))
)
.hook('send', st => st
.reads(send)
.push(msg => () => server.post(msg))
);
//------ View ------
let view = {};
// .msg : Msg -> Node
view.msg = dom(':msg > msgs', [
['.msg-head', [
['.sender', {
html: m => m.sender === m.user ? 'you say:' : m.sender + ' says:'
}],
['.date', {html: m => `on 1 Jan. 1970 and ${m.date} ms`}]
]],
['.msg-body', {
html: m => m.body,
class: m => m.sender === m.user ? 'sent' : 'received'
}]
]);
// .msgs : Model -> [Node]
view.msgs = dom(':msgs')
.pull(read)
.branch(dom.map(view.msg))
// .input : Model -> Node
view.input = dom(':input', [
['textarea', {
onkeyup: (e, io) => io.channel('input', e.target.value)
}],
['button', {
html: 'Send',
onclick: (e, io) => io.channel('send')
}]
]);
// .main : Model -> Node
view.main = dom('.chat')
.append(view.msgs, view.input)
.put(M => '#' + M.user);
//------ Start a romance ------
['alice', 'bob'].forEach(server.join);