aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2018-11-06 09:45:19 +0000
committers-ol <s-ol@users.noreply.github.com>2018-11-06 09:45:19 +0000
commit33ec5f940f9bd180b6bf1e847f3c6d6b1f644dcc (patch)
tree4e28fcfa45aed08f1543ae84c9f0ea5e2956a63b
parentfix mmmfs article for now (diff)
downloadmmm-33ec5f940f9bd180b6bf1e847f3c6d6b1f644dcc.tar.gz
mmm-33ec5f940f9bd180b6bf1e847f3c6d6b1f644dcc.zip
add inspector
-rw-r--r--mmm/component/init.client.moon1
-rw-r--r--mmm/component/init.server.moon16
-rw-r--r--mmm/mmmfs/browser.moon153
-rw-r--r--mmm/mmmfs/conversion.moon17
-rw-r--r--mmm/mmmfs/fileder.moon12
-rw-r--r--scss/browser.scss51
6 files changed, 154 insertions, 96 deletions
diff --git a/mmm/component/init.client.moon b/mmm/component/init.client.moon
index 86432e4..19074c5 100644
--- a/mmm/component/init.client.moon
+++ b/mmm/component/init.client.moon
@@ -14,7 +14,6 @@ tohtml = (val) ->
assert (js.instanceof val, js.global.Node), "userdata is not a Node"
val
else
- warn "NOT A NODE: #{val}, ", debug.traceback!
error "not a Node: #{val}, #{type val}"
-- shorthand to form a text node from strings
diff --git a/mmm/component/init.server.moon b/mmm/component/init.server.moon
index c9f2109..dce09e1 100644
--- a/mmm/component/init.server.moon
+++ b/mmm/component/init.server.moon
@@ -9,9 +9,7 @@ void_tags = { t,t for t in *void_tags }
-- * string
tohtml = (val) ->
if 'table' == type val
- if not val.render
- warn val
- assert val.render, "Table doesn't have .render"
+ assert val.render, "Table doesn't have .render"
val = val\render!
if 'string' == type val
val
@@ -42,7 +40,7 @@ class ReactiveElement
new: (element, ...) =>
@element = element
- @attrs = { style: {} }
+ @attrs = {}
@children = {}
children = { ... }
@@ -73,11 +71,6 @@ class ReactiveElement
if 'table' == (type value) and ReactiveVar.isinstance value
value = value\get!
- if attr == 'style' and 'table' == type value
- for k,v in opairs value
- @attrs.style[k] = v
- return
-
@attrs[attr] = value
append: (child, last) =>
@@ -85,8 +78,9 @@ class ReactiveElement
if ReactiveVar.isinstance child
child = child\get!
- child = tohtml child
- table.insert @children, child
+ if child
+ child = tohtml child
+ table.insert @children, child
remove: (child) =>
error "remove called serverside"
diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon
index 50de0f8..9bcf294 100644
--- a/mmm/mmmfs/browser.moon
+++ b/mmm/mmmfs/browser.moon
@@ -1,8 +1,24 @@
require = relative ..., 1
import Key from require '.fileder'
-import get_conversions from require '.conversion'
+import converts, get_conversions, apply_conversions from require '.conversion'
import ReactiveVar, get_or_create, text, elements from require 'mmm.component'
-import div, span, a, select, option from elements
+import pre, code, div, nav, span, button, a, select, option from elements
+
+code_cast = (lang) -> {
+ inp: "text/#{lang}.*",
+ out: 'mmm/dom',
+ transform: (val) -> pre code val
+ }
+
+casts = {
+ code_cast 'moonscript',
+ code_cast 'lua',
+ code_cast 'markdown',
+ code_cast 'html',
+}
+
+for convert in *converts
+ table.insert casts, convert
class Browser
new: (@root, path='/', rehydrate=false) =>
@@ -12,8 +28,8 @@ class Browser
-- active path
@path = ReactiveVar path
+ -- update URL bar
if MODE == 'CLIENT'
- -- update URL bar
@path\subscribe (path) ->
path ..= '/' unless '/' == path\sub -1
window.history\pushState nil, '', path
@@ -23,21 +39,24 @@ class Browser
@active = @path\map @root\walk
-- currently active property
- -- (re)set to default every time @active changes
+ -- (re)set to default when @active changes
@prop = @active\map (fileder) ->
return unless fileder
last = @prop and @prop\get!
-- (fileder\find 'mmm/dom') or next fileder.props
Key if last then last.type else 'mmm/dom'
- -- retrieve or create the root
- @dom = get_or_create 'div', 'browser-root'
+ -- whether inspect tab is active
+ @inspect = ReactiveVar false
+
+ -- retrieve or create the wrapper and main elements
+ main = get_or_create 'div', 'browser-root', class: 'main view'
-- prepend the navbar
if MODE == 'SERVER'
- @dom\append div 'please stand by... interactivity loading :)', id: 'browser-navbar'
+ main\append nav { id: 'browser-navbar', span 'please stand by... interactivity loading :)' }
else
- @dom\prepend with get_or_create 'div', 'browser-navbar'
+ main\prepend with get_or_create 'nav', 'browser-navbar'
.node.innerHTML = ''
\append span 'path: ', @path\map (path) -> with div style: { display: 'inline-block' }
path_segment = (name, href) ->
@@ -61,9 +80,8 @@ class Browser
\append '/'
\append path_segment name, href
- \append span {
- 'view property: ',
- @active\map (fileder) ->
+ \append span 'view property:', style: { 'margin-right': '0' }
+ \append @active\map (fileder) ->
onchange = (_, e) ->
{ :type } = @prop\get!
@prop\set Key name: e.target.value, :type
@@ -75,69 +93,86 @@ class Browser
for i, value in ipairs fileder\get_prop_names!
label = if value == '' then '(main)' else value
\append option label, :value, selected: value == current
--- ' as ',
--- @active\map (fileder) ->
--- onchange = (_, e) ->
--- { :name } = @prop\get!
--- @prop\set Key :name, type: e.target.value
---
--- current = @prop\get!
--- curent = current and current.type
--- with select :onchange
--- opt = (value) -> option value, :value, selected: value == current
--- \append opt 'mmm/dom'
--- \append opt 'text/plain'
--- -- if fileder
--- -- for key, _ in pairs fileder.props
--- -- value = key.type
--- -- \append option value, :value, selected: value == current
- }
+ \append @inspect\map (enabled) ->
+ if not enabled
+ button 'inspect', onclick: (_, e) -> @inspect\set true
-- append or patch #browser-content
- @dom\append with get_or_create 'div', 'browser-content'
- \append @get_content!, (rehydrate and .node.lastChild)
+ main\append with get_or_create 'div', 'browser-content', class: 'content'
+ \append (@prop\map (p) -> @get_content p), (rehydrate and .node.lastChild)
if rehydrate
-- force one rerender to set onclick handlers etc
@prop\set @prop\get!
+ inspector = @inspect\map (enabled) -> if enabled then @get_inspector!
+
-- export mmm/component interface
- @node = @dom.node
- @render = @dom\render
+ wrapper = get_or_create 'div', 'browser-wrapper', main, inspector, class: 'browser'
+ @node = wrapper.node
+ @render = wrapper\render
+
+ err_and_trace = (err) -> err, debug.traceback!
+ default_convert = (key) => @get key.name, 'mmm/dom'
-- render #browser-content
- get_content: () =>
+ get_content: (prop, convert=default_convert) =>
disp_error = (msg) -> span msg, style: { color: '#f00' }
- @prop\map (prop) ->
- active = @active\get!
+ active = @active\get!
- return disp_error "fileder not found!" unless active
- return disp_error "property not found!" unless prop
+ return disp_error "fileder not found!" unless active
+ return disp_error "property not found!" unless prop
- convert = ->
- value = active\get prop
+ ok, res, trace = xpcall convert, err_and_trace, active, prop
- return unless value
-
- conversions = get_conversions 'mmm/dom', prop.type
-
- for i=#conversions,1,-1
- { :inp, :out, :transform } = conversions[i]
- value = transform value, active, prop
-
- value
-
- ok, res, trace = xpcall convert, (err) -> err, debug.traceback!
+ if ok
+ res or disp_error "[no conversion path to #{prop.type}]"
+ elseif res\match '%[nossr%]$'
+ warn '(SSR disabled)'
+ div!
+ else
+ warn "error: #{res}", trace
+ disp_error "error: #{res}"
- if ok
- res or disp_error "[no conversion path to #{prop.type}]"
- elseif res\match '%[nossr%]$'
- warn '(SSR disabled)'
- div!
- else
- warn "error: ", res
- warn trace
- disp_error "[unknown error displaying]"
+ get_inspector: =>
+ -- active property in inspect tab
+ -- (re)set to match when @prop changes
+ @inspect_prop = @prop\map (prop) ->
+ active = @active\get!
+ key = active\find prop
+ key = key.original if key and key.original
+ key
+
+ with div class: 'view inspector'
+ \append nav {
+ span 'inspector'
+ @inspect_prop\map (current) ->
+ current = current and current\tostring!
+ fileder = @active\get!
+
+ onchange = (_, e) ->
+ { :name } = @prop\get!
+ @inspect_prop\set Key e.target.value
+
+ with select :onchange
+ if fileder
+ for key, _ in pairs fileder.props
+ value = key\tostring!
+ \append option value, :value, selected: value == current
+ @inspect\map (enabled) ->
+ if enabled
+ button 'close', onclick: (_, e) -> @inspect\set false
+ }
+ \append with div class: 'content'
+ \append @inspect_prop\map (prop) ->
+ @get_content prop, (prop) =>
+ value, key = @get prop
+
+ conversions = get_conversions 'mmm/dom', key.type, casts
+ assert conversions, "cannot cast '#{key.type}'"
+ apply_conversions conversions, value, @, prop
+
+ default_convert = (key) => @get key.name, 'mmm/dom'
navigate: (new) => @path\set new
diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon
index df7318a..6896c7d 100644
--- a/mmm/mmmfs/conversion.moon
+++ b/mmm/mmmfs/conversion.moon
@@ -105,7 +105,7 @@ escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$"
-- * want - stop type string
-- * limit - limit conversion amount
-- returns a list of conversion steps
-get_conversions = (want, have, limit=3) ->
+get_conversions = (want, have, _converts=converts, limit=3) ->
assert have, 'need starting type(s)'
if 'string' == type have
@@ -122,7 +122,7 @@ get_conversions = (want, have, limit=3) ->
if want == rest
return conversions, start
else
- for convert in *converts
+ for convert in *_converts
inp = escape_inp convert.inp
matches = { rest\match inp }
continue unless #matches > 0
@@ -138,7 +138,20 @@ get_conversions = (want, have, limit=3) ->
have = next_have
return unless #have > 0
+-- apply transforms for conversion path sequentially
+-- * conversions - conversions from get_conversions
+-- * value - value
+-- * ... - other transform parameters (fileder, key)
+-- returns converted value
+apply_conversions = (conversions, value, ...) ->
+ for i=#conversions,1,-1
+ { :inp, :out, :transform } = conversions[i]
+ value = transform value, ...
+
+ value
+
{
:converts
:get_conversions
+ :apply_conversions
}
diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon
index cd4bbe6..63fc9f8 100644
--- a/mmm/mmmfs/fileder.moon
+++ b/mmm/mmmfs/fileder.moon
@@ -1,5 +1,5 @@
require = relative ..., 1
-import get_conversions from require '.conversion'
+import get_conversions, apply_conversions from require '.conversion'
-- Key of a Fileder Property
-- contains:
@@ -143,13 +143,7 @@ class Fileder
key, conversions = @find want
if key
- value = @props[key]
-
- -- apply conversions (in reverse order)
- for i=#conversions,1,-1
- { :inp, :out, :transform } = conversions[i]
- value = transform value, @, key
-
+ value = apply_conversions conversions, @props[key], @, key
value, key
-- like @get, throw if no value or conversion path
@@ -157,7 +151,7 @@ class Fileder
want = Key ...
value, key = @get want
- assert value, "#{@} doesn't have value for '#{want\tostring!}'"
+ assert value, "#{@} doesn't have value for '#{want}'"
value, key
__tostring: => "Fileder:#{@path}"
diff --git a/scss/browser.scss b/scss/browser.scss
index 611a157..ce93604 100644
--- a/scss/browser.scss
+++ b/scss/browser.scss
@@ -1,24 +1,47 @@
-#browser-root {
+.browser {
position: absolute;
+ display: flex;
top: 0;
bottom: 0;
left: 0;
right: 0;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- #browser-navbar {
+ .view {
display: flex;
- flex: 0 0 1.2em;
- padding: 1em;
- justify-content: space-between;
- background: #eeeeee;
- }
+ flex-direction: column;
+
+ flex: 1 1 0;
+ min-width: 0;
+
+ &.inspector {
+ border-left: 8px solid #eeeeee;
+ }
+
+ nav {
+ display: flex;
+ flex: 0 0 3.2em;
+ justify-content: space-between;
+ background: #eeeeee;
+
+ /*
+ > * {
+ flex: 0 0 auto;
+ }
+ */
+
+ > span:first-of-type {
+ flex: 1 0 auto;
+ }
+
+ > * {
+ margin: 1em;
+ }
+ }
- #browser-content {
- flex: 1 0 0;
- overflow: auto;
- padding: 1em 2em;
+ .content {
+ flex: 1 1 auto;
+ overflow: auto;
+ padding: 1em 2em;
+ }
}
}