added vstyles karax module for inline CSS support

This commit is contained in:
Araq 2017-05-18 15:53:58 +02:00
commit d6c7be7106
6 changed files with 175 additions and 5 deletions

View file

@ -1,5 +1,5 @@
import vdom, components, karax, karaxdsl, jdict, jstrutils, dom import vdom, vstyles, components, karax, karaxdsl, jdict, jstrutils, dom
var var
images: seq[cstring] = @[cstring"a", "b", "c", "d"] images: seq[cstring] = @[cstring"a", "b", "c", "d"]
@ -24,10 +24,20 @@ proc carousel*(key: VKey): VNode {.component.} =
clearTimeout(timer) clearTimeout(timer)
timer = setTimeout(docount, 30) timer = setTimeout(docount, 30)
let col =
case counter
of 0: cstring"#4d4d4d"
of 1: cstring"#ff00ff"
of 2: cstring"#00ffff"
of 3: cstring"#ffff00"
else: cstring"red"
result = buildHtml(tdiv(key=key)): result = buildHtml(tdiv(key=key)):
text images[counter] text images[counter]
button(onclick = next): button(onclick = next):
text "Next" text "Next"
tdiv(style = style(StyleAttr.color, col)):
text "This changes its color."
if cntdown != 5: if cntdown != 5:
text &cntdown text &cntdown

View file

@ -188,7 +188,7 @@ type
vspace*: int vspace*: int
width*: int width*: int
Style = ref StyleObj Style* = ref StyleObj
StyleObj {.importc.} = object of RootObj StyleObj {.importc.} = object of RootObj
background*: cstring background*: cstring
backgroundAttachment*: cstring backgroundAttachment*: cstring

View file

@ -1,6 +1,6 @@
## Karax -- Single page applications for Nim. ## Karax -- Single page applications for Nim.
import dom, vdom, jstrutils, components, jdict import dom, vdom, jstrutils, components, jdict, vstyles
export dom.Event export dom.Event
@ -104,6 +104,7 @@ proc vnodeToDom(n: VNode): Node =
wrapEvent(result, n, e, h) wrapEvent(result, n, e, h)
if n == toFocusV and toFocus.isNil: if n == toFocusV and toFocus.isNil:
toFocus = result toFocus = result
if not n.style.isNil: applyStyle(result, n.style)
proc same(n: VNode, e: Node): bool = proc same(n: VNode, e: Node): bool =
if toTag[n.kind] == e.nodename: if toTag[n.kind] == e.nodename:
@ -135,6 +136,7 @@ proc equalsShallow(a, b: VNode): bool =
if not equalsShallow(a[i], b[i]): return false if not equalsShallow(a[i], b[i]): return false
if not sameAttrs(a, b): return false if not sameAttrs(a, b): return false
if a.class != b.class: return false if a.class != b.class: return false
if a.style != b.style: return false
# XXX test event listeners here? # XXX test event listeners here?
return true return true

View file

@ -4,7 +4,7 @@ from strutils import startsWith, toLowerAscii
const const
StmtContext = ["kout", "inc", "echo", "dec", "!"] StmtContext = ["kout", "inc", "echo", "dec", "!"]
SpecialAttrs = ["id", "class", "value", "key"] SpecialAttrs = ["id", "class", "value", "key", "style"]
proc getName(n: NimNode): string = proc getName(n: NimNode): string =
case n.kind case n.kind

View file

@ -1,7 +1,7 @@
## Virtual DOM implementation for Karax. ## Virtual DOM implementation for Karax.
from dom import Event, Node from dom import Event, Node
import shash, macros import shash, macros, vstyles
from strutils import toUpperAscii from strutils import toUpperAscii
type type
@ -77,6 +77,7 @@ type
onkeyuplater ## vdom extension: a key was pressed and some time onkeyuplater ## vdom extension: a key was pressed and some time
## passed (useful for on-the-fly text completions) ## passed (useful for on-the-fly text completions)
macro buildLookupTables(): untyped = macro buildLookupTables(): untyped =
var a = newTree(nnkBracket) var a = newTree(nnkBracket)
for i in low(VNodeKind)..high(VNodeKind): for i in low(VNodeKind)..high(VNodeKind):
@ -99,6 +100,7 @@ buildLookupTables()
type type
EventHandler* = proc (ev: Event; target: VNode) {.closure.} EventHandler* = proc (ev: Event; target: VNode) {.closure.}
VKey* = int VKey* = int
VNode* = ref object VNode* = ref object
kind*: VNodeKind kind*: VNodeKind
key*: VKey key*: VKey
@ -109,6 +111,7 @@ type
events*: seq[(EventKind, EventHandler)] events*: seq[(EventKind, EventHandler)]
hash*: Hash hash*: Hash
validHash*: bool validHash*: bool
style*: VStyle ## the style that should be applied to the virtual node.
dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node
## is not part of the virtual DOM anymore. ## is not part of the virtual DOM anymore.
@ -143,6 +146,7 @@ proc eq*(a, b: VNode): bool =
if a.attrs.len != b.attrs.len: return false if a.attrs.len != b.attrs.len: return false
for i in 0..<a.attrs.len: for i in 0..<a.attrs.len:
if a.attrs[i] != b.attrs[i]: return false if a.attrs[i] != b.attrs[i]: return false
if a.style != b.style: return false
result = true result = true
proc setAttr*(n: VNode; key: cstring; val: cstring = "") = proc setAttr*(n: VNode; key: cstring; val: cstring = "") =

154
src/vstyles.nim Normal file
View file

@ -0,0 +1,154 @@
import dom, macros
type
StyleAttr* {.pure.} = enum ## the style attributes supported by the virtual DOM.
background
backgroundAttachment
backgroundColor
backgroundImage
backgroundPosition
backgroundRepeat
border
borderBottom
borderBottomColor
borderBottomStyle
borderBottomWidth
borderColor
borderLeft
borderLeftColor
borderLeftStyle
borderLeftWidth
borderRight
borderRightColor
borderRightStyle
borderRightWidth
borderStyle
borderTop
borderTopColor
borderTopStyle
borderTopWidth
borderWidth
bottom
captionSide
clear
clip
color
cursor
direction
display
emptyCells
cssFloat
font
fontFamily
fontSize
fontStretch
fontStyle
fontVariant
fontWeight
height
left
letterSpacing
lineHeight
listStyle
listStyleImage
listStylePosition
listStyleType
margin
marginBottom
marginLeft
marginRight
marginTop
maxHeight
maxWidth
minHeight
minWidth
overflow
padding
paddingBottom
paddingLeft
paddingRight
paddingTop
pageBreakAfter
pageBreakBefore
position
right
scrollbar3dLightColor
scrollbarArrowColor
scrollbarBaseColor
scrollbarDarkshadowColor
scrollbarFaceColor
scrollbarHighlightColor
scrollbarShadowColor
scrollbarTrackColor
tableLayout
textAlign
textDecoration
textIndent
textTransform
top
verticalAlign
visibility
width
wordSpacing
zIndex
macro buildLookupTables(): untyped =
var e = newTree(nnkBracket)
for i in low(StyleAttr)..high(StyleAttr):
e.add(newCall("cstring", newLit($i)))
template tmpl(e) {.dirty.} =
const
toStyleAttrName: array[StyleAttr, cstring] = e
result = getAst tmpl(e)
buildLookupTables()
type
VStyle* = ref object
attrs: array[StyleAttr, cstring]
mask: set[StyleAttr]
proc `==`*(a, b: VStyle): bool =
if a.isNil:
if b.isNil: return true
else: return false
elif b.isNil: return false
if a.mask != b.mask: return false
for x in a.mask:
if a.attrs[x] != b.attrs[x]: return false
return true
proc setAttr*(s: VStyle; attr: StyleAttr, value: cstring) =
assert value != nil, "value must not be nil"
s.attrs[attr] = value
incl(s.mask, attr)
proc getAttr*(s: VStyle; attr: StyleAttr): cstring =
## returns 'nil' if the attribute has not been set.
result = s.attrs[attr]
proc style*(pairs: varargs[(StyleAttr, cstring)]): VStyle =
## constructs a VStyle object from a list of (attribute, value)-pairs.
result = VStyle(mask: {})
for x in pairs:
result.setAttr x[0], x[1]
proc style*(a: StyleAttr; val: cstring): VStyle =
## constructs a VStyle object from a single (attribute, value)-pair.
result = VStyle(mask: {})
result.setAttr a, val
proc setStyle(d: Style; key, val: cstring) {.importcpp: "#[#] = #".}
proc merge*(a, b: VStyle): VStyle =
## merges two styles. ``b`` takes precedence over ``a``.
result = VStyle(mask: a.mask + b.mask)
for i in low(StyleAttr)..high(StyleAttr):
result.attrs[i] = if b.attrs[i].isNil: a.attrs[i] else: b.attrs[i]
proc applyStyle*(n: Node; s: VStyle) =
## apply the style to the real DOM node ``n``.
n.style = Style()
for x in s.mask:
n.style.setStyle(toStyleAttrName[x], s.attrs[x])