karax/experiments/trello/trello.nim
2018-06-10 12:09:30 +02:00

151 lines
3.9 KiB
Nim

import knete, widgets
import karax / jstrutils
type
Attachable* = ref object of RootObj ## an element that is attachable to
## DOM elements.
attachedTo*: seq[Element]
TaskId = int
Task = ref object
id: TaskId
name, desc: kstring
ColumnId = distinct int
Column = ref object of Attachable
id: ColumnId
header: kstring
tasks: seq[Task]
Board = ref object
columns: seq[Column]
var b = Board(columns: @[Column(id: ColumnId 0, header: "To Do"),
Column(id: ColumnId 1, header: "Doing"),
Column(id: ColumnId 2, header: "Done")])
proc removeTask(t: TaskId) =
for c in b.columns:
for i in 0 ..< c.tasks.len:
if c.tasks[i].id == t:
delete(c.tasks, i)
break
proc moveTask(t: TaskId; dest: Column) =
for c in b.columns:
for i in 0 ..< c.tasks.len:
let task = c.tasks[i]
if task.id == t:
delete(c.tasks, i)
dest.tasks.add task
return
var nextTaskId = 0 ## negative because they are not yet backed
## up by the database
proc createTask(c: Column; name, desc: kstring): Task =
dec nextTaskId
result = Task(id: TaskId nextTaskId, name: name, desc: desc)
c.tasks.add result
# --------------------- UI -----------------------------------------------
proc renderTask(t: Task): Element =
proc dodelete =
removeTask t.id
delete result
proc dragstart(ev: Event) =
ev.prepareDragData("taskid", ev.target.id)
result = buildHtml():
tdiv(draggable="true", ondragstart=dragstart, id = &t.id):
bindField t.name
br()
bindField t.desc
button(onclick = dodelete):
text cross
type
NewTaskPanel = object
c: Column
e: Element
proc open(p: var NewTaskPanel; c: Column) =
p.e.style.display = "block"
p.c = c
proc newTaskDialog(): NewTaskPanel =
var nameInp = buildHtml():
input(setFocus = true)
var descInp = buildHtml():
input()
proc close =
result.e.style.display = "none"
proc submit =
let t = createTask(result.c, nameInp.value, descInp.value)
close()
result.c.attachedTo[0].add renderTask(t)
result.e = buildHtml():
tdiv(style={display: "none", position: "fixed",
left: "0", top: "0", width: "100%", height: "100%",
overflow: "auto",
backgroundColor: "rgb(0,0,0)",
backgroundColor: "rgba(0,0,0,0.4)", zIndex: "1"}):
tdiv(style={backgroundColor: "#fefefe",
margin: "15% auto", padding: "20px", border: "1px solid #888",
width: "80%"}):
span(onclick = close, style={color: "#aaa",
cssFloat: "right",
fontSize: "28px",
fontWeight: "bold"}):
text cross
p:
text "Task name"
nameInp
p:
text "Task description"
descInp
span(onclick = submit, style={color: "#0f0",
cssFloat: "left",
fontWeight: "bold"}):
text "Submit"
var dialog = newTaskDialog()
proc renderColumn(c: Column): Element =
proc doadd(c: Column): proc () =
result = proc() = dialog.open(c)
proc allowDrop(ev: Event) = ev.preventDefault()
proc drop(ev: Event) =
ev.preventDefault()
let data = ev.recvDragData("taskid")
moveTask(parseInt data, c)
ev.target.up("mycolumn").add(getElementById(data))
result = buildHtml():
tdiv(class = "mycolumn", style = {cssFloat: "left", width: "20%"},
ondrop = drop, ondragover = allowDrop):
tdiv(class = "myheader"):
bindField c.header
span(onclick = doadd(c)):
text plus
for t in c.tasks:
renderTask(t)
c.attachedTo.add result
proc renderBoard(b: Board): Element =
result = buildHtml(tdiv):
dialog.e
for c in b.columns:
renderColumn(c)
proc main(hashPart: kstring): Element =
result = renderBoard(b)
setInitializer main