diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-02-02 00:21:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-02 00:21:13 +0100 |
commit | 17d0ce9c1c32827e5fc40cb486d4e8fb16f377fc (patch) | |
tree | 8aa88a3e4e72e13ec157de05fdc503efcd1668af /tools/dochack | |
parent | f4c76bc8e574d998d4ed2052e9349c76015058b7 (diff) | |
download | Nim-17d0ce9c1c32827e5fc40cb486d4e8fb16f377fc.tar.gz |
DOM API: make compatible with Karax's requirements (#10517)
* DOM API: make compatible with Karax's requirements * make tools\dochack.nim compile again
Diffstat (limited to 'tools/dochack')
-rw-r--r-- | tools/dochack/dochack.nim | 45 | ||||
-rw-r--r-- | tools/dochack/karax.nim | 344 |
2 files changed, 38 insertions, 351 deletions
diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 61c61225d..2f8465a63 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -1,6 +1,38 @@ -import karax +import dom import fuzzysearch +proc textContent(e: Element): cstring {. + importcpp: "#.textContent", nodecl.} + +proc textContent(e: Node): cstring {. + importcpp: "#.textContent", nodecl.} + +proc tree(tag: string; kids: varargs[Element]): Element = + result = document.createElement tag + for k in kids: + result.appendChild k + +proc add(parent, kid: Element) = + if parent.nodeName == cstring"TR" and ( + kid.nodeName == cstring"TD" or kid.nodeName == cstring"TH"): + let k = document.createElement("TD") + appendChild(k, kid) + appendChild(parent, k) + else: + appendChild(parent, kid) + +proc setClass(e: Element; value: string) = + e.setAttribute("class", value) +proc text(s: string): Element = cast[Element](document.createTextNode(s)) +proc text(s: cstring): Element = cast[Element](document.createTextNode(s)) + +proc getElementById(id: cstring): Element {.importc: "document.getElementById", nodecl.} + +proc replaceById(id: cstring; newTree: Node) = + let x = getElementById(id) + x.parentNode.replaceChild(newTree, x) + newTree.id = id + proc findNodeWith(x: Element; tag, content: cstring): Element = if x.nodeName == tag and x.textContent == content: return x @@ -182,7 +214,7 @@ proc buildToc(orig: TocEntry; types, procs: seq[Element]): TocEntry = t.markElement() for p in procs: if not isMarked(p): - let xx = karax.getElementsByClass(p.parent, cstring"attachedType") + let xx = getElementsByClass(p.parent, cstring"attachedType") if xx.len == 1 and xx[0].textContent == t.textContent: #kout(cstring"found ", p.nodeName) let q = tree("A", text(p.title)) @@ -230,7 +262,7 @@ proc groupBy*(value: cstring) {.exportc.} = togglevis(getElementById"toc-list") var - db: seq[Element] + db: seq[Node] contents: seq[cstring] template normalize(x: cstring): cstring = x.toLower.replace("_", "") @@ -258,7 +290,7 @@ proc dosearch(value: cstring): Element = let ul = tree("UL") result = tree("DIV") result.setClass"search_results" - var matches: seq[(Element, int)] = @[] + var matches: seq[(Node, int)] = @[] for i in 0..<db.len: let c = contents[i] if c == cstring"Examples" or c == cstring"PEG construction": @@ -270,11 +302,10 @@ proc dosearch(value: cstring): Element = if matched: matches.add((db[i], score)) - matches.sort do (a, b: auto) -> int: - b[1] - a[1] + matches.sort(proc(a, b: auto): int = b[1] - a[1]) for i in 0 ..< min(matches.len, 19): matches[i][0].innerHTML = matches[i][0].getAttribute("data-doc-search-tag") - ul.add(tree("LI", matches[i][0])) + ul.add(tree("LI", cast[Element](matches[i][0]))) if ul.len == 0: result.add tree("B", text"no search results") else: diff --git a/tools/dochack/karax.nim b/tools/dochack/karax.nim deleted file mode 100644 index 020fd37d1..000000000 --- a/tools/dochack/karax.nim +++ /dev/null @@ -1,344 +0,0 @@ -# Simple lib to write JS UIs - -import dom - -export dom.Element, dom.Event, dom.cloneNode, dom - -proc kout*[T](x: T) {.importc: "console.log", varargs.} - ## the preferred way of debugging karax applications. - -proc id*(e: Node): cstring {.importcpp: "#.id", nodecl.} -proc `id=`*(e: Node; x: cstring) {.importcpp: "#.id = #", nodecl.} -proc className*(e: Node): cstring {.importcpp: "#.className", nodecl.} -proc `className=`*(e: Node; v: cstring) {.importcpp: "#.className = #", nodecl.} - -proc value*(e: Element): cstring {.importcpp: "#.value", nodecl.} -proc `value=`*(e: Element; v: cstring) {.importcpp: "#.value = #", nodecl.} - -proc getElementsByClass*(e: Element; name: cstring): seq[Element] {.importcpp: "#.getElementsByClassName(#)", nodecl.} - -proc toLower*(x: cstring): cstring {. - importcpp: "#.toLowerCase()", nodecl.} -proc replace*(x: cstring; search, by: cstring): cstring {. - importcpp: "#.replace(#, #)", nodecl.} - -type - EventHandler* = proc(ev: Event) - EventHandlerId* = proc(ev: Event; id: int) - - Timeout* = ref object - -var document* {.importc.}: Document - -var - dorender: proc (): Element {.closure.} - drawTimeout: Timeout - currentTree: Element - -proc setRenderer*(renderer: proc (): Element) = - dorender = renderer - -proc setTimeout*(action: proc(); ms: int): Timeout {.importc, nodecl.} -proc clearTimeout*(t: Timeout) {.importc, nodecl.} -proc targetElem*(e: Event): Element = cast[Element](e.target) - -proc getElementById*(id: cstring): Element {.importc: "document.getElementById", nodecl.} - -proc getElementsByClassName*(cls: cstring): seq[Element] {.importc: - "document.getElementsByClassName", nodecl.} - -proc textContent*(e: Element): cstring {. - importcpp: "#.textContent", nodecl.} - -proc replaceById*(id: cstring; newTree: Node) = - let x = getElementById(id) - x.parentNode.replaceChild(newTree, x) - newTree.id = id - -proc equals(a, b: Node): bool = - if a.nodeType != b.nodeType: return false - if a.id != b.id: return false - if a.nodeName != b.nodeName: return false - if a.nodeType == TextNode: - if a.data != b.data: return false - elif a.childNodes.len != b.childNodes.len: - return false - if a.className != b.className: - # style differences are updated in place and we pretend - # it's still the same node - a.className = b.className - #return false - return true - -proc diffTree(parent, a, b: Node) = - if equals(a, b): - if a.nodeType != TextNode: - # we need to do this correctly in the presence of asyncronous - # DOM updates: - var i = 0 - while i < a.childNodes.len and a.childNodes.len == b.childNodes.len: - diffTree(a, a.childNodes[i], b.childNodes[i]) - inc i - elif parent == nil: - replaceById("ROOT", b) - else: - parent.replaceChild(b, a) - -proc dodraw() = - let newtree = dorender() - newtree.id = "ROOT" - if currentTree == nil: - currentTree = newtree - replaceById("ROOT", currentTree) - else: - diffTree(nil, currentTree, newtree) - -proc redraw*() = - # we buffer redraw requests: - if drawTimeout != nil: - clearTimeout(drawTimeout) - drawTimeout = setTimeout(dodraw, 30) - -proc tree*(tag: string; kids: varargs[Element]): Element = - result = document.createElement tag - for k in kids: - result.appendChild k - -proc tree*(tag: string; attrs: openarray[(string, string)]; - kids: varargs[Element]): Element = - result = tree(tag, kids) - for a in attrs: result.setAttribute(a[0], a[1]) - -proc text*(s: string): Element = cast[Element](document.createTextNode(s)) -proc text*(s: cstring): Element = cast[Element](document.createTextNode(s)) -proc add*(parent, kid: Element) = - if parent.nodeName == cstring"TR" and ( - kid.nodeName == cstring"TD" or kid.nodeName == cstring"TH"): - let k = document.createElement("TD") - appendChild(k, kid) - appendChild(parent, k) - else: - appendChild(parent, kid) - -proc len*(x: Element): int {.importcpp: "#.childNodes.length".} -proc `[]`*(x: Element; idx: int): Element {.importcpp: "#.childNodes[#]".} - -proc isInt*(s: cstring): bool {.asmNoStackFrame.} = - asm """ - return s.match(/^[0-9]+$/); - """ - -var - linkCounter: int - -proc link*(id: int): Element = - result = document.createElement("a") - result.setAttribute("href", "#") - inc linkCounter - result.setAttribute("id", $linkCounter & ":" & $id) - -proc link*(action: EventHandler): Element = - result = document.createElement("a") - result.setAttribute("href", "#") - addEventListener(result, "click", action) - -proc parseInt*(s: cstring): int {.importc, nodecl.} -proc parseFloat*(s: cstring): float {.importc, nodecl.} -proc split*(s, sep: cstring): seq[cstring] {.importcpp, nodecl.} - -proc startsWith*(a, b: cstring): bool {.importcpp: "startsWith", nodecl.} -proc contains*(a, b: cstring): bool {.importcpp: "(#.indexOf(#)>=0)", nodecl.} -proc substr*(s: cstring; start: int): cstring {.importcpp: "substr", nodecl.} -proc substr*(s: cstring; start, length: int): cstring {.importcpp: "substr", nodecl.} - -#proc len*(s: cstring): int {.importcpp: "#.length", nodecl.} -proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)", nodecl.} -proc toCstr*(s: int): cstring {.importcpp: "((#)+'')", nodecl.} - -proc suffix*(s, prefix: cstring): cstring = - if s.startsWith(prefix): - result = s.substr(prefix.len) - else: - kout(cstring"bug! " & s & cstring" does not start with " & prefix) - -proc valueAsInt*(e: Element): int = parseInt(e.value) -proc suffixAsInt*(s, prefix: cstring): int = parseInt(suffix(s, prefix)) - -proc scrollTop*(e: Element): int {.importcpp: "#.scrollTop", nodecl.} -proc offsetHeight*(e: Element): int {.importcpp: "#.offsetHeight", nodecl.} -proc offsetTop*(e: Element): int {.importcpp: "#.offsetTop", nodecl.} - -template onImpl(s) {.dirty} = - proc wrapper(ev: Event) = - action(ev) - redraw() - addEventListener(e, s, wrapper) - -proc setOnclick*(e: Element; action: proc(ev: Event)) = - onImpl "click" - -proc setOnclick*(e: Element; action: proc(ev: Event; id: int)) = - proc wrapper(ev: Event) = - let id = ev.target.id - let a = id.split(":") - if a.len == 2: - action(ev, parseInt(a[1])) - redraw() - else: - kout(cstring("cannot deal with id "), id) - addEventListener(e, "click", wrapper) - -proc setOnfocuslost*(e: Element; action: EventHandler) = - onImpl "blur" - -proc setOnchanged*(e: Element; action: EventHandler) = - onImpl "change" - -proc setOnscroll*(e: Element; action: EventHandler) = - onImpl "scroll" - -proc select*(choices: openarray[string]): Element = - result = document.createElement("select") - var i = 0 - for c in choices: - result.add tree("option", [("value", $i)], text(c)) - inc i - -proc select*(choices: openarray[(int, string)]): Element = - result = document.createElement("select") - for c in choices: - result.add tree("option", [("value", $c[0])], text(c[1])) - -var radioCounter: int - -proc radio*(choices: openarray[(int, string)]): Element = - result = document.createElement("fieldset") - var i = 0 - inc radioCounter - for c in choices: - let id = "radio_" & c[1] & $i - var kid = tree("input", [("type", "radio"), - ("id", id), ("name", "radio" & $radioCounter), - ("value", $c[0])]) - if i == 0: - kid.setAttribute("checked", "checked") - var lab = tree("label", [("for", id)], text(c[1])) - kid.add lab - result.add kid - inc i - -proc tag*(name: string; id="", class=""): Element = - result = document.createElement(name) - if id.len > 0: - result.setAttribute("id", id) - if class.len > 0: - result.setAttribute("class", class) - -proc tdiv*(id="", class=""): Element = tag("div", id, class) -proc span*(id="", class=""): Element = tag("span", id, class) - -proc th*(s: string): Element = - result = tag("th") - result.add text(s) - -proc td*(s: string): Element = - result = tag("td") - result.add text(s) - -proc td*(s: Element): Element = - result = tag("td") - result.add s - -proc td*(class: string; s: Element): Element = - result = tag("td") - result.add s - result.setAttribute("class", class) - -proc table*(class="", kids: varargs[Element]): Element = - result = tag("table", "", class) - for k in kids: result.add k - -proc tr*(kids: varargs[Element]): Element = - result = tag("tr") - for k in kids: - if k.nodeName == cstring"TD" or k.nodeName == cstring"TH": - result.add k - else: - result.add td(k) - -proc setClass*(e: Element; value: string) = - e.setAttribute("class", value) - -proc setAttr*(e: Element; key, value: cstring) = - e.setAttribute(key, value) - -proc getAttr*(e: Element; key: cstring): cstring {. - importcpp: "#.getAttribute(#)", nodecl.} - -proc realtimeInput*(id, val: string; changed: proc(value: cstring)): Element = - let oldElem = getElementById(id) - #if oldElem != nil: return oldElem - let newVal = if oldElem.isNil: val else: $oldElem.value - var timer: Timeout - proc wrapper() = - changed(getElementById(id).value) - redraw() - proc onkeyup(ev: Event) = - if timer != nil: clearTimeout(timer) - timer = setTimeout(wrapper, 400) - result = tree("input", [("type", "text"), - ("value", newVal), - ("id", id)]) - result.addEventListener("keyup", onkeyup) - -proc ajax(meth, url: cstring; headers: openarray[(string, string)]; - data: cstring; - cont: proc (httpStatus: int; response: cstring)) = - proc setRequestHeader(a, b: cstring) {.importc: "ajax.setRequestHeader".} - {.emit: """ - var ajax = new XMLHttpRequest(); - ajax.open(`meth`,`url`,true);""".} - for a, b in items(headers): - setRequestHeader(a, b) - {.emit: """ - ajax.onreadystatechange = function(){ - if(this.readyState == 4){ - if(this.status == 200){ - `cont`(this.status, this.responseText); - } else { - `cont`(this.status, this.statusText); - } - } - } - ajax.send(`data`); - """.} - -proc ajaxPut*(url: string; headers: openarray[(string, string)]; - data: cstring; - cont: proc (httpStatus: int, response: cstring)) = - ajax("PUT", url, headers, data, cont) - -proc ajaxGet*(url: string; headers: openarray[(string, string)]; - cont: proc (httpStatus: int, response: cstring)) = - ajax("GET", url, headers, nil, cont) - -{.push stackTrace:off.} - -proc setupErrorHandler*(useAlert=false) = - ## Installs an error handler that transforms native JS unhandled - ## exceptions into Nim based stack traces. If `useAlert` is false, - ## the error message it put into the console, otherwise `alert` - ## is called. - proc stackTraceAsCstring(): cstring = cstring(getStackTrace()) - {.emit: """ - window.onerror = function(msg, url, line, col, error) { - var x = "Error: " + msg + "\n" + `stackTraceAsCstring`() - if (`useAlert`) - alert(x); - else - console.log(x); - var suppressErrorAlert = true; - return suppressErrorAlert; - };""".} - -{.pop.} |