diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 5e6c415..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,31 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: CI - -# Controls when the action will run. -on: - # Triggers the workflow on push or pull request events but only for the master branch - push: - branches: [ master ] - pull_request: - branches: [ master ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - container: nimlang/nim - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - # Runs a single command using the runners shell - - name: Tests - run: | - nimble develop -y - nim c -r tests/tester.nim diff --git a/.gitignore b/.gitignore index 842e140..67d9b34 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1 @@ nimcache/ -/tests/tester -karax/tools/karun -*.code-workspace -*.exe -app.js -app.html diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index ac49796..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Xored Software, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/docs/benchmark.png b/docs/benchmark.png deleted file mode 100644 index 3949ad5..0000000 Binary files a/docs/benchmark.png and /dev/null differ diff --git a/docs/docs.rst b/docs/docs.rst deleted file mode 100644 index 3eec1a4..0000000 --- a/docs/docs.rst +++ /dev/null @@ -1,58 +0,0 @@ - -Virtual DOM -=========== - -The virtual dom is in the ``vdom`` module. - -The ``VNodeKind`` enum describes every tag that the HTML 5 spec includes -and some extensions that allow for an efficient component system. - -These extensions are: - -``VNodeKind.int`` - The node has a single integer field. - -``VNodeKind.bool`` - The node has a single boolean field. - -``VNodeKind.vthunk`` - The node is a `virtual thunk`:idx:. This means there is a - function attached to it that produces the ``VNode`` structure - on demand. - -``VNodeKind.dthunk`` - The node is a `DOM thunk`:idx:. This means there is a - function attached to it that produces the ``Node`` DOM structure - on demand. - -For convenience of the resulting Nim DSL these tags have enum names -that differ from their HTML equivalent: - -================= ======================================================= -Enum value HTML -================= ======================================================= -``tdiv`` ``div`` (changed because ``div`` is a keyword in Nim) -``italic`` ``i`` -``bold`` ``b`` -``strikethrough`` ``s`` -``underlined`` ``u`` -================= ======================================================= - - -A virtual dom node also has a special field set called ``key``, an integer -that can be used as a data model specific key/id. It can be accessed in event -handlers to change the data model. See the todoapp for an example of how to -use it. - -**Note**: This is not a hint for the DOM diff algorithm, multipe nodes can -all have the same key value. - - -Event system -============ - -Karax does not abstract over the event system the DOM offers much: The same -``Event`` structure is used. Every callback has the -signature ``proc (ev: Event; n: VNode)`` or empty ``proc ()``. - - diff --git a/examples/button.nim b/examples/button.nim deleted file mode 100644 index d86fa82..0000000 --- a/examples/button.nim +++ /dev/null @@ -1,15 +0,0 @@ -include karax / prelude - -var lines: seq[kstring] = @[] - -proc createDom(): VNode = - result = buildHtml(tdiv): - button: - text "Say hello!" - proc onclick(ev: Event; n: VNode) = - lines.add "Hello simulated universe" - for x in lines: - tdiv: - text x - -setRenderer createDom diff --git a/examples/buttonlambda.nim b/examples/buttonlambda.nim deleted file mode 100644 index 2ddadff..0000000 --- a/examples/buttonlambda.nim +++ /dev/null @@ -1,14 +0,0 @@ -include karax / prelude -from future import `=>` - -var lines: seq[kstring] = @[] - -proc createDom(): VNode = - result = buildHtml(tdiv): - button(onclick = () => lines.add "Hello simulated universe"): - text "Say hello!" - for x in lines: - tdiv: - text x - -setRenderer createDom diff --git a/examples/carousel/carousel.html b/examples/carousel/carousel.html deleted file mode 100644 index 500e73a..0000000 --- a/examples/carousel/carousel.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Carousel app - - - - -
- - - - - diff --git a/examples/carousel/carousel.nim b/examples/carousel/carousel.nim deleted file mode 100644 index c2db56c..0000000 --- a/examples/carousel/carousel.nim +++ /dev/null @@ -1,69 +0,0 @@ -## This demo shows how you can develop your own stateful components with Karax. - -import vdom, vstyles, karax, karaxdsl, jdict, jstrutils, kdom - -type - Carousel = ref object of VComponent - counter: int - cntdown: int - timer: TimeOut - list: seq[cstring] - -const ticksUntilChange = 5 - -var - images: seq[cstring] = @[cstring"a", "b", "c", "d"] - -proc render(x: VComponent): VNode = - let self = Carousel(x) - - proc docount() = - dec self.cntdown - if self.cntdown == 0: - self.counter = (self.counter + 1) mod self.list.len - self.cntdown = ticksUntilChange - else: - self.timer = setTimeout(docount, 30) - markDirty(self) - redraw() - - proc onclick(ev: Event; n: VNode) = - if self.timer != nil: - clearTimeout(self.timer) - self.timer = setTimeout(docount, 30) - - let col = - case self.counter - of 0: cstring"#4d4d4d" - of 1: cstring"#ff00ff" - of 2: cstring"#00ffff" - of 3: cstring"#ffff00" - else: cstring"red" - result = buildHtml(tdiv()): - text self.list[self.counter] - button(onclick = onclick): - text "Next" - tdiv(style = style(StyleAttr.color, col)): - text "This changes its color." - if self.cntdown != ticksUntilChange: - text &self.cntdown - -proc carousel(): Carousel = - result = newComponent(Carousel, render) - result.list = images - result.cntdown = ticksUntilChange - -proc createDom(): VNode = - result = buildHtml(table): - tr: - td: - carousel() - td: - carousel() - tr: - td: - carousel() - td: - carousel() - -setRenderer createDom diff --git a/examples/carousel/carousel.nims b/examples/carousel/carousel.nims deleted file mode 100644 index cef2dec..0000000 --- a/examples/carousel/carousel.nims +++ /dev/null @@ -1 +0,0 @@ ---path: "../../karax" diff --git a/examples/config.nims b/examples/config.nims deleted file mode 100644 index 76ed4d9..0000000 --- a/examples/config.nims +++ /dev/null @@ -1 +0,0 @@ ---path: ".." diff --git a/examples/hellostyle.nim b/examples/hellostyle.nim deleted file mode 100644 index 716c2f0..0000000 --- a/examples/hellostyle.nim +++ /dev/null @@ -1,17 +0,0 @@ -include karax / prelude -import karax / vstyles - -proc createDom(): VNode = - result = buildHtml(tdiv): - tdiv(style = style(StyleAttr.color, "red".cstring)): - text "red" - tdiv(style = style(StyleAttr.color, "blue")): - text "blue" - # explicit `kstring` required for varargs overload - tdiv(style = style((fontStyle, "italic".kstring), (color, "orange".kstring))): - text "italic orange" - # can use a string directly - tdiv(style = "font-style: oblique; color: pink".toCss): - text "oblique pink" - -setRenderer createDom diff --git a/examples/hellouniverse.nim b/examples/hellouniverse.nim deleted file mode 100644 index 8343d07..0000000 --- a/examples/hellouniverse.nim +++ /dev/null @@ -1,12 +0,0 @@ -include karax / prelude -import random - -proc createDom(): VNode = - result = buildHtml(tdiv): - if rand(100) <= 50: - text "Hello World!" - else: - text "Hello Universe" - -randomize() -setRenderer createDom diff --git a/examples/helloworld.nim b/examples/helloworld.nim deleted file mode 100644 index 76c43db..0000000 --- a/examples/helloworld.nim +++ /dev/null @@ -1,7 +0,0 @@ -include karax / prelude - -proc createDom(): VNode = - result = buildHtml(tdiv): - text "Hello World!" - -setRenderer createDom diff --git a/examples/login.nim b/examples/login.nim deleted file mode 100644 index 0350e23..0000000 --- a/examples/login.nim +++ /dev/null @@ -1,46 +0,0 @@ -include karax / prelude -from sugar import `=>` -import karax / errors - -proc loginField(desc, field, class: kstring; - validator: proc (field: kstring): proc ()): VNode = - result = buildHtml(tdiv): - label(`for` = field): - text desc - input(class = class, id = field, onchange = validator(field)) - -# some consts in order to prevent typos: -const - username = kstring"username" - password = kstring"password" - -proc validateNotEmpty(field: kstring): proc () = - result = proc () = - let x = getVNodeById(field) - if x.text == "": - errors.setError(field, field & " must not be empty") - else: - errors.setError(field, "") - -var loggedIn: bool - -proc loginDialog(): VNode = - result = buildHtml(tdiv): - if not loggedIn: - loginField("Name: ", username, "input", validateNotEmpty) - loginField("Password: ", password, "password", validateNotEmpty) - button(onclick = () => (loggedIn = true), disabled = errors.disableOnError()): - text "Login" - p: - text errors.getError(username) - p: - text errors.getError(password) - else: - p: - text "You are now logged in." - -setError username, username & " must not be empty" -setError password, password & " must not be empty" - -when not declared(toychat): - setRenderer loginDialog diff --git a/examples/mediaplayer/mediaplayer.nim b/examples/mediaplayer/mediaplayer.nim deleted file mode 100644 index c84b68b..0000000 --- a/examples/mediaplayer/mediaplayer.nim +++ /dev/null @@ -1,42 +0,0 @@ - -import karax / [karax, karaxdsl, vdom, kdom, compact] - -const - Play = 0 - Big = 1 - Small = 2 - Normal = 3 - -proc paused(n: Node): bool {.importcpp: "#.paused".} -proc play(n: Node) {.importcpp.} -proc pause(n: Node) {.importcpp.} -proc `width=`(n: Node, w: int) {.importcpp: "#.width = #".} - -proc mplayer*(id, resource: cstring): VNode {.compact.} = - proc handler(ev: Event; n: VNode) = - let myVideo = document.getElementById(id) - case n.index - of Play: - if myVideo.paused: - myVideo.play() - else: - myVideo.pause() - of Big: myVideo.width = 560 - of Small: myVideo.width = 320 - of Normal: myVideo.width = 420 - else: discard - - result = buildHtml(tdiv): - button(onclick=handler, index=Play): - text "Play/Pause" - button(onclick=handler, index=Big): - text "Big" - button(onclick=handler, index=Small): - text "Small" - button(onclick=handler, index=Normal): - text "Normal" - br() - br() - video(id=id, width="420"): - source(src=resource, `type`="video/mp4"): - text "Your browser does not support HTML5 video." diff --git a/examples/mediaplayer/playerapp.html b/examples/mediaplayer/playerapp.html deleted file mode 100644 index a45a2e8..0000000 --- a/examples/mediaplayer/playerapp.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Player app - - - - -
- - - - - diff --git a/examples/mediaplayer/playerapp.nim b/examples/mediaplayer/playerapp.nim deleted file mode 100644 index acb2e68..0000000 --- a/examples/mediaplayer/playerapp.nim +++ /dev/null @@ -1,21 +0,0 @@ -## Example app that shows how to write and embed a custom component. - -include karax/prelude -import mediaplayer - -const url = "https://www.w3schools.com/html/mov_bbb.mp4" - -proc createDom(): VNode = - result = buildHtml(table): - tr: - td: - mplayer("vid1", url) - td: - mplayer("vid2", url) - tr: - td: - mplayer("vid3", url) - td: - mplayer("vid4", url) - -setRenderer createDom diff --git a/examples/mediaplayer/playerapp.nims b/examples/mediaplayer/playerapp.nims deleted file mode 100644 index cf2eb9e..0000000 --- a/examples/mediaplayer/playerapp.nims +++ /dev/null @@ -1 +0,0 @@ ---path: "../.." diff --git a/examples/scrollapp/scrollapp.html b/examples/scrollapp/scrollapp.html deleted file mode 100644 index 44d657e..0000000 --- a/examples/scrollapp/scrollapp.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Todo app - - - - -
- - - - - diff --git a/examples/scrollapp/scrollapp.nim b/examples/scrollapp/scrollapp.nim deleted file mode 100644 index 4490447..0000000 --- a/examples/scrollapp/scrollapp.nim +++ /dev/null @@ -1,25 +0,0 @@ -## Example that shows how to accomplish an "infinitely scrolling" app. - -include karax/prelude -import karax / [jstrutils, kdom, vstyles] - -var entries: seq[cstring] = @[] -for i in 1..500: - entries.add(cstring("Entry ") & &i) - -proc scrollEvent(ev: Event; n: VNode) = - let d = n.dom - if d != nil and inViewport(d.lastChild): - # "load" more data: - for i in 1..50: - entries.add(cstring("Loaded Entry ") & &i) - -proc createDom(): VNode = - result = buildHtml(): - tdiv(onscroll=scrollEvent, style=style( - (StyleAttr.height, cstring"400px"), (StyleAttr.overflow, cstring"scroll"))): - for x in entries: - tdiv: - text x - -setRenderer createDom diff --git a/examples/scrollapp/scrollapp.nims b/examples/scrollapp/scrollapp.nims deleted file mode 100644 index cf2eb9e..0000000 --- a/examples/scrollapp/scrollapp.nims +++ /dev/null @@ -1 +0,0 @@ ---path: "../.." diff --git a/examples/todoapp/todoapp.html b/examples/todoapp/todoapp.html index ab3daa7..726070a 100644 --- a/examples/todoapp/todoapp.html +++ b/examples/todoapp/todoapp.html @@ -1,16 +1,19 @@ - - Todo app - - + + Todo app + + - + -
+
- + + - + diff --git a/examples/todoapp/todoapp.nim b/examples/todoapp/todoapp.nim index e3720fd..23840f7 100644 --- a/examples/todoapp/todoapp.nim +++ b/examples/todoapp/todoapp.nim @@ -1,152 +1,116 @@ -import karax / [vdom, karax, karaxdsl, jstrutils, compact, localstorage] +import vdom, karax, karaxdsl, jstrutils type Filter = enum all, active, completed var + entries: seq[(cstring, bool)] selectedEntry = -1 filter: Filter - entriesLen: int - doneswitch = true -const - contentSuffix = cstring"content" - completedSuffix = cstring"completed" - lenSuffix = cstring"entriesLen" - -proc getEntryContent(pos: int): cstring = - result = getItem(&pos & contentSuffix) - if result == cstring"null": - result = nil - -proc isCompleted(pos: int): bool = - var value = getItem(&pos & completedSuffix) - result = value == cstring"true" - -proc setEntryContent(pos: int, content: cstring) = - setItem(&pos & contentSuffix, content) - -proc markAsCompleted(pos: int, completed: bool) = - setItem(&pos & completedSuffix, &completed) - -proc addEntry(content: cstring, completed: bool) = - setEntryContent(entriesLen, content) - markAsCompleted(entriesLen, completed) - inc entriesLen - setItem(lenSuffix, &entriesLen) - -proc updateEntry(pos: int, content: cstring, completed: bool) = - setEntryContent(pos, content) - markAsCompleted(pos, completed) proc onTodoEnter(ev: Event; n: VNode) = - if n.value.strip() != "": - addEntry(n.value, false) - n.value = "" + entries.add((n.value, false)) + n.value = "" proc removeHandler(ev: Event; n: VNode) = - updateEntry(n.index, cstring(nil), false) + entries[n.key] = (cstring(nil), false) proc editHandler(ev: Event; n: VNode) = - selectedEntry = n.index + selectedEntry = n.key proc focusLost(ev: Event; n: VNode) = selectedEntry = -1 proc editEntry(ev: Event; n: VNode) = - setEntryContent(n.index, n.value) + entries[n.key][0] = n.value selectedEntry = -1 proc toggleEntry(ev: Event; n: VNode) = - let id = n.index - markAsCompleted(id, not isCompleted(id)) + let id = n.key + entries[id][1] = not entries[id][1] proc onAllDone(ev: Event; n: VNode) = - for i in 0.. - - - - Karax AJAX Test - - - - -
- - - diff --git a/experiments/ajaxtest.nim b/experiments/ajaxtest.nim deleted file mode 100644 index 720b6b2..0000000 --- a/experiments/ajaxtest.nim +++ /dev/null @@ -1,6 +0,0 @@ -import kdom, kajax - -proc cb(httpStatus: int, response: cstring) = - echo "Worked!" - -ajaxGet("https://httpbin.org/get", @[], cb) diff --git a/experiments/config.nims b/experiments/config.nims deleted file mode 100644 index 86673aa..0000000 --- a/experiments/config.nims +++ /dev/null @@ -1,2 +0,0 @@ ---path: "../karax" ---path: ".." diff --git a/experiments/echartstest.html b/experiments/echartstest.html deleted file mode 100644 index 8c9b225..0000000 --- a/experiments/echartstest.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Karax ECharts Test - - - - -
- - - - diff --git a/experiments/echartstest.nim b/experiments/echartstest.nim deleted file mode 100644 index 950c6ce..0000000 --- a/experiments/echartstest.nim +++ /dev/null @@ -1,58 +0,0 @@ -import karax / [kbase, vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils, jjson] - -type - Views = enum - Customers, Products - -var - currentView = Customers - -type - EChart* = ref object - -proc echartsInit(n: Element): EChart {.importc: "echarts.init".} -proc setOption(x: EChart; option: JsonNode) {.importcpp.} - -proc postRender(data: RouterData) = - if currentView == Products: - let myChart = echartsInit(kdom.getElementById("echartSection")) - # specify chart configuration item and data - let option = %*{ - "title": { - "text": "ECharts entry example" - }, - "tooltip": {}, - "legend": { - "data": ["Sales"] - }, - "xAxis": { - "data": ["shirt","cardign","chiffon shirt","pants","heels","socks"] - }, - "yAxis": {}, - "series": [{ - "name": "Sales", - "type": "bar", - "data": [5, 20, 36, 10, 10, 20] - }] - } - myChart.setOption(option) - -proc createDom(data: RouterData): VNode = - let hash = data.hashPart - if hash == cstring"#/Products": currentView = Products - else: currentView = Customers - - result = buildHtml(tdiv): - ul(class = "tabs"): - for v in low(Views)..high(Views): - li: - a(href = "#/" & $v): - text cstring($v) - - if currentView == Products: - tdiv(id = "echartSection", style = style((width, kstring"600px"), (height, kstring"400px"))) - tdiv: - text "other section" - -setRenderer createDom, "ROOT", postRender -setForeignNodeId "echartSection" diff --git a/experiments/example.html b/experiments/example.html new file mode 100644 index 0000000..35b9837 --- /dev/null +++ b/experiments/example.html @@ -0,0 +1,19 @@ + + + + + Todo app + + + + + +
+ + + + + + diff --git a/experiments/example.nim b/experiments/example.nim new file mode 100644 index 0000000..0ea805e --- /dev/null +++ b/experiments/example.nim @@ -0,0 +1,135 @@ + +import vdom, karax, karaxdsl, jdict, jstrutils + +type + Filter = enum + all, active, completed + +var + entries: seq[(cstring, bool)] + selectedEntry = -1 + filter: Filter + +proc onTodoEnter(ev: Event; n: VNode) = + entries.add((n.value, false)) + n.value = "" + +proc removeHandler(ev: Event; n: VNode) = + let id = suffixAsInt(n.id, "remove:") + entries[id] = (cstring(nil), false) + +proc editHandler(ev: Event; n: VNode) = + let id = suffixAsInt(n.id, "edit:") + selectedEntry = id + +when defined(usecache): + var entryCache = newJDict[int, VNode]() + +proc focusLost(ev: Event; n: VNode) = selectedEntry = -1 + +proc editEntry(ev: Event; n: VNode) = + let id = suffixAsInt(n.id, "todo-edit:") + entries[id][0] = n.value + selectedEntry = -1 + +proc toggleEntry(ev: Event; n: VNode) = + let id = suffixAsInt(n.id, "toggle:") + entries[id][1] = not entries[id][1] + +proc onAllDone(ev: Event; n: VNode) = + entries = @[] + selectedEntry = -1 + +proc clearCompleted(ev: Event, n: VNode) = + for i in 0.. 0: - let p = prevSelected #selected.value - if p != nil: - if isFirstName: - p.firstname = v - else: - p.lastname = v - unselect() - errmsg <- "" - else: - errmsg <- "name must not be empty" - -var inpFirstname = toUI(true) -var inpLastname = toUI(false) - -proc adaptFocus(def = false): RBool = - result = RBool() - result.value = def - when false: - result.subscribe proc (hasFocus: bool) = - if not hasFocus: - unselect() - -var focusA = adaptFocus() -var focusB = adaptFocus() - -proc styler(): VStyle = - result = 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 8px " & (if focusA.value: cstring"red" else: cstring"black")), - (StyleAttr.fontSize, cstring"12px"), - (StyleAttr.fontWeight, cstring"600") - ) - -var clicks = 0 - -proc renderUser(u: User): VNode {.track.} = - result = buildHtml(tdiv): - if u.selected: - inpFirstname <- u.firstname - tdiv: - textInput inpFirstname, focusA - inpLastname <- u.lastname - tdiv: - textInput inpLastname, focusB - else: - button: - text "..." - proc onclick(ev: Event; n: VNode) = - select(u) - text u.firstname & " " & u.lastname - button: - text "(x)" - proc onclick(ev: Event; n: VNode) = - gu.deleteElem(u) - -proc main(gu: RSeq[User]): VNode = - result = buildHtml(tdiv): - tdiv: - button: - text "Add User" - proc onclick(ev: Event; n: VNode) = - inc clicks - gu.add User(rawFirstname: "Added", rawLastname: &clicks) - tdiv: - text errmsg - vmapIt(gu, tdiv, renderUser(it)) - -proc init(): VNode = main(gu) - -setInitializer(init) diff --git a/experiments/oldwidgets.nim b/experiments/oldwidgets.nim deleted file mode 100644 index c947d7f..0000000 --- a/experiments/oldwidgets.nim +++ /dev/null @@ -1,251 +0,0 @@ -var - linkCounter: int - -proc link*(id: int): VNode = - result = newVNode(VNodeKind.anchor) - result.setAttr("href", "#") - inc linkCounter - result.setAttr("id", $linkCounter & ":" & $id) - -proc link*(action: EventHandler): VNode = - result = newVNode(VNodeKind.anchor) - result.setAttr("href", "#") - result.setOnclick action - -when false: - proc button*(caption: cstring; action: EventHandler; disabled=false): VNode = - result = newVNode(VNodeKind.button) - result.add text(caption) - if action != nil: - result.setOnClick action - if disabled: - result.setAttr("disabled", "true") - -proc select*(choices: openarray[cstring]): VNode = - result = newVNode(VNodeKind.select) - var i = 0 - for c in choices: - result.add tree(VNodeKind.option, [(cstring"value", toCstr(i))], text(c)) - inc i - -proc select*(choices: openarray[(int, cstring)]): VNode = - result = newVNode(VNodeKind.select) - for c in choices: - result.add tree(VNodeKind.option, [(cstring"value", toCstr(c[0]))], text(c[1])) - -var radioCounter: int - -proc radio*(choices: openarray[(int, cstring)]): VNode = - result = newVNode(VNodeKind.fieldset) - var i = 0 - inc radioCounter - for c in choices: - let id = cstring"radio_" & c[1] & toCstr(i) - var kid = tree(VNodeKind.input, [(cstring"type", cstring"radio"), - (cstring"id", id), (cstring"name", cstring"radio" & toCStr(radioCounter)), - (cstring"value", toCStr(c[0]))]) - if i == 0: - kid.setAttr(cstring"checked", cstring"checked") - var lab = tree(VNodeKind.label, [(cstring"for", id)], text(c[1])) - kid.add lab - result.add kid - inc i - -proc tag*(kind: VNodeKind; id=cstring(nil), class=cstring(nil)): VNode = - result = newVNode(kind) - result.id = id - result.class = class - -proc tdiv*(id=cstring(nil), class=cstring(nil)): VNode = tag(VNodeKind.tdiv, id, class) -proc span*(id=cstring(nil), class=cstring(nil)): VNode = tag(VNodeKind.span, id, class) - -proc valueAsInt*(e: Node): int = parseInt(e.value) - -proc th*(s: cstring): VNode = - result = newVNode(VNodeKind.th) - result.add text(s) - -proc td*(s: string): VNode = - result = newVNode(VNodeKind.td) - result.add text(s) - -proc td*(s: VNode): VNode = - result = newVNode(VNodeKind.td) - result.add s - -proc td*(class: cstring; s: VNode): VNode = - result = newVNode(VNodeKind.td) - result.add s - result.class = class - -proc table*(class=cstring(nil), kids: varargs[VNode]): VNode = - result = tag(VNodeKind.table, nil, class) - for k in kids: result.add k - -proc tr*(kids: varargs[VNode]): VNode = - result = newVNode(VNodeKind.tr) - for k in kids: - if k.kind in {VNodeKind.td, VNodeKind.th}: - result.add k - else: - result.add td(k) - -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 suffixAsInt*(s, prefix: cstring): int = parseInt(suffix(s, prefix)) - -#proc ceil(f: float): int {.importc: "Math.ceil", nodecl.} - -proc realtimeInput*(val: cstring; action: EventHandler): VNode = - var timer: Timeout - proc onkeyup(ev: Event; n: VNode) = - proc wrapper() = keyeventBody() - - if timer != nil: clearTimeout(timer) - timer = setTimeout(wrapper, 400) - result = tree(VNodeKind.input, [(cstring"type", cstring"text")]) - result.value = val - result.addEventListener(EventKind.onkeyup, onkeyup) - -proc enterInput*(id, val: cstring; action: EventHandler): VNode = - proc onkeyup(ev: Event; n: VNode) = - if ev.keyCode == 13: keyeventBody() - - result = tree(VNodeKind.input, [(cstring"type", cstring"text")]) - result.id = id - result.value = val - result.addEventListener(EventKind.onkeyup, onkeyup) - -proc setOnEnter*(n: VNode; action: EventHandler) = - proc onkeyup(ev: Event; n: VNode) = - if ev.keyCode == 13: keyeventBody() - n.addEventListener(EventKind.onkeyup, onkeyup) - -proc setOnscroll*(action: proc(min, max: VKey; diff: int)) = - var oldY = window.pageYOffset - - proc wrapper(ev: Event) = - let dir = window.pageYOffset - oldY - if dir == 0: return - - var a = VKey high(int) - var b = VKey 0 - var h, count: int - document.visibleKeys(a, b, h, count) - let avgh = h / count - let diff = toInt(dir.float / avgh) - if diff != 0: - oldY = window.pageYOffset - action(a, b, diff) - redraw() - - document.addEventListener("scroll", wrapper) - -when false: - var plugins {.exportc.}: seq[(string, proc())] = @[] - - proc onInput(val: cstring) = - kout val - if val == "dyn": - kout(plugins.len) - if plugins.len > 0: - plugins[0][1]() - -var - images: seq[cstring] = @[cstring"a", "b", "c", "d"] - -proc carousel*(): VNode = - var currentIndex = 0 - - proc next(ev: Event; n: VNode) = - currentIndex = (currentIndex + 1) mod images.len - - proc prev(ev: Event; n: VNode) = - currentIndex = (currentIndex - 1) mod images.len - - result = buildHtml(tdiv): - text images[currentIndex] - button(onclick = next): - text "Next" - button(onclick = prev): - text "Previous" - -#proc targetElem*(e: Event): Element = cast[Element](e.target) - -#proc getElementsByClassName*(cls: cstring): seq[Element] {.importc: -# "document.getElementsByClassName", nodecl.} -#proc textContent(e: Node): cstring {. -# importcpp: "#.textContent", nodecl.} - -proc isElementInViewport(el: Node; h: var int): bool = - let rect = el.getBoundingClientRect() - h = rect.bottom - rect.top - result = rect.top >= 0 and rect.left >= 0 and - rect.bottom <= clientHeight() and - rect.right <= clientWidth() - -proc visibleKeys(e: Node; a, b: var VKey; h, count: var int) = - # we only care about nodes that have a key: - var hh = 0 - # do not recurse if there is a 'key' field already: - if e.key >= 0: - if isElementInViewport(e, hh): - inc count - inc h, hh - a = min(a, e.key) - b = max(b, e.key) - else: - for i in 0.. - - - - - Refs - - - -
- - - diff --git a/experiments/refs/demo.nim b/experiments/refs/demo.nim deleted file mode 100644 index a0db59f..0000000 --- a/experiments/refs/demo.nim +++ /dev/null @@ -1,58 +0,0 @@ -include karaxprelude -import future, sequtils - -type - CustomRef = ref object of VComponent - -method onAttach(r: CustomRef) = - kout(cstring"custom ref attached") - -method onDetach(r: CustomRef) = - kout(cstring"custom ref detached") - -var - modelData = @[5, 2, 4] - - refA = VComponent() - refB = VComponent() - refC = CustomRef() - refSeq = newSeq[VComponent]() - -proc onClick(ev: Event, n: VNode) = - modelData.add(0) - -proc showRefs() = - kout(refA) - kout(refB) - kout(refC) - for i in 0 ..< refSeq.len: - kout(refSeq[i].vnode) - #kout(refSeq.map(nref => nref.vnode)) - -proc secureRefSlot(i: int): VComponent = - while refSeq.len <= i: - refSeq.add(VComponent()) - result = refSeq[i] - -proc view(): VNode = - result = buildHtml(): - tdiv: - button(onclick=onClick): - text "click me" - # storing refs to single elements is straightforward now - if modelData.len mod 2 == 0: - tdiv(nref=refA): - text "A" - tdiv(nref=refB): - text "B" - tdiv(nref=refC): - text "C" - # It's a bit more tricky when containers are involved: - for i, x in modelData.pairs: - tdiv(nref=secureRefSlot(i)): - text "List item: " & $x - -proc renderer(): VNode = - view() - -setRenderer(renderer, "ROOT", showRefs) diff --git a/experiments/refs/demo.nims b/experiments/refs/demo.nims deleted file mode 100644 index 9028ff1..0000000 --- a/experiments/refs/demo.nims +++ /dev/null @@ -1 +0,0 @@ ---path: "../../src" diff --git a/experiments/scrollapp.html b/experiments/scrollapp.html index 8b909f1..ad3ce2f 100644 --- a/experiments/scrollapp.html +++ b/experiments/scrollapp.html @@ -10,7 +10,7 @@
- + diff --git a/experiments/scrollapp.nim b/experiments/scrollapp.nim index 86a802f..7b7ce8e 100644 --- a/experiments/scrollapp.nim +++ b/experiments/scrollapp.nim @@ -1,14 +1,17 @@ -import vdom, karax, karaxdsl, jdict, jstrutils, compact +import vdom, karax, karaxdsl, jdict, jstrutils type Filter = enum all, active, completed +const + WindowSize = 50 # overestimating it does not harm + var entries: seq[(cstring, bool)] visibleA = 0 - visibleB = 10 + visibleB = 10_000 selectedEntry = -1 filter: Filter @@ -49,15 +52,34 @@ proc toChecked(checked: bool): cstring = proc selected(v: Filter): cstring = (if filter == v: cstring"selected" else: cstring(nil)) -proc createEntry(id: int; d: cstring; - completed: bool, selected: bool): VNode {.component.} = +when false: + proc entry(id: int, d: cstring; completed, selected: bool): proc (): VNode = + var lastid: type(id) + var lastd: type(d) + var lastCompleted: type(completed) + var lastSelected: type(selected) + proc inner(): VNode = + if lastid != id or lastd != d or lastCompleted != completed or lastSelected != selected: + result = logic(id, d, completed, selected) + lastid = id + lastd = d + lastCompleted = completed + lastSelected = selected + + result = inner + +proc lazyEntry(args: seq[VNode]): VNode = + let id = args[0].intValue + let d = args[1].text + let completed = args[2].intValue != 0 + let selected = args[3].intValue != 0 result = buildHtml(tr): li(class=toClass(completed), key = id): if not selected: tdiv(class = "view"): input(class = "toggle", `type` = "checkbox", checked = toChecked(completed), onclick=toggleEntry, key = id) - label(onclick=editHandler, key = id): + label(onDblClick=editHandler, key = id): text d button(class = "destroy", key = id, onclick = removeHandler) else: @@ -65,6 +87,9 @@ proc createEntry(id: int; d: cstring; onfocusLost = focusLost, onenter = editEntry, value = d, setFocus) +proc createEntry(id: int; d: cstring; completed, selected: bool): VNode = + result = thunk(lazyEntry, id, d, completed, selected) + proc myscroll(ev: Event; n: VNode) = kout cstring"scrolling event here" @@ -80,6 +105,10 @@ proc createDom(): VNode = input(class = "toggle-all", `type` = "checkbox", name = "toggle") label(`for` = "toggle-all", onclick = onAllDone): text "Mark all as complete" + tdiv(onscroll = myscroll, style = "overflow: visible; width: 0px; display: block; max-height: 1em"): + for i in 0..4: + tdiv: + text entries[i][0] var entriesCount = 0 var completedCount = 0 diff --git a/experiments/scrollapp_simple.nim b/experiments/scrollapp_simple.nim deleted file mode 100644 index cdd19cd..0000000 --- a/experiments/scrollapp_simple.nim +++ /dev/null @@ -1,25 +0,0 @@ -## Example that shows how to accomplish an "infinitely scrolling" app. - -include karax / prelude -import karax / [kdom, vstyles] - -var entries: seq[cstring] = @[] -for i in 1..500: - entries.add(cstring("Entry ") & &i) - -proc scrollEvent(ev: Event; n: VNode) = - let d = n.dom - if d != nil and inViewport(d.lastChild): - # "load" more data: - for i in 1..50: - entries.add(cstring("Loaded Entry ") & &i) - -proc createDom(): VNode = - result = buildHtml(): - tdiv(onscroll=scrollEvent, style=style( - (StyleAttr.height, cstring"400px"), (StyleAttr.overflow, cstring"scroll"))): - for x in entries: - tdiv: - text x - -setRenderer createDom diff --git a/experiments/style.css b/experiments/style.css deleted file mode 100644 index ceaf090..0000000 --- a/experiments/style.css +++ /dev/null @@ -1,378 +0,0 @@ -html, -body { - margin: 0; - padding: 0; -} - -.todomvc-wrapper { - visibility: visible !important; -} - -button { - margin: 0; - padding: 0; - border: 0; - background: none; - font-size: 100%; - vertical-align: baseline; - font-family: inherit; - font-weight: inherit; - color: inherit; - -webkit-appearance: none; - appearance: none; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; -} - -body { - font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; - line-height: 1.4em; - background: #f5f5f5; - color: #4d4d4d; - min-width: 230px; - max-width: 550px; - margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; - font-weight: 300; -} - -button, -input[type="checkbox"] { - outline: none; -} - -.hidden { - display: none; -} - -.todoapp { - background: #fff; - margin: 130px 0 40px 0; - position: relative; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), - 0 25px 50px 0 rgba(0, 0, 0, 0.1); -} - -.todoapp input::-webkit-input-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp input::-moz-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp input::input-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp h1 { - position: absolute; - top: -155px; - width: 100%; - font-size: 100px; - font-weight: 100; - text-align: center; - color: rgba(175, 47, 47, 0.15); - -webkit-text-rendering: optimizeLegibility; - -moz-text-rendering: optimizeLegibility; - text-rendering: optimizeLegibility; -} - -.new-todo, -.edit { - position: relative; - margin: 0; - width: 100%; - font-size: 24px; - font-family: inherit; - font-weight: inherit; - line-height: 1.4em; - border: 0; - outline: none; - color: inherit; - padding: 6px; - border: 1px solid #999; - box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); - box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; -} - -.new-todo { - padding: 16px 16px 16px 60px; - border: none; - background: rgba(0, 0, 0, 0.003); - box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); -} - -.main { - position: relative; - z-index: 2; - border-top: 1px solid #e6e6e6; -} - -label[for='toggle-all'] { - display: none; -} - -.toggle-all { - position: absolute; - top: -55px; - left: -12px; - width: 60px; - height: 34px; - text-align: center; - border: none; /* Mobile Safari */ -} - -.toggle-all:before { - content: '>'; - font-size: 22px; - color: #e6e6e6; - padding: 10px 27px 10px 27px; -} - -.toggle-all:checked:before { - color: #737373; -} - -.todo-list { - margin: 0; - padding: 0; - list-style: none; -} - -.todo-list li { - position: relative; - font-size: 24px; - border-bottom: 1px solid #ededed; -} - -.todo-list li:last-child { - border-bottom: none; -} - -.todo-list li.editing { - border-bottom: none; - padding: 0; -} - -.todo-list li.editing .edit { - display: block; - width: 506px; - padding: 13px 17px 12px 17px; - margin: 0 0 0 43px; -} - -.todo-list li.editing .view { - display: none; -} - -.todo-list li .toggle { - text-align: center; - width: 40px; - /* auto, since non-WebKit browsers doesn't support input styling */ - height: auto; - position: absolute; - top: 0; - bottom: 0; - margin: auto 0; - border: none; /* Mobile Safari */ - -webkit-appearance: none; - appearance: none; -} - -.todo-list li .toggle:after { - content: url('data:image/svg+xml,'); -} - -.todo-list li .toggle:checked:after { - content: url('data:image/svg+xml,'); -} - -.todo-list li label { - white-space: pre-line; - word-break: break-all; - padding: 15px 60px 15px 15px; - margin-left: 45px; - display: block; - line-height: 1.2; - transition: color 0.4s; -} - -.todo-list li.completed label { - color: #d9d9d9; - text-decoration: line-through; -} - -.todo-list li .destroy { - display: none; - position: absolute; - top: 0; - right: 10px; - bottom: 0; - width: 40px; - height: 40px; - margin: auto 0; - font-size: 30px; - color: #cc9a9a; - margin-bottom: 11px; - transition: color 0.2s ease-out; -} - -.todo-list li .destroy:hover { - color: #af5b5e; -} - -.todo-list li .destroy:after { - content: 'x'; -} - -.todo-list li:hover .destroy { - display: block; -} - -.todo-list li.editing:last-child { - margin-bottom: -1px; -} - -.footer { - color: #777; - padding: 10px 15px; - height: 20px; - text-align: center; - border-top: 1px solid #e6e6e6; -} - -.footer:before { - content: ''; - position: absolute; - right: 0; - bottom: 0; - left: 0; - height: 50px; - overflow: hidden; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), - 0 8px 0 -3px #f6f6f6, - 0 9px 1px -3px rgba(0, 0, 0, 0.2), - 0 16px 0 -6px #f6f6f6, - 0 17px 2px -6px rgba(0, 0, 0, 0.2); -} - -.todo-count { - float: left; - text-align: left; -} - -.todo-count strong { - font-weight: 300; -} - -.filters { - margin: 0; - padding: 0; - list-style: none; - position: absolute; - right: 0; - left: 0; -} - -.filters li { - display: inline; -} - -.filters li a { - color: inherit; - margin: 3px; - padding: 3px 7px; - text-decoration: none; - border: 1px solid transparent; - border-radius: 3px; -} - -.filters li a.selected, -.filters li a:hover { - border-color: rgba(175, 47, 47, 0.1); -} - -.filters li a.selected { - border-color: rgba(175, 47, 47, 0.2); -} - -.clear-completed, -html .clear-completed:active { - float: right; - position: relative; - line-height: 20px; - text-decoration: none; - cursor: pointer; - position: relative; -} - -.clear-completed:hover { - text-decoration: underline; -} - -.info { - margin: 65px auto 0; - color: #bfbfbf; - /* font-size: 10px; */ - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - text-align: center; -} - -.info p { - line-height: 1; -} - -.info a { - color: inherit; - text-decoration: none; - font-weight: 400; -} - -.info a:hover { - text-decoration: underline; -} - -/* - Hack to remove background from Mobile Safari. - Can't use it globally since it destroys checkboxes in Firefox -*/ -@media screen and (-webkit-min-device-pixel-ratio:0) { - .toggle-all, - .todo-list li .toggle { - background: none; - } - - .todo-list li .toggle { - height: 40px; - } - - .toggle-all { - -webkit-transform: rotate(90deg); - transform: rotate(90deg); - -webkit-appearance: none; - appearance: none; - } -} - -@media (max-width: 430px) { - .footer { - height: 50px; - } - - .filters { - bottom: 10px; - } -} \ No newline at end of file diff --git a/experiments/trello/knete.nim b/experiments/trello/knete.nim deleted file mode 100644 index 3a09ee3..0000000 --- a/experiments/trello/knete.nim +++ /dev/null @@ -1,752 +0,0 @@ -## Raw DOM manipulation. No DOM diff'ing, no cry. - -import macros, tables -from strutils import startsWith, toLowerAscii, toUpperAscii - -when defined(js): - type kstring* = cstring -else: - type kstring* = string - -type - Tag* {.pure.} = enum - text = "#text", - - 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", - - a, 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 ## The events supported by the virtual DOM. - onclick, ## An element is clicked. - oncontextmenu, ## An element is right-clicked. - ondblclick, ## An element is double clicked. - onkeyup, ## A key was released. - onkeydown, ## A key is pressed. - onkeypressed, # A key was pressed. - onfocus, ## An element got the focus. - onblur, ## An element lost the focus. - onchange, ## The selected value of an element was changed. - onscroll, ## The user scrolled within an element. - - onmousedown, ## A pointing device button (usually a mouse) is pressed - ## on an element. - onmouseenter, ## A pointing device is moved onto the element that - ## has the listener attached. - onmouseleave, ## A pointing device is moved off the element that - ## has the listener attached. - onmousemove, ## A pointing device is moved over an element. - onmouseout, ## A pointing device is moved off the element that - ## has the listener attached or off one of its children. - onmouseover, ## A pointing device is moved onto the element that has - ## the listener attached or onto one of its children. - onmouseup, ## A pointing device button is released over 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. - - onsubmit, ## A form is submitted - oninput, ## An input value changes - - onkeyupenter, ## vdom extension: an input field received the ENTER key press - onkeyuplater ## vdom extension: a key was pressed and some time - ## passed (useful for on-the-fly text completions) - - -macro buildLookupTables(): untyped = - var a = newTree(nnkBracket) - for i in low(Tag)..high(Tag): - let x = $i - let y = if x[0] == '#': x else: toUpperAscii(x) - a.add(newCall("kstring", newLit(y))) - var e = newTree(nnkBracket) - for i in low(EventKind)..high(EventKind): - e.add(newCall("kstring", newLit(substr($i, 2)))) - - template tmpl(a, e) {.dirty.} = - const - toTagName*: array[Tag, kstring] = a - toEventName*: array[EventKind, kstring] = e - - result = getAst tmpl(a, e) - -buildLookupTables() - -# ---------------- CSS ---------------------------------------------- - -type - StyleAttr* {.pure.} = enum - ## The style attributes supported by the virtual DOM. - ## Reference: https://www.w3schools.com/jsref/dom_obj_style.asp - alignContent - alignItems - alignSelf - animation - animationDelay - animationDirection - animationDuration - animationFillMode - animationIterationCount - animationName - animationTimingFunction - animationPlayState - background - backgroundAttachment - backgroundColor - backgroundImage - backgroundPosition - backgroundRepeat - backgroundClip - backgroundOrigin - backgroundSize - backfaceVisibility - border - borderBottom - borderBottomColor - borderBottomLeftRadius - borderBottomRightRadius - borderBottomStyle - borderBottomWidth - borderCollapse - borderColor - borderImage - borderImageOutset - borderImageRepeat - borderImageSlice - borderImageSource - borderImageWidth - borderLeft - borderLeftColor - borderLeftStyle - borderLeftWidth - borderRadius - borderRight - borderRightColor - borderRightStyle - borderRightWidth - borderSpacing - borderStyle - borderTop - borderTopColor - borderTopLeftRadius - borderTopRightRadius - borderTopStyle - borderTopWidth - borderWidth - bottom - boxDecorationBreak - boxShadow - boxSizing - captionSide - clear - clip - color - columnCount - columnFill - columnGap - columnRule - columnRuleColor - columnRuleStyle - columnRuleWidth - columns - columnSpan - columnWidth - content - counterIncrement - counterReset - cursor - direction - display - emptyCells - filter - flex - flexBasis - flexDirection - flexFlow - flexGrow - flexShrink - flexWrap - cssFloat - font - fontFamily - fontSize - fontSizeAdjust - fontStretch - fontStyle - fontVariant - fontWeight - hangingPunctuation - height - hyphens - icon - imageOrientation - justifyContent - left - letterSpacing - lineHeight - listStyle - listStyleImage - listStylePosition - listStyleType - margin - marginBottom - marginLeft - marginRight - marginTop - maxHeight - maxWidth - minHeight - minWidth - navDown - navIndex - navLeft - navRight - navUp - opacity - order - orphans - outline - outlineColor - outlineOffset - outlineStyle - outlineWidth - overflow - overflowX - overflowY - padding - paddingBottom - paddingLeft - paddingRight - paddingTop - pageBreakAfter - pageBreakBefore - pageBreakInside - perspective - perspectiveOrigin - pointerEvents - position - quotes - resize - right - scrollbar3dLightColor # note: missing in w3schools reference - scrollbarArrowColor # note: missing in w3schools reference - scrollbarBaseColor # note: missing in w3schools reference - scrollbarDarkshadowColor # note: missing in w3schools reference - scrollbarFaceColor # note: missing in w3schools reference - scrollbarHighlightColor # note: missing in w3schools reference - scrollbarShadowColor # note: missing in w3schools reference - scrollbarTrackColor # note: missing in w3schools reference - tableLayout - tabSize - textAlign - textAlignLast - textDecoration - textDecorationColor - textDecorationLine - textDecorationStyle - textIndent - textJustify - textOverflow - textShadow - textTransform - top - transform - transformOrigin - transformStyle - transition - transitionDelay - transitionDuration - transitionProperty - transitionTimingFunction - unicodeBidi - userSelect - verticalAlign - visibility - whiteSpace - width - wordBreak - wordSpacing - wordWrap - widows - zIndex - -macro buildStyleLookupTable(): untyped = - var e = newTree(nnkBracket) - for i in low(StyleAttr)..high(StyleAttr): - e.add(newCall("kstring", newLit($i))) - template tmpl(e) {.dirty.} = - const - toStyleAttrName: array[StyleAttr, kstring] = e - result = getAst tmpl(e) - -buildStyleLookupTable() - -type - StyleObj {.importc.} = object - background*: cstring - backgroundAttachment*: cstring - backgroundColor*: cstring - backgroundImage*: cstring - backgroundPosition*: cstring - backgroundRepeat*: cstring - border*: cstring - borderBottom*: cstring - borderBottomColor*: cstring - borderBottomStyle*: cstring - borderBottomWidth*: cstring - borderColor*: cstring - borderLeft*: cstring - borderLeftColor*: cstring - borderLeftStyle*: cstring - borderLeftWidth*: cstring - borderRight*: cstring - borderRightColor*: cstring - borderRightStyle*: cstring - borderRightWidth*: cstring - borderStyle*: cstring - borderTop*: cstring - borderTopColor*: cstring - borderTopStyle*: cstring - borderTopWidth*: cstring - borderWidth*: cstring - bottom*: cstring - captionSide*: cstring - clear*: cstring - clip*: cstring - color*: cstring - cursor*: cstring - direction*: cstring - display*: cstring - emptyCells*: cstring - cssFloat*: cstring - font*: cstring - fontFamily*: cstring - fontSize*: cstring - fontStretch*: cstring - fontStyle*: cstring - fontVariant*: cstring - fontWeight*: cstring - height*: cstring - left*: cstring - letterSpacing*: cstring - lineHeight*: cstring - listStyle*: cstring - listStyleImage*: cstring - listStylePosition*: cstring - listStyleType*: cstring - margin*: cstring - marginBottom*: cstring - marginLeft*: cstring - marginRight*: cstring - marginTop*: cstring - maxHeight*: cstring - maxWidth*: cstring - minHeight*: cstring - minWidth*: cstring - overflow*: cstring - padding*: cstring - paddingBottom*: cstring - paddingLeft*: cstring - paddingRight*: cstring - paddingTop*: cstring - pageBreakAfter*: cstring - pageBreakBefore*: cstring - pointerEvents*: cstring - position*: cstring - right*: cstring - scrollbar3dLightColor*: cstring - scrollbarArrowColor*: cstring - scrollbarBaseColor*: cstring - scrollbarDarkshadowColor*: cstring - scrollbarFaceColor*: cstring - scrollbarHighlightColor*: cstring - scrollbarShadowColor*: cstring - scrollbarTrackColor*: cstring - tableLayout*: cstring - textAlign*: cstring - textDecoration*: cstring - textIndent*: cstring - textTransform*: cstring - transform*: cstring - top*: cstring - verticalAlign*: cstring - visibility*: cstring - width*: cstring - wordSpacing*: cstring - zIndex*: int - Style* = ref StyleObj - - ElementObj {.importc.} = object - id*, class*, value*: cstring - disabled*: bool - style*: Style - Element* = ref ElementObj - - DocumentObj {.importc.} = object - Document = ref DocumentObj - -proc setStyle(s: Style; key, val: cstring) {.importcpp: "#[#] = #", noSideEffect.} - -proc applyStyles*(e: Element; pairs: openArray[(StyleAttr, kstring)]) = - for x in pairs: - e.style.setStyle(toStyleAttrName[x[0]], x[1]) - -# ------- Tree manipulation --------------------------- - -var document {.importc.}: Document - -proc parent*(x: Element): Element {.importcpp: "#.parentNode".} - -proc up*(x: Element; className: cstring): Element = - result = x - while result != nil and result.class != className: - result = result.parent - -proc len*(x: Element): int {.importcpp: "#.childNodes.length".} -proc `[]`*(x: Element; idx: int): Element {.importcpp: "#.childNodes[#]".} -proc getElementById*(id: cstring): Element {.importc: "document.getElementById", nodecl.} -proc add*(n, child: Element) {.importcpp: "appendChild".} - -proc removeChild(n, child: Element) {.importcpp.} -proc replaceChild(n, newNode, oldNode: Element) {.importcpp.} - -proc replace*(self, by: Element) = replaceChild(self.parent, by, self) -proc delete*(self: Element) = removeChild(self.parent, self) - -proc insertBefore(n, newNode, before: Element) {.importcpp.} -proc insert*(before, newNode: Element) = insertBefore(before.parent, newNode, before) - -proc createTextNode(d: Document, text: cstring): Element {.importcpp.} -proc text*(s: kstring): Element = createTextNode(document, s) - -iterator items*(n: Element): Element = - for i in 0.. 0: - result[L-1] = tcall2(result[L-1], tmpContext) - of nnkStmtList, nnkStmtListExpr, nnkWhenStmt, nnkIfStmt, nnkTryStmt, - nnkFinally: - # recurse for every child: - result = copyNimNode(n) - for x in n: - result.add tcall2(x, tmpContext) - of nnkCaseStmt: - # recurse for children, but don't add call for case ident - result = copyNimNode(n) - result.add n[0] - for i in 1 ..< n.len: - result.add tcall2(n[i], tmpContext) - of nnkProcDef: - let name = getName n[0] - if name.startsWith"on": - # turn it into an anon proc: - let anon = copyNimTree(n) - anon[0] = newEmptyNode() - if tmpContext == nil: - error "no Element to attach the event handler to" - else: - result = newCall(evHandler(), tmpContext, - newDotExpr(bindSym"EventKind", n[0]), anon, ident("kxi")) - else: - result = n - of nnkVarSection, nnkLetSection, nnkConstSection: - result = n - of nnkCallKinds - {nnkInfix}: - let op = getName(n[0]) - if isComponent(op) == ComponentKind.Tag: - let tmp = genSym(nskLet, "tmp") - let call = newCall(bindSym"tree", newDotExpr(bindSym"Tag", n[0])) - result = newTree( - if tmpContext == nil: nnkStmtListExpr else: nnkStmtList, - newLetStmt(tmp, call)) - for i in 1 ..< n.len: - # named parameters are transformed into attributes or events: - let x = n[i] - if x.kind == nnkExprEqExpr: - let key = getName x[0] - if key.startsWith("on"): - result.add newCall(evHandler(), - tmp, newDotExpr(bindSym"EventKind", x[0]), x[1]) - elif key in SpecialAttrs: - result.add newDotAsgn(tmp, key, x[1]) - elif eqIdent(key, "style"): - result.add newCall(bindSym"applyStyles", tmp, toKstring x[1]) - elif eqIdent(key, "setFocus"): - result.add newCall(bindSym"focus", tmp) - else: - result.add newCall(bindSym"setAttr", tmp, newLit(key), x[1]) - elif eqIdent(x, "setFocus"): - result.add newCall(bindSym"focus", tmp) - else: - result.add tcall2(x, tmp) - if tmpContext == nil: - result.add tmp - else: - result.add newCall(bindSym"add", tmpContext, tmp) - elif tmpContext != nil and op notin StmtContext: - var hasEventHandlers = false - for i in 1..= 0.18.0" -requires "ws" -requires "dotenv" -skipDirs = @["examples", "experiments", "tests"] +requires "nim >= 0.16.1" -bin = @["karax/tools/karun"] -installExt = @["nim"] +skipDirs = @["examples/todoapp"] \ No newline at end of file diff --git a/karax/autocomplete.nim b/karax/autocomplete.nim deleted file mode 100644 index 210ed4a..0000000 --- a/karax/autocomplete.nim +++ /dev/null @@ -1,160 +0,0 @@ - -import karax, karaxdsl, vdom, kdom, jstrutils - -type - AutocompleteState* = ref object - choices, candidates: seq[cstring] - selected, maxMatches: int - showCandidates, controlPressed: bool - -proc newAutocomplete*(choices: seq[cstring]; maxMatches = 5): AutocompleteState = - ## Creates a new state for the autocomplete widget. ``maxMatches`` is the maximum - ## number of elements to show. - AutocompleteState(choices: choices, candidates: @[], - selected: -1, maxMatches: maxMatches, showCandidates: false, - controlPressed: false) - -proc autocomplete*(s: AutocompleteState; onselection: proc(s: cstring)): VNode = - var inp: VNode - - proc commit(ev: Event) = - s.showCandidates = false - onselection(inp.dom.value) - when false: - if inp.dom != nil: - echo "setting to A ", inp.dom.value.isNil - result.text = inp.dom.value - else: - echo "setting to B ", inp.text.isNil - result.text = inp.text - for e in result.events: - if e[0] == EventKind.onchange: - e[1](ev, result) - - proc onkeyuplater(ev: Event; n: VNode) = - if not s.controlPressed: - let v = n.value - s.candidates.setLen 0 - for c in s.choices: - if v.len == 0 or c.containsIgnoreCase(v): s.candidates.add(c) - - proc onkeydown(ev: Event; n: VNode) = - const - LEFT = 37 - UP = 38 - RIGHT = 39 - DOWN = 40 - TAB = 9 - ESC = 27 - ENTER = 13 - # UP: Move focus to the previous item. If on first item, move focus to the input. - # If on the input, move focus to last item. - # DOWN: Move focus to the next item. If on last item, move focus to the input. - # If on the input, move focus to the first item. - # ESCAPE: Close the menu. - # ENTER: Select the currently focused item and close the menu. - # TAB: Select the currently focused item, close the menu, and - # move focus to the next focusable element - s.controlPressed = false - case ev.keyCode - of UP: - s.controlPressed = true - s.showCandidates = true - if s.selected > 0: - dec s.selected - n.setInputText s.candidates[s.selected] - of DOWN: - s.controlPressed = true - s.showCandidates = true - if s.selected < s.candidates.len - 1: - inc s.selected - n.setInputText s.candidates[s.selected] - of ESC: - s.showCandidates = false - s.controlPressed = true - of ENTER: - s.controlPressed = true -# inp.setInputText s.choices[i] - commit(ev) - else: - discard - - proc window(s: AutocompleteState): (int, int) = - var first, last: int - if s.selected >= 0: - first = s.selected - (s.maxMatches div 2) - last = s.selected + (s.maxMatches div 2) - if first < 0: first = 0 - # too few because we had to trim first? - if (last - first + 1) < s.maxMatches: last = first + s.maxMatches - 1 - else: - first = 0 - last = s.maxMatches - 1 - if last > high(s.candidates): last = high(s.candidates) - # still too few because we're at the end? - if (last - first + 1) < s.maxMatches: - first = last - s.maxMatches + 1 - if first < 0: first = 0 - - result = (first, last) - - inp = buildHtml: - input(onkeyuplater = onkeyuplater, - onkeydown = onkeydown, - # onblur = proc (ev: Event; n: VNode) = commit(ev), - onfocus = proc (ev: Event; n: VNode) = - onkeyuplater(ev, n) - s.showCandidates = true) - - proc select(i: int): proc(ev: Event; n: VNode) = - result = proc(ev: Event; n: VNode) = - s.selected = i - s.showCandidates = false - inp.setInputText s.choices[i] - commit(ev) - - result = buildHtml(table): - tr: - td: - inp - if s.showCandidates: - let (first, last) = window(s) - for i in first..last: - tr: - td(onclick = select(i), class = cstring"button " & - (if i == s.selected: cstring"is-primary" else: "")): - text s.candidates[i] - -when isMainModule: - const suggestions = @[cstring"ActionScript", - "AppleScript", - "Asp", - "BASIC", - "C", - "C++", - "Clojure", - "COBOL", - "Erlang", - "Fortran", - "Groovy", - "Haskell", - "Java", - "JavaScript", - "Lisp", - "Nim", - "Perl", - "PHP", - "Python", - "Ruby", - "Scala", - "Scheme"] - - var s = newAutocomplete(suggestions) - - proc main(): VNode = - result = buildHtml(tdiv): - autocomplete(s, proc (s: cstring) = echo "now ", s)#: - # proc onchange(ev: Event; n: VNode) = - # echo "now selected ", n.kind - - setRenderer(main) diff --git a/karax/compact.nim b/karax/compact.nim deleted file mode 100644 index 4e5dd6d..0000000 --- a/karax/compact.nim +++ /dev/null @@ -1,114 +0,0 @@ -## Components in Karax are built by the ``.component`` macro annotation. - -when defined(js): - import jdict, kdom - -import macros, vdom, tables, strutils, kbase - -when defined(js): - var - vcomponents* = newJDict[cstring, proc(args: seq[VNode]): VNode]() -else: - var - vcomponents* = newTable[kstring, proc(args: seq[VNode]): VNode]() - -type - ComponentKind* {.pure.} = enum - None, - Tag, - VNode - -var - allcomponents {.compileTime.} = initTable[string, ComponentKind]() - -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) - case t - of "cstring": - result = quote do: - args[`index`].text - of "int", "VKey": - result = quote do: - args[`index`].intValue - of "bool": - result = quote do: - args[`index`].intValue != 0 - elif t.endsWith"Kind": - result = quote do: - `symbolicType`(args[`index`].intValue) - else: - # just pass it along, maybe there is some conversion for it: - result = quote do: - args[`index`] - -proc newname*(n: NimNode): NimNode = - if n.kind == nnkPostfix: - n[1] = newname(n[1]) - result = n - elif n.kind == nnkSym: - result = ident(n.strVal) - else: - result = n - -when defined(js): - macro compact*(prc: untyped): untyped = - ## A 'compact' tree generation proc is one that only depends on its - ## inputs and should be stored as a compact virtual DOM tree and - ## only expanded on demand (when its inputs changed). - var n = prc.copyNimNode - for i in 0..6: n.add prc[i].copyNimTree - expectKind(n, nnkProcDef) - if n[0].kind == nnkEmpty: - error("please pass a non anonymous proc", n[0]) - let name = n[0] - let params = params(n) - let rettype = repr params[0] - var isvirtual = ComponentKind.None - if rettype == "VNode": - isvirtual = ComponentKind.VNode - else: - error "component must return VNode", params[0] - let realName = if name.kind == nnkPostfix: name[1] else: name - let nn = $realName - n[0] = ident("inner" & nn) - var unpackCall = newCall(n[0]) - var counter = 0 - for i in 1 ..< params.len: - let param = params[i] - let L = param.len - let typ = param[L-2] - for j in 0 .. L-3: - unpackCall.add unpack(typ, counter) - inc counter - - template vwrapper(pname, unpackCall) {.dirty.} = - proc pname(args: seq[VNode]): VNode = - unpackCall - - template vregister(key, val) = - bind jdict.`[]=` - `[]=`(vcomponents, kstring(key), val) - - result = newTree(nnkStmtList, n) - - if isvirtual == ComponentKind.VNode: - result.add getAst(vwrapper(newname name, unpackCall)) - result.add getAst(vregister(newLit(nn), realName)) - allcomponents[nn] = isvirtual - when defined(debugKaraxDsl): - echo repr result diff --git a/karax/errors.nim b/karax/errors.nim deleted file mode 100644 index aedd103..0000000 --- a/karax/errors.nim +++ /dev/null @@ -1,32 +0,0 @@ -## Error handling logic for form input validation. - -import karax, jdict - -var - gerrorMsgs = newJDict[cstring, cstring]() - gerrorCounter = 0 - -proc hasErrors*(): bool = gerrorCounter != 0 - -proc hasError*(field: cstring): bool = gerrorMsgs.contains(field) and len(gerrorMsgs[field]) > 0 - -proc disableOnError*(): cstring = toDisabled(hasErrors()) - -proc getError*(field: cstring): cstring = - if not gerrorMsgs.contains(field): - result = "" - else: - result = gerrorMsgs[field] - -proc setError*(field, msg: cstring) = - let previous = getError(field) - if len(msg) == 0: - if len(previous) != 0: dec(gerrorCounter) - else: - if len(previous) == 0: inc(gerrorCounter) - gerrorMsgs[field] = msg - -proc clearErrors*() = - let m = gerrorMsgs - for k in m.keys: - setError(k, "") diff --git a/karax/i18n.nim b/karax/i18n.nim deleted file mode 100644 index 42274ff..0000000 --- a/karax/i18n.nim +++ /dev/null @@ -1,152 +0,0 @@ -## Karax -- Single page applications for Nim. - -## i18n support for Karax applications. We distinguish between: -## -## - translate: Lookup text translations -## - localize: Localize Date and Time objects to local formats -## -## Localization has not yet been implemented. - -import languages, jdict, jstrutils - -var currentLanguage = Language.enUS - -proc getLanguage(): cstring = - {.emit: "`result` = (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;".} - -proc detectLanguage*(): Language = - let x = getLanguage() - for i in low(Language)..high(Language): - if languageToCode[i] == x: return i - return Language.enUS - -proc setCurrentLanguage*(newLanguage = detectLanguage()) = - currentLanguage = newLanguage - -proc getCurrentLanguage*(): Language = currentLanguage - -type Translation* = JDict[cstring, cstring] - -var - translations: array[Language, Translation] - -proc registerTranslation*(lang: Language; t: Translation) = translations[lang] = t - -proc addTranslation*(lang: Language; key, val: cstring) = - if translations[lang].isNil: translations[lang] = newJDict[cstring, cstring]() - translations[lang][key] = val - -proc translate(x: cstring): cstring = - let y = translations[currentLanguage] - if y != nil and y.contains(x): - result = y[x] - else: - result = x - -type TranslatedString* = distinct cstring - -template i18n*(x: string): TranslatedString = TranslatedString(translate(cstring x)) - -proc raiseInvalidFormat(errmsg: string) = - raise newException(ValueError, errmsg) - -discard """ - $[1:item|items]1$ selected. -""" - -proc `{}`(x: cstring; i: int): char {.importcpp: "#.charCodeAt(#)".} -proc sadd(s: JSeq[char]; c: char) {.importcpp: "#.push(String.fromCharCode(#))".} - -proc parseChoice(f: cstring; i, choice: int, - r: JSeq[char]) = - var i = i - while i < f.len: - var n = 0 - let oldI = i - var toAdd = false - while i < f.len and f{i} >= '0' and f{i} <= '9': - n = n * 10 + ord(f{i}) - ord('0') - inc i - if oldI != i: - if f{i} == ':': - inc i - else: - raiseInvalidFormat"':' after number expected" - toAdd = choice == n - else: - # an else section does not start with a number: - toAdd = true - while i < f.len and f{i} != ']' and f{i} != '|': - if toAdd: r.sadd f{i} - inc i - if toAdd: break - inc i - -proc join(x: JSeq[char]): cstring {.importcpp: "#.join(\"\")".} -proc add(x: JSeq[char]; y: cstring) = - for i in 0..= '0' and f{i} <= '9': - j = j * 10 + ord(f{i}) - ord('0') - inc i - let idx = if not negative: j-1 else: args.len-j - r.add args[idx] - of '$': - inc(i) - r.add '$' - of '[': - let start = i+1 - while i < f.len and f{i} != ']': inc i - inc i - if i >= f.len: raiseInvalidFormat"']' expected" - case f{i} - of '#': - parseChoice(f, start, parseInt args[num], r) - inc i - inc num - of '1'..'9', '-': - var j = 0 - var negative = f{i} == '-' - if negative: inc i - while f{i} >= '0' and f{i} <= '9': - j = j * 10 + ord(f{i}) - ord('0') - inc i - let idx = if not negative: j-1 else: args.len-j - parseChoice(f, start, parseInt args[idx], r) - else: raiseInvalidFormat"argument index expected after ']'" - else: - raiseInvalidFormat("'#', '$', or number expected") - if i < f.len and f{i} == '$': inc i - else: - r.sadd f{i} - inc i - result = join(r) - - -when isMainModule: - addTranslation(Language.deDE, "$#$ -> $#$", "$2 macht $1") - setCurrentLanguage(Language.deDE) - - echo(i18n"$#$ -> $#$" % [cstring"1", "2"]) - echo(i18n"$[1:item |items ]1$ -> $1" % [cstring"1", "2"]) - echo(i18n"$[1:item |items ]1 -> $1" % [cstring"0", "2"]) - echo(i18n"$[1:item |items ]1 -> $1" % [cstring"2", "2"]) - echo(i18n"$[1:item |items ]1$ -> $1" % [cstring"3", "2"]) - echo(i18n"$1 $[1:item |4:huha |items ]1$ -> $1" % [cstring"4", "2"]) diff --git a/karax/jdict.nim b/karax/jdict.nim deleted file mode 100644 index c9e2224..0000000 --- a/karax/jdict.nim +++ /dev/null @@ -1,30 +0,0 @@ - -type - JDict*[K, V] = ref object - -proc `[]`*[K, V](d: JDict[K, V], k: K): V {.importcpp: "#[#]".} -proc `[]=`*[K, V](d: JDict[K, V], k: K, v: V) {.importcpp: "#[#] = #".} - -proc newJDict*[K, V](): JDict[K, V] {.importcpp: "{@}".} - -proc contains*[K, V](d: JDict[K, V], k: K): bool {.importcpp: "#.hasOwnProperty(#)".} - -proc del*[K, V](d: JDict[K, V], k: K) {.importcpp: "delete #[#]".} - -iterator keys*[K, V](d: JDict[K, V]): K = - var kkk: K - {.emit: ["for (", kkk, " in ", d, ") {"].} - yield kkk - {.emit: ["}"].} - -type - JSeq*[T] = ref object - -proc `[]`*[T](s: JSeq[T], i: int): T {.importcpp: "#[#]", noSideEffect.} -proc `[]=`*[T](s: JSeq[T], i: int, v: T) {.importcpp: "#[#] = #", noSideEffect.} - -proc newJSeq*[T](len: int = 0): JSeq[T] {.importcpp: "new Array(#)".} -proc len*[T](s: JSeq[T]): int {.importcpp: "#.length", noSideEffect.} -proc add*[T](s: JSeq[T]; x: T) {.importcpp: "#.push(#)", noSideEffect.} - -proc shrink*[T](s: JSeq[T]; shorterLen: int) {.importcpp: "#.length = #", noSideEffect.} diff --git a/karax/jjson.nim b/karax/jjson.nim deleted file mode 100644 index ad6106b..0000000 --- a/karax/jjson.nim +++ /dev/null @@ -1,67 +0,0 @@ -## This module implements some small zero-overhead 'JsonNode' type -## and helper that maps directly to JavaScript objects. - -type - JsonNode* {.importc.} = ref object - -proc `[]`*(obj: JsonNode; fieldname: cstring): JsonNode {.importcpp: "#[#]".} -proc `[]`*(obj: JsonNode; index: int): JsonNode {.importcpp: "#[#]".} -proc `[]=`*[T](obj: JsonNode; fieldname: cstring; value: T) - {.importcpp: "#[#] = #".} -proc length(x: JsonNode): int {.importcpp: "#.length".} -proc len*(x: JsonNode): int = (if x.isNil: 0 else: x.length) - -proc newJsonNode*(fields: varargs[(cstring, JsonNode)]): JsonNode = - result = JsonNode() - for f in fields: - result[f[0]] = f[1] - -proc newJObject*(): JsonNode = - result = JsonNode() - -proc newJArray*(elements: varargs[JsonNode]): JsonNode {.importcpp: "#".} - -proc newJNull*(): JsonNode = nil - -template `%`*(x: typed): JsonNode = cast[JsonNode](x) -template `%`*(x: string): JsonNode = cast[JsonNode](cstring x) - -proc getNum*(x: JsonNode): int {.importcpp: "#".} - -proc getInt*(x: JsonNode): int {.importcpp: "#".} -proc getStr*(x: JsonNode): cstring {.importcpp: "#".} -proc getFNum*(x: JsonNode): cstring {.importcpp: "#".} - -iterator items*(x: JsonNode): JsonNode = - for i in 0..= 0: - # result.key = n.key - for k, v in attrs(n): - if v != nil: - result.setAttr(k, v) - applyEvents(n) - if kxi != nil and n == kxi.toFocusV and kxi.toFocus.isNil: - kxi.toFocus = result - if not n.style.isNil: applyStyle(result, n.style) - -proc same(n: VNode, e: Node; nesting = 0): bool = - if kxi.orphans.contains(n.id): return true - if n.kind == VNodeKind.component: - result = same(VComponent(n).expanded, e, nesting+1) - elif n.kind == VNodeKind.verbatim: - result = true - elif n.kind == VNodeKind.vthunk or n.kind == VNodeKind.dthunk: - # we don't check these: - result = true - elif toTag[n.kind] == e.nodename: - result = true - if n.kind != VNodeKind.text: - # BUGFIX: Microsoft's Edge gives the textarea a child containing the text node! - if e.len != n.len and n.kind != VNodeKind.textarea: - echo "expected ", n.len, " real ", e.len, " ", toTag[n.kind], " nesting ", nesting - return false - for i in 0 ..< n.len: - if not same(n[i], e[i], nesting+1): return false - else: - echo "VDOM: ", toTag[n.kind], " DOM: ", e.nodename - -proc replaceById(id: cstring; newTree: Node) = - let x = document.getElementById(id) - x.parentNode.replaceChild(newTree, x) - newTree.id = id - -type - EqResult = enum - componentsIdentical, different, similar, identical, usenewNode - -when defined(profileKarax): - type - DifferEnum = enum - deKind, deId, deIndex, deText, deComponent, deClass, - deSimilar - - var - reasons: array[DifferEnum, int] - - proc echa(a: array[DifferEnum, int]) = - for i in low(DifferEnum)..high(DifferEnum): - echo i, " value: ", a[i] - -proc eq(a, b: VNode; recursive: bool): EqResult = - if a.kind != b.kind: - when defined(profileKarax): inc reasons[deKind] - return different - if a.id != b.id: - when defined(profileKarax): inc reasons[deId] - return different - result = identical - if a.index != b.index: - when defined(profileKarax): inc reasons[deIndex] - return different - if a.kind == VNodeKind.text: - if a.text != b.text: - when defined(profileKarax): inc reasons[deText] - return different # similar - elif a.kind == VNodeKind.vthunk: - if a.text != b.text: return different - if a.len != b.len: return different - for i in 0..>" & depth) - elif n.kind == VNodeKind.text: - kout depth, n.text - for i in 0 ..< n.len: - printV(n[i], depth & " ") - -proc addPatch(kxi: KaraxInstance; ka: PatchKind; parenta, currenta: Node; - na, oldNode: VNode) = - let L = kxi.patchLen - if L >= kxi.patches.len: - # allocate more space: - kxi.patches.add(Patch(k: ka, parent: parenta, current: currenta, - newNode: na, oldNode: oldNode)) - else: - kxi.patches[L].k = ka - kxi.patches[L].parent = parenta - kxi.patches[L].current = currenta - kxi.patches[L].newNode = na - kxi.patches[L].oldNode = oldNode - inc kxi.patchLen - -proc addPatchV(kxi: KaraxInstance; parent: VNode; pos: int; newChild: VNode) = - let L = kxi.patchLenV - if L >= kxi.patchesV.len: - # allocate more space: - kxi.patchesV.add(PatchV(parent: parent, newChild: newChild, pos: pos)) - else: - kxi.patchesV[L].parent = parent - kxi.patchesV[L].newChild = newChild - kxi.patchesV[L].pos = pos - inc kxi.patchLenV - -proc moveDom(dest, src: VNode) = - dest.dom = src.dom - src.dom = nil - if dest.id != nil: - kxi.byId[dest.id] = dest - assert dest.len == src.len - for i in 0.. We cannot ever use the old VDOM, we have to use the new virtual -# DOM. For identical nodes we need to take over the .dom field from the old -# node since we don't recompute them. This must be done recursively. In -# vnodeToDom we have to check whether the 'dom' field was already set. If so, -# There is nothing to do. -# "Similar" nodes can have the opposite effect; consider -# -# AAAABAAAA -# AAAACDAAAA -# -# In this example B did change to C and 'D' is new. However, replacing B by -# CD is fine. -# - - -proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance) = - when defined(stats): - if kxi.recursion > 100: - echo "newNode ", newNode.kind, " oldNode ", oldNode.kind, " eq ", eq(newNode, oldNode, false) - if oldNode.kind == VNodeKind.text: - echo oldNode.text - inc kxi.recursion - let result = eq(newNode, oldNode, false) - case result - of componentsIdentical: - kxi.components.add ComponentPair(oldNode: VComponent(oldNode), - newNode: VComponent(newNode), - parent: parent, - current: current) - of identical, similar: - newNode.dom = oldNode.dom - if result == similar: - updateStyles(newNode, oldNode) - updateAttributes(newNode, oldNode) - if oldNode.kind == VNodeKind.text: - oldNode.text = newNode.text - oldNode.dom.nodeValue = newNode.text - - if newNode.events.len != 0 or oldNode.events.len != 0: - mergeEvents(newNode, oldNode, kxi) - - let newLength = newNode.len - let oldLength = oldNode.len - if newLength == 0 and oldLength == 0: return - let minLength = min(newLength, oldLength) - - assert oldNode.kind == newNode.kind - var commonPrefix = 0 - - # compute common prefix: - while commonPrefix < minLength: - if eq(newNode[commonPrefix], oldNode[commonPrefix], true) == identical: - kxi.addPatch(pkSame, nil, nil, newNode[commonPrefix], oldNode[commonPrefix]) - inc commonPrefix - else: - break - - # compute common suffix: - var oldPos = oldLength - 1 - var newPos = newLength - 1 - while oldPos >= commonPrefix and newPos >= commonPrefix: - if eq(newNode[newPos], oldNode[oldPos], true) == identical: - kxi.addPatch(pkSame, nil, nil, newNode[newPos], oldNode[oldPos]) - dec oldPos - dec newPos - else: - break - - let pos = min(oldPos, newPos) + 1 - # now the different children are in commonPrefix .. pos - 1: - for i in commonPrefix..pos-1: - diff(newNode[i], oldNode[i], current, current.childNodes[i], kxi) - - if oldPos + 1 == oldLength: - for i in pos..newPos: - kxi.addPatch(pkAppend, current, nil, newNode[i], nil) - else: - let before = current.childNodes[oldPos + 1] - for i in pos..newPos: - kxi.addPatch(pkInsertBefore, current, before, newNode[i], nil) - # XXX call 'attach' here? - for i in pos..oldPos: - detach(oldNode[i]) - #doAssert i < current.childNodes.len - kxi.addPatch(pkRemove, current, current.childNodes[i], nil, nil) - of different: - detach(oldNode) - kxi.addPatch(pkReplace, parent, current, newNode, nil) - of usenewNode: doAssert(false, "eq returned usenewNode") - when defined(stats): - dec kxi.recursion - -proc applyComponents(kxi: KaraxInstance) = - # the first 'diff' pass detects components in the VDOM. The - # 'applyComponents' expands components and so on until no - # components are left to check. - var i = 0 - # beware: 'diff' appends to kxi.components! - # So this is actually a fixpoint iteration: - while i < kxi.components.len: - let x = kxi.components[i].oldNode - let newNode = kxi.components[i].newNode - when defined(karaxDebug): - echo "Processing component ", newNode.text, " changed impl set ", x.changedImpl != nil - if x.changedImpl != nil and x.changedImpl(x, newNode): - when defined(karaxDebug): - echo "Component ", newNode.text, " did change" - let current = kxi.components[i].current - let parent = kxi.components[i].parent - x.updatedImpl(x, newNode) - let oldExpanded = x.expanded - x.expanded = x.renderImpl(x) - when defined(karaxDebug): - echo "Component ", newNode.text, " re-rendered" - x.renderedVersion = x.version - if oldExpanded == nil: - detach(x) - kxi.addPatch(pkReplace, parent, current, x.expanded, nil) - when defined(karaxDebug): - echo "Component ", newNode.text, ": old expansion didn't exist" - else: - diff(x.expanded, oldExpanded, parent, current, kxi) - when false: - if res == usenewNode: - when defined(karaxDebug): - echo "Component ", newNode.text, ": re-render triggered a DOM change (case A)" - discard "diff created a patchset for us, so this is fine" - elif res != different: - when defined(karaxDebug): - echo "Component ", newNode.text, ": re-render triggered no DOM change whatsoever" - x.expanded = oldExpanded - assert oldExpanded.dom != nil, "old expanded.dom is nil" - else: - when defined(karaxDebug): - echo "Component ", newNode.text, ": re-render triggered a DOM change (case B)" - assert x.expanded.dom != nil, "expanded.dom is nil" - inc i - setLen(kxi.components, 0) - -when defined(stats): - proc depth(n: VNode; total: var int): int = - var m = 0 - for i in 0..= parent.len: - kxi.addPatch(pkAppend, current, nil, kid, nil) - parent.add(kid) - else: - let before = current.childNodes[position] - kxi.addPatch(pkInsertBefore, current, before, kid, nil) - parent.insert(kid, position) - applyPatch(kxi) - doAssert same(kxi.currentTree, document.getElementById(kxi.rootId)) - -proc runDiff*(kxi: KaraxInstance; oldNode, newNode: VNode) = - let olddom = oldNode.dom - doAssert olddom != nil - diff(newNode, oldNode, nil, olddom, kxi) - # this is a bit nasty: Since we cannot patch the 'parent' of - # the current VNode (because we don't store it at all!), we - # need to override the fields individually: - takeOverFields(newNode, oldNode) - applyComponents(kxi) - applyPatch(kxi) - if kxi.currentTree == oldNode: - kxi.currentTree = newNode - doAssert same(kxi.currentTree, document.getElementById(kxi.rootId)) - -var onhashChange {.importc: "window.onhashchange".}: proc() -var hashPart {.importc: "window.location.hash".}: cstring - -proc avoidDomDiffing*(kxi: KaraxInstance = kxi) = - ## enforce a full redraw for the next redraw operation. - ## This can be used as a temporary way to workaround DOM diffing - ## problems or to avoid the DOM diffing when you already know - ## it should use a completely new DOM. - ## This is an experimental API. - kxi.currentTree = nil - -proc reqFrame(callback: proc()): int {.importc: "window.requestAnimationFrame".} -when false: - proc cancelFrame(id: int) {.importc: "window.cancelAnimationFrame".} - -proc dodraw(kxi: KaraxInstance) = - if kxi.renderer.isNil: return - kxi.renderId = 0 - - if kxi.rendering: - # there is a render already running, delay 1 frame - kxi.renderId = reqFrame(proc () = kxi.dodraw) - return - - kxi.rendering = true - - let rdata = RouterData(hashPart: hashPart) - let newtree = kxi.renderer(rdata) - inc kxi.runCount - newtree.id = kxi.rootId - kxi.toFocus = nil - if kxi.currentTree == nil: - let asdom = toDom(newtree, useAttachedNode = true, kxi) - replaceById(kxi.rootId, asdom) - else: - doAssert same(kxi.currentTree, document.getElementById(kxi.rootId)) - let olddom = document.getElementById(kxi.rootId) - diff(newtree, kxi.currentTree, nil, olddom, kxi) - when defined(profileKarax): - echo "<<<<<<<<<<<<<<" - echa reasons - applyComponents(kxi) - when defined(profileKarax): - echo "--------------" - echa reasons - echo ">>>>>>>>>>>>>>" - applyPatch(kxi) - kxi.currentTree = newtree - doAssert same(kxi.currentTree, document.getElementById(kxi.rootId)) - - if not kxi.postRenderCallback.isNil: - kxi.postRenderCallback(rdata) - - # now that it's part of the DOM, give it the focus: - if kxi.toFocus != nil: - kxi.toFocus.focus() - kxi.rendering = false - when defined(stats): - kxi.recursion = 0 - var total = 0 - echo "depth ", depth(kxi.currentTree, total), " total ", total - -proc redraw*(kxi: KaraxInstance = kxi) = - # we buffer redraw requests: - when false: - if drawTimeout != nil: - clearTimeout(drawTimeout) - drawTimeout = setTimeout(dodraw, 30) - elif true: - if kxi.renderId == 0: - kxi.renderId = reqFrame(proc () = kxi.dodraw) - else: - dodraw(kxi) - -proc redrawSync*(kxi: KaraxInstance = kxi) = dodraw(kxi) - -proc init(ev: Event) = - kxi.renderId = reqFrame(proc () = kxi.dodraw) - -proc setRenderer*(renderer: proc (data: RouterData): VNode, - root: cstring = "ROOT", - clientPostRenderCallback: - proc (data: RouterData) = nil): KaraxInstance {. - discardable.} = - ## Setup Karax. Usually the return value can be ignored. - if document.getElementById(root).isNil: - let msg = "Could not find a
with id=" & root & - ". Karax needs it as its rendering target." - raise newException(Exception, $msg) - - result = KaraxInstance(rootId: root, renderer: renderer, - postRenderCallback: clientPostRenderCallback, - patches: newSeq[Patch](60), - patchesV: newSeq[PatchV](30), - components: @[], - surpressRedraws: false, - byId: newJDict[cstring, VNode](), - orphans: newJDict[cstring, bool]()) - kxi = result - window.onload = init - onhashChange = proc() = redraw() - -proc setRenderer*(renderer: proc (): VNode, root: cstring = "ROOT", - clientPostRenderCallback: proc () = nil): KaraxInstance {.discardable.} = - ## Setup Karax. Usually the return value can be ignored. - proc wrapRenderer(data: RouterData): VNode = result = renderer() - proc wrapPostRender(data: RouterData) = - if clientPostRenderCallback != nil: clientPostRenderCallback() - setRenderer(wrapRenderer, root, wrapPostRender) - -proc setInitializer*(renderer: proc (data: RouterData): VNode, root: cstring = "ROOT", - clientPostRenderCallback: - proc (data: RouterData) = nil): KaraxInstance {.discardable.} = - ## Setup Karax. Usually the return value can be ignored. - result = KaraxInstance(rootId: root, renderer: renderer, - postRenderCallback: clientPostRenderCallback, - patches: newSeq[Patch](60), - patchesV: newSeq[PatchV](30), - components: @[], - surpressRedraws: true, - byId: newJDict[cstring, VNode](), - orphans: newJDict[cstring, bool]()) - kxi = result - window.onload = init - -proc addEventHandler*(n: VNode; k: EventKind; action: EventHandler; - kxi: KaraxInstance = kxi) = - ## Implements the foundation of Karax's event management. - ## Karax DSL transforms ``tag(onEvent = handler)`` to - ## ``tempNode.addEventHandler(tagNode, EventKind.onEvent, wrapper)`` - ## where ``wrapper`` calls the passed ``action`` and then triggers - ## a ``redraw``. - proc wrapper(ev: Event; n: VNode) = - action(ev, n) - if not kxi.surpressRedraws: redraw(kxi) - addEventListener(n, k, wrapper) - -proc addEventHandler*(n: VNode; k: EventKind; action: proc(); - kxi: KaraxInstance = kxi) = - ## Implements the foundation of Karax's event management. - ## Karax DSL transforms ``tag(onEvent = handler)`` to - ## ``tempNode.addEventHandler(tagNode, EventKind.onEvent, wrapper)`` - ## where ``wrapper`` calls the passed ``action`` and then triggers - ## a ``redraw``. - proc wrapper(ev: Event; n: VNode) = - action() - if not kxi.surpressRedraws: redraw(kxi) - addEventListener(n, k, wrapper) - -proc setOnHashChange*(action: proc (hashPart: cstring)) {.deprecated: "use setRenderer instead".} = - ## Now deprecated, instead pass a callback to ``setRenderer`` that receives - ## a ``data: RouterData`` parameter. - proc wrapper() = - action(hashPart) - redraw() - onhashchange = wrapper - -proc setForeignNodeId*(id: cstring; kxi: KaraxInstance = kxi) = - ## Declares a node ID as "foreign". Foreign nodes are not - ## under Karax's control in the sense that Karax does not attempt - ## to perform structural checks on them. - kxi.orphans[id] = true - -{.push stackTrace:off.} -proc setupErrorHandler*() = - ## Installs an error handler that transforms native JS unhandled - ## exceptions into Nim based stack traces. If `useAlert` is false, - ## the error message is put into the console, otherwise `alert` - ## is called. - proc stackTraceAsCstring(): cstring = cstring(getStackTrace()) - var onerror {.importc: "window.onerror", used.} = - proc (msg, url: cstring, line, col: int, error: cstring): bool = - var x = cstring"Error: " & msg & "\n" & stackTraceAsCstring() - echo(x) - return true # suppressErrorAlert -{.pop.} - -proc prepend(parent, kid: Element) = - parent.insertBefore(kid, parent.firstChild) - -proc loadScript*(jsfilename: cstring; kxi: KaraxInstance = kxi) = - let s = document.createElement("script") - s.setAttr "type", "text/javascript" - s.setAttr "src", jsfilename - document.body.prepend(s) - redraw(kxi) - -proc runLater*(action: proc(); later = 400): Timeout {.discardable.} = - proc wrapper() = - action() - redraw() - result = setTimeout(wrapper, later) - -proc setInputText*(n: VNode; s: cstring) = - ## Sets the text of input elements. - n.text = s - if n.dom != nil: n.dom.value = s - -proc getInputText*(n: VNode): cstring = - if n.dom != nil: - result = n.dom.value - -proc toChecked*(checked: bool): cstring = - (if checked: cstring"checked" else: cstring(nil)) - -proc toDisabled*(disabled: bool): cstring = - (if disabled: cstring"disabled" else: cstring(nil)) - -proc toSelected*(selected: bool): cstring = - (if selected: cstring"selected" else: cstring(nil)) - -proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node = - result = toDom(n, useAttachedNode = false, kxi) diff --git a/karax/karaxdsl.nim b/karax/karaxdsl.nim deleted file mode 100644 index 451632c..0000000 --- a/karax/karaxdsl.nim +++ /dev/null @@ -1,200 +0,0 @@ - -import macros, vdom, compact, kbase -from strutils import startsWith, toLowerAscii - -when defined(js): - import karax - -const - StmtContext = ["kout", "inc", "echo", "dec", "!"] - SpecialAttrs = ["id", "class", "value", "index", "style"] - -proc getName(n: NimNode): string = - case n.kind - of nnkIdent, nnkSym: - result = $n - of nnkAccQuoted: - result = "" - for i in 0.. 0: - result[L-1] = tcall2(result[L-1], tmpContext) - of nnkStmtList, nnkStmtListExpr, nnkWhenStmt, nnkIfStmt, nnkTryStmt, - nnkFinally: - # recurse for every child: - result = copyNimNode(n) - for x in n: - result.add tcall2(x, tmpContext) - of nnkCaseStmt: - # recurse for children, but don't add call for case ident - result = copyNimNode(n) - result.add n[0] - for i in 1 ..< n.len: - result.add tcall2(n[i], tmpContext) - of nnkProcDef: - let name = getName n[0] - if name.startsWith"on": - # turn it into an anon proc: - let anon = copyNimTree(n) - anon[0] = newEmptyNode() - if tmpContext == nil: - error "no VNode to attach the event handler to" - else: - result = newCall(evHandler(), tmpContext, - newDotExpr(bindSym"EventKind", n[0]), anon, ident("kxi")) - else: - result = n - of nnkVarSection, nnkLetSection, nnkConstSection: - result = n - of nnkCallKinds - {nnkInfix}: - let op = getName(n[0]) - let ck = isComponent(op) - if ck != ComponentKind.None: - let tmp = genSym(nskLet, "tmp") - let call = if ck == ComponentKind.Tag: - newCall(bindSym"tree", newDotExpr(bindSym"VNodeKind", n[0])) - elif ck == ComponentKind.VNode: - newCall(bindSym"vthunk", newLit(op)) - else: - newCall(bindSym"dthunk", newLit(op)) - result = newTree( - if tmpContext == nil: nnkStmtListExpr else: nnkStmtList, - newLetStmt(tmp, call)) - for i in 1 ..< n.len: - # named parameters are transformed into attributes or events: - let x = n[i] - if x.kind == nnkExprEqExpr: - let key = getName x[0] - if key.startsWith("on"): - result.add newCall(evHandler(), - tmp, newDotExpr(bindSym"EventKind", x[0]), x[1], ident("kxi")) - elif eqIdent(key, "style") and x[1].kind == nnkTableConstr: - result.add newDotAsgn(tmp, key, newCall("style", toKstring x[1])) - elif key in SpecialAttrs: - result.add newDotAsgn(tmp, key, x[1]) - if key == "value": - result.add newCall(bindSym"setAttr", tmp, newLit(key), x[1]) - elif eqIdent(key, "setFocus"): - result.add newCall(key, tmp, x[1], ident"kxi") - elif eqIdent(key, "events"): - result.add newCall(bindSym"mergeEvents", tmp, x[1]) - else: - result.add newCall(bindSym"setAttr", tmp, newLit(key), x[1]) - elif ck != ComponentKind.Tag: - call.add x - elif eqIdent(x, "setFocus"): - result.add newCall(x, tmp, bindSym"true", ident"kxi") - else: - result.add tcall2(x, tmp) - if tmpContext == nil: - result.add tmp - else: - result.add newCall(bindSym"add", tmpContext, tmp) - elif tmpContext != nil and op notin StmtContext: - var hasEventHandlers = false - for i in 1..`_. - -when not defined(js) and not defined(Nimdoc): - {.error: "This module only works on the JavaScript platform".} - -type - EventTarget* = ref EventTargetObj - EventTargetObj {.importc.} = object of RootObj - onabort*: proc (event: Event) {.nimcall.} - onblur*: proc (event: Event) {.nimcall.} - onchange*: proc (event: Event) {.nimcall.} - onclick*: proc (event: Event) {.nimcall.} - ondblclick*: proc (event: Event) {.nimcall.} - onerror*: proc (event: Event) {.nimcall.} - onfocus*: proc (event: Event) {.nimcall.} - onkeydown*: proc (event: Event) {.nimcall.} - onkeypress*: proc (event: Event) {.nimcall.} - onkeyup*: proc (event: Event) {.nimcall.} - onload*: proc (event: Event) {.nimcall.} - onmousedown*: proc (event: Event) {.nimcall.} - onmousemove*: proc (event: Event) {.nimcall.} - onmouseout*: proc (event: Event) {.nimcall.} - onmouseover*: proc (event: Event) {.nimcall.} - onmouseup*: proc (event: Event) {.nimcall.} - onreset*: proc (event: Event) {.nimcall.} - onselect*: proc (event: Event) {.nimcall.} - onsubmit*: proc (event: Event) {.nimcall.} - onunload*: proc (event: Event) {.nimcall.} - - # https://developer.mozilla.org/en-US/docs/Web/Events - DomEvent* {.pure.} = enum - Abort = "abort", - BeforeInput = "beforeinput", - Blur = "blur", - Click = "click", - CompositionEnd = "compositionend", - CompositionStart = "compositionstart", - CompositionUpdate = "compositionupdate", - DblClick = "dblclick", - Error = "error", - Focus = "focus", - FocusIn = "focusin", - FocusOut = "focusout", - Input = "input", - KeyDown = "keydown", - KeyPress = "keypress", - KeyUp = "keyup", - Load = "load", - MouseDown = "mousedown", - MouseEnter = "mouseenter", - MouseLeave = "mouseleave", - MouseMove = "mousemove", - MouseOut = "mouseout", - MouseOver = "mouseover", - MouseUp = "mouseup", - Resize = "resize", - Scroll = "scroll", - Select = "select", - Unload = "unload", - Wheel = "wheel" - - Window* = ref WindowObj - WindowObj {.importc.} = object of EventTargetObj - document*: Document - event*: Event - history*: History - location*: Location - closed*: bool - defaultStatus*: cstring - innerHeight*, innerWidth*: int - locationbar*: ref LocationBar - menubar*: ref MenuBar - name*: cstring - outerHeight*, outerWidth*: int - pageXOffset*, pageYOffset*: int - personalbar*: ref PersonalBar - scrollbars*: ref ScrollBars - statusbar*: ref StatusBar - status*: cstring - toolbar*: ref ToolBar - frames*: seq[Frame] - screen*: Screen - - Frame* = ref FrameObj - FrameObj {.importc.} = object of WindowObj - - ClassList* = ref ClassListObj - ClassListObj {.importc.} = object of RootObj - - NodeType* = enum - ElementNode = 1, - AttributeNode, - TextNode, - CDATANode, - EntityRefNode, - EntityNode, - ProcessingInstructionNode, - CommentNode, - DocumentNode, - DocumentTypeNode, - DocumentFragmentNode, - NotationNode - - Node* = ref NodeObj - NodeObj {.importc.} = object of EventTargetObj - attributes*: seq[Node] - childNodes*: seq[Node] - children*: seq[Node] - data*: cstring - firstChild*: Node - lastChild*: Node - nextSibling*: Node - nodeName*: cstring - nodeType*: NodeType - nodeValue*: cstring - parentNode*: Node - previousSibling*: Node - innerHTML*: cstring - style*: Style - when defined(nodejs): - id*: cstring - - Document* = ref DocumentObj - DocumentObj {.importc.} = object of NodeObj - alinkColor*: cstring - bgColor*: cstring - body*: Element - charset*: cstring - cookie*: cstring - defaultCharset*: cstring - fgColor*: cstring - head*: Element - lastModified*: cstring - linkColor*: cstring - referrer*: cstring - title*: cstring - URL*: cstring - vlinkColor*: cstring - anchors*: seq[AnchorElement] - forms*: seq[FormElement] - images*: seq[ImageElement] - applets*: seq[Element] - embeds*: seq[EmbedElement] - links*: seq[LinkElement] - - Element* = ref ElementObj - ElementObj {.importc.} = object of NodeObj - classList*: Classlist - checked*: bool - defaultChecked*: bool - defaultValue*: cstring - disabled*: bool - form*: FormElement - name*: cstring - readOnly*: bool - options*: seq[OptionElement] - selectedOptions*: seq[OptionElement] - clientWidth*, clientHeight*: int - contentEditable*: string - isContentEditable*: bool - dir*: string - offsetHeight*: int - offsetWidth*: int - offsetLeft*: int - offsetTop*: int - - # https://developer.mozilla.org/en-US/docs/Web/API/ValidityState - ValidityState* = ref ValidityStateObj - ValidityStateObj {.importc.} = object - badInput*: bool - customError*: bool - patternMismatch*: bool - rangeOverflow*: bool - rangeUnderflow*: bool - stepMismatch*: bool - tooLong*: bool - tooShort*: bool - typeMismatch*: bool - valid*: bool - valueMissing*: bool - - # https://developer.mozilla.org/en-US/docs/Web/API/Blob - Blob* = ref BlobObj - BlobObj {.importc.} = object of RootObj - size*: int - `type`*: cstring - - # https://developer.mozilla.org/en-US/docs/Web/API/File - File* = ref FileObj - FileObj {.importc.} = object of Blob - lastModified*: int - name*: cstring - - # https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement - InputElement* = ref InputElementObj - InputElementObj {.importc.} = object of Element - # Properties related to the parent form - formAction*: cstring - formEncType*: cstring - formMethod*: cstring - formNoValidate*: bool - formTarget*: cstring - - # Properties that apply to any type of input element that is not hidden - `type`*: cstring - autofocus*: bool - required*: bool - value*: cstring - validity*: ValidityState - validationMessage*: cstring - willValidate*: bool - - # Properties that apply only to elements of type "checkbox" or "radio" - indeterminate*: bool - - # Properties that apply only to elements of type "image" - alt*: cstring - height*: cstring - src*: cstring - width*: cstring - - # Properties that apply only to elements of type "file" - accept*: cstring - files*: seq[Blob] - - # Properties that apply only to text/number-containing or elements - autocomplete*: cstring - maxLength*: int - size*: int - pattern*: cstring - placeholder*: cstring - min*: cstring - max*: cstring - selectionStart*: int - selectionEnd*: int - selectionDirection*: cstring - - # Properties not yet categorized - dirName*: cstring - accessKey*: cstring - list*: Element - multiple*: bool - labels*: seq[Element] - step*: cstring - valueAsDate*: cstring - valueAsNumber*: float - - LinkElement* = ref LinkObj - LinkObj {.importc.} = object of ElementObj - target*: cstring - text*: cstring - x*: int - y*: int - - EmbedElement* = ref EmbedObj - EmbedObj {.importc.} = object of ElementObj - height*: int - hspace*: int - src*: cstring - width*: int - `type`*: cstring - vspace*: int - - AnchorElement* = ref AnchorObj - AnchorObj {.importc.} = object of ElementObj - text*: cstring - x*, y*: int - - OptionElement* = ref OptionObj - OptionObj {.importc.} = object of ElementObj - defaultSelected*: bool - selected*: bool - selectedIndex*: int - text*: cstring - value*: cstring - - # https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement - FormElement* = ref FormObj - FormObj {.importc.} = object of ElementObj - acceptCharset*: cstring - action*: cstring - autocomplete*: cstring - elements*: seq[Element] - encoding*: cstring - enctype*: cstring - length*: int - `method`*: cstring - noValidate*: bool - target*: cstring - - ImageElement* = ref ImageObj - ImageObj {.importc.} = object of ElementObj - border*: int - complete*: bool - height*: int - hspace*: int - lowsrc*: cstring - src*: cstring - vspace*: int - width*: int - - Style* = ref StyleObj - StyleObj {.importc.} = object of RootObj - background*: cstring - backgroundAttachment*: cstring - backgroundColor*: cstring - backgroundImage*: cstring - backgroundPosition*: cstring - backgroundRepeat*: cstring - border*: cstring - borderBottom*: cstring - borderBottomColor*: cstring - borderBottomStyle*: cstring - borderBottomWidth*: cstring - borderColor*: cstring - borderLeft*: cstring - borderLeftColor*: cstring - borderLeftStyle*: cstring - borderLeftWidth*: cstring - borderRight*: cstring - borderRightColor*: cstring - borderRightStyle*: cstring - borderRightWidth*: cstring - borderStyle*: cstring - borderTop*: cstring - borderTopColor*: cstring - borderTopStyle*: cstring - borderTopWidth*: cstring - borderWidth*: cstring - bottom*: cstring - captionSide*: cstring - clear*: cstring - clip*: cstring - color*: cstring - cursor*: cstring - direction*: cstring - display*: cstring - emptyCells*: cstring - cssFloat*: cstring - font*: cstring - fontFamily*: cstring - fontSize*: cstring - fontStretch*: cstring - fontStyle*: cstring - fontVariant*: cstring - fontWeight*: cstring - height*: cstring - left*: cstring - letterSpacing*: cstring - lineHeight*: cstring - listStyle*: cstring - listStyleImage*: cstring - listStylePosition*: cstring - listStyleType*: cstring - margin*: cstring - marginBottom*: cstring - marginLeft*: cstring - marginRight*: cstring - marginTop*: cstring - maxHeight*: cstring - maxWidth*: cstring - minHeight*: cstring - minWidth*: cstring - overflow*: cstring - padding*: cstring - paddingBottom*: cstring - paddingLeft*: cstring - paddingRight*: cstring - paddingTop*: cstring - pageBreakAfter*: cstring - pageBreakBefore*: cstring - pointerEvents*: cstring - position*: cstring - right*: cstring - scrollbar3dLightColor*: cstring - scrollbarArrowColor*: cstring - scrollbarBaseColor*: cstring - scrollbarDarkshadowColor*: cstring - scrollbarFaceColor*: cstring - scrollbarHighlightColor*: cstring - scrollbarShadowColor*: cstring - scrollbarTrackColor*: cstring - tableLayout*: cstring - textAlign*: cstring - textDecoration*: cstring - textIndent*: cstring - textTransform*: cstring - transform*: cstring - top*: cstring - verticalAlign*: cstring - visibility*: cstring - width*: cstring - wordSpacing*: cstring - zIndex*: int - - EventPhase* = enum - None = 0, - CapturingPhase, - AtTarget, - BubblingPhase - - # https://developer.mozilla.org/en-US/docs/Web/API/Event - Event* = ref EventObj - EventObj {.importc.} = object of RootObj - bubbles*: bool - cancelBubble*: bool - cancelable*: bool - composed*: bool - currentTarget*: Node - defaultPrevented*: bool - eventPhase*: int - target*: Node - `type`*: cstring - isTrusted*: bool - - # https://developer.mozilla.org/en-US/docs/Web/API/UIEvent - UIEvent* = ref UIEventObj - UIEventObj {.importc.} = object of Event - detail*: int64 - view*: Window - - # https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent - KeyboardEvent* = ref KeyboardEventObj - KeyboardEventObj {.importc.} = object of UIEvent - altKey*, ctrlKey*, metaKey*, shiftKey*: bool - code*: cstring - isComposing*: bool - key*: cstring - keyCode*: int - location*: int - - # https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values - KeyboardEventKey* {.pure.} = enum - # Modifier keys - Alt, - AltGraph, - CapsLock, - Control, - Fn, - FnLock, - Hyper, - Meta, - NumLock, - ScrollLock, - Shift, - Super, - Symbol, - SymbolLock, - - # Whitespace keys - ArrowDown, - ArrowLeft, - ArrowRight, - ArrowUp, - End, - Home, - PageDown, - PageUp, - - # Editing keys - Backspace, - Clear, - Copy, - CrSel, - Cut, - Delete, - EraseEof, - ExSel, - Insert, - Paste, - Redo, - Undo, - - # UI keys - Accept, - Again, - Attn, - Cancel, - ContextMenu, - Escape, - Execute, - Find, - Finish, - Help, - Pause, - Play, - Props, - Select, - ZoomIn, - ZoomOut, - - # Device keys - BrigtnessDown, - BrigtnessUp, - Eject, - LogOff, - Power, - PowerOff, - PrintScreen, - Hibernate, - Standby, - WakeUp, - - # Common IME keys - AllCandidates, - Alphanumeric, - CodeInput, - Compose, - Convert, - Dead, - FinalMode, - GroupFirst, - GroupLast, - GroupNext, - GroupPrevious, - ModeChange, - NextCandidate, - NonConvert, - PreviousCandidate, - Process, - SingleCandidate, - - # Korean keyboards only - HangulMode, - HanjaMode, - JunjaMode, - - # Japanese keyboards only - Eisu, - Hankaku, - Hiragana, - HiraganaKatakana, - KanaMode, - KanjiMode, - Katakana, - Romaji, - Zenkaku, - ZenkakuHanaku, - - # Function keys - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - F11, - F12, - F13, - F14, - F15, - F16, - F17, - F18, - F19, - F20, - Soft1, - Soft2, - Soft3, - Soft4, - - # Phone keys - AppSwitch, - Call, - Camera, - CameraFocus, - EndCall, - GoBack, - GoHome, - HeadsetHook, - LastNumberRedial, - Notification, - MannerMode, - VoiceDial, - - # Multimedia keys - ChannelDown, - ChannelUp, - MediaFastForward, - MediaPause, - MediaPlay, - MediaPlayPause, - MediaRecord, - MediaRewind, - MediaStop, - MediaTrackNext, - MediaTrackPrevious, - - # Audio control keys - AudioBalanceLeft, - AudioBalanceRight, - AudioBassDown, - AudioBassBoostDown, - AudioBassBoostToggle, - AudioBassBoostUp, - AudioBassUp, - AudioFaderFront, - AudioFaderRear, - AudioSurroundModeNext, - AudioTrebleDown, - AudioTrebleUp, - AudioVolumeDown, - AUdioVolumeMute, - AudioVolumeUp, - MicrophoneToggle, - MicrophoneVolumeDown, - MicrophoneVolumeMute, - MicrophoneVolumeUp, - - # TV control keys - TV, - TV3DMode, - TVAntennaCable, - TVAudioDescription, - TVAudioDescriptionMixDown, - TVAudioDescriptionMixUp, - TVContentsMenu, - TVDataService, - TVInput, - TVInputComponent1, - TVInputComponent2, - TVInputComposite1, - TVInputComposite2, - TVInputHDMI1, - TVInputHDMI2, - TVInputHDMI3, - TVInputHDMI4, - TVInputVGA1, - TVMediaContext, - TVNetwork, - TVNumberEntry, - TVPower, - TVRadioService, - TVSatellite, - TVSatelliteBS, - TVSatelliteCS, - TVSatelliteToggle, - TVTerrestrialAnalog, - TVTerrestrialDigital, - TVTimer, - - # Media controller keys - AVRInput, - AVRPower, - ColorF0Red, - ColorF1Green, - ColorF2Yellow, - ColorF3Blue, - ColorF4Grey, - ColorF5Brown, - ClosedCaptionToggle, - Dimmer, - DisplaySwap, - DVR, - Exit, - FavoriteClear0, - FavoriteClear1, - FavoriteClear2, - FavoriteClear3, - FavoriteRecall0, - FavoriteRecall1, - FavoriteRecall2, - FavoriteRecall3, - FavoriteStore0, - FavoriteStore1, - FavoriteStore2, - FavoriteStore3, - Guide, - GuideNextDay, - GuidePreviousDay, - Info, - InstantReplay, - Link, - ListProgram, - LiveContent, - Lock, - MediaApps, - MediaAudioTrack, - MediaLast, - MediaSkipBackward, - MediaSkipForward, - MediaStepBackward, - MediaStepForward, - MediaTopMenu, - NavigateIn, - NavigateNext, - NavigateOut, - NavigatePrevious, - NextFavoriteChannel, - NextUserProfile, - OnDemand, - Pairing, - PinPDown, - PinPMove, - PinPUp, - PlaySpeedDown, - PlaySpeedReset, - PlaySpeedUp, - RandomToggle, - RcLowBattery, - RecordSpeedNext, - RfBypass, - ScanChannelsToggle, - ScreenModeNext, - Settings, - SplitScreenToggle, - STBInput, - STBPower, - Subtitle, - Teletext, - VideoModeNext, - Wink, - ZoomToggle, - - # Speech recognition keys - SpeechCorrectionList, - SpeechInputToggle, - - # Document keys - Close, - New, - Open, - Print, - Save, - SpellCheck, - MailForward, - MailReply, - MailSend, - - # Application selector keys - LaunchCalculator, - LaunchCalendar, - LaunchContacts, - LaunchMail, - LaunchMediaPlayer, - LaunchMusicPlayer, - LaunchMyComputer, - LaunchPhone, - LaunchScreenSaver, - LaunchSpreadsheet, - LaunchWebBrowser, - LaunchWebCam, - LaunchWordProcessor, - LaunchApplication1, - LaunchApplication2, - LaunchApplication3, - LaunchApplication4, - LaunchApplication5, - LaunchApplication6, - LaunchApplication7, - LaunchApplication8, - LaunchApplication9, - LaunchApplication10, - LaunchApplication11, - LaunchApplication12, - LaunchApplication13, - LaunchApplication14, - LaunchApplication15, - LaunchApplication16, - - # Browser control keys - BrowserBack, - BrowserFavorites, - BrowserForward, - BrowserHome, - BrowserRefresh, - BrowserSearch, - BrowserStop, - - # Numeric keypad keys - Key11, - Key12, - Separator - - MouseButtons* = enum - NoButton = 0, - PrimaryButton = 1, - SecondaryButton = 2, - AuxilaryButton = 4, - FourthButton = 8, - FifthButton = 16 - - # https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent - MouseEvent* = ref MouseEventObj - MouseEventObj {.importc.} = object of UIEvent - altKey*, ctrlKey*, metaKey*, shiftKey*: bool - button*: int - buttons*: int - clientX*, clientY*: int - movementX*, movementY*: int - offsetX*, offsetY*: int - pageX*, pageY*: int - relatedTarget*: EventTarget - #region*: cstring - screenX*, screenY*: int - x*, y*: int - - DataTransferItemKind* {.pure.} = enum - File = "file", - String = "string" - - # https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem - DataTransferItem* = ref DataTransferItemObj - DataTransferItemObj {.importc.} = object of RootObj - kind*: cstring - `type`*: cstring - - # https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer - DataTransfer* = ref DataTransferObj - DataTransferObj {.importc.} = object of RootObj - dropEffect*: cstring - effectAllowed*: cstring - files*: seq[Element] - items*: seq[DataTransferItem] - types*: seq[cstring] - - DataTransferDropEffect* {.pure.} = enum - None = "none", - Copy = "copy", - Link = "link", - Move = "move" - - DataTransferEffectAllowed* {.pure.} = enum - None = "none", - Copy = "copy", - CopyLink = "copyLink", - CopyMove = "copyMove", - Link = "link", - LinkMove = "linkMove", - Move = "move", - All = "all", - Uninitialized = "uninitialized" - - DragEventTypes* = enum - Drag = "drag", - DragEnd = "dragend", - DragEnter = "dragenter", - DragExit = "dragexit", - DragLeave = "dragleave", - DragOver = "dragover", - DragStart = "dragstart", - Drop = "drop" - - # https://developer.mozilla.org/en-US/docs/Web/API/DragEvent - DragEvent* {.importc.} = object of MouseEvent - dataTransfer*: DataTransfer - - TouchList* {.importc.} = ref object of RootObj - length*: int - - Touch* = ref TouchObj - TouchObj {.importc.} = object of RootObj - identifier*: int - screenX*, screenY*, clientX*, clientY*, pageX*, pageY*: int - target*: Element - radiusX*, radiusY*: int - rotationAngle*: int - force*: float - - TouchEvent* = ref TouchEventObj - TouchEventObj {.importc.} = object of UIEvent - changedTouches*, targetTouches*, touches*: seq[Touch] - - Location* = ref LocationObj - LocationObj {.importc.} = object of RootObj - hash*: cstring - host*: cstring - hostname*: cstring - href*: cstring - pathname*: cstring - port*: cstring - protocol*: cstring - search*: cstring - - History* = ref HistoryObj - HistoryObj {.importc.} = object of RootObj - length*: int - - Navigator* = ref NavigatorObj - NavigatorObj {.importc.} = object of RootObj - appCodeName*: cstring - appName*: cstring - appVersion*: cstring - cookieEnabled*: bool - language*: cstring - platform*: cstring - userAgent*: cstring - mimeTypes*: seq[ref MimeType] - - Plugin* {.importc.} = object of RootObj - description*: cstring - filename*: cstring - name*: cstring - - MimeType* {.importc.} = object of RootObj - description*: cstring - enabledPlugin*: ref Plugin - suffixes*: seq[cstring] - `type`*: cstring - - LocationBar* {.importc.} = object of RootObj - visible*: bool - MenuBar* = LocationBar - PersonalBar* = LocationBar - ScrollBars* = LocationBar - ToolBar* = LocationBar - StatusBar* = LocationBar - - Screen = ref ScreenObj - ScreenObj {.importc.} = object of RootObj - availHeight*: int - availWidth*: int - colorDepth*: int - height*: int - pixelDepth*: int - width*: int - - TimeOut* {.importc.} = ref object of RootObj - Interval* {.importc.} = object of RootObj - - AddEventListenerOptions* = object - capture*: bool - once*: bool - passive*: bool - -when defined(nodejs): - # we provide a dummy DOM for nodejs for testing purposes - proc len*(x: Node): int = x.childNodes.len - proc `[]`*(x: Node; idx: int): Element = - assert idx >= 0 and idx < x.childNodes.len - result = cast[Element](x.childNodes[idx]) - - var document* = Document(nodeType: DocumentNode) - - proc getElem(x: Element; id: cstring): Element = - if x.id == id: return x - for i in 0..= 0 and rect.left >= 0 and - rect.bottom <= clientHeight().float and - rect.right <= clientWidth().float - -proc scrollTop*(e: Node): int {.importcpp: "#.scrollTop", nodecl.} -proc offsetHeight*(e: Node): int {.importcpp: "#.offsetHeight", nodecl.} -proc offsetTop*(e: Node): int {.importcpp: "#.offsetTop", nodecl.} -proc offsetLeft*(e: Node): int {.importcpp: "#.offsetLeft", nodecl.} diff --git a/karax/languages.nim b/karax/languages.nim deleted file mode 100644 index 6b6b027..0000000 --- a/karax/languages.nim +++ /dev/null @@ -1,616 +0,0 @@ -## Karax -- Single page applications for Nim. - -type - Language* {.pure.} = enum ## A pure enum that contains most (all?) - ## known human languages in current use. - afZA ## "South Africa - Afrikaans" - amET ## "Ethiopia - Amharic" - arAE ## "U.A.E. - Arabic" - arBH ## "Bahrain - Arabic" - arDZ ## "Algeria - Arabic" - arEG ## "Egypt - Arabic" - arIQ ## "Iraq - Arabic" - arJO ## "Jordan - Arabic" - arKW ## "Kuwait - Arabic" - arLB ## "Lebanon - Arabic" - arLY ## "Libya - Arabic" - arMA ## "Morocco - Arabic" - arOM ## "Oman - Arabic" - arQA ## "Qatar - Arabic" - arSA ## "Saudi Arabia - Arabic" - arSY ## "Syria - Arabic" - arTN ## "Tunisia - Arabic" - arYE ## "Yemen - Arabic" - arnCL ## "Chile - Mapudungun" - asIN ## "India - Assamese" - azAZ ## "Azerbaijan - Azeri (Cyrillic)" - baRU ## "Russia - Bashkir" - beBY ## "Belarus - Belarusian" - bgBG ## "Bulgaria - Bulgarian" - bnBD ## "Bangladesh - Bengali" - bnIN ## "India - Bengali" - boCN ## "People's Republic of China - Tibetan" - brFR ## "France - Breton" - bsBA ## "Bosnia and Herzegovina - Bosnian (Cyrillic)" - caES ## "Spain - Catalan" - coFR ## "France - Corsican" - csCZ ## "Czech Republic - Czech" - cyGB ## "United Kingdom - Welsh" - daDK ## "Denmark - Danish" - deAT ## "Austria - German" - deCH ## "Switzerland - German" - deDE ## "Germany - German" - deLI ## "Liechtenstein - German" - deLU ## "Luxembourg - German" - dsbDE ## "Germany - Lower Sorbian" - dvMV ## "Maldives - Divehi" - elGR ## "Greece - Greek" - en029 ## "Caribbean - English" - enAU ## "Australia - English" - enBZ ## "Belize - English" - enCA ## "Canada - English" - enGB ## "United Kingdom - English" - enIE ## "Ireland - English" - enIN ## "India - English" - enJM ## "Jamaica - English" - enMY ## "Malaysia - English" - enNZ ## "New Zealand - English" - enPH ## "Republic of the Philippines - English" - enSG ## "Singapore - English" - enTT ## "Trinidad and Tobago - English" - enUS ## "United States - English" - enZA ## "South Africa - English" - enZW ## "Zimbabwe - English" - esAR ## "Argentina - Spanish" - esBO ## "Bolivia - Spanish" - esCL ## "Chile - Spanish" - esCO ## "Colombia - Spanish" - esCR ## "Costa Rica - Spanish" - esDO ## "Dominican Republic - Spanish" - esEC ## "Ecuador - Spanish" - esES ## "Spain - Spanish" - esGT ## "Guatemala - Spanish" - esHN ## "Honduras - Spanish" - esMX ## "Mexico - Spanish" - esNI ## "Nicaragua - Spanish" - esPA ## "Panama - Spanish" - esPE ## "Peru - Spanish" - esPR ## "Puerto Rico - Spanish" - esPY ## "Paraguay - Spanish" - esSV ## "El Salvador - Spanish" - esUS ## "United States - Spanish" - esUY ## "Uruguay - Spanish" - esVE ## "Bolivarian Republic of Venezuela - Spanish" - etEE ## "Estonia - Estonian" - euES ## "Spain - Basque" - faIR ## "Iran - Persian" - fiFI ## "Finland - Finnish" - filPH ## "Philippines - Filipino" - foFO ## "Faroe Islands - Faroese" - frBE ## "Belgium - French" - frCA ## "Canada - French" - frCH ## "Switzerland - French" - frFR ## "France - French" - frLU ## "Luxembourg - French" - frMC ## "Principality of Monaco - French" - fyNL ## "Netherlands - Frisian" - gaIE ## "Ireland - Irish" - gdGB ## "United Kingdom - Scottish Gaelic" - glES ## "Spain - Galician" - gswFR ## "France - Alsatian" - guIN ## "India - Gujarati" - haNG ## "Nigeria - Hausa (Latin)" - heIL ## "Israel - Hebrew" - hiIN ## "India - Hindi" - hrBA ## "Bosnia and Herzegovina - Croatian" - hrHR ## "Croatia - Croatian" - hsbDE ## "Germany - Upper Sorbian" - huHU ## "Hungary - Hungarian" - hyAM ## "Armenia - Armenian" - idID ## "Indonesia - Indonesian" - igNG ## "Nigeria - Igbo" - iiCN ## "People's Republic of China - Yi" - isIS ## "Iceland - Icelandic" - itCH ## "Switzerland - Italian" - itIT ## "Italy - Italian" - iuCA ## "Canada - Inuktitut (Latin)" - jaJP ## "Japan - Japanese" - kaGE ## "Georgia - Georgian" - kkKZ ## "Kazakhstan - Kazakh" - klGL ## "Greenland - Greenlandic" - kmKH ## "Cambodia - Khmer" - knIN ## "India - Kannada" - koKR ## "Korea - Korean" - kokIN ## "India - Konkani" - kyKG ## "Kyrgyzstan - Kyrgyz" - lbLU ## "Luxembourg - Luxembourgish" - loLA ## "Lao P.D.R. - Lao" - ltLT ## "Lithuania - Lithuanian" - lvLV ## "Latvia - Latvian" - miNZ ## "New Zealand - Maori" - mkMK ## "Macedonia (FYROM) - Macedonian (FYROM)" - mlIN ## "India - Malayalam" - mnCN ## "People's Republic of China - Mongolian (Traditional Mongolian)" - mnMN ## "Mongolia - Mongolian (Cyrillic)" - mohCA ## "Canada - Mohawk" - mrIN ## "India - Marathi" - msBN ## "Brunei Darussalam - Malay" - msMY ## "Malaysia - Malay" - mtMT ## "Malta - Maltese" - nbNO ## "Norway - Norwegian (Bokmal)" - neNP ## "Nepal - Nepali" - nlBE ## "Belgium - Dutch" - nlNL ## "Netherlands - Dutch" - nnNO ## "Norway - Norwegian (Nynorsk)" - nsoZA ## "South Africa - Sesotho sa Leboa" - ocFR ## "France - Occitan" - orIN ## "India - Oriya" - paIN ## "India - Punjabi" - plPL ## "Poland - Polish" - prsAF ## "Afghanistan - Dari" - psAF ## "Afghanistan - Pashto" - ptBR ## "Brazil - Portuguese" - ptPT ## "Portugal - Portuguese" - qutGT ## "Guatemala - K'iche" - quzBO ## "Bolivia - Quechua" - quzEC ## "Ecuador - Quechua" - quzPE ## "Peru - Quechua" - rmCH ## "Switzerland - Romansh" - roRO ## "Romania - Romanian" - ruRU ## "Russia - Russian" - rwRW ## "Rwanda - Kinyarwanda" - saIN ## "India - Sanskrit" - sahRU ## "Russia - Yakut" - seFI ## "Finland - Sami (Northern)" - seNO ## "Norway - Sami (Northern)" - seSE ## "Sweden - Sami (Northern)" - siLK ## "Sri Lanka - Sinhala" - skSK ## "Slovakia - Slovak" - slSI ## "Slovenia - Slovenian" - smaNO ## "Norway - Sami (Southern)" - smaSE ## "Sweden - Sami (Southern)" - smjNO ## "Norway - Sami (Lule)" - smjSE ## "Sweden - Sami (Lule)" - smnFI ## "Finland - Sami (Inari)" - smsFI ## "Finland - Sami (Skolt)" - sqAL ## "Albania - Albanian" - srBA ## "Bosnia and Herzegovina - Serbian (Cyrillic)" - srCS ## "Serbia and Montenegro (Former) - Serbian (Cyrillic)" - srME ## "Montenegro - Serbian (Cyrillic)" - srRS ## "Serbia - Serbian (Cyrillic)" - svFI ## "Finland - Swedish" - svSE ## "Sweden - Swedish" - swKE ## "Kenya - Kiswahili" - syrSY ## "Syria - Syriac" - taIN ## "India - Tamil" - teIN ## "India - Telugu" - tgTJ ## "Tajikistan - Tajik (Cyrillic)" - thTH ## "Thailand - Thai" - tkTM ## "Turkmenistan - Turkmen" - tnZA ## "South Africa - Setswana" - trTR ## "Turkey - Turkish" - ttRU ## "Russia - Tatar" - tzmDZ ## "Algeria - Tamazight (Latin)" - ugCN ## "People's Republic of China - Uyghur" - ukUA ## "Ukraine - Ukrainian" - urPK ## "Islamic Republic of Pakistan - Urdu" - uzUZ ## "Uzbekistan - Uzbek (Cyrillic)" - viVN ## "Vietnam - Vietnamese" - woSN ## "Senegal - Wolof" - xhZA ## "South Africa - isiXhosa" - yoNG ## "Nigeria - Yoruba" - zhCN ## "People's Republic of China - Chinese (Simplified) Legacy" - zhHK ## "Hong Kong S.A.R. - Chinese (Traditional) Legacy" - zhMO ## "Macao S.A.R. - Chinese (Traditional) Legacy" - zhSG ## "Singapore - Chinese (Simplified) Legacy" - zhTW ## "Taiwan - Chinese (Traditional) Legacy" - zuZA ## "South Africa - isiZulu" - -const - languageToName*: array[Language, cstring] = [ - Language.afZA: cstring"South Africa - Afrikaans", - Language.amET: cstring"Ethiopia - Amharic", - Language.arAE: cstring"U.A.E. - Arabic", - Language.arBH: cstring"Bahrain - Arabic", - Language.arDZ: cstring"Algeria - Arabic", - Language.arEG: cstring"Egypt - Arabic", - Language.arIQ: cstring"Iraq - Arabic", - Language.arJO: cstring"Jordan - Arabic", - Language.arKW: cstring"Kuwait - Arabic", - Language.arLB: cstring"Lebanon - Arabic", - Language.arLY: cstring"Libya - Arabic", - Language.arMA: cstring"Morocco - Arabic", - Language.arOM: cstring"Oman - Arabic", - Language.arQA: cstring"Qatar - Arabic", - Language.arSA: cstring"Saudi Arabia - Arabic", - Language.arSY: cstring"Syria - Arabic", - Language.arTN: cstring"Tunisia - Arabic", - Language.arYE: cstring"Yemen - Arabic", - Language.arnCL: cstring"Chile - Mapudungun", - Language.asIN: cstring"India - Assamese", - Language.azAZ: cstring"Azerbaijan - Azeri (Cyrillic)", - Language.baRU: cstring"Russia - Bashkir", - Language.beBY: cstring"Belarus - Belarusian", - Language.bgBG: cstring"Bulgaria - Bulgarian", - Language.bnBD: cstring"Bangladesh - Bengali", - Language.bnIN: cstring"India - Bengali", - Language.boCN: cstring"People's Republic of China - Tibetan", - Language.brFR: cstring"France - Breton", - Language.bsBA: cstring"Bosnia and Herzegovina - Bosnian (Cyrillic)", - Language.caES: cstring"Spain - Catalan", - Language.coFR: cstring"France - Corsican", - Language.csCZ: cstring"Czech Republic - Czech", - Language.cyGB: cstring"United Kingdom - Welsh", - Language.daDK: cstring"Denmark - Danish", - Language.deAT: cstring"Austria - German", - Language.deCH: cstring"Switzerland - German", - Language.deDE: cstring"Germany - German", - Language.deLI: cstring"Liechtenstein - German", - Language.deLU: cstring"Luxembourg - German", - Language.dsbDE: cstring"Germany - Lower Sorbian", - Language.dvMV: cstring"Maldives - Divehi", - Language.elGR: cstring"Greece - Greek", - Language.en029: cstring"Caribbean - English", - Language.enAU: cstring"Australia - English", - Language.enBZ: cstring"Belize - English", - Language.enCA: cstring"Canada - English", - Language.enGB: cstring"United Kingdom - English", - Language.enIE: cstring"Ireland - English", - Language.enIN: cstring"India - English", - Language.enJM: cstring"Jamaica - English", - Language.enMY: cstring"Malaysia - English", - Language.enNZ: cstring"New Zealand - English", - Language.enPH: cstring"Republic of the Philippines - English", - Language.enSG: cstring"Singapore - English", - Language.enTT: cstring"Trinidad and Tobago - English", - Language.enUS: cstring"United States - English", - Language.enZA: cstring"South Africa - English", - Language.enZW: cstring"Zimbabwe - English", - Language.esAR: cstring"Argentina - Spanish", - Language.esBO: cstring"Bolivia - Spanish", - Language.esCL: cstring"Chile - Spanish", - Language.esCO: cstring"Colombia - Spanish", - Language.esCR: cstring"Costa Rica - Spanish", - Language.esDO: cstring"Dominican Republic - Spanish", - Language.esEC: cstring"Ecuador - Spanish", - Language.esES: cstring"Spain - Spanish", - Language.esGT: cstring"Guatemala - Spanish", - Language.esHN: cstring"Honduras - Spanish", - Language.esMX: cstring"Mexico - Spanish", - Language.esNI: cstring"Nicaragua - Spanish", - Language.esPA: cstring"Panama - Spanish", - Language.esPE: cstring"Peru - Spanish", - Language.esPR: cstring"Puerto Rico - Spanish", - Language.esPY: cstring"Paraguay - Spanish", - Language.esSV: cstring"El Salvador - Spanish", - Language.esUS: cstring"United States - Spanish", - Language.esUY: cstring"Uruguay - Spanish", - Language.esVE: cstring"Bolivarian Republic of Venezuela - Spanish", - Language.etEE: cstring"Estonia - Estonian", - Language.euES: cstring"Spain - Basque", - Language.faIR: cstring"Iran - Persian", - Language.fiFI: cstring"Finland - Finnish", - Language.filPH: cstring"Philippines - Filipino", - Language.foFO: cstring"Faroe Islands - Faroese", - Language.frBE: cstring"Belgium - French", - Language.frCA: cstring"Canada - French", - Language.frCH: cstring"Switzerland - French", - Language.frFR: cstring"France - French", - Language.frLU: cstring"Luxembourg - French", - Language.frMC: cstring"Principality of Monaco - French", - Language.fyNL: cstring"Netherlands - Frisian", - Language.gaIE: cstring"Ireland - Irish", - Language.gdGB: cstring"United Kingdom - Scottish Gaelic", - Language.glES: cstring"Spain - Galician", - Language.gswFR: cstring"France - Alsatian", - Language.guIN: cstring"India - Gujarati", - Language.haNG: cstring"Nigeria - Hausa (Latin)", - Language.heIL: cstring"Israel - Hebrew", - Language.hiIN: cstring"India - Hindi", - Language.hrBA: cstring"Bosnia and Herzegovina - Croatian", - Language.hrHR: cstring"Croatia - Croatian", - Language.hsbDE: cstring"Germany - Upper Sorbian", - Language.huHU: cstring"Hungary - Hungarian", - Language.hyAM: cstring"Armenia - Armenian", - Language.idID: cstring"Indonesia - Indonesian", - Language.igNG: cstring"Nigeria - Igbo", - Language.iiCN: cstring"People's Republic of China - Yi", - Language.isIS: cstring"Iceland - Icelandic", - Language.itCH: cstring"Switzerland - Italian", - Language.itIT: cstring"Italy - Italian", - Language.iuCA: cstring"Canada - Inuktitut (Latin)", - Language.jaJP: cstring"Japan - Japanese", - Language.kaGE: cstring"Georgia - Georgian", - Language.kkKZ: cstring"Kazakhstan - Kazakh", - Language.klGL: cstring"Greenland - Greenlandic", - Language.kmKH: cstring"Cambodia - Khmer", - Language.knIN: cstring"India - Kannada", - Language.koKR: cstring"Korea - Korean", - Language.kokIN: cstring"India - Konkani", - Language.kyKG: cstring"Kyrgyzstan - Kyrgyz", - Language.lbLU: cstring"Luxembourg - Luxembourgish", - Language.loLA: cstring"Lao P.D.R. - Lao", - Language.ltLT: cstring"Lithuania - Lithuanian", - Language.lvLV: cstring"Latvia - Latvian", - Language.miNZ: cstring"New Zealand - Maori", - Language.mkMK: cstring"Macedonia (FYROM) - Macedonian (FYROM)", - Language.mlIN: cstring"India - Malayalam", - Language.mnCN: cstring"People's Republic of China - Mongolian (Traditional Mongolian)", - Language.mnMN: cstring"Mongolia - Mongolian (Cyrillic)", - Language.mohCA: cstring"Canada - Mohawk", - Language.mrIN: cstring"India - Marathi", - Language.msBN: cstring"Brunei Darussalam - Malay", - Language.msMY: cstring"Malaysia - Malay", - Language.mtMT: cstring"Malta - Maltese", - Language.nbNO: cstring"Norway - Norwegian (Bokmal)", - Language.neNP: cstring"Nepal - Nepali", - Language.nlBE: cstring"Belgium - Dutch", - Language.nlNL: cstring"Netherlands - Dutch", - Language.nnNO: cstring"Norway - Norwegian (Nynorsk)", - Language.nsoZA: cstring"South Africa - Sesotho sa Leboa", - Language.ocFR: cstring"France - Occitan", - Language.orIN: cstring"India - Oriya", - Language.paIN: cstring"India - Punjabi", - Language.plPL: cstring"Poland - Polish", - Language.prsAF: cstring"Afghanistan - Dari", - Language.psAF: cstring"Afghanistan - Pashto", - Language.ptBR: cstring"Brazil - Portuguese", - Language.ptPT: cstring"Portugal - Portuguese", - Language.qutGT: cstring"Guatemala - K'iche", - Language.quzBO: cstring"Bolivia - Quechua", - Language.quzEC: cstring"Ecuador - Quechua", - Language.quzPE: cstring"Peru - Quechua", - Language.rmCH: cstring"Switzerland - Romansh", - Language.roRO: cstring"Romania - Romanian", - Language.ruRU: cstring"Russia - Russian", - Language.rwRW: cstring"Rwanda - Kinyarwanda", - Language.saIN: cstring"India - Sanskrit", - Language.sahRU: cstring"Russia - Yakut", - Language.seFI: cstring"Finland - Sami (Northern)", - Language.seNO: cstring"Norway - Sami (Northern)", - Language.seSE: cstring"Sweden - Sami (Northern)", - Language.siLK: cstring"Sri Lanka - Sinhala", - Language.skSK: cstring"Slovakia - Slovak", - Language.slSI: cstring"Slovenia - Slovenian", - Language.smaNO: cstring"Norway - Sami (Southern)", - Language.smaSE: cstring"Sweden - Sami (Southern)", - Language.smjNO: cstring"Norway - Sami (Lule)", - Language.smjSE: cstring"Sweden - Sami (Lule)", - Language.smnFI: cstring"Finland - Sami (Inari)", - Language.smsFI: cstring"Finland - Sami (Skolt)", - Language.sqAL: cstring"Albania - Albanian", - Language.srBA: cstring"Bosnia and Herzegovina - Serbian (Cyrillic)", - Language.srCS: cstring"Serbia and Montenegro (Former) - Serbian (Cyrillic)", - Language.srME: cstring"Montenegro - Serbian (Cyrillic)", - Language.srRS: cstring"Serbia - Serbian (Cyrillic)", - Language.svFI: cstring"Finland - Swedish", - Language.svSE: cstring"Sweden - Swedish", - Language.swKE: cstring"Kenya - Kiswahili", - Language.syrSY: cstring"Syria - Syriac", - Language.taIN: cstring"India - Tamil", - Language.teIN: cstring"India - Telugu", - Language.tgTJ: cstring"Tajikistan - Tajik (Cyrillic)", - Language.thTH: cstring"Thailand - Thai", - Language.tkTM: cstring"Turkmenistan - Turkmen", - Language.tnZA: cstring"South Africa - Setswana", - Language.trTR: cstring"Turkey - Turkish", - Language.ttRU: cstring"Russia - Tatar", - Language.tzmDZ: cstring"Algeria - Tamazight (Latin)", - Language.ugCN: cstring"People's Republic of China - Uyghur", - Language.ukUA: cstring"Ukraine - Ukrainian", - Language.urPK: cstring"Islamic Republic of Pakistan - Urdu", - Language.uzUZ: cstring"Uzbekistan - Uzbek (Cyrillic)", - Language.viVN: cstring"Vietnam - Vietnamese", - Language.woSN: cstring"Senegal - Wolof", - Language.xhZA: cstring"South Africa - isiXhosa", - Language.yoNG: cstring"Nigeria - Yoruba", - Language.zhCN: cstring"People's Republic of China - Chinese (Simplified) Legacy", - Language.zhHK: cstring"Hong Kong S.A.R. - Chinese (Traditional) Legacy", - Language.zhMO: cstring"Macao S.A.R. - Chinese (Traditional) Legacy", - Language.zhSG: cstring"Singapore - Chinese (Simplified) Legacy", - Language.zhTW: cstring"Taiwan - Chinese (Traditional) Legacy", - Language.zuZA: cstring"South Africa - isiZulu"] - - languageToCode*: array[Language, cstring] = [ - Language.afZA: cstring"af-ZA", - Language.amET: cstring"am-ET", - Language.arAE: cstring"ar-AE", - Language.arBH: cstring"ar-BH", - Language.arDZ: cstring"ar-DZ", - Language.arEG: cstring"ar-EG", - Language.arIQ: cstring"ar-IQ", - Language.arJO: cstring"ar-JO", - Language.arKW: cstring"ar-KW", - Language.arLB: cstring"ar-LB", - Language.arLY: cstring"ar-LY", - Language.arMA: cstring"ar-MA", - Language.arOM: cstring"ar-OM", - Language.arQA: cstring"ar-QA", - Language.arSA: cstring"ar-SA", - Language.arSY: cstring"ar-SY", - Language.arTN: cstring"ar-TN", - Language.arYE: cstring"ar-YE", - Language.arnCL: cstring"arn-CL", - Language.asIN: cstring"as-IN", - Language.azAZ: cstring"az-AZ", - Language.baRU: cstring"ba-RU", - Language.beBY: cstring"be-BY", - Language.bgBG: cstring"bg-BG", - Language.bnBD: cstring"bn-BD", - Language.bnIN: cstring"bn-IN", - Language.boCN: cstring"bo-CN", - Language.brFR: cstring"br-FR", - Language.bsBA: cstring"bs-BA", - Language.caES: cstring"ca-ES", - Language.coFR: cstring"co-FR", - Language.csCZ: cstring"cs-CZ", - Language.cyGB: cstring"cy-GB", - Language.daDK: cstring"da-DK", - Language.deAT: cstring"de-AT", - Language.deCH: cstring"de-CH", - Language.deDE: cstring"de-DE", - Language.deLI: cstring"de-LI", - Language.deLU: cstring"de-LU", - Language.dsbDE: cstring"dsb-DE", - Language.dvMV: cstring"dv-MV", - Language.elGR: cstring"el-GR", - Language.en029: cstring"en-029", - Language.enAU: cstring"en-AU", - Language.enBZ: cstring"en-BZ", - Language.enCA: cstring"en-CA", - Language.enGB: cstring"en-GB", - Language.enIE: cstring"en-IE", - Language.enIN: cstring"en-IN", - Language.enJM: cstring"en-JM", - Language.enMY: cstring"en-MY", - Language.enNZ: cstring"en-NZ", - Language.enPH: cstring"en-PH", - Language.enSG: cstring"en-SG", - Language.enTT: cstring"en-TT", - Language.enUS: cstring"en-US", - Language.enZA: cstring"en-ZA", - Language.enZW: cstring"en-ZW", - Language.esAR: cstring"es-AR", - Language.esBO: cstring"es-BO", - Language.esCL: cstring"es-CL", - Language.esCO: cstring"es-CO", - Language.esCR: cstring"es-CR", - Language.esDO: cstring"es-DO", - Language.esEC: cstring"es-EC", - Language.esES: cstring"es-ES", - Language.esGT: cstring"es-GT", - Language.esHN: cstring"es-HN", - Language.esMX: cstring"es-MX", - Language.esNI: cstring"es-NI", - Language.esPA: cstring"es-PA", - Language.esPE: cstring"es-PE", - Language.esPR: cstring"es-PR", - Language.esPY: cstring"es-PY", - Language.esSV: cstring"es-SV", - Language.esUS: cstring"es-US", - Language.esUY: cstring"es-UY", - Language.esVE: cstring"es-VE", - Language.etEE: cstring"et-EE", - Language.euES: cstring"eu-ES", - Language.faIR: cstring"fa-IR", - Language.fiFI: cstring"fi-FI", - Language.filPH: cstring"fil-PH", - Language.foFO: cstring"fo-FO", - Language.frBE: cstring"fr-BE", - Language.frCA: cstring"fr-CA", - Language.frCH: cstring"fr-CH", - Language.frFR: cstring"fr-FR", - Language.frLU: cstring"fr-LU", - Language.frMC: cstring"fr-MC", - Language.fyNL: cstring"fy-NL", - Language.gaIE: cstring"ga-IE", - Language.gdGB: cstring"gd-GB", - Language.glES: cstring"gl-ES", - Language.gswFR: cstring"gsw-FR", - Language.guIN: cstring"gu-IN", - Language.haNG: cstring"ha-NG", - Language.heIL: cstring"he-IL", - Language.hiIN: cstring"hi-IN", - Language.hrBA: cstring"hr-BA", - Language.hrHR: cstring"hr-HR", - Language.hsbDE: cstring"hsb-DE", - Language.huHU: cstring"hu-HU", - Language.hyAM: cstring"hy-AM", - Language.idID: cstring"id-ID", - Language.igNG: cstring"ig-NG", - Language.iiCN: cstring"ii-CN", - Language.isIS: cstring"is-IS", - Language.itCH: cstring"it-CH", - Language.itIT: cstring"it-IT", - Language.iuCA: cstring"iu-CA", - Language.jaJP: cstring"ja-JP", - Language.kaGE: cstring"ka-GE", - Language.kkKZ: cstring"kk-KZ", - Language.klGL: cstring"kl-GL", - Language.kmKH: cstring"km-KH", - Language.knIN: cstring"kn-IN", - Language.koKR: cstring"ko-KR", - Language.kokIN: cstring"kok-IN", - Language.kyKG: cstring"ky-KG", - Language.lbLU: cstring"lb-LU", - Language.loLA: cstring"lo-LA", - Language.ltLT: cstring"lt-LT", - Language.lvLV: cstring"lv-LV", - Language.miNZ: cstring"mi-NZ", - Language.mkMK: cstring"mk-MK", - Language.mlIN: cstring"ml-IN", - Language.mnCN: cstring"mn-CN", - Language.mnMN: cstring"mn-MN", - Language.mohCA: cstring"moh-CA", - Language.mrIN: cstring"mr-IN", - Language.msBN: cstring"ms-BN", - Language.msMY: cstring"ms-MY", - Language.mtMT: cstring"mt-MT", - Language.nbNO: cstring"nb-NO", - Language.neNP: cstring"ne-NP", - Language.nlBE: cstring"nl-BE", - Language.nlNL: cstring"nl-NL", - Language.nnNO: cstring"nn-NO", - Language.nsoZA: cstring"nso-ZA", - Language.ocFR: cstring"oc-FR", - Language.orIN: cstring"or-IN", - Language.paIN: cstring"pa-IN", - Language.plPL: cstring"pl-PL", - Language.prsAF: cstring"prs-AF", - Language.psAF: cstring"ps-AF", - Language.ptBR: cstring"pt-BR", - Language.ptPT: cstring"pt-PT", - Language.qutGT: cstring"qut-GT", - Language.quzBO: cstring"quz-BO", - Language.quzEC: cstring"quz-EC", - Language.quzPE: cstring"quz-PE", - Language.rmCH: cstring"rm-CH", - Language.roRO: cstring"ro-RO", - Language.ruRU: cstring"ru-RU", - Language.rwRW: cstring"rw-RW", - Language.saIN: cstring"sa-IN", - Language.sahRU: cstring"sah-RU", - Language.seFI: cstring"se-FI", - Language.seNO: cstring"se-NO", - Language.seSE: cstring"se-SE", - Language.siLK: cstring"si-LK", - Language.skSK: cstring"sk-SK", - Language.slSI: cstring"sl-SI", - Language.smaNO: cstring"sma-NO", - Language.smaSE: cstring"sma-SE", - Language.smjNO: cstring"smj-NO", - Language.smjSE: cstring"smj-SE", - Language.smnFI: cstring"smn-FI", - Language.smsFI: cstring"sms-FI", - Language.sqAL: cstring"sq-AL", - Language.srBA: cstring"sr-BA", - Language.srCS: cstring"sr-CS", - Language.srME: cstring"sr-ME", - Language.srRS: cstring"sr-RS", - Language.svFI: cstring"sv-FI", - Language.svSE: cstring"sv-SE", - Language.swKE: cstring"sw-KE", - Language.syrSY: cstring"syr-SY", - Language.taIN: cstring"ta-IN", - Language.teIN: cstring"te-IN", - Language.tgTJ: cstring"tg-TJ", - Language.thTH: cstring"th-TH", - Language.tkTM: cstring"tk-TM", - Language.tnZA: cstring"tn-ZA", - Language.trTR: cstring"tr-TR", - Language.ttRU: cstring"tt-RU", - Language.tzmDZ: cstring"tzm-DZ", - Language.ugCN: cstring"ug-CN", - Language.ukUA: cstring"uk-UA", - Language.urPK: cstring"ur-PK", - Language.uzUZ: cstring"uz-UZ", - Language.viVN: cstring"vi-VN", - Language.woSN: cstring"wo-SN", - Language.xhZA: cstring"xh-ZA", - Language.yoNG: cstring"yo-NG", - Language.zhCN: cstring"zh-CN", - Language.zhHK: cstring"zh-HK", - Language.zhMO: cstring"zh-MO", - Language.zhSG: cstring"zh-SG", - Language.zhTW: cstring"zh-TW", - Language.zuZA: cstring"zu-ZA"] diff --git a/karax/localstorage.nim b/karax/localstorage.nim deleted file mode 100644 index e2fb62e..0000000 --- a/karax/localstorage.nim +++ /dev/null @@ -1,10 +0,0 @@ -## Karax -- Single page applications for Nim. - -## This module contains wrappers for the HTML 5 local storage. - -proc getItem*(key: cstring): cstring {.importc: "localStorage.getItem".} -proc setItem*(key, value: cstring) {.importc: "localStorage.setItem".} -proc hasItem*(key: cstring): bool {.importcpp: "(localStorage.getItem(#) !== null)".} -proc clear*() {.importc: "localStorage.clear".} - -proc removeItem*(key: cstring) {.importc: "localStorage.removeItem".} diff --git a/karax/lookuptables.nim b/karax/lookuptables.nim deleted file mode 100644 index 1a1d51d..0000000 --- a/karax/lookuptables.nim +++ /dev/null @@ -1,38 +0,0 @@ - -import macros, kbase -from strutils import `%` - -macro fieldNamesAsArray*(t: typed; pattern = "$1"): untyped = - var impl = getTypeImpl(getTypeImpl(t)[1]) - if impl.kind == nnkRefTy: impl = getTypeImpl(impl[0]) - expectKind impl, nnkObjectTy - impl = impl[2] - expectKind impl, nnkRecList - result = newTree(nnkBracket) - for x in impl: - expectKind x, nnkIdentDefs - result.add(newCall(bindSym"kstring", newLit(pattern.strVal % $x[0]))) - -proc str(n: NimNode): NimNode = - if n.kind in {nnkStrLit, nnkTripleStrLit}: - result = newCall(bindSym"kstring", n) - else: - result = copyNimNode(n) - for i in 0..= 0: - x.s.delete(position) - x.broadcast(Mark) - x.broadcast(Deleted, position) - -when false: - proc `:=`[T](x: Reactive[T], f: proc(): T) = - toTrack = wrapObserver(f()) - x.value = f() - toTrack = nil - - proc map*[T, U](x: RSeq[T], f: proc(x: T): U): RSeq[U] = - let xl = x.L.value - let res = newRSeq[U](xl) - for i in 0..