aboutsummaryrefslogtreecommitdiffstats
path: root/lib/component.server.moon
diff options
context:
space:
mode:
Diffstat (limited to 'lib/component.server.moon')
-rw-r--r--lib/component.server.moon115
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/component.server.moon b/lib/component.server.moon
new file mode 100644
index 0000000..456ca71
--- /dev/null
+++ b/lib/component.server.moon
@@ -0,0 +1,115 @@
+-- convert anything to HTML string
+-- val must be one of:
+-- * MMMElement (have a .render method that returns a string)
+-- * string
+tohtml = (val) ->
+ if 'table' == type val
+ assert val.render, "Table doesn't have .render"
+ val = val\render!
+ if 'string' == type val
+ val
+ else
+ error "not a Node: #{val}, #{type val}"
+
+-- overloaded append
+-- see tohtml for acceptable values
+g_append = append
+append = (value) -> g_append tohtml value
+
+-- shorthand to form a text node from strings
+text = (...) -> table.concat { ... }, ' '
+
+class ReactiveVar
+ @isinstance: (val) -> 'table' == (type val) and val.subscribe
+
+ new: (@value) =>
+
+ set: (value) =>
+ error "attempting to update ReactiveVar serverside"
+
+ get: => @value
+
+ subscribe: (callback) =>
+ error "attempting to subscribe to ReactiveVar serverside"
+
+ map: (transform) =>
+ ReactiveVar transform @value
+
+class ReactiveElement
+ @isinstance: (val) -> 'table' == (type val) and val.render
+
+ new: (element, ...) =>
+ @element = element
+ @attrs = { style: {} }
+ @children = {}
+
+ children = { ... }
+
+ -- attributes are last arguments but mustn't be a ReactiveVar
+ attributes = children[#children]
+ if 'table' == (type attributes) and
+ (not ReactiveElement.isinstance attributes) and
+ (not ReactiveVar.isinstance attributes)
+ table.remove children
+ else
+ attributes = {}
+
+ for k,v in pairs attributes
+ @set k, v if 'string' == type k
+
+ -- if there is only one argument,
+ -- children can be in attributes table too
+ if #children == 0
+ children = attributes
+
+ for child in *children
+ @append child
+
+ destroy: =>
+
+ set: (attr, value) =>
+ if attr == 'style' and 'table' == type value
+ for k,v in pairs value
+ @attrs.style[k] = v
+ return
+
+ @attrs[attr] = value
+
+ append: (child, last) =>
+ assert not last, "last passed to append on server"
+ if ReactiveVar.isinstance child
+ child = child\get!
+
+ child = tohtml child
+ table.insert @children, child
+
+ remove: (child) =>
+ error "remove called serverside"
+
+ render: =>
+ b = "<#{@element}"
+ for k,v in pairs @attrs
+ if 'table' == type v
+ tmp = ''
+ for kk, vv in pairs v
+ tmp ..= "#{kk}: #{vv}; "
+ v = tmp
+ b ..= " #{k}=\"#{v}\""
+ b ..= ">" .. table.concat @children, ''
+ b ..= "</#{@element}>"
+ b
+
+with exports = {
+ :ReactiveVar,
+ :ReactiveElement,
+ :tohtml,
+ :flush,
+ :append,
+ :text,
+ }
+ add = (e) -> exports[e] = (...) -> ReactiveElement e, ...
+
+ for e in *{'div', 'form', 'span', 'a', 'p', 'button', 'ul', 'ol', 'li', 'i', 'b', 'u', 'tt'} do add e
+ for e in *{'article', 'section', 'header', 'footer', 'content'} do add e
+ for e in *{'br', 'hr', 'img', 'input', 'p', 'textarea'} do add e
+ for i=1,8 do add "h" .. i