clean todoapp example
This commit is contained in:
parent
c633e72a8d
commit
d22a1833cc
11 changed files with 713 additions and 95 deletions
154
example.nim
154
example.nim
|
|
@ -1,30 +1,22 @@
|
|||
|
||||
import vdom, karax, karaxdsl, jdict, jstrutils
|
||||
|
||||
when false:
|
||||
var plugins {.exportc.}: seq[(string, proc())] = @[]
|
||||
|
||||
proc onInput(val: cstring) =
|
||||
kout val
|
||||
if val == "dyn":
|
||||
let body = getElementById("body")
|
||||
body.prepend(tree("script", [("type", "text/javascript"), ("src", "nimcache/dyn.js")]))
|
||||
redraw()
|
||||
kout(plugins.len)
|
||||
if plugins.len > 0:
|
||||
plugins[0][1]()
|
||||
type
|
||||
Filter = enum
|
||||
all, active, completed
|
||||
|
||||
var
|
||||
entries: seq[cstring]
|
||||
entries: seq[(cstring, bool)]
|
||||
selectedEntry = -1
|
||||
filter: Filter
|
||||
|
||||
proc onTodoEnter(val: cstring) =
|
||||
entries.add val
|
||||
proc onTodoEnter(ev: Event; n: VNode) =
|
||||
entries.add((n.value, false))
|
||||
n.value = ""
|
||||
|
||||
proc removeHandler(ev: Event; n: VNode) =
|
||||
let id = suffixAsInt(n.id, "remove:")
|
||||
#entries.delete(id)
|
||||
entries[id] = nil
|
||||
entries[id] = (cstring(nil), false)
|
||||
|
||||
proc editHandler(ev: Event; n: VNode) =
|
||||
let id = suffixAsInt(n.id, "edit:")
|
||||
|
|
@ -33,57 +25,111 @@ proc editHandler(ev: Event; n: VNode) =
|
|||
when defined(usecache):
|
||||
var entryCache = newJDict[int, VNode]()
|
||||
|
||||
proc editInput(i: int; d: cstring): VNode =
|
||||
proc onTodoChange(val: cstring) =
|
||||
entries[i] = val
|
||||
selectedEntry = -1
|
||||
result = enterInput("todo-edit", d, onTodoChange)
|
||||
result.setOnfocuslost(proc (ev: Event; n: VNode) = selectedEntry = -1)
|
||||
proc focusLost(ev: Event; n: VNode) = selectedEntry = -1
|
||||
|
||||
proc createEntry(i: int; d: cstring; selected: bool): VNode =
|
||||
proc editEntry(ev: Event; n: VNode) =
|
||||
let id = suffixAsInt(n.id, "todo-edit:")
|
||||
entries[id][0] = n.value
|
||||
selectedEntry = -1
|
||||
|
||||
proc toggleEntry(ev: Event; n: VNode) =
|
||||
let id = suffixAsInt(n.id, "toggle:")
|
||||
entries[id][1] = not entries[id][1]
|
||||
|
||||
proc onAllDone(ev: Event; n: VNode) =
|
||||
entries = @[]
|
||||
selectedEntry = -1
|
||||
|
||||
proc clearCompleted(ev: Event, n: VNode) =
|
||||
for i in 0..<entries.len:
|
||||
if entries[i][1]: entries[i][0] = nil
|
||||
|
||||
proc toClass(completed: bool): cstring =
|
||||
(if completed: cstring"completed" else: cstring"")
|
||||
|
||||
proc toVis(visible: bool): cstring =
|
||||
(if visible: cstring"visible" else: "hidden")
|
||||
|
||||
proc toChecked(checked: bool): cstring =
|
||||
(if checked: cstring"checked" else: cstring(nil))
|
||||
|
||||
proc selected(v: Filter): cstring =
|
||||
(if filter == v: cstring"selected" else: cstring(nil))
|
||||
|
||||
proc createEntry(id: int; d: cstring; completed, selected: bool): VNode =
|
||||
# implement caching:
|
||||
when defined(usecache):
|
||||
if entryCache.contains(i):
|
||||
let old = entryCache[i]
|
||||
return old
|
||||
|
||||
result = buildHtml(tr) do:
|
||||
td(id="edit:" & $i, onclick=editHandler):
|
||||
if selected:
|
||||
editInput(i, d)
|
||||
result = buildHtml(tr):
|
||||
li(class=toClass(completed)):
|
||||
if not selected:
|
||||
tdiv(class = "view"):
|
||||
input(class = "toggle", `type` = "checkbox", checked = toChecked(completed),
|
||||
onclick=toggleEntry, id="toggle:" & &id)
|
||||
label(onDblClick=editHandler, id="edit:" & &id):
|
||||
text d
|
||||
button(class = "destroy", id="remove:" & $id, onclick=removeHandler)
|
||||
else:
|
||||
text d
|
||||
td:
|
||||
span(id="remove:" & $i, onclick=removeHandler):
|
||||
text "[remove]"
|
||||
input(class = "edit", name = "title", id = "todo-edit:" & &id,
|
||||
onfocusLost = focusLost,
|
||||
onenter = editEntry, value = d)
|
||||
when defined(usecache):
|
||||
entryCache[i] = result
|
||||
|
||||
proc createDom(): VNode =
|
||||
result = buildHtml(tdiv) do:
|
||||
tdiv(id = "sheader"):
|
||||
#text "plugin"
|
||||
#realtimeInput("by-name", "", onInput)
|
||||
#br()
|
||||
|
||||
text cstring"todo"
|
||||
enterInput("todo-input", "", onTodoEnter)
|
||||
var entriesCount = 0
|
||||
table(class = "wl"):
|
||||
for i, d in entries:
|
||||
if d != nil:
|
||||
createEntry(i, d, i == selectedEntry)
|
||||
inc entriesCount
|
||||
tdiv(id = "footer"):
|
||||
text cstring"Entries: " & &entriesCount
|
||||
proc onAllDone(ev: Event; n: VNode) =
|
||||
entries = @[]
|
||||
selectedEntry = -1
|
||||
button "All done!", onAllDone, entriesCount == 0 or selectedEntry >= 0
|
||||
result = buildHtml(tdiv(class="todomvc-wrapper")):
|
||||
section(class = "todoapp"):
|
||||
header(class = "header"):
|
||||
h1:
|
||||
text "todos"
|
||||
input(class = "new-todo", placeholder="What needs to be done?", name = "newTodo",
|
||||
onenter = onTodoEnter)
|
||||
section(class = "main"):
|
||||
input(class = "toggle-all", `type` = "checkbox", name = "toggle")
|
||||
label(`for` = "toggle-all", onclick = onAllDone):
|
||||
text "Mark all as complete"
|
||||
var entriesCount = 0
|
||||
var completedCount = 0
|
||||
ul(class = "todo-list"):
|
||||
for i, d in pairs(entries):
|
||||
if d[0] != nil:
|
||||
let b = case filter
|
||||
of all: true
|
||||
of active: not d[1]
|
||||
of completed: d[1]
|
||||
if b:
|
||||
createEntry(i, d[0], d[1], i == selectedEntry)
|
||||
inc completedCount, ord(d[1])
|
||||
inc entriesCount
|
||||
footer(class = "footer"):
|
||||
span(class = "todo-count"):
|
||||
strong:
|
||||
text(&entriesCount)
|
||||
text cstring" item" & &(if entriesCount != 1: "s left" else: " left")
|
||||
ul(class = "filters"):
|
||||
li:
|
||||
anchor(class = selected(all), href = "#/"):
|
||||
text "All"
|
||||
li:
|
||||
anchor(class = selected(active), href = "#/active"):
|
||||
text "Active"
|
||||
li:
|
||||
anchor(class = selected(completed), href = "#/completed"):
|
||||
text "Completed"
|
||||
button(class = "clear-completed", onclick = clearCompleted):
|
||||
text "Clear completed (" & &completedCount & ")"
|
||||
|
||||
setOnHashChange(proc(hash: cstring) =
|
||||
if hash == cstring"#/": filter = all
|
||||
elif hash == cstring"#/completed": filter = completed
|
||||
elif hash == cstring"#/active": filter = active
|
||||
)
|
||||
setRenderer createDom
|
||||
|
||||
proc onload(session: cstring) {.exportc.} =
|
||||
for i in 0..10_000:
|
||||
entries.add("Entry " & $i)
|
||||
for i in 0..1: # 0_000:
|
||||
entries.add((cstring"Entry " & &i, false))
|
||||
init()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue