diff --git a/src/components.nim b/src/components.nim index 6d6a8f2..30d5922 100644 --- a/src/components.nim +++ b/src/components.nim @@ -9,6 +9,7 @@ var type ComponentKind* {.pure.} = enum None, + Tag, VNode, Node @@ -18,6 +19,17 @@ var proc isComponent*(x: string): ComponentKind {.compileTime.} = allcomponents.getOrDefault(x) +proc addTags() {.compileTime.} = + let x = (bindSym"VNodeKind").getTypeImpl + expectKind(x, nnkEnumTy) + for i in ord(VNodeKind.html)..ord(VNodeKind.high): + # +1 because of empty node at the start of the enum AST: + let tag = $x[i+1] + allcomponents[tag] = ComponentKind.Tag + +static: + addTags() + proc unpack(symbolicType: NimNode; index: int): NimNode {.compileTime.} = #let t = symbolicType.getTypeImpl let t = repr(symbolicType) diff --git a/src/karax.nim b/src/karax.nim index 80d67c8..0007ce5 100644 --- a/src/karax.nim +++ b/src/karax.nim @@ -111,7 +111,6 @@ proc same(n: VNode, e: Node): bool = var dorender: proc (): VNode {.closure.} - drawTimeout: Timeout currentTree: VNode proc setRenderer*(renderer: proc (): VNode) = @@ -125,9 +124,8 @@ proc getElementById*(id: cstring): Element {.importc: "document.getElementById", #proc getElementsByClassName*(cls: cstring): seq[Element] {.importc: # "document.getElementsByClassName", nodecl.} - -proc textContent(e: Node): cstring {. - importcpp: "#.textContent", nodecl.} +#proc textContent(e: Node): cstring {. +# importcpp: "#.textContent", nodecl.} proc replaceById(id: cstring; newTree: Node) = let x = document.getElementById(id) @@ -215,6 +213,8 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode) = for i in 0..oldPos-pos: current.removeChild(current.childNodes[pos]) +when false: + var drawTimeout: Timeout proc dodraw() = let newtree = dorender() @@ -316,9 +316,6 @@ proc setOnHashChange*(action: proc (hashPart: cstring)) = redraw() onhashchange = wrapper -proc getAttr(e: Node; key: cstring): cstring {. - importcpp: "#.getAttribute(#)", nodecl.} - template nativeValue(ev): cstring = cast[Element](ev.target).value template setNativeValue(ev, val) = cast[Element](ev.target).value = val diff --git a/src/vdom.nim b/src/vdom.nim index 2670be5..1f55e61 100644 --- a/src/vdom.nim +++ b/src/vdom.nim @@ -1,37 +1,81 @@ -# Virtual DOM implementation +## Virtual DOM implementation for Karax. from dom import Event -import shash +import shash, macros +from strutils import toUpperAscii type VNodeKind* {.pure.} = enum - text, int, bool, vthunk, dthunk, - anchor, - tdiv, - table, tr, td, th, thead, tbody, - link, span, label, br, select, option, - fieldset, input, button, ul, li, section, header, footer, - h1, h2, h3, h4, h5, strong + text = "#text", int = "#int", bool = "#bool", + vthunk = "#vthunk", dthunk = "#dthunk", -const - toTag*: array[VNodeKind, cstring] = [ - cstring"#text", "#int", "#bool", "#vthunk", "#dthunk", - "A", "DIV", "TABLE", "TR", "TD", - "TH", "THEAD", - "TBODY", "LINK", - "SPAN", "LABEL", "BR", "SELECT", "OPTION", "FIELDSET", "INPUT", "BUTTON", "UL", - "LI", "SECTION", "HEADER", "FOOTER", "H1", "H2", "H3", "H4", "H5", "STRONG" - ] + html, head, title, base, link, meta, style, + script, noscript, + body, section, nav, article, aside, + h1, h2, h3, h4, h5, h6, + header, footer, address, main + + p, hr, pre, blockquote, ol, ul, li, + dl, dt, dd, + figure, figcaption, + + tdiv = "div", + + anchor, em, strong, small, + strikethrough = "s", cite, quote, + dfn, abbr, data, time, code, `var` = "var", samp, + kdb, sub, sup, italic = "i", bold = "b", underlined = "u", + mark, ruby, rt, rp, bdi, dbo, span, br, wbr, + ins, del, img, iframe, embed, `object` = "object", + param, video, audio, source, track, canvas, map, + area, svg, math, + + table, caption, colgroup, col, tbody, thead, + tfoot, tr, td, th, + + form, fieldset, legend, label, input, button, + select, datalist, optgroup, option, textarea, + keygen, output, progress, meter, + details, summary, command, menu type - EventKind* {.pure.} = enum - onclick, ondblclick, onkeyup, onkeydown, onkeypressed, onblur, onchange, onscroll + EventKind* {.pure.} = enum ## The events supported by the virtual DOM. + onclick, ## An element is clicked. + ondblclick, ## An element is double clicked. + onkeyup, ## A key was released. + onkeydown, ## A key is pressed. + onkeypressed, # A key was pressed. + onblur, ## An element lost the focus. + onchange, ## The selected value of an element was changed. + onscroll, ## The user scrolled within an element. + ondrag, ## An element or text selection is being dragged (every 350ms). + ondragend, ## A drag operation is being ended (by releasing a mouse button + ## or hitting the escape key). + ondragenter, ## A dragged element or text selection enters a valid drop target. + ondragleave, ## A dragged element or text selection leaves a valid drop target. + ondragover, ## An element or text selection is being dragged over a valid + ## drop target (every 350ms). + ondragstart, ## The user starts dragging an element or text selection. + ondrop ## An element is dropped on a valid drop target. -const - toEventName*: array[EventKind, cstring] = [ - cstring"click", "dblclick", "keyup", "keydown", "keypressed", "blur", - "change", "scroll" - ] +macro buildLookupTables(): untyped = + var a = newTree(nnkBracket) + for i in low(VNodeKind)..high(VNodeKind): + let x = $i + let y = if x[0] == '#': x else: toUpperAscii(x) + a.add(newCall("cstring", newLit(y))) + var e = newTree(nnkBracket) + for i in low(EventKind)..high(EventKind): + e.add(newCall("cstring", newLit(substr($i, 2)))) + + template tmpl(a, e) {.dirty.} = + const + toTag*: array[VNodeKind, cstring] = a + toEventName*: array[EventKind, cstring] = e + + result = getAst tmpl(a, e) + +buildLookupTables() type EventHandler* = proc (ev: Event; target: VNode) {.closure.}