added a new way for native DOM <-> virtual DOM interop, see nativenodes.nim example

This commit is contained in:
Araq 2018-12-12 15:02:58 +01:00
commit 18b5a12d1e
5 changed files with 36 additions and 30 deletions

View file

@ -1 +1,2 @@
--path: "../karax" --path: "../karax"
--path: ".."

View file

@ -0,0 +1,18 @@
include karax / prelude
import karax / kdom
proc myInput: VNode =
result = buildHtml:
input()
var inp = vnodeToDom(myInput())
proc myAwesomeComponent(x: Node): VNode =
result = dthunk(x)
proc main: VNode =
result = myAwesomeComponent(inp)
setRenderer main

View file

@ -8,18 +8,15 @@ import macros, vdom, tables, strutils, kbase
when defined(js): when defined(js):
var var
vcomponents* = newJDict[cstring, proc(args: seq[VNode]): VNode]() vcomponents* = newJDict[cstring, proc(args: seq[VNode]): VNode]()
dcomponents* = newJDict[cstring, proc(args: seq[VNode]): Node]()
else: else:
var var
vcomponents* = newTable[kstring, proc(args: seq[VNode]): VNode]() vcomponents* = newTable[kstring, proc(args: seq[VNode]): VNode]()
dcomponents* = newTable[kstring, proc(args: seq[VNode]): Node]()
type type
ComponentKind* {.pure.} = enum ComponentKind* {.pure.} = enum
None, None,
Tag, Tag,
VNode, VNode
Node
var var
allcomponents {.compileTime.} = initTable[string, ComponentKind]() allcomponents {.compileTime.} = initTable[string, ComponentKind]()
@ -84,10 +81,8 @@ when defined(js):
var isvirtual = ComponentKind.None var isvirtual = ComponentKind.None
if rettype == "VNode": if rettype == "VNode":
isvirtual = ComponentKind.VNode isvirtual = ComponentKind.VNode
elif rettype == "Node":
isvirtual = ComponentKind.Node
else: else:
error "component must return VNode or Node", params[0] error "component must return VNode", params[0]
let realName = if name.kind == nnkPostfix: name[1] else: name let realName = if name.kind == nnkPostfix: name[1] else: name
let nn = $realName let nn = $realName
n[0] = ident("inner" & nn) n[0] = ident("inner" & nn)
@ -105,26 +100,15 @@ when defined(js):
proc pname(args: seq[VNode]): VNode = proc pname(args: seq[VNode]): VNode =
unpackCall unpackCall
template dwrapper(pname, unpackCall) {.dirty.} =
proc pname(args: seq[VNode]): Node =
unpackCall
template vregister(key, val) = template vregister(key, val) =
bind jdict.`[]=` bind jdict.`[]=`
`[]=`(vcomponents, kstring(key), val) `[]=`(vcomponents, kstring(key), val)
template dregister(key, val) =
bind jdict.`[]=`
`[]=`(dcomponents, kstring(key), val)
result = newTree(nnkStmtList, n) result = newTree(nnkStmtList, n)
if isvirtual == ComponentKind.VNode: if isvirtual == ComponentKind.VNode:
result.add getAst(vwrapper(newname name, unpackCall)) result.add getAst(vwrapper(newname name, unpackCall))
result.add getAst(vregister(newLit(nn), realName)) result.add getAst(vregister(newLit(nn), realName))
else:
result.add getAst(dwrapper(newname name, unpackCall))
result.add getAst(dregister(newLit(nn), realName))
allcomponents[nn] = isvirtual allcomponents[nn] = isvirtual
when defined(debugKaraxDsl): when defined(debugKaraxDsl):
echo repr result echo repr result

View file

@ -123,7 +123,7 @@ template attach(n: VNode) =
n.dom = result n.dom = result
if n.id != nil: kxi.byId[n.id] = n if n.id != nil: kxi.byId[n.id] = n
proc applyEvents(n: VNode; kxi: KaraxInstance) = proc applyEvents(n: VNode) =
let dest = n.dom let dest = n.dom
for i in 0..<len(n.events): for i in 0..<len(n.events):
n.events[i][2] = wrapEvent(dest, n, n.events[i][0], n.events[i][1]) n.events[i][2] = wrapEvent(dest, n, n.events[i][0], n.events[i][1])
@ -134,7 +134,7 @@ proc getVNodeById*(id: cstring; kxi: KaraxInstance = kxi): VNode =
if kxi.byId.contains(id): if kxi.byId.contains(id):
result = kxi.byId[id] result = kxi.byId[id]
proc vnodeToDom*(n: VNode; kxi: KaraxInstance): Node = proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node =
if n.kind == VNodeKind.text: if n.kind == VNodeKind.text:
result = document.createTextNode(n.text) result = document.createTextNode(n.text)
attach n attach n
@ -150,7 +150,8 @@ proc vnodeToDom*(n: VNode; kxi: KaraxInstance): Node =
attach n attach n
return result return result
elif n.kind == VNodeKind.dthunk: elif n.kind == VNodeKind.dthunk:
result = callThunk(dcomponents[n.text], n) result = n.dom #callThunk(dcomponents[n.text], n)
assert result != nil
#n.key = result.key #n.key = result.key
attach n attach n
return result return result
@ -182,8 +183,8 @@ proc vnodeToDom*(n: VNode; kxi: KaraxInstance): Node =
for k, v in attrs(n): for k, v in attrs(n):
if v != nil: if v != nil:
result.setAttr(k, v) result.setAttr(k, v)
applyEvents(n, kxi) applyEvents(n)
if n == kxi.toFocusV and kxi.toFocus.isNil: if kxi != nil and n == kxi.toFocusV and kxi.toFocus.isNil:
kxi.toFocus = result kxi.toFocus = result
if not n.style.isNil: applyStyle(result, n.style) if not n.style.isNil: applyStyle(result, n.style)
@ -194,7 +195,7 @@ proc same(n: VNode, e: Node; nesting = 0): bool =
elif n.kind == VNodeKind.verbatim: elif n.kind == VNodeKind.verbatim:
result = true result = true
elif n.kind == VNodeKind.vthunk or n.kind == VNodeKind.dthunk: elif n.kind == VNodeKind.vthunk or n.kind == VNodeKind.dthunk:
# we don't check these for now: # we don't check these:
result = true result = true
elif toTag[n.kind] == e.nodename: elif toTag[n.kind] == e.nodename:
result = true result = true
@ -245,11 +246,13 @@ proc eq(a, b: VNode): EqResult =
if a.text != b.text: if a.text != b.text:
when defined(profileKarax): inc reasons[deText] when defined(profileKarax): inc reasons[deText]
return different # similar return different # similar
elif a.kind == VNodeKind.vthunk or a.kind == VNodeKind.dthunk: elif a.kind == VNodeKind.vthunk:
if a.text != b.text: return different if a.text != b.text: return different
if a.len != b.len: return different if a.len != b.len: return different
for i in 0..<a.len: for i in 0..<a.len:
if eq(a[i], b[i]) == different: return different if eq(a[i], b[i]) == different: return different
elif a.kind == VNodeKind.dthunk:
return identical
elif a.kind == VNodeKind.verbatim: elif a.kind == VNodeKind.verbatim:
if a.text != b.text: if a.text != b.text:
return different return different
@ -302,7 +305,7 @@ proc mergeEvents(newNode, oldNode: VNode; kxi: KaraxInstance) =
else: toEventName[k] else: toEventName[k]
d.removeEventListener(name, oldNode.events[i][2]) d.removeEventListener(name, oldNode.events[i][2])
shallowCopy(oldNode.events, newNode.events) shallowCopy(oldNode.events, newNode.events)
applyEvents(oldNode, kxi) applyEvents(oldNode)
when false: when false:
proc printV(n: VNode; depth: cstring = "") = proc printV(n: VNode; depth: cstring = "") =

View file

@ -20,7 +20,7 @@ type
script, noscript, script, noscript,
body, section, nav, article, aside, body, section, nav, article, aside,
h1, h2, h3, h4, h5, h6, h1, h2, h3, h4, h5, h6,
header, footer, address, main header, footer, address, main,
p, hr, pre, blockquote, ol, ul, li, p, hr, pre, blockquote, ol, ul, li,
dl, dt, dd, dl, dt, dd,
@ -167,8 +167,8 @@ template callThunk*(fn: typed; n: VNode): untyped =
proc vthunk*(name: kstring; args: varargs[VNode, vn]): VNode = proc vthunk*(name: kstring; args: varargs[VNode, vn]): VNode =
VNode(kind: VNodeKind.vthunk, text: name, index: -1, kids: @args) VNode(kind: VNodeKind.vthunk, text: name, index: -1, kids: @args)
proc dthunk*(name: kstring; args: varargs[VNode, vn]): VNode = proc dthunk*(dom: Node): VNode =
VNode(kind: VNodeKind.dthunk, text: name, index: -1, kids: @args) VNode(kind: VNodeKind.dthunk, dom: dom)
proc setEventIfNoConflict(v: VNode; kind: EventKind; handler: EventHandler) = proc setEventIfNoConflict(v: VNode; kind: EventKind; handler: EventHandler) =
assert handler != nil assert handler != nil