From 14660f9d685d1b14cdead9cb09421f0f8ff7512e Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Thu, 15 Jun 2017 13:53:53 +0200 Subject: [PATCH 1/3] implemented refs draft --- experiments/refs/demo.html | 13 +++++++++++++ experiments/refs/demo.nim | 39 ++++++++++++++++++++++++++++++++++++++ experiments/refs/demo.nims | 1 + src/karax.nim | 10 ++++++++-- src/karaxdsl.nim | 2 +- src/vdom.nim | 4 ++++ 6 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 experiments/refs/demo.html create mode 100644 experiments/refs/demo.nim create mode 100644 experiments/refs/demo.nims diff --git a/experiments/refs/demo.html b/experiments/refs/demo.html new file mode 100644 index 0000000..e1fe419 --- /dev/null +++ b/experiments/refs/demo.html @@ -0,0 +1,13 @@ + + + + + + Refs + + + +
+ + + diff --git a/experiments/refs/demo.nim b/experiments/refs/demo.nim new file mode 100644 index 0000000..dffb1e9 --- /dev/null +++ b/experiments/refs/demo.nim @@ -0,0 +1,39 @@ +include karaxprelude +import random + +var + modelData = @[5, 2, 4] + + refA = VNodeRef() + refB = VNodeRef() + refSeq = newSeq[VNodeRef]() + +proc onClick(ev: Event, n: VNode) = + kout(refA) + kout(refB) + kout(refSeq) + +proc secureRefSlot(i: int): VNodeRef = + while refSeq.len <= i: + refSeq.add(VNodeRef()) + result = refSeq[i] + +proc view(): VNode = + result = buildHtml(): + tdiv: + button(onclick=onClick): + text "click me" + # storing refs to single elements is straightforward now + tdiv(nref=refA): + text "A" + tdiv(nref=refB): + text "B" + # It's a bit more tricky when containers are involved: + for i, x in modelData.pairs: + tdiv(nref=secureRefSlot(i)): + text "List item: " & $x + +proc renderer(): VNode = + view() + +setRenderer renderer diff --git a/experiments/refs/demo.nims b/experiments/refs/demo.nims new file mode 100644 index 0000000..9028ff1 --- /dev/null +++ b/experiments/refs/demo.nims @@ -0,0 +1 @@ +--path: "../../src" diff --git a/src/karax.nim b/src/karax.nim index cc52e2f..d8a4cb1 100644 --- a/src/karax.nim +++ b/src/karax.nim @@ -65,8 +65,14 @@ proc wrapEvent(d: Node; n: VNode; k: EventKind; action: EventHandler) = # --------------------- DOM diff ----------------------------------------- -template detach(n: VNode) = n.dom = nil -template attach(n: Vnode) = n.dom = result +template detach(n: VNode) = + if not n.nref.isNil(): + n.nref.vnode = nil + n.dom = nil +template attach(n: VNode) = + if not n.nref.isNil(): + n.nref.vnode = n + n.dom = result proc vnodeToDom(n: VNode): Node = if n.kind == VNodeKind.text: diff --git a/src/karaxdsl.nim b/src/karaxdsl.nim index 190545c..8693f5b 100644 --- a/src/karaxdsl.nim +++ b/src/karaxdsl.nim @@ -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", "key", "style", "nref"] proc getName(n: NimNode): string = case n.kind diff --git a/src/vdom.nim b/src/vdom.nim index d55e7b4..f4ccff8 100644 --- a/src/vdom.nim +++ b/src/vdom.nim @@ -101,6 +101,9 @@ macro buildLookupTables(): untyped = buildLookupTables() type + VNodeRef* = ref object + vnode*: VNode + EventHandler* = proc (ev: Event; target: VNode) {.closure.} VKey* = int @@ -108,6 +111,7 @@ type kind*: VNodeKind key*: VKey id*, class*, text*: cstring + nref*: VNodeRef kids: seq[VNode] # even index: key, odd index: value; done this way for memory efficiency: attrs: seq[cstring] From 472f1deb58cb1ae718e395034e1e4099cf53c7c9 Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Thu, 15 Jun 2017 14:38:39 +0200 Subject: [PATCH 2/3] cleaned up example --- experiments/refs/demo.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/experiments/refs/demo.nim b/experiments/refs/demo.nim index dffb1e9..cfbf7a3 100644 --- a/experiments/refs/demo.nim +++ b/experiments/refs/demo.nim @@ -1,5 +1,5 @@ include karaxprelude -import random +import future, sequtils var modelData = @[5, 2, 4] @@ -9,9 +9,9 @@ var refSeq = newSeq[VNodeRef]() proc onClick(ev: Event, n: VNode) = - kout(refA) - kout(refB) - kout(refSeq) + kout(refA.vnode) + kout(refB.vnode) + kout(refSeq.map(nref => nref.vnode)) proc secureRefSlot(i: int): VNodeRef = while refSeq.len <= i: From e33b9dc09a2242b6b85c027ebc76d0ba982018b2 Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Thu, 15 Jun 2017 19:01:15 +0200 Subject: [PATCH 3/3] added base methods for VNodeRef --- experiments/refs/demo.nim | 31 ++++++++++++++++++++++++------- src/karax.nim | 2 ++ src/vdom.nim | 6 +++++- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/experiments/refs/demo.nim b/experiments/refs/demo.nim index cfbf7a3..6ecc7db 100644 --- a/experiments/refs/demo.nim +++ b/experiments/refs/demo.nim @@ -1,16 +1,30 @@ include karaxprelude import future, sequtils +type + CustomRef = ref object of VNodeRef + +method onAttach(r: CustomRef) = + kout(cstring"custom ref attached") + +method onDetach(r: CustomRef) = + kout(cstring"custom ref detached") + var modelData = @[5, 2, 4] refA = VNodeRef() refB = VNodeRef() + refC = CustomRef() refSeq = newSeq[VNodeRef]() proc onClick(ev: Event, n: VNode) = - kout(refA.vnode) - kout(refB.vnode) + modelData.add(0) + +proc showRefs() = + kout(refA) + kout(refB) + kout(refC) kout(refSeq.map(nref => nref.vnode)) proc secureRefSlot(i: int): VNodeRef = @@ -24,10 +38,13 @@ proc view(): VNode = button(onclick=onClick): text "click me" # storing refs to single elements is straightforward now - tdiv(nref=refA): - text "A" - tdiv(nref=refB): - text "B" + if modelData.len mod 2 == 0: + tdiv(nref=refA): + text "A" + tdiv(nref=refB): + text "B" + tdiv(nref=refC): + text "C" # It's a bit more tricky when containers are involved: for i, x in modelData.pairs: tdiv(nref=secureRefSlot(i)): @@ -36,4 +53,4 @@ proc view(): VNode = proc renderer(): VNode = view() -setRenderer renderer +setRenderer(renderer, showRefs) diff --git a/src/karax.nim b/src/karax.nim index d8a4cb1..b454050 100644 --- a/src/karax.nim +++ b/src/karax.nim @@ -68,10 +68,12 @@ proc wrapEvent(d: Node; n: VNode; k: EventKind; action: EventHandler) = template detach(n: VNode) = if not n.nref.isNil(): n.nref.vnode = nil + n.nref.onDetach() n.dom = nil template attach(n: VNode) = if not n.nref.isNil(): n.nref.vnode = n + n.nref.onAttach() n.dom = result proc vnodeToDom(n: VNode): Node = diff --git a/src/vdom.nim b/src/vdom.nim index f4ccff8..9f9c642 100644 --- a/src/vdom.nim +++ b/src/vdom.nim @@ -101,7 +101,7 @@ macro buildLookupTables(): untyped = buildLookupTables() type - VNodeRef* = ref object + VNodeRef* = ref object of RootObj vnode*: VNode EventHandler* = proc (ev: Event; target: VNode) {.closure.} @@ -122,6 +122,10 @@ type dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node ## is not part of the virtual DOM anymore. +method onAttach*(v: VNodeRef) {.base.} = discard +method onDetach*(v: VNodeRef) {.base.} = discard +method changed*(v: VNodeRef): bool {.base.} = false + proc value*(n: VNode): cstring = n.text proc `value=`*(n: VNode; v: cstring) = n.text = v