Karax: better support for routing; easier to use; todoapp bugfix: misapplied .compact macro
This commit is contained in:
parent
b36380a48e
commit
5576c4809d
3 changed files with 51 additions and 33 deletions
|
|
@ -89,7 +89,7 @@ proc createEntry(id: int; d: cstring; completed, selected: bool): VNode {.compac
|
||||||
onblur = focusLost,
|
onblur = focusLost,
|
||||||
onkeyupenter = editEntry, value = d, setFocus=true)
|
onkeyupenter = editEntry, value = d, setFocus=true)
|
||||||
|
|
||||||
proc makeFooter(entriesCount, completedCount: int): VNode {.compact.} =
|
proc makeFooter(entriesCount, completedCount: int): VNode =
|
||||||
result = buildHtml(footer(class = "footer")):
|
result = buildHtml(footer(class = "footer")):
|
||||||
span(class = "todo-count"):
|
span(class = "todo-count"):
|
||||||
strong:
|
strong:
|
||||||
|
|
@ -115,7 +115,10 @@ proc makeHeader(): VNode {.compact.} =
|
||||||
input(class = "new-todo", placeholder="What needs to be done?", name = "newTodo",
|
input(class = "new-todo", placeholder="What needs to be done?", name = "newTodo",
|
||||||
onkeyupenter = onTodoEnter, setFocus)
|
onkeyupenter = onTodoEnter, setFocus)
|
||||||
|
|
||||||
proc createDom(): VNode =
|
proc createDom(data: RouterData): VNode =
|
||||||
|
if data.hashPart == "#/": filter = all
|
||||||
|
elif data.hashPart == "#/completed": filter = completed
|
||||||
|
elif data.hashPart == "#/active": filter = active
|
||||||
result = buildHtml(tdiv(class="todomvc-wrapper")):
|
result = buildHtml(tdiv(class="todomvc-wrapper")):
|
||||||
section(class = "todoapp"):
|
section(class = "todoapp"):
|
||||||
makeHeader()
|
makeHeader()
|
||||||
|
|
@ -141,12 +144,6 @@ proc createDom(): VNode =
|
||||||
inc entriesCount
|
inc entriesCount
|
||||||
makeFooter(entriesCount, completedCount)
|
makeFooter(entriesCount, completedCount)
|
||||||
|
|
||||||
setOnHashChange(proc(hash: cstring) =
|
|
||||||
if hash == "#/": filter = all
|
|
||||||
elif hash == "#/completed": filter = completed
|
|
||||||
elif hash == "#/active": filter = active
|
|
||||||
)
|
|
||||||
|
|
||||||
if hasItem(lenSuffix):
|
if hasItem(lenSuffix):
|
||||||
entriesLen = parseInt getItem(lenSuffix)
|
entriesLen = parseInt getItem(lenSuffix)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,15 @@ type
|
||||||
parent, current: Node
|
parent, current: Node
|
||||||
|
|
||||||
type
|
type
|
||||||
|
RouterData* = ref object ## information that is passed to the 'renderer' callback
|
||||||
|
hashPart*: cstring ## the hash part of the URL for routing.
|
||||||
|
|
||||||
KaraxInstance* = ref object ## underlying karax instance. Usually you don't have
|
KaraxInstance* = ref object ## underlying karax instance. Usually you don't have
|
||||||
## know about this.
|
## know about this.
|
||||||
rootId: cstring not nil
|
rootId: cstring not nil
|
||||||
renderer: proc (): VNode {.closure.}
|
renderer: proc (data: RouterData): VNode {.closure.}
|
||||||
currentTree: VNode
|
currentTree: VNode
|
||||||
postRenderCallback: proc ()
|
postRenderCallback: proc (data: RouterData)
|
||||||
toFocus: Node
|
toFocus: Node
|
||||||
toFocusV: VNode
|
toFocusV: VNode
|
||||||
renderId: int
|
renderId: int
|
||||||
|
|
@ -287,7 +290,8 @@ proc mergeEvents(newNode, oldNode: VNode; kxi: KaraxInstance) =
|
||||||
shallowCopy(oldNode.events, newNode.events)
|
shallowCopy(oldNode.events, newNode.events)
|
||||||
applyEvents(oldNode, kxi)
|
applyEvents(oldNode, kxi)
|
||||||
|
|
||||||
proc printV(n: VNode; depth: cstring = "") =
|
when false:
|
||||||
|
proc printV(n: VNode; depth: cstring = "") =
|
||||||
kout depth, cstring($n.kind), cstring"key ", n.index
|
kout depth, cstring($n.kind), cstring"key ", n.index
|
||||||
#for k, v in pairs(n.style):
|
#for k, v in pairs(n.style):
|
||||||
# kout depth, "style: ", k, v
|
# kout depth, "style: ", k, v
|
||||||
|
|
@ -559,9 +563,13 @@ proc runDiff*(kxi: KaraxInstance; oldNode, newNode: VNode) =
|
||||||
kxi.currentTree = newNode
|
kxi.currentTree = newNode
|
||||||
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
|
||||||
|
var onhashChange {.importc: "window.onhashchange".}: proc()
|
||||||
|
var hashPart {.importc: "window.location.hash".}: cstring
|
||||||
|
|
||||||
proc dodraw(kxi: KaraxInstance) =
|
proc dodraw(kxi: KaraxInstance) =
|
||||||
if kxi.renderer.isNil: return
|
if kxi.renderer.isNil: return
|
||||||
let newtree = kxi.renderer()
|
let rdata = RouterData(hashPart: hashPart)
|
||||||
|
let newtree = kxi.renderer(rdata)
|
||||||
inc kxi.runCount
|
inc kxi.runCount
|
||||||
newtree.id = kxi.rootId
|
newtree.id = kxi.rootId
|
||||||
kxi.toFocus = nil
|
kxi.toFocus = nil
|
||||||
|
|
@ -586,7 +594,7 @@ proc dodraw(kxi: KaraxInstance) =
|
||||||
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
|
||||||
if not kxi.postRenderCallback.isNil:
|
if not kxi.postRenderCallback.isNil:
|
||||||
kxi.postRenderCallback()
|
kxi.postRenderCallback(rdata)
|
||||||
|
|
||||||
# now that it's part of the DOM, give it the focus:
|
# now that it's part of the DOM, give it the focus:
|
||||||
if kxi.toFocus != nil:
|
if kxi.toFocus != nil:
|
||||||
|
|
@ -598,7 +606,8 @@ proc dodraw(kxi: KaraxInstance) =
|
||||||
echo "depth ", depth(kxi.currentTree, total), " total ", total
|
echo "depth ", depth(kxi.currentTree, total), " total ", total
|
||||||
|
|
||||||
proc reqFrame(callback: proc()): int {.importc: "window.requestAnimationFrame".}
|
proc reqFrame(callback: proc()): int {.importc: "window.requestAnimationFrame".}
|
||||||
proc cancelFrame(id: int) {.importc: "window.cancelAnimationFrame".}
|
when false:
|
||||||
|
proc cancelFrame(id: int) {.importc: "window.cancelAnimationFrame".}
|
||||||
|
|
||||||
proc redraw*(kxi: KaraxInstance = kxi) =
|
proc redraw*(kxi: KaraxInstance = kxi) =
|
||||||
# we buffer redraw requests:
|
# we buffer redraw requests:
|
||||||
|
|
@ -617,8 +626,11 @@ proc redrawSync*(kxi: KaraxInstance = kxi) = dodraw(kxi)
|
||||||
proc init(ev: Event) =
|
proc init(ev: Event) =
|
||||||
kxi.renderId = reqFrame(proc () = kxi.dodraw)
|
kxi.renderId = reqFrame(proc () = kxi.dodraw)
|
||||||
|
|
||||||
proc setRenderer*(renderer: proc (): VNode, root: cstring = "ROOT",
|
proc setRenderer*(renderer: proc (data: RouterData): VNode,
|
||||||
clientPostRenderCallback: proc () = nil): KaraxInstance {.discardable.} =
|
root: cstring = "ROOT",
|
||||||
|
clientPostRenderCallback:
|
||||||
|
proc (data: RouterData) = nil): KaraxInstance {.
|
||||||
|
discardable.} =
|
||||||
## Setup Karax. Usually the return value can be ignored.
|
## Setup Karax. Usually the return value can be ignored.
|
||||||
result = KaraxInstance(rootId: root, renderer: renderer,
|
result = KaraxInstance(rootId: root, renderer: renderer,
|
||||||
postRenderCallback: clientPostRenderCallback,
|
postRenderCallback: clientPostRenderCallback,
|
||||||
|
|
@ -630,10 +642,19 @@ proc setRenderer*(renderer: proc (): VNode, root: cstring = "ROOT",
|
||||||
orphans: newJDict[cstring, bool]())
|
orphans: newJDict[cstring, bool]())
|
||||||
kxi = result
|
kxi = result
|
||||||
window.onload = init
|
window.onload = init
|
||||||
|
onhashChange = proc() = redraw()
|
||||||
|
|
||||||
proc setInitializer*(renderer: proc (): VNode, root: cstring = "ROOT",
|
proc setRenderer*(renderer: proc (): VNode, root: cstring = "ROOT",
|
||||||
clientPostRenderCallback: proc () = nil): KaraxInstance {.discardable.} =
|
clientPostRenderCallback: proc () = nil): KaraxInstance {.discardable.} =
|
||||||
## Setup Karax. Usually the return value can be ignored.
|
## Setup Karax. Usually the return value can be ignored.
|
||||||
|
proc wrapRenderer(data: RouterData): VNode = result = renderer()
|
||||||
|
proc wrapPostRender(data: RouterData) = clientPostRenderCallback()
|
||||||
|
setRenderer(wrapRenderer, root, wrapPostRender)
|
||||||
|
|
||||||
|
proc setInitializer*(renderer: proc (data: RouterData): VNode, root: cstring = "ROOT",
|
||||||
|
clientPostRenderCallback:
|
||||||
|
proc (data: RouterData) = nil): KaraxInstance {.discardable.} =
|
||||||
|
## Setup Karax. Usually the return value can be ignored.
|
||||||
result = KaraxInstance(rootId: root, renderer: renderer,
|
result = KaraxInstance(rootId: root, renderer: renderer,
|
||||||
postRenderCallback: clientPostRenderCallback,
|
postRenderCallback: clientPostRenderCallback,
|
||||||
patches: newSeq[Patch](60),
|
patches: newSeq[Patch](60),
|
||||||
|
|
@ -669,9 +690,9 @@ proc addEventHandler*(n: VNode; k: EventKind; action: proc();
|
||||||
if not kxi.surpressRedraws: redraw(kxi)
|
if not kxi.surpressRedraws: redraw(kxi)
|
||||||
addEventListener(n, k, wrapper)
|
addEventListener(n, k, wrapper)
|
||||||
|
|
||||||
proc setOnHashChange*(action: proc (hashPart: cstring)) =
|
proc setOnHashChange*(action: proc (hashPart: cstring)) {.deprecated.} =
|
||||||
var onhashChange {.importc: "window.onhashchange".}: proc()
|
## Now deprecated, instead pass a callback to ``setRenderer`` that receives
|
||||||
var hashPart {.importc: "window.location.hash".}: cstring
|
## a ``data: RouterData`` parameter.
|
||||||
proc wrapper() =
|
proc wrapper() =
|
||||||
action(hashPart)
|
action(hashPart)
|
||||||
redraw()
|
redraw()
|
||||||
|
|
@ -693,7 +714,7 @@ proc setupErrorHandler*() =
|
||||||
var onerror {.importc: "window.onerror", used.} =
|
var onerror {.importc: "window.onerror", used.} =
|
||||||
proc (msg, url: cstring, line, col: int, error: cstring): bool =
|
proc (msg, url: cstring, line, col: int, error: cstring): bool =
|
||||||
var x = cstring"Error: " & msg & "\n" & stackTraceAsCstring()
|
var x = cstring"Error: " & msg & "\n" & stackTraceAsCstring()
|
||||||
kout(x)
|
echo(x)
|
||||||
return true # suppressErrorAlert
|
return true # suppressErrorAlert
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ proc testWildInsert() =
|
||||||
let b = createEntries(entries)
|
let b = createEntries(entries)
|
||||||
doDiff(a, b, "pkInsertBefore button 7", "pkAppend div 5")
|
doDiff(a, b, "pkInsertBefore button 7", "pkAppend div 5")
|
||||||
|
|
||||||
kxi = KaraxInstance(rootId: cstring"ROOT", renderer: proc (): VNode = discard,
|
kxi = KaraxInstance(rootId: cstring"ROOT", renderer: proc (data: RouterData): VNode = discard,
|
||||||
byId: newJDict[cstring, VNode]())
|
byId: newJDict[cstring, VNode]())
|
||||||
|
|
||||||
testAppend()
|
testAppend()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue