wip
This commit is contained in:
parent
79270c3423
commit
9aa3ba545d
5 changed files with 118 additions and 13 deletions
|
|
@ -106,7 +106,10 @@ proc vnodeToDom(n: VNode; kxi: KaraxInstance): Node =
|
||||||
let x = VComponent(n)
|
let x = VComponent(n)
|
||||||
if x.onAttachImpl != nil: x.onAttachImpl(x)
|
if x.onAttachImpl != nil: x.onAttachImpl(x)
|
||||||
assert x.renderImpl != nil
|
assert x.renderImpl != nil
|
||||||
result = vnodeToDom(x.renderImpl(x), kxi)
|
if x.expanded == nil:
|
||||||
|
x.expanded = x.renderImpl(x)
|
||||||
|
x.updatedImpl(x)
|
||||||
|
result = vnodeToDom(x.expanded, kxi)
|
||||||
attach n
|
attach n
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
|
|
@ -133,7 +136,9 @@ proc vnodeToDom(n: VNode; kxi: KaraxInstance): Node =
|
||||||
if not n.style.isNil: applyStyle(result, n.style)
|
if not n.style.isNil: applyStyle(result, n.style)
|
||||||
|
|
||||||
proc same(n: VNode, e: Node): bool =
|
proc same(n: VNode, e: Node): bool =
|
||||||
if toTag[n.kind] == e.nodename:
|
if n.kind == VNodeKind.component:
|
||||||
|
result = same(VComponent(n).expanded, e)
|
||||||
|
elif toTag[n.kind] == e.nodename:
|
||||||
result = true
|
result = true
|
||||||
if n.kind != VNodeKind.text:
|
if n.kind != VNodeKind.text:
|
||||||
if e.len != n.len: return false
|
if e.len != n.len: return false
|
||||||
|
|
@ -177,7 +182,9 @@ proc eq(a, b: VNode; deep: bool): EqResult =
|
||||||
result = similar
|
result = similar
|
||||||
if not sameAttrs(a, b): return different
|
if not sameAttrs(a, b): return different
|
||||||
if a.class != b.class: return different
|
if a.class != b.class: return different
|
||||||
if a.style != b.style: return similar
|
if not eq(a.style, b.style):
|
||||||
|
kout cstring"yes, styles differ"
|
||||||
|
return similar
|
||||||
# Do not test event listeners here!
|
# Do not test event listeners here!
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -218,11 +225,22 @@ proc updateDom(newNode, oldNode: VNode) =
|
||||||
for i in 0 ..< newNode.len:
|
for i in 0 ..< newNode.len:
|
||||||
updateDom(newNode[i], oldNode[i])
|
updateDom(newNode[i], oldNode[i])
|
||||||
|
|
||||||
|
proc printV(n: VNode; depth: cstring = "") =
|
||||||
|
kout depth, cstring($n.kind), n.myid, cstring"key ", n.key
|
||||||
|
#for k, v in pairs(n.style):
|
||||||
|
# kout depth, "style: ", k, v
|
||||||
|
if n.kind == VNodeKind.component:
|
||||||
|
let nn = VComponent(n)
|
||||||
|
if nn.expanded != nil: printV(nn.expanded, ">>" & depth)
|
||||||
|
for i in 0 ..< n.len:
|
||||||
|
printV(n[i], depth & " ")
|
||||||
|
|
||||||
proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
||||||
kxi: KaraxInstance): EqResult =
|
kxi: KaraxInstance): EqResult =
|
||||||
result = eq(newNode, oldNode, deep=false)
|
result = eq(newNode, oldNode, deep=false)
|
||||||
if result <= different:
|
if result <= different:
|
||||||
var n: Node
|
var n: Node
|
||||||
|
var state = 0
|
||||||
if result == changed:
|
if result == changed:
|
||||||
assert oldNode.kind == VNodeKind.component
|
assert oldNode.kind == VNodeKind.component
|
||||||
let x = VComponent(oldNode)
|
let x = VComponent(oldNode)
|
||||||
|
|
@ -231,7 +249,11 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
||||||
x.updatedImpl(x)
|
x.updatedImpl(x)
|
||||||
if oldExpanded == nil:
|
if oldExpanded == nil:
|
||||||
n = vnodeToDom(x.expanded, kxi)
|
n = vnodeToDom(x.expanded, kxi)
|
||||||
|
state = 1
|
||||||
else:
|
else:
|
||||||
|
kout cstring"now comparing components"
|
||||||
|
printV(oldExpanded)
|
||||||
|
printV(x.expanded)
|
||||||
if updateElement(parent, current, x.expanded, oldExpanded, kxi) >= similar:
|
if updateElement(parent, current, x.expanded, oldExpanded, kxi) >= similar:
|
||||||
x.expanded = oldExpanded
|
x.expanded = oldExpanded
|
||||||
n = oldExpanded.dom
|
n = oldExpanded.dom
|
||||||
|
|
@ -239,12 +261,16 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
||||||
else:
|
else:
|
||||||
n = x.expanded.dom
|
n = x.expanded.dom
|
||||||
doAssert n != nil, "expanded.dom is nil"
|
doAssert n != nil, "expanded.dom is nil"
|
||||||
|
state = 2
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
detach(oldNode)
|
detach(oldNode)
|
||||||
n = vnodeToDom(newNode, kxi)
|
n = vnodeToDom(newNode, kxi)
|
||||||
|
state = 3
|
||||||
if parent == nil:
|
if parent == nil:
|
||||||
replaceById(kxi.rootId, n)
|
replaceById(kxi.rootId, n)
|
||||||
else:
|
else:
|
||||||
|
kout cstring"state ", state, parent, current
|
||||||
parent.replaceChild(n, current)
|
parent.replaceChild(n, current)
|
||||||
elif result == similar:
|
elif result == similar:
|
||||||
updateStyles(newNode, oldNode, false)
|
updateStyles(newNode, oldNode, false)
|
||||||
|
|
@ -295,8 +321,9 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
||||||
|
|
||||||
var pos = min(oldPos, newPos) + 1
|
var pos = min(oldPos, newPos) + 1
|
||||||
for i in commonPrefix..pos-1:
|
for i in commonPrefix..pos-1:
|
||||||
if updateElement(current, current.childNodes[i],
|
let res = updateElement(current, current.childNodes[i],
|
||||||
newNode[i], oldNode[i], kxi) >= similar:
|
newNode[i], oldNode[i], kxi)
|
||||||
|
if res != different:
|
||||||
newNode[i] = oldNode[i]
|
newNode[i] = oldNode[i]
|
||||||
|
|
||||||
var nextChildPos = oldPos + 1
|
var nextChildPos = oldPos + 1
|
||||||
|
|
@ -323,6 +350,9 @@ proc dodraw(kxi: KaraxInstance) =
|
||||||
let newtree = kxi.renderer()
|
let newtree = kxi.renderer()
|
||||||
newtree.id = kxi.rootId
|
newtree.id = kxi.rootId
|
||||||
kxi.toFocus = nil
|
kxi.toFocus = nil
|
||||||
|
#if kxi.currentTree != nil:
|
||||||
|
# kout cstring"same? ", same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
kout cstring"dodraw -----------------------------"
|
||||||
if kxi.currentTree == nil:
|
if kxi.currentTree == nil:
|
||||||
kxi.currentTree = newtree
|
kxi.currentTree = newtree
|
||||||
let asdom = vnodeToDom(kxi.currentTree, kxi)
|
let asdom = vnodeToDom(kxi.currentTree, kxi)
|
||||||
|
|
@ -330,8 +360,8 @@ proc dodraw(kxi: KaraxInstance) =
|
||||||
else:
|
else:
|
||||||
let olddom = document.getElementById(kxi.rootId)
|
let olddom = document.getElementById(kxi.rootId)
|
||||||
discard updateElement(nil, olddom, newtree, kxi.currentTree, kxi)
|
discard updateElement(nil, olddom, newtree, kxi.currentTree, kxi)
|
||||||
#assert same(newtree, document.getElementById("ROOT"))
|
|
||||||
kxi.currentTree = newtree
|
kxi.currentTree = newtree
|
||||||
|
#kout cstring"same? ", same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
|
||||||
if not kxi.postRenderCallback.isNil:
|
if not kxi.postRenderCallback.isNil:
|
||||||
kxi.postRenderCallback()
|
kxi.postRenderCallback()
|
||||||
|
|
@ -348,10 +378,10 @@ proc redraw*(kxi: KaraxInstance = kxi) =
|
||||||
if drawTimeout != nil:
|
if drawTimeout != nil:
|
||||||
clearTimeout(drawTimeout)
|
clearTimeout(drawTimeout)
|
||||||
drawTimeout = setTimeout(dodraw, 30)
|
drawTimeout = setTimeout(dodraw, 30)
|
||||||
elif true:
|
elif false:
|
||||||
reqFrame(proc () = kxi.dodraw)
|
reqFrame(proc () = kxi.dodraw)
|
||||||
else:
|
else:
|
||||||
dodraw()
|
dodraw(kxi)
|
||||||
|
|
||||||
proc init(ev: Event) =
|
proc init(ev: Event) =
|
||||||
reqFrame(proc () = kxi.dodraw)
|
reqFrame(proc () = kxi.dodraw)
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ type
|
||||||
style*: VStyle ## the style that should be applied to the virtual node.
|
style*: VStyle ## the style that should be applied to the virtual node.
|
||||||
dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node
|
dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node
|
||||||
## is not part of the virtual DOM anymore.
|
## is not part of the virtual DOM anymore.
|
||||||
|
myid*: int
|
||||||
|
|
||||||
VComponent* = ref object of VNode ## The abstract class for every karax component.
|
VComponent* = ref object of VNode ## The abstract class for every karax component.
|
||||||
renderImpl*: proc(self: VComponent): VNode
|
renderImpl*: proc(self: VComponent): VNode
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,9 @@ type
|
||||||
attrs: array[StyleAttr, cstring]
|
attrs: array[StyleAttr, cstring]
|
||||||
mask: set[StyleAttr]
|
mask: set[StyleAttr]
|
||||||
|
|
||||||
proc `==`*(a, b: VStyle): bool =
|
proc kout[T](x: T) {.importc: "console.log", varargs.}
|
||||||
|
|
||||||
|
proc eq*(a, b: VStyle): bool =
|
||||||
if a.isNil:
|
if a.isNil:
|
||||||
if b.isNil: return true
|
if b.isNil: return true
|
||||||
else: return false
|
else: return false
|
||||||
|
|
@ -247,9 +249,10 @@ proc setStyle(d: Style; key, val: cstring) {.importcpp: "#[#] = #".}
|
||||||
|
|
||||||
proc merge*(a, b: VStyle): VStyle =
|
proc merge*(a, b: VStyle): VStyle =
|
||||||
## merges two styles. ``b`` takes precedence over ``a``.
|
## merges two styles. ``b`` takes precedence over ``a``.
|
||||||
result = VStyle(mask: a.mask + b.mask)
|
result = VStyle(mask: {})
|
||||||
for i in low(StyleAttr)..high(StyleAttr):
|
for i in low(StyleAttr)..high(StyleAttr):
|
||||||
result.attrs[i] = if b.attrs[i].isNil: a.attrs[i] else: b.attrs[i]
|
result.attrs[i] = if b.attrs[i].isNil: a.attrs[i] else: b.attrs[i]
|
||||||
|
if result.attrs[i] != nil: incl(result.mask, i)
|
||||||
|
|
||||||
proc applyStyle*(n: Node; s: VStyle) =
|
proc applyStyle*(n: Node; s: VStyle) =
|
||||||
## apply the style to the real DOM node ``n``.
|
## apply the style to the real DOM node ``n``.
|
||||||
|
|
@ -257,6 +260,11 @@ proc applyStyle*(n: Node; s: VStyle) =
|
||||||
for x in s.mask:
|
for x in s.mask:
|
||||||
n.style.setStyle(toStyleAttrName[x], s.attrs[x])
|
n.style.setStyle(toStyleAttrName[x], s.attrs[x])
|
||||||
|
|
||||||
|
iterator pairs*(v: VStyle): (cstring, cstring) =
|
||||||
|
if v != nil:
|
||||||
|
for x in v.mask:
|
||||||
|
yield (toStyleAttrName[x], v.attrs[x])
|
||||||
|
|
||||||
import jstrutils
|
import jstrutils
|
||||||
|
|
||||||
proc rgb*(r, g, b: range[0..255]): cstring =
|
proc rgb*(r, g, b: range[0..255]): cstring =
|
||||||
|
|
|
||||||
58
tests/blur.nim
Normal file
58
tests/blur.nim
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils
|
||||||
|
|
||||||
|
type TextInput* = ref object of VComponent
|
||||||
|
value: cstring
|
||||||
|
isActive: bool
|
||||||
|
|
||||||
|
var renderId: int
|
||||||
|
proc render(x: VComponent): VNode =
|
||||||
|
let self = TextInput(x)
|
||||||
|
|
||||||
|
let style = style(
|
||||||
|
(StyleAttr.position, cstring"relative"),
|
||||||
|
(StyleAttr.paddingLeft, cstring"10px"),
|
||||||
|
(StyleAttr.paddingRight, cstring"5px"),
|
||||||
|
(StyleAttr.height, cstring"30px"),
|
||||||
|
(StyleAttr.lineHeight, cstring"30px"),
|
||||||
|
(StyleAttr.border, cstring"solid 1px " & (if self.isActive: cstring"red" else: cstring"black")),
|
||||||
|
(StyleAttr.fontSize, cstring"12px"),
|
||||||
|
(StyleAttr.fontWeight, cstring"600")
|
||||||
|
).merge(self.style)
|
||||||
|
|
||||||
|
let inputStyle = style.merge(style(
|
||||||
|
(StyleAttr.color, cstring"inherit"),
|
||||||
|
(StyleAttr.fontSize, cstring"inherit"),
|
||||||
|
(StyleAttr.fontWeight, cstring"inherit"),
|
||||||
|
(StyleAttr.fontFamily, cstring"inherit"),
|
||||||
|
(StyleAttr.position, cstring"absolute"),
|
||||||
|
(StyleAttr.top, cstring"0"),
|
||||||
|
(StyleAttr.left, cstring"0"),
|
||||||
|
(StyleAttr.height, cstring"100%"),
|
||||||
|
(StyleAttr.width, cstring"100%"),
|
||||||
|
(StyleAttr.border, cstring"none"),
|
||||||
|
(StyleAttr.backgroundColor, cstring"transparent"),
|
||||||
|
))
|
||||||
|
|
||||||
|
proc flip(ev: Event; n: VNode) =
|
||||||
|
self.isActive = not self.isActive
|
||||||
|
markDirty(self)
|
||||||
|
|
||||||
|
kout cstring"rendering ", self.myid
|
||||||
|
inc renderId
|
||||||
|
result = buildHtml(tdiv(style=style, key=renderId)):
|
||||||
|
input(style=inputStyle, value=self.value, onblur=flip, onfocus=flip,
|
||||||
|
key=renderId)
|
||||||
|
|
||||||
|
var gid = 0
|
||||||
|
proc newTextInput*(style: VStyle = VStyle(); value: cstring = cstring""): TextInput =
|
||||||
|
result = newComponent(TextInput, render)
|
||||||
|
result.style = style
|
||||||
|
result.value = value
|
||||||
|
inc gid
|
||||||
|
result.myid = gid
|
||||||
|
|
||||||
|
proc createDom(): VNode =
|
||||||
|
result = buildHtml(tdiv):
|
||||||
|
newTextInput(value=cstring"test")
|
||||||
|
|
||||||
|
setRenderer createDom
|
||||||
|
|
@ -21,12 +21,20 @@ proc exec(cmd: string) =
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
var op = initOptParser()
|
var op = initOptParser()
|
||||||
let rest = op.cmdLineRest
|
var rest = op.cmdLineRest
|
||||||
var file = ""
|
var file = ""
|
||||||
|
var run = false
|
||||||
while true:
|
while true:
|
||||||
op.next()
|
op.next()
|
||||||
case op.kind
|
case op.kind
|
||||||
of cmdLongOption, cmdShortOption: discard
|
of cmdLongOption:
|
||||||
|
if op.key == "run":
|
||||||
|
run = true
|
||||||
|
rest = rest.replace("--run ")
|
||||||
|
of cmdShortOption:
|
||||||
|
if op.key == "r":
|
||||||
|
run = true
|
||||||
|
rest = rest.replace("-r ")
|
||||||
of cmdArgument: file = op.key
|
of cmdArgument: file = op.key
|
||||||
of cmdEnd: break
|
of cmdEnd: break
|
||||||
|
|
||||||
|
|
@ -36,6 +44,6 @@ proc main =
|
||||||
exec("nim js --out:nimcache/" & name & ".js " & rest)
|
exec("nim js --out:nimcache/" & name & ".js " & rest)
|
||||||
let dest = "nimcache" / name & ".html"
|
let dest = "nimcache" / name & ".html"
|
||||||
writeFile(dest, html % name)
|
writeFile(dest, html % name)
|
||||||
openDefaultBrowser(dest)
|
if run: openDefaultBrowser(dest)
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue