renamed key to 'index'; all virtual components have a 'key' attribute

This commit is contained in:
Andreas Rumpf 2017-07-11 12:54:53 +02:00
commit 91d7ba25ea
5 changed files with 37 additions and 41 deletions

View file

@ -15,7 +15,7 @@ proc `width=`(n: Node, w: int) {.importcpp: "#.width = #".}
proc mplayer*(id, resource: cstring): VNode {.compact.} =
proc handler(ev: Event; n: VNode) =
let myVideo = document.getElementById(id)
case n.key
case n.index
of Play:
if myVideo.paused:
myVideo.play()
@ -27,13 +27,13 @@ proc mplayer*(id, resource: cstring): VNode {.compact.} =
else: discard
result = buildHtml(tdiv):
button(onclick=handler, key=Play):
button(onclick=handler, index=Play):
text "Play/Pause"
button(onclick=handler, key=Big):
button(onclick=handler, index=Big):
text "Big"
button(onclick=handler, key=Small):
button(onclick=handler, index=Small):
text "Small"
button(onclick=handler, key=Normal):
button(onclick=handler, index=Normal):
text "Normal"
br()
br()

View file

@ -45,19 +45,19 @@ proc onTodoEnter(ev: Event; n: VNode) =
n.value = ""
proc removeHandler(ev: Event; n: VNode) =
updateEntry(n.key, cstring(nil), false)
updateEntry(n.index, cstring(nil), false)
proc editHandler(ev: Event; n: VNode) =
selectedEntry = n.key
selectedEntry = n.index
proc focusLost(ev: Event; n: VNode) = selectedEntry = -1
proc editEntry(ev: Event; n: VNode) =
setEntryContent(n.key, n.value)
setEntryContent(n.index, n.value)
selectedEntry = -1
proc toggleEntry(ev: Event; n: VNode) =
let id = n.key
let id = n.index
markAsCompleted(id, not isCompleted(id))
proc onAllDone(ev: Event; n: VNode) =
@ -83,12 +83,12 @@ proc createEntry(id: int; d: cstring; completed, selected: bool): VNode {.compac
if not selected:
tdiv(class = "view"):
input(class = "toggle", `type` = "checkbox", checked = toChecked(completed),
onclick=toggleEntry, key=id)
label(onDblClick=editHandler, key=id):
onclick=toggleEntry, index=id)
label(onDblClick=editHandler, index=id):
text d
button(class = "destroy", key=id, onclick=removeHandler)
button(class = "destroy", index=id, onclick=removeHandler)
else:
input(class = "edit", name = "title", key=id,
input(class = "edit", name = "title", index=id,
onblur = focusLost,
onkeyupenter = editEntry, value = d, setFocus=true)

View file

@ -7,13 +7,6 @@ export kdom.Event
proc kout*[T](x: T) {.importc: "console.log", varargs.}
## 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
PatchKind = enum
pkReplace, pkRemove, pkAppend, pkInsertBefore, pkDetach
@ -200,7 +193,7 @@ proc eq(a, b: VNode): EqResult =
if a.kind != b.kind: return different
if a.id != b.id: return different
result = identical
if a.key != b.key: return different
if a.index != b.index: return different
if a.kind == VNodeKind.text:
if a.text != b.text: return different
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:
# different component names mean different components:
if a.text != b.text: return different
if VComponent(a).key != VComponent(b).key: return different
return componentsIdentical
if a.class != b.class: return different
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)
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):
# kout depth, "style: ", k, v
if n.kind == VNodeKind.component:
@ -323,16 +317,16 @@ proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): E
inc kxi.recursion
result = eq(newNode, oldNode)
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
if result == similar:
updateStyles(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:
mergeEvents(newNode, oldNode, kxi)
if oldNode.kind == VNodeKind.input or oldNode.kind == VNodeKind.textarea:

View file

@ -4,7 +4,7 @@ from strutils import startsWith, toLowerAscii
const
StmtContext = ["kout", "inc", "echo", "dec", "!"]
SpecialAttrs = ["id", "class", "value", "key", "style"]
SpecialAttrs = ["id", "class", "value", "index", "style"]
proc getName(n: NimNode): string =
case n.kind

View file

@ -105,11 +105,11 @@ buildLookupTables()
type
EventHandler* = proc (ev: Event; target: VNode) {.closure.}
NativeEventHandler* = proc (ev: Event) {.closure.}
VKey* = int
VKey* = cstring
VNode* = ref object of RootObj
kind*: VNodeKind
key*: VKey
index*: int ## a generally useful 'index'
id*, class*, text*: cstring
kids: seq[VNode]
# 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.
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
changedImpl*: proc(self, newInstance: VComponent): bool
updatedImpl*: proc(self, newInstance: VComponent)
@ -140,20 +142,20 @@ type
proc value*(n: VNode): cstring = n.text
proc `value=`*(n: VNode; v: cstring) = n.text = v
proc intValue*(n: VNode): int = n.key
proc vn*(i: int): VNode = VNode(kind: VNodeKind.int, key: i)
proc vn*(b: bool): VNode = VNode(kind: VNodeKind.int, key: ord(b))
proc vn*(x: cstring): VNode = VNode(kind: VNodeKind.text, key: -1, text: x)
proc intValue*(n: VNode): int = n.index
proc vn*(i: int): VNode = VNode(kind: VNodeKind.int, index: i)
proc vn*(b: bool): VNode = VNode(kind: VNodeKind.int, index: ord(b))
proc vn*(x: cstring): VNode = VNode(kind: VNodeKind.text, index: -1, text: x)
template callThunk*(fn: typed; n: VNode): untyped =
## for internal usage only.
fn(n.kids)
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 =
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 =
## The default implementation of 'changed'.
@ -174,7 +176,7 @@ template newComponent*[T](t: typeDesc[T];
changed: (proc(self, newInstance: VComponent): bool) = defaultChangedImpl,
updated: proc(self, newInstance: VComponent) = defaultUpdatedImpl): T =
## 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,
changedImpl: changed, updatedImpl: updated,
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; y: VNode) = x.kids[idx] = y
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 =
result = newVNode(kind)
@ -217,8 +219,8 @@ proc tree*(kind: VNodeKind; attrs: openarray[(cstring, cstring)];
result = tree(kind, kids)
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: cstring): VNode = VNode(kind: VNodeKind.text, text: 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, index: -1)
iterator items*(n: VNode): VNode =
for i in 0..<n.kids.len: yield n.kids[i]