# Virtual DOM implementation from dom import Event type VNodeKind* {.pure.} = enum text, 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 const toTag*: array[VNodeKind, cstring] = [ cstring"#text", "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" ] type EventKind* {.pure.} = enum onclick, ondblclick, onkeyup, onkeydown, onkeypressed, onblur, onchange, onscroll const toEventName*: array[EventKind, cstring] = [ cstring"click", "dblclick", "keyup", "keydown", "keypressed", "blur", "change", "scroll" ] type EventHandler* = proc (ev: Event; target: VNode) {.closure.} VNode* = ref object kind*: VNodeKind id*, class*, text*: cstring kids: seq[VNode] # even index: key, odd index: value; done this way for memory efficiency: attrs: seq[cstring] events*: seq[(EventKind, EventHandler)] hash*: uint64 validHash*: bool proc value*(n: VNode): cstring = n.text proc `value=`*(n: VNode; v: cstring) = n.text = v proc eq*(a, b: VNode): bool = if a.kind != b.kind: return false if a.id != b.id: return false if a.class != b.class: return false if a.kind != VNodeKind.text: if a.kids.len != b.kids.len: return false for i in 0..\L" if n.kind == VNodeKind.text: result.add n.text else: if n.text != nil: result.add " value = " result.add n.text for child in items(n): toString(child, result, indent+2) for i in 1..indent: result.add ' ' result.add "\L" proc getVNodeData*(n: VNode): string = result.add "<" & $n.kind toStringAttr(id) toStringAttr(class) #for k, v in attrs(n): # result.add " " & $k & " = " & $v result.add ">" if n.kind == VNodeKind.text: result.add n.text else: if n.text != nil: result.add " value = " result.add n.text result.add "" proc `$`*(n: VNode): cstring = var res = "" toString(n, res, 0) result = cstring(res)