nimforum/src/frontend/karaxutils.nim
2018-05-24 14:15:53 +01:00

123 lines
No EOL
3.9 KiB
Nim

import strutils, options, strformat, parseutils, tables
proc parseIntSafe*(s: string, value: var int) {.noSideEffect.} =
## parses `s` into an integer in the range `validRange`. If successful,
## `value` is modified to contain the result. Otherwise no exception is
## raised and `value` is not touched; this way a reasonable default value
## won't be overwritten.
try:
discard parseutils.parseInt(s, value, 0)
except OverflowError:
discard
proc getInt*(s: string, default = 0): int =
## Safely parses an int and returns it.
result = default
parseIntSafe(s, result)
proc getInt64*(s: string, default = 0): int64 =
## Safely parses an int and returns it.
result = default
try:
discard parseutils.parseBiggestInt(s, result, 0)
except OverflowError:
discard
when defined(js):
include karax/prelude
import karax / [kdom]
from dom import nil
const appName* = "/"
proc class*(classes: varargs[tuple[name: string, present: bool]],
defaultClasses: string = ""): string =
result = defaultClasses & " "
for class in classes:
if class.present: result.add(class.name & " ")
proc makeUri*(relative: string, appName=appName, includeHash=false,
search: string=""): string =
## Concatenates ``relative`` to the current URL in a way that is
## (possibly) sane.
var relative = relative
assert appName in $window.location.pathname
if relative[0] == '/': relative = relative[1..^1]
return $window.location.protocol & "//" &
$window.location.host &
appName &
relative &
search &
(if includeHash: $window.location.hash else: "")
proc makeUri*(relative: string, params: varargs[(string, string)],
appName=appName, includeHash=false,
reuseSearch=true): string =
var query = ""
for i in 0 ..< params.len:
let param = params[i]
if i != 0: query.add("&")
query.add(param[0] & "=" & param[1])
if query.len > 0:
var search = if reuseSearch: $window.location.search else: ""
if search.len != 0: search.add("&")
search.add(query)
if search[0] != '?': search = "?" & search
makeUri(relative, appName, search=search)
else:
makeUri(relative, appName)
proc navigateTo*(uri: cstring) =
# TODO: This was annoying. Karax also shouldn't have its own `window`.
dom.pushState(dom.window.history, 0, cstring"", uri)
# Fire the popState event.
dom.dispatchEvent(dom.window, dom.newEvent("popstate"))
proc anchorCB*(e: Event, n: VNode) =
let mE = e.MouseEvent
if not (mE.metaKey or mE.ctrlKey):
e.preventDefault()
# TODO: Why does Karax have it's own Node type? That's just silly.
let url = n.getAttr("href")
navigateTo(url)
type
FormData* = ref object
proc newFormData*(): FormData
{.importcpp: "new FormData()", constructor.}
proc newFormData*(form: dom.Element): FormData
{.importcpp: "new FormData(@)", constructor.}
proc get*(form: FormData, key: cstring): cstring
{.importcpp: "#.get(@)".}
proc append*(form: FormData, key, val: cstring)
{.importcpp: "#.append(@)".}
proc renderProfileUrl*(username: string): string =
makeUri(fmt"/profile/{username}")
proc renderPostUrl*(threadId, postId: int): string =
makeUri(fmt"/t/{threadId}#{postId}")
proc parseUrlQuery*(query: string, result: var Table[string, string])
{.deprecated: "use stdlib".} =
## Based on copy from Jester. Use stdlib when
## https://github.com/nim-lang/Nim/pull/7761 is merged.
var i = 0
i = query.skip("?")
while i < query.len()-1:
var key = ""
var val = ""
i += query.parseUntil(key, '=', i)
if query[i] != '=':
raise newException(ValueError, "Expected '=' at " & $i &
" but got: " & $query[i])
inc(i) # Skip =
i += query.parseUntil(val, '&', i)
inc(i) # Skip &
result[$decodeUri(key)] = $decodeUri(val)