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)
|
||||
if x.onAttachImpl != nil: x.onAttachImpl(x)
|
||||
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
|
||||
return result
|
||||
else:
|
||||
|
|
@ -133,7 +136,9 @@ proc vnodeToDom(n: VNode; kxi: KaraxInstance): Node =
|
|||
if not n.style.isNil: applyStyle(result, n.style)
|
||||
|
||||
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
|
||||
if n.kind != VNodeKind.text:
|
||||
if e.len != n.len: return false
|
||||
|
|
@ -177,7 +182,9 @@ proc eq(a, b: VNode; deep: bool): EqResult =
|
|||
result = similar
|
||||
if not sameAttrs(a, b): 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!
|
||||
return result
|
||||
|
||||
|
|
@ -218,11 +225,22 @@ proc updateDom(newNode, oldNode: VNode) =
|
|||
for i in 0 ..< newNode.len:
|
||||
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;
|
||||
kxi: KaraxInstance): EqResult =
|
||||
result = eq(newNode, oldNode, deep=false)
|
||||
if result <= different:
|
||||
var n: Node
|
||||
var state = 0
|
||||
if result == changed:
|
||||
assert oldNode.kind == VNodeKind.component
|
||||
let x = VComponent(oldNode)
|
||||
|
|
@ -231,7 +249,11 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
|||
x.updatedImpl(x)
|
||||
if oldExpanded == nil:
|
||||
n = vnodeToDom(x.expanded, kxi)
|
||||
state = 1
|
||||
else:
|
||||
kout cstring"now comparing components"
|
||||
printV(oldExpanded)
|
||||
printV(x.expanded)
|
||||
if updateElement(parent, current, x.expanded, oldExpanded, kxi) >= similar:
|
||||
x.expanded = oldExpanded
|
||||
n = oldExpanded.dom
|
||||
|
|
@ -239,12 +261,16 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
|||
else:
|
||||
n = x.expanded.dom
|
||||
doAssert n != nil, "expanded.dom is nil"
|
||||
state = 2
|
||||
return
|
||||
else:
|
||||
detach(oldNode)
|
||||
n = vnodeToDom(newNode, kxi)
|
||||
state = 3
|
||||
if parent == nil:
|
||||
replaceById(kxi.rootId, n)
|
||||
else:
|
||||
kout cstring"state ", state, parent, current
|
||||
parent.replaceChild(n, current)
|
||||
elif result == similar:
|
||||
updateStyles(newNode, oldNode, false)
|
||||
|
|
@ -295,8 +321,9 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
|||
|
||||
var pos = min(oldPos, newPos) + 1
|
||||
for i in commonPrefix..pos-1:
|
||||
if updateElement(current, current.childNodes[i],
|
||||
newNode[i], oldNode[i], kxi) >= similar:
|
||||
let res = updateElement(current, current.childNodes[i],
|
||||
newNode[i], oldNode[i], kxi)
|
||||
if res != different:
|
||||
newNode[i] = oldNode[i]
|
||||
|
||||
var nextChildPos = oldPos + 1
|
||||
|
|
@ -323,6 +350,9 @@ proc dodraw(kxi: KaraxInstance) =
|
|||
let newtree = kxi.renderer()
|
||||
newtree.id = kxi.rootId
|
||||
kxi.toFocus = nil
|
||||
#if kxi.currentTree != nil:
|
||||
# kout cstring"same? ", same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||
kout cstring"dodraw -----------------------------"
|
||||
if kxi.currentTree == nil:
|
||||
kxi.currentTree = newtree
|
||||
let asdom = vnodeToDom(kxi.currentTree, kxi)
|
||||
|
|
@ -330,8 +360,8 @@ proc dodraw(kxi: KaraxInstance) =
|
|||
else:
|
||||
let olddom = document.getElementById(kxi.rootId)
|
||||
discard updateElement(nil, olddom, newtree, kxi.currentTree, kxi)
|
||||
#assert same(newtree, document.getElementById("ROOT"))
|
||||
kxi.currentTree = newtree
|
||||
#kout cstring"same? ", same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||
|
||||
if not kxi.postRenderCallback.isNil:
|
||||
kxi.postRenderCallback()
|
||||
|
|
@ -348,10 +378,10 @@ proc redraw*(kxi: KaraxInstance = kxi) =
|
|||
if drawTimeout != nil:
|
||||
clearTimeout(drawTimeout)
|
||||
drawTimeout = setTimeout(dodraw, 30)
|
||||
elif true:
|
||||
elif false:
|
||||
reqFrame(proc () = kxi.dodraw)
|
||||
else:
|
||||
dodraw()
|
||||
dodraw(kxi)
|
||||
|
||||
proc init(ev: Event) =
|
||||
reqFrame(proc () = kxi.dodraw)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ type
|
|||
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
|
||||
## is not part of the virtual DOM anymore.
|
||||
myid*: int
|
||||
|
||||
VComponent* = ref object of VNode ## The abstract class for every karax component.
|
||||
renderImpl*: proc(self: VComponent): VNode
|
||||
|
|
|
|||
|
|
@ -213,7 +213,9 @@ type
|
|||
attrs: array[StyleAttr, cstring]
|
||||
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 b.isNil: return true
|
||||
else: return false
|
||||
|
|
@ -247,9 +249,10 @@ proc setStyle(d: Style; key, val: cstring) {.importcpp: "#[#] = #".}
|
|||
|
||||
proc merge*(a, b: VStyle): VStyle =
|
||||
## 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):
|
||||
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) =
|
||||
## apply the style to the real DOM node ``n``.
|
||||
|
|
@ -257,6 +260,11 @@ proc applyStyle*(n: Node; s: VStyle) =
|
|||
for x in s.mask:
|
||||
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
|
||||
|
||||
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 =
|
||||
var op = initOptParser()
|
||||
let rest = op.cmdLineRest
|
||||
var rest = op.cmdLineRest
|
||||
var file = ""
|
||||
var run = false
|
||||
while true:
|
||||
op.next()
|
||||
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 cmdEnd: break
|
||||
|
||||
|
|
@ -36,6 +44,6 @@ proc main =
|
|||
exec("nim js --out:nimcache/" & name & ".js " & rest)
|
||||
let dest = "nimcache" / name & ".html"
|
||||
writeFile(dest, html % name)
|
||||
openDefaultBrowser(dest)
|
||||
if run: openDefaultBrowser(dest)
|
||||
|
||||
main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue