This commit is contained in:
Philippe PITTOLI 2019-11-22 18:42:46 +01:00
parent 3ce9915469
commit 5cb3eec194
4 changed files with 150 additions and 89 deletions

View File

@ -3,7 +3,53 @@ h = require 'maquette' .h
module.exports = { module.exports = {
login-widget: (model, socket) -> create-socket: ->
self = {}
# users can record functions to run on events
self.user-on-error = []
self.user-on-close = []
self.user-on-message = []
self.open-socket = ->
console.log "Opening socket to #{socket-url}"
self.socket := new WebSocket socket-url
self.socket.onerror = (event) ->
for f in self.user-on-error
f event
self.socket.close!
self.socket.onclose = (event) ->
for f in self.user-on-close
f event
self.socket.onmessage = (event) ->
data = JSON.parse(event.data).payload
for f in self.user-on-message
f data
self.reopen = ->
self.socket.close!
self.open-socket!
self.open-socket!
self.send = (opts) ->
console.log JSON.stringify { mtype: 0, payload: opts }
self.socket.send JSON.stringify { mtype: 0, payload: opts }
self.login = (login, password) ->
self.send JSON.stringify {
type: "login",
login: login
password: password
}
self
login-widget: (model) ->
h \div.container [ h \div.container [
h \div.box [ h \div.box [
if model.login-error if model.login-error
@ -36,13 +82,13 @@ module.exports = {
e.prevent-default! e.prevent-default!
model.login-error = undefined model.login-error = undefined
socket.login model.login, model.password model.authd-ws.login model.login, model.password
} [ "Connexion" ] } [ "Connexion" ]
] ]
] ]
] ]
login-page: (model, socket) -> login-page: (model) ->
h \div.container [ h \div.container [
h \div.box [ h \div.box [
if model.login-error if model.login-error
@ -74,8 +120,7 @@ module.exports = {
onclick: (e) -> onclick: (e) ->
e.prevent-default! e.prevent-default!
model.login-error = undefined model.authd-ws.login model.login, model.password
socket.login model.login, model.password
} [ "Connexion" ] } [ "Connexion" ]
] ]
] ]

View File

@ -25,43 +25,48 @@ model = {
selected: undefined selected: undefined
users: {} users: {}
projects: {} projects: {}
list-todos: [] todo-list: []
connection: {
port: 9999 port: 9999
url: undefined todod-url: undefined
socket: undefined
} authd-ws: undefined
todod-ws: undefined
previous-error: undefined
error: undefined
# authentication token
jwt: undefined
} }
# '://' + location.hostname + \: + # '://' + location.hostname + \: +
model.connection.url = model.todod-url =
(if location.protocol == 'https' then 'wss' else 'ws') + (if location.protocol == 'https' then 'wss' else 'ws') +
"://www.junkos.netlib.re:" + "://www.junkos.netlib.re:" +
model.connection.port + model.port +
"/kanban.JSON" "/kanban.JSON"
console.log model.connection.url console.log model.todod-url
# #
# network configuration # network configuration
# #
socket = todows.create-socket model.connection.url model.authd-ws = authd.create-socket model.authd-url
model.todod-ws = todows.create-socket model.todod-url
on-websocket-error = (event) -> on-websocket-error = (event) ->
console.log "WebSocket error.", event console.log "WebSocket error.", event
model.state := "network-error" model.current-view := "network-error"
projector.schedule-render! projector.schedule-render!
on-websocket-close = -> on-websocket-close = (event) ->
model.current-view := "login" model.current-view := "login"
# socket.reopen! console.log "WebSocket has been closed.", event
# model.todod-ws.reopen!
# Exporting the error in case the UI is able to deal with it.
model.previous-state := model.state
model.state := "network-error"
model.websocket-error := event.reason
projector.schedule-render! projector.schedule-render!
on-websocket-message = (data) -> on-websocket-message = (data) ->
@ -69,13 +74,11 @@ on-websocket-message = (data) ->
switch message.type switch message.type
when "login" when "login"
model.current-view := "list-todos" model.current-view := "todo-list"
when "list-projects" when "list-projects"
for project in message.projects model.todo-list := message.projects || []
model.projects[project.id] = Project.new project, model, socket
model.list-todos := message.projects
when "project" when "project"
model.projects[message.project.id] = Project.new message.project, model, socket model.projects[message.project.id] = Project.new message.project, model
when "user" when "user"
if message.user if message.user
model.users[message.user.uid] := message.user model.users[message.user.uid] := message.user
@ -89,11 +92,52 @@ on-websocket-message = (data) ->
console.log message console.log message
# record changes that need to happen on a network event # record changes that need to happen on a network event
socket.user-on-error ++= [ on-websocket-error ] model.todod-ws.user-on-error ++= [ on-websocket-error ]
socket.user-on-close ++= [ on-websocket-close ] model.todod-ws.user-on-close ++= [ on-websocket-close ]
socket.user-on-message ++= [ on-websocket-message ] model.todod-ws.user-on-message ++= [ on-websocket-message ]
render-navbar = ->
h \div.navbar [
h \div.navbar-start [
h \a.navbar-item.is-size-1 {
onclick: ->
model.viewed-project := undefined
model.current-view := "todo-list"
} [ "⌂" ]
]
h \div.navbar-end [
h \a.navbar-item {
onclick: ->
model.current-view := "login"
model.todod-ws.reopen!
} [ "Logout" ]
]
authd.login-widget model
]
render-todo-list = ->
h \div.section model.todo-list.map (project) ->
h \a.box {
key: project.id
onclick: ->
model.current-view := "todo"
model.viewed-project := project.id
model.todod-ws.get-project project.id
} [
bulma.title 3 project.name
]
render-new-project-button = ->
h \div.button.is-primary.is-large.is-fullwidth {
onclick: ->
model.todod-ws.new-project "New project"
} [ "New project! (random atm)" ]
render-todo = (todo-id) ->
if model.projects[todo-id]
model.projects[todo-id].render!
# #
# Pages: # Pages:
# login # login
@ -102,60 +146,26 @@ socket.user-on-message ++= [ on-websocket-message ]
# network-error # network-error
# #
render-body = ->
renderer = ->
render-navbar = ->
h \div.navbar [
h \div.navbar-start [
h \a.navbar-item.is-size-1 {
onclick: ->
model.viewed-project := undefined
model.current-view := "list-todos"
} [ "⌂" ]
]
h \div.navbar-end [
h \a.navbar-item {
onclick: ->
model.current-view := "login"
socket.reopen!
} [ "Logout" ]
]
authd.login-widget model, socket
]
h \div.section [ h \div.section [
switch model.current-view switch model.current-view
when "login" when "login"
authd.login-page model, socket authd.login-page model
when "list-todos" when "todo-list"
h \div#list-todos [ h \div#todo-list [
render-navbar! render-navbar!
h \div.section (model.list-todos || []).map (project) -> render-todo-list!
h \a.box {
key: project.id
onclick: ->
model.current-view := "project"
model.viewed-project := project.id
socket.get-project project.id
} [
bulma.title 3 project.name
]
h \div.button.is-primary.is-large.is-fullwidth { render-new-project-button!
onclick: ->
socket.new-project "Hello, there!"
} [ "New project! (random atm)" ]
] ]
when "project" when "todo"
h \div [ h \div [
render-navbar! render-navbar!
if model.projects[model.viewed-project] render-todo model.viewed-project
model.projects[model.viewed-project].render!
] ]
else else
@ -164,6 +174,12 @@ renderer = ->
] ]
] ]
renderer = ->
render-navbar!
render-body!
document.add-event-listener 'DOMContentLoaded' -> document.add-event-listener 'DOMContentLoaded' ->
projector.append document.body, renderer projector.append document.body, renderer

View File

@ -5,8 +5,8 @@ Task = require "./task.ls"
module.exports = { module.exports = {
new: (self, model, socket) -> new: (self, model) ->
self.tasks = self.tasks.map (e) -> Task.new e, self, model, socket self.tasks = self.tasks.map (e) -> Task.new e, self, model
self.render-column = (column) -> self.render-column = (column) ->
h \div.column.is-3 { h \div.column.is-3 {
@ -24,7 +24,7 @@ module.exports = {
console.log "onchange??" console.log "onchange??"
model.editing := undefined model.editing := undefined
socket.edit-column self.id, column.id, { model.todod-ws.edit-column self.id, column.id, {
name: e.target.value name: e.target.value
} }
} }
@ -57,7 +57,7 @@ module.exports = {
h \div.card-content [ h \div.card-content [
h \div.button.is-fullwidth.is-danger { h \div.button.is-fullwidth.is-danger {
onclick: -> onclick: ->
socket.delete-column self.id, column.id model.todod-ws.delete-column self.id, column.id
} [ "Delete me!"] } [ "Delete me!"]
] ]
] ]
@ -69,7 +69,7 @@ module.exports = {
h \div.button.is-fullwidth { h \div.button.is-fullwidth {
onclick: -> onclick: ->
socket.new-task self.id, column.id, { model.todod-ws.new-task self.id, column.id, {
title: "General Kenobi…" title: "General Kenobi…"
description: "" description: ""
} }
@ -94,7 +94,7 @@ module.exports = {
h \input.input { h \input.input {
onchange: (e) -> onchange: (e) ->
model.editing := undefined model.editing := undefined
socket.edit-project self.id, { model.todod-ws.edit-project self.id, {
name: e.target.value name: e.target.value
} }
value: self.name value: self.name
@ -113,7 +113,7 @@ module.exports = {
} [ } [
h \div.button.is-fullwidth { h \div.button.is-fullwidth {
onclick: -> onclick: ->
socket.new-column self.id, "Hello, there!" model.todod-ws.new-column self.id, "Hello, there!"
} [ "New Column" ] } [ "New Column" ]
] ]
] ]

View File

@ -32,19 +32,19 @@ get-next = (collection, element) ->
module.exports = { module.exports = {
new: (self, project, model, socket) -> new: (self, project, model) ->
self.render = -> self.render = ->
author = model.users[self.author] author = model.users[self.author]
if typeof(author) != "object" and author != "request sent" if typeof(author) != "object" and author != "request sent"
model.users[self.author] = "request sent" model.users[self.author] = "request sent"
# FIXME: This should go directly to authd. # FIXME: This should go directly to authd.
socket.get-user self.author model.todod-ws.get-user self.author
assigned_to = model.users[self.assigned_to] assigned_to = model.users[self.assigned_to]
if self.assigned_to and typeof(assigned_to) != "object" and assigned_to != "request sent" if self.assigned_to and typeof(assigned_to) != "object" and assigned_to != "request sent"
model.users[self.assigned_to] = "request sent" model.users[self.assigned_to] = "request sent"
# FIXME: This should go directly to authd. # FIXME: This should go directly to authd.
socket.get-user self.assigned_to model.todod-ws.get-user self.assigned_to
is-selected = model.selected == self.id is-selected = model.selected == self.id
@ -73,7 +73,7 @@ module.exports = {
value: self.title value: self.title
onchange: (e) -> onchange: (e) ->
model.editing := undefined model.editing := undefined
socket.edit-task project.id, self.id, { model.todod-ws.edit-task project.id, self.id, {
title: e.target.value title: e.target.value
} }
} [ self.title ] } [ self.title ]
@ -133,7 +133,7 @@ module.exports = {
} }
h \div.button.is-fullwidth { h \div.button.is-fullwidth {
onclick: -> onclick: ->
socket.edit-task project.id, self.id, { model.todod-ws.edit-task project.id, self.id, {
description: model.editing-data description: model.editing-data
} }
model.editing-data := undefined model.editing-data := undefined
@ -161,7 +161,7 @@ module.exports = {
h \input.input { h \input.input {
onchange: (e) -> onchange: (e) ->
model.editing := undefined model.editing := undefined
socket.edit-task project.id, self.id, { model.todod-ws.edit-task project.id, self.id, {
assigned_to: Number e.target.value assigned_to: Number e.target.value
} }
} }
@ -183,7 +183,7 @@ module.exports = {
h \input.input { h \input.input {
onchange: (e) -> onchange: (e) ->
model.editing := undefined model.editing := undefined
socket.edit-task project.id, self.id, { model.todod-ws.edit-task project.id, self.id, {
color: e.target.value color: e.target.value
} }
} }
@ -201,7 +201,7 @@ module.exports = {
h \a.card-footer-item { h \a.card-footer-item {
key: "⇐" key: "⇐"
onclick: -> onclick: ->
socket.edit-task project.id, self.id, { model.todod-ws.edit-task project.id, self.id, {
column: get-previous project.columns.map((.id)), self.column column: get-previous project.columns.map((.id)), self.column
} }
} [ "⇐" ] } [ "⇐" ]
@ -212,14 +212,14 @@ module.exports = {
} [ } [
h \div.button.is-danger { h \div.button.is-danger {
onclick: -> onclick: ->
socket.delete-task project.id, self.id model.todod-ws.delete-task project.id, self.id
} [ "Delete! For real!" ] } [ "Delete! For real!" ]
] ]
h \a.card-footer-item { h \a.card-footer-item {
key: "⇒" key: "⇒"
onclick: -> onclick: ->
socket.edit-task project.id, self.id, { model.todod-ws.edit-task project.id, self.id, {
column: get-next project.columns.map((.id)), self.column column: get-next project.columns.map((.id)), self.column
} }
} [ "⇒" ] } [ "⇒" ]