renamed key to 'index'; all virtual components have a 'key' attribute
This commit is contained in:
parent
5838271f8b
commit
91d7ba25ea
5 changed files with 37 additions and 41 deletions
|
|
@ -15,7 +15,7 @@ proc `width=`(n: Node, w: int) {.importcpp: "#.width = #".}
|
||||||
proc mplayer*(id, resource: cstring): VNode {.compact.} =
|
proc mplayer*(id, resource: cstring): VNode {.compact.} =
|
||||||
proc handler(ev: Event; n: VNode) =
|
proc handler(ev: Event; n: VNode) =
|
||||||
let myVideo = document.getElementById(id)
|
let myVideo = document.getElementById(id)
|
||||||
case n.key
|
case n.index
|
||||||
of Play:
|
of Play:
|
||||||
if myVideo.paused:
|
if myVideo.paused:
|
||||||
myVideo.play()
|
myVideo.play()
|
||||||
|
|
@ -27,13 +27,13 @@ proc mplayer*(id, resource: cstring): VNode {.compact.} =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
result = buildHtml(tdiv):
|
result = buildHtml(tdiv):
|
||||||
button(onclick=handler, key=Play):
|
button(onclick=handler, index=Play):
|
||||||
text "Play/Pause"
|
text "Play/Pause"
|
||||||
button(onclick=handler, key=Big):
|
button(onclick=handler, index=Big):
|
||||||
text "Big"
|
text "Big"
|
||||||
button(onclick=handler, key=Small):
|
button(onclick=handler, index=Small):
|
||||||
text "Small"
|
text "Small"
|
||||||
button(onclick=handler, key=Normal):
|
button(onclick=handler, index=Normal):
|
||||||
text "Normal"
|
text "Normal"
|
||||||
br()
|
br()
|
||||||
br()
|
br()
|
||||||
|
|
|
||||||
|
|
@ -45,19 +45,19 @@ proc onTodoEnter(ev: Event; n: VNode) =
|
||||||
n.value = ""
|
n.value = ""
|
||||||
|
|
||||||
proc removeHandler(ev: Event; n: VNode) =
|
proc removeHandler(ev: Event; n: VNode) =
|
||||||
updateEntry(n.key, cstring(nil), false)
|
updateEntry(n.index, cstring(nil), false)
|
||||||
|
|
||||||
proc editHandler(ev: Event; n: VNode) =
|
proc editHandler(ev: Event; n: VNode) =
|
||||||
selectedEntry = n.key
|
selectedEntry = n.index
|
||||||
|
|
||||||
proc focusLost(ev: Event; n: VNode) = selectedEntry = -1
|
proc focusLost(ev: Event; n: VNode) = selectedEntry = -1
|
||||||
|
|
||||||
proc editEntry(ev: Event; n: VNode) =
|
proc editEntry(ev: Event; n: VNode) =
|
||||||
setEntryContent(n.key, n.value)
|
setEntryContent(n.index, n.value)
|
||||||
selectedEntry = -1
|
selectedEntry = -1
|
||||||
|
|
||||||
proc toggleEntry(ev: Event; n: VNode) =
|
proc toggleEntry(ev: Event; n: VNode) =
|
||||||
let id = n.key
|
let id = n.index
|
||||||
markAsCompleted(id, not isCompleted(id))
|
markAsCompleted(id, not isCompleted(id))
|
||||||
|
|
||||||
proc onAllDone(ev: Event; n: VNode) =
|
proc onAllDone(ev: Event; n: VNode) =
|
||||||
|
|
@ -83,12 +83,12 @@ proc createEntry(id: int; d: cstring; completed, selected: bool): VNode {.compac
|
||||||
if not selected:
|
if not selected:
|
||||||
tdiv(class = "view"):
|
tdiv(class = "view"):
|
||||||
input(class = "toggle", `type` = "checkbox", checked = toChecked(completed),
|
input(class = "toggle", `type` = "checkbox", checked = toChecked(completed),
|
||||||
onclick=toggleEntry, key=id)
|
onclick=toggleEntry, index=id)
|
||||||
label(onDblClick=editHandler, key=id):
|
label(onDblClick=editHandler, index=id):
|
||||||
text d
|
text d
|
||||||
button(class = "destroy", key=id, onclick=removeHandler)
|
button(class = "destroy", index=id, onclick=removeHandler)
|
||||||
else:
|
else:
|
||||||
input(class = "edit", name = "title", key=id,
|
input(class = "edit", name = "title", index=id,
|
||||||
onblur = focusLost,
|
onblur = focusLost,
|
||||||
onkeyupenter = editEntry, value = d, setFocus=true)
|
onkeyupenter = editEntry, value = d, setFocus=true)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,6 @@ export kdom.Event
|
||||||
proc kout*[T](x: T) {.importc: "console.log", varargs.}
|
proc kout*[T](x: T) {.importc: "console.log", varargs.}
|
||||||
## the preferred way of debugging karax applications.
|
## the preferred way of debugging karax applications.
|
||||||
|
|
||||||
proc hasProp(e: Node; prop: cstring): bool {.importcpp: "(#.hasOwnProperty(#))".}
|
|
||||||
proc rawkey(e: Node): VKey {.importcpp: "#.karaxKey", nodecl.}
|
|
||||||
proc key*(e: Node): VKey =
|
|
||||||
if e.hasProp"karaxKey": result = e.rawkey
|
|
||||||
else: result = -1
|
|
||||||
proc `key=`*(e: Node; x: VKey) {.importcpp: "#.karaxKey = #", nodecl.}
|
|
||||||
|
|
||||||
type
|
type
|
||||||
PatchKind = enum
|
PatchKind = enum
|
||||||
pkReplace, pkRemove, pkAppend, pkInsertBefore, pkDetach
|
pkReplace, pkRemove, pkAppend, pkInsertBefore, pkDetach
|
||||||
|
|
@ -200,7 +193,7 @@ proc eq(a, b: VNode): EqResult =
|
||||||
if a.kind != b.kind: return different
|
if a.kind != b.kind: return different
|
||||||
if a.id != b.id: return different
|
if a.id != b.id: return different
|
||||||
result = identical
|
result = identical
|
||||||
if a.key != b.key: return different
|
if a.index != b.index: return different
|
||||||
if a.kind == VNodeKind.text:
|
if a.kind == VNodeKind.text:
|
||||||
if a.text != b.text: return different
|
if a.text != b.text: return different
|
||||||
elif a.kind == VNodeKind.vthunk or a.kind == VNodeKind.dthunk:
|
elif a.kind == VNodeKind.vthunk or a.kind == VNodeKind.dthunk:
|
||||||
|
|
@ -211,6 +204,7 @@ proc eq(a, b: VNode): EqResult =
|
||||||
elif b.kind == VNodeKind.component:
|
elif b.kind == VNodeKind.component:
|
||||||
# different component names mean different components:
|
# different component names mean different components:
|
||||||
if a.text != b.text: return different
|
if a.text != b.text: return different
|
||||||
|
if VComponent(a).key != VComponent(b).key: return different
|
||||||
return componentsIdentical
|
return componentsIdentical
|
||||||
if a.class != b.class: return different
|
if a.class != b.class: return different
|
||||||
if not eq(a.style, b.style) or not sameAttrs(a, b): return similar
|
if not eq(a.style, b.style) or not sameAttrs(a, b): return similar
|
||||||
|
|
@ -246,7 +240,7 @@ proc mergeEvents(newNode, oldNode: VNode; kxi: KaraxInstance) =
|
||||||
applyEvents(oldNode, kxi)
|
applyEvents(oldNode, kxi)
|
||||||
|
|
||||||
proc printV(n: VNode; depth: cstring = "") =
|
proc printV(n: VNode; depth: cstring = "") =
|
||||||
kout depth, cstring($n.kind), cstring"key ", n.key
|
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
|
||||||
if n.kind == VNodeKind.component:
|
if n.kind == VNodeKind.component:
|
||||||
|
|
@ -323,16 +317,16 @@ proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): E
|
||||||
inc kxi.recursion
|
inc kxi.recursion
|
||||||
result = eq(newNode, oldNode)
|
result = eq(newNode, oldNode)
|
||||||
case result
|
case result
|
||||||
of identical, componentsIdentical, similar:
|
of componentsIdentical:
|
||||||
|
kxi.components.add ComponentPair(oldNode: VComponent(oldNode),
|
||||||
|
newNode: VComponent(newNode),
|
||||||
|
parent: parent,
|
||||||
|
current: current)
|
||||||
|
of identical, similar:
|
||||||
newNode.dom = oldNode.dom
|
newNode.dom = oldNode.dom
|
||||||
if result == similar:
|
if result == similar:
|
||||||
updateStyles(newNode, oldNode)
|
updateStyles(newNode, oldNode)
|
||||||
updateAttributes(newNode, oldNode)
|
updateAttributes(newNode, oldNode)
|
||||||
elif result == componentsIdentical:
|
|
||||||
kxi.components.add ComponentPair(oldNode: VComponent(oldNode),
|
|
||||||
newNode: VComponent(newNode),
|
|
||||||
parent: parent,
|
|
||||||
current: current)
|
|
||||||
if newNode.events.len != 0 or oldNode.events.len != 0:
|
if newNode.events.len != 0 or oldNode.events.len != 0:
|
||||||
mergeEvents(newNode, oldNode, kxi)
|
mergeEvents(newNode, oldNode, kxi)
|
||||||
if oldNode.kind == VNodeKind.input or oldNode.kind == VNodeKind.textarea:
|
if oldNode.kind == VNodeKind.input or oldNode.kind == VNodeKind.textarea:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from strutils import startsWith, toLowerAscii
|
||||||
|
|
||||||
const
|
const
|
||||||
StmtContext = ["kout", "inc", "echo", "dec", "!"]
|
StmtContext = ["kout", "inc", "echo", "dec", "!"]
|
||||||
SpecialAttrs = ["id", "class", "value", "key", "style"]
|
SpecialAttrs = ["id", "class", "value", "index", "style"]
|
||||||
|
|
||||||
proc getName(n: NimNode): string =
|
proc getName(n: NimNode): string =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
|
||||||
26
src/vdom.nim
26
src/vdom.nim
|
|
@ -105,11 +105,11 @@ buildLookupTables()
|
||||||
type
|
type
|
||||||
EventHandler* = proc (ev: Event; target: VNode) {.closure.}
|
EventHandler* = proc (ev: Event; target: VNode) {.closure.}
|
||||||
NativeEventHandler* = proc (ev: Event) {.closure.}
|
NativeEventHandler* = proc (ev: Event) {.closure.}
|
||||||
VKey* = int
|
VKey* = cstring
|
||||||
|
|
||||||
VNode* = ref object of RootObj
|
VNode* = ref object of RootObj
|
||||||
kind*: VNodeKind
|
kind*: VNodeKind
|
||||||
key*: VKey
|
index*: int ## a generally useful 'index'
|
||||||
id*, class*, text*: cstring
|
id*, class*, text*: cstring
|
||||||
kids: seq[VNode]
|
kids: seq[VNode]
|
||||||
# even index: key, odd index: value; done this way for memory efficiency:
|
# even index: key, odd index: value; done this way for memory efficiency:
|
||||||
|
|
@ -123,6 +123,8 @@ type
|
||||||
## is not part of the virtual DOM anymore.
|
## is not part of the virtual DOM anymore.
|
||||||
|
|
||||||
VComponent* = ref object of VNode ## The abstract class for every karax component.
|
VComponent* = ref object of VNode ## The abstract class for every karax component.
|
||||||
|
key*: VKey ## key that determines if two components are
|
||||||
|
## identical.
|
||||||
renderImpl*: proc(self: VComponent): VNode
|
renderImpl*: proc(self: VComponent): VNode
|
||||||
changedImpl*: proc(self, newInstance: VComponent): bool
|
changedImpl*: proc(self, newInstance: VComponent): bool
|
||||||
updatedImpl*: proc(self, newInstance: VComponent)
|
updatedImpl*: proc(self, newInstance: VComponent)
|
||||||
|
|
@ -140,20 +142,20 @@ type
|
||||||
proc value*(n: VNode): cstring = n.text
|
proc value*(n: VNode): cstring = n.text
|
||||||
proc `value=`*(n: VNode; v: cstring) = n.text = v
|
proc `value=`*(n: VNode; v: cstring) = n.text = v
|
||||||
|
|
||||||
proc intValue*(n: VNode): int = n.key
|
proc intValue*(n: VNode): int = n.index
|
||||||
proc vn*(i: int): VNode = VNode(kind: VNodeKind.int, key: i)
|
proc vn*(i: int): VNode = VNode(kind: VNodeKind.int, index: i)
|
||||||
proc vn*(b: bool): VNode = VNode(kind: VNodeKind.int, key: ord(b))
|
proc vn*(b: bool): VNode = VNode(kind: VNodeKind.int, index: ord(b))
|
||||||
proc vn*(x: cstring): VNode = VNode(kind: VNodeKind.text, key: -1, text: x)
|
proc vn*(x: cstring): VNode = VNode(kind: VNodeKind.text, index: -1, text: x)
|
||||||
|
|
||||||
template callThunk*(fn: typed; n: VNode): untyped =
|
template callThunk*(fn: typed; n: VNode): untyped =
|
||||||
## for internal usage only.
|
## for internal usage only.
|
||||||
fn(n.kids)
|
fn(n.kids)
|
||||||
|
|
||||||
proc vthunk*(name: cstring; args: varargs[VNode, vn]): VNode =
|
proc vthunk*(name: cstring; args: varargs[VNode, vn]): VNode =
|
||||||
VNode(kind: VNodeKind.vthunk, text: name, key: -1, kids: @args)
|
VNode(kind: VNodeKind.vthunk, text: name, index: -1, kids: @args)
|
||||||
|
|
||||||
proc dthunk*(name: cstring; args: varargs[VNode, vn]): VNode =
|
proc dthunk*(name: cstring; args: varargs[VNode, vn]): VNode =
|
||||||
VNode(kind: VNodeKind.dthunk, text: name, key: -1, kids: @args)
|
VNode(kind: VNodeKind.dthunk, text: name, index: -1, kids: @args)
|
||||||
|
|
||||||
proc defaultChangedImpl*(v, newInstance: VComponent): bool =
|
proc defaultChangedImpl*(v, newInstance: VComponent): bool =
|
||||||
## The default implementation of 'changed'.
|
## The default implementation of 'changed'.
|
||||||
|
|
@ -174,7 +176,7 @@ template newComponent*[T](t: typeDesc[T];
|
||||||
changed: (proc(self, newInstance: VComponent): bool) = defaultChangedImpl,
|
changed: (proc(self, newInstance: VComponent): bool) = defaultChangedImpl,
|
||||||
updated: proc(self, newInstance: VComponent) = defaultUpdatedImpl): T =
|
updated: proc(self, newInstance: VComponent) = defaultUpdatedImpl): T =
|
||||||
## Use this template to create new components.
|
## Use this template to create new components.
|
||||||
T(kind: VNodeKind.component, key: -1,
|
T(kind: VNodeKind.component, index: -1,
|
||||||
text: cstring(astToStr(t)), renderImpl: render,
|
text: cstring(astToStr(t)), renderImpl: render,
|
||||||
changedImpl: changed, updatedImpl: updated,
|
changedImpl: changed, updatedImpl: updated,
|
||||||
onAttachImpl: onAttach, onDetachImpl: onDetach,
|
onAttachImpl: onAttach, onDetachImpl: onDetach,
|
||||||
|
|
@ -206,7 +208,7 @@ proc len*(x: VNode): int = x.kids.len
|
||||||
proc `[]`*(x: VNode; idx: int): VNode = x.kids[idx]
|
proc `[]`*(x: VNode; idx: int): VNode = x.kids[idx]
|
||||||
proc `[]=`*(x: VNode; idx: int; y: VNode) = x.kids[idx] = y
|
proc `[]=`*(x: VNode; idx: int; y: VNode) = x.kids[idx] = y
|
||||||
proc add*(parent, kid: VNode) = parent.kids.add kid
|
proc add*(parent, kid: VNode) = parent.kids.add kid
|
||||||
proc newVNode*(kind: VNodeKind): VNode = VNode(kind: kind, key: -1)
|
proc newVNode*(kind: VNodeKind): VNode = VNode(kind: kind, index: -1)
|
||||||
|
|
||||||
proc tree*(kind: VNodeKind; kids: varargs[VNode]): VNode =
|
proc tree*(kind: VNodeKind; kids: varargs[VNode]): VNode =
|
||||||
result = newVNode(kind)
|
result = newVNode(kind)
|
||||||
|
|
@ -217,8 +219,8 @@ proc tree*(kind: VNodeKind; attrs: openarray[(cstring, cstring)];
|
||||||
result = tree(kind, kids)
|
result = tree(kind, kids)
|
||||||
for a in attrs: result.setAttr(a[0], a[1])
|
for a in attrs: result.setAttr(a[0], a[1])
|
||||||
|
|
||||||
proc text*(s: string): VNode = VNode(kind: VNodeKind.text, text: cstring(s), key: -1)
|
proc text*(s: string): VNode = VNode(kind: VNodeKind.text, text: cstring(s), index: -1)
|
||||||
proc text*(s: cstring): VNode = VNode(kind: VNodeKind.text, text: s, key: -1)
|
proc text*(s: cstring): VNode = VNode(kind: VNodeKind.text, text: s, index: -1)
|
||||||
|
|
||||||
iterator items*(n: VNode): VNode =
|
iterator items*(n: VNode): VNode =
|
||||||
for i in 0..<n.kids.len: yield n.kids[i]
|
for i in 0..<n.kids.len: yield n.kids[i]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue