git.s-ol.nu mmm / 4b8d9be
save edited changes s-ol 2 years ago
7 changed file(s) with 138 addition(s) and 60 deletion(s). Raw diff Collapse all Expand all
3737 print "[#{@@__name}]", "running at #{ip}:#{port}"
3838 assert @server\loop!
3939
40 handle: (method, path, facet) =>
40 handle_interactive: (fileder, facet) =>
41 root = Fileder @store
42 browser = Browser root, fileder.path, facet.name
43
44 deps = [[
45 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script>
46 <script type="text/javascript" src="//unpkg.com/mermaid@8.4.0/dist/mermaid.min.js"></script>
47 <script type="text/javascript" src="//unpkg.com/marked@0.7.0/marked.min.js"></script>
48 <link rel="stylesheet" type="text/css" href="//unpkg.com/codemirror@5.49.2/lib/codemirror.css" />
49 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/lib/codemirror.js"></script>
50 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/lua/lua.js"></script>
51 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/markdown/markdown.js"></script>
52 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/addon/display/autorefresh.js"></script>
53 <script type="text/javascript" src="/static/fengari-web/:text/javascript"></script>
54 <script type="text/lua" src="/static/mmm/:text/lua"></script>
55 <script type="text/lua">require 'mmm'; require 'mmm.mmmfs'</script>]]
56
57 render browser\todom!, fileder, noview: true, scripts: deps .. "
58 <script type=\"text/lua\">
59 on_load = on_load or {}
60 table.insert(on_load, function()
61 local path = #{string.format '%q', fileder.path}
62 local facet = #{string.format '%q', facet.name}
63 local browser = require 'mmm.mmmfs.browser'
64 local fileder = require 'mmm.mmmfs.fileder'
65 local web = require 'mmm.mmmfs.stores.web'
66
67 local store = web.WebStore({ verbose = true })
68 local root = fileder.Fileder(store, store:get_index(nil, -1))
69
70 local err_and_trace = function (msg) return debug.traceback(msg, 2) end
71 local ok, browser = xpcall(browser.Browser, err_and_trace, root, path, facet, true)
72 if not ok then error(browser) end
73 end)
74 </script>"
75
76 handle: (method, path, facet, value) =>
4177 fileder = Fileder @store, path
4278
4379 if not fileder
5692 convert 'table', facet.type, index, fileder, facet.name
5793 else
5894 if facet.type == 'text/html+interactive'
59 root = Fileder @store
60 browser = Browser root, path, facet.name
61
62 deps = [[
63 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script>
64 <script type="text/javascript" src="//unpkg.com/mermaid@8.4.0/dist/mermaid.min.js"></script>
65 <script type="text/javascript" src="//unpkg.com/marked@0.7.0/marked.min.js"></script>
66 <link rel="stylesheet" type="text/css" href="//unpkg.com/codemirror@5.49.2/lib/codemirror.css" />
67 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/lib/codemirror.js"></script>
68 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/lua/lua.js"></script>
69 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/markdown/markdown.js"></script>
70 <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/addon/display/autorefresh.js"></script>
71 <script type="text/javascript" src="/static/fengari-web/:text/javascript"></script>
72 <script type="text/lua" src="/static/mmm/:text/lua"></script>
73 <script type="text/lua">require 'mmm'; require 'mmm.mmmfs'</script>
74 ]]
75
76 render browser\todom!, fileder, noview: true, scripts: deps .. "
77 <script type=\"text/lua\">
78 on_load = on_load or {}
79 table.insert(on_load, function()
80 local path = #{string.format '%q', path}
81 local facet = #{string.format '%q', facet.name}
82 local browser = require 'mmm.mmmfs.browser'
83 local fileder = require 'mmm.mmmfs.fileder'
84 local web = require 'mmm.mmmfs.stores.web'
85
86 local store = web.WebStore({ verbose = true })
87 local root = fileder.Fileder(store, store:get_index(nil, -1))
88
89 local err_and_trace = function (msg) return debug.traceback(msg, 2) end
90 local ok, browser = xpcall(browser.Browser, err_and_trace, root, path, facet, true)
91 if not ok then error(browser) end
92 end)
93 </script>"
95 @handle_interactive fileder, facet
9496 else if not fileder\has_facet facet.name
9597 404, "facet '#{facet.name}' not found in fileder '#{path}'"
9698 else
100102 200, val
101103 else
102104 406, "cant convert facet '#{facet.name}' to '#{facet.type}'"
105 when 'POST'
106 @store\create_facet path, facet.name, facet.type, value
107 200, 'ok'
108 when 'PUT'
109 @store\update_facet path, facet.name, facet.type, value
110 200, 'ok'
111 when 'DELETE'
112 @store\remove_facet path, facet.name, facet.type
113 200, 'ok'
103114 else
104115 501, "not implemented"
105116
118129 type = type\match '%s*(.*)'
119130 facet = Key facet, type
120131
121 ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet
132 value = stream\get_body_as_string!
133 ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet, value
122134 if not ok
123135 warn "Error handling request (#{method} #{path} #{facet}):\n#{status}"
124136 body = "Internal Server Error:\n#{status}"
277277 assert value, "#{@} doesn't have value for '#{want}'"
278278 value, key
279279
280 -- set a facet value and propagate to the store
281 set: (key, key2, value) =>
282 if value
283 key = Key key, key2
284 else
285 key = Key key
286 value = key2
287
288 if @facet_keys[key]
289 @store\update_facet @path, key.name, key.type, value
290 else
291 @store\create_facet @path, key.name, key.type, value
292
293 @facets[key] = value
294
280295 __tostring: => "Fileder:#{@path}"
281296
282297 {
129129 <html>
130130 <head>
131131 <link rel="stylesheet" type="text/css" href="/static/style/:text/css" />
132 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,600" />
133 ]]
132 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,600" />]]
134133 buf ..= "
135134 #{get_meta fileder}
136135 </head>
139138
140139 #{content}
141140
142 #{footer}
143 "
141 #{footer}"
144142 buf ..= [[
145143 <script type="text/javascript" src="/static/highlight-pack/:text/javascript"></script>
146144 <script type="text/javascript">hljs.initHighlighting()</script>
147 <script type="text/javascript" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
148 ]]
145 <script type="text/javascript" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>]]
149146
150147 buf ..= opts.scripts
151148 buf ..= "
152149 </body>
153 </html>
154 "
150 </html>"
155151
156152 buf
157153
0 import div from require 'mmm.dom'
0 import div, button from require 'mmm.dom'
11 import languages from require 'mmm.highlighting'
22
33 class Editor
99 obj[k] = v
1010
1111 new: (value, mode, @fileder, @key) =>
12 @node = div class: 'editor'
12 @node = div {
13 class: 'editor'
14 style:
15 display: 'flex'
16 'flex-direction': 'column'
17 'justify-content': 'space-around'
18
19 div {
20 style:
21 display: 'flex'
22 flex: '0'
23 'justify-content': 'flex-end'
24 'border-bottom': '2px solid var(--gray-dark)'
25 'padding-bottom': '0.5em'
26 'margin': '-0.5em 0 0.5em'
27
28 with @saveBtn = button 'save changes'
29 .disabled = true
30 .onclick = (_, e) -> @save e
31 }
32 }
1333 @cm = window\CodeMirror @node, o {
1434 :value
1535 :mode
1939 theme: 'hybrid'
2040 }
2141
42 @lastSave = @cm\getDoc!\changeGeneration true
43
2244 @cm\on 'changes', (_, mirr) ->
45 doc = @cm\getDoc!
46 @saveBtn.disabled = doc\isClean @lastSave
47
2348 window\clearTimeout @timeout if @timeout
2449 @timeout = window\setTimeout (-> @change!), 300
2550
2651 change: =>
2752 @timeout = nil
2853 doc = @cm\getDoc!
29 if @lastState and doc\isClean @lastState
54
55 if @lastPreview and doc\isClean @lastPreview
3056 -- no changes since last event
3157 return
3258
33 @lastState = doc\changeGeneration true
59 @lastPreview = doc\changeGeneration!
3460 value = doc\getValue!
3561
3662 @fileder.facets[@key] = value
3763 BROWSER\refresh!
64
65 save: (e) =>
66 e\preventDefault!
67
68 doc = @cm\getDoc!
69 @fileder\set @key, doc\getValue!
70 @lastSave = doc\changeGeneration true
3871
3972 -- syntax-highlighted code
4073 {
2424 facets: [{:name, :type} for name, type in @list_facets path]
2525 children: [@get_index child, depth - 1 for child in @list_fileders_in path]
2626 }
27
28 create_fileder: => error "not implemented"
29 remove_fileder: => error "not implemented"
30 rename_fileder: => error "not implemented"
31 move_fileder: => error "not implemented"
32
33 list_facets: => error "not implemented"
34 create_facet: => error "not implemented"
35 remove_facet: => error "not implemented"
36 load_facet: => error "not implemented"
37 rename_facet: (path, name, type, next_name) =>
38 @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
39 blob = assert "no such facet", @load_facet path, name, type
40 @create_facet path, next_name, type, blob
41 @remove_facet path, name, type update_facet: => error "not implemented"
2742
2843 close: =>
2944
99
1010 dir, base
1111
12 fetch = (url) ->
12 req = (method, url, content=js.null) ->
13 if not url
14 url = method
15 method = 'GET'
16
1317 request = js.new XMLHttpRequest
14 request\open 'GET', url, false
15 request\send js.null
18 request\open method, url, false
19 request\send content
1620
1721 assert request.status == 200, "unexpected status code: #{request.status}"
1822 request.responseText
4448
4549 get_index: (path='', depth=1) =>
4650 pseudo = if depth > 1 or depth < 0 '?tree' else '?index'
47 json = fetch "#{@host .. path}/#{pseudo}: text/json"
51 json = req "#{@host .. path}/#{pseudo}: text/json"
4852 parse_json json
4953
5054 -- fileders
5155 list_fileders_in: (path='') =>
5256 coroutine.wrap ->
53 json = fetch "#{@host .. path}/?index: text/json"
57 json = req "#{@host .. path}/?index: text/json"
5458 index = parse_json json
5559 for child in js.of index.children
5660 coroutine.yield child.path
7478 -- facets
7579 list_facets: (path) =>
7680 coroutine.wrap ->
77 json = fetch "#{@host .. path}/?index: text/json"
81 json = req "#{@host .. path}/?index: text/json"
7882 index = JSON\parse json
7983 for facet in js.of index.facets
8084 coroutine.yield facet.name, facet.type
8185
8286 load_facet: (path, name, type) =>
8387 @log "loading facet #{path} #{name}: #{type}"
84 fetch "#{@host .. path}/#{name}: #{type}"
88 req "#{@host .. path}/#{name}: #{type}"
8589
8690 create_facet: (path, name, type, blob) =>
8791 @log "creating facet #{path} | #{name}: #{type}"
88 error "not implemented"
92 req 'POST', "#{@host .. path}/#{name}: #{type}", blob
8993
9094 remove_facet: (path, name, type) =>
9195 @log "removing facet #{path} | #{name}: #{type}"
92 error "not implemented"
96 req 'DELETE', "#{@host .. path}/#{name}: #{type}"
9397
9498 rename_facet: (path, name, type, next_name) =>
9599 @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
96 error "not implemented"
100 blob = assert "no such facet", @load_facet path, name, type
101 @create_facet path, next_name, type, blob
102 @remove_facet path, name, type
97103
98104 update_facet: (path, name, type, blob) =>
99105 @log "updating facet #{path} | #{name}: #{type}"
100 error "not implemented"
106 req 'PUT', "#{@host .. path}/#{name}: #{type}", blob
101107
102108 {
103109 :WebStore
77 background: #1d1f21;
88
99 height: auto;
10 flex: 1;
1011
1112 /*selection color*/
1213 .CodeMirror-selected,