git.s-ol.nu mmm / 28653c9
facet editing with CodeMirror! s-ol 2 years ago
9 changed file(s) with 160 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
6363 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script>
6464 <script type="text/javascript" src="//unpkg.com/mermaid@8.4.0/dist/mermaid.min.js"></script>
6565 <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>
6671 <script type="text/javascript" src="/static/fengari-web/:text/javascript"></script>
6772 <script type="text/lua" src="/static/mmm/:text/lua"></script>
6873 <script type="text/lua">require 'mmm'; require 'mmm.mmmfs'</script>
00 require = relative ..., 1
11 import Key from require '.fileder'
2 import converts from require '.plugins'
2 import converts, editors from require '.plugins'
33 import get_conversions, apply_conversions from require '.conversion'
44 import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component'
5 import pre, div, nav, span, button, a, code, select, option from elements
5 import pre, div, nav, span, button, a, code, option from elements
66 import languages from require 'mmm.highlighting'
77
88 keep = (var) ->
1111 last = val or last
1212 last
1313
14 combine = (...) ->
15 res = {}
16 lists = {...}
17 for list in *lists
18 for val in *list
19 table.insert res, val
20
21 res
22
1423 casts = {
15 {
16 inp: 'text/.*',
17 out: 'mmm/dom',
18 cost: 0
19 transform: (val) =>
20 lang = @from\match 'text/(.*)'
21 languages[lang] val
22 }
2324 {
2425 inp: 'URL.*'
2526 out: 'mmm/dom'
2728 transform: (href) => span a (code href), :href
2829 }
2930 }
30
31 for convert in *converts
32 table.insert casts, convert
31 casts = combine casts, converts, editors
3332
3433 export BROWSER
3534 class Browser
127126
128127 current = @facet\get!
129128 current = current and current.name
130 with select :onchange, disabled: not fileder, value: @facet\map (f) -> f and f.name
129 with elements.select :onchange, disabled: not fileder, value: @facet\map (f) -> f and f.name
131130 has_main = fileder and fileder\has_facet ''
132131 \append option '(main)', value: '', disabled: not has_main, selected: current == ''
133132 if fileder
145144
146145 -- append or patch #browser-content
147146 main\append with get_or_create 'div', 'browser-content', class: 'content'
148 content = ReactiveVar if rehydrate then .node.lastChild else @get_content @facet\get!
149 \append keep content
147 @content = ReactiveVar if rehydrate then .node.lastChild else @get_content @facet\get!
148 \append keep @content
150149 if MODE == 'CLIENT'
151150 @facet\subscribe (p) ->
152 window\setTimeout (-> content\set @get_content p), 150
151 window\setTimeout (-> @refresh p), 150
153152
154153 if rehydrate
155154 -- force one rerender to set onclick handlers etc
164163
165164 err_and_trace = (msg) -> debug.traceback msg, 2
166165 default_convert = (key) => @get key.name, 'mmm/dom'
166
167 -- rerender main content
168 refresh: (facet=@facet\get!) =>
169 @content\set @get_content facet
167170
168171 -- render #browser-content
169172 get_content: (prop, err=@error, convert=default_convert) =>
217220 { :name } = @facet\get!
218221 @inspect_prop\set Key e.target.value
219222
220 with select :onchange
223 with elements.select :onchange
221224 \append option '(none)', value: '', disabled: true, selected: not value
222225 if fileder
223226 for value in pairs fileder.facet_keys
133133
134134 rawset t, k, v
135135
136 v = k unless v == nil
137 @facet_keys[k] = v
136 if not v
137 @facet_keys[k] = nil
138138 }
139139
140140 -- this fails with JS objects from JSON.parse
0 import pre from require 'mmm.dom'
0 import div from require 'mmm.dom'
11 import languages from require 'mmm.highlighting'
2
3 class Editor
4 o = do
5 mkobj = window\eval "(function () { return {}; })"
6 (tbl) ->
7 with obj = mkobj!
8 for k,v in pairs(tbl)
9 obj[k] = v
10
11 new: (value, mode, @fileder, @key) =>
12 @node = div class: 'editor'
13 @cm = window\CodeMirror @node, o {
14 :value
15 :mode
16 lineNumber: true
17 lineWrapping: true
18 autoRefresh: true
19 theme: 'hybrid'
20 }
21
22 @cm\on 'changes', (_, mirr) ->
23 window\clearTimeout @timeout if @timeout
24 @timeout = window\setTimeout (-> @change!), 300
25
26 change: =>
27 @timeout = nil
28 doc = @cm\getDoc!
29 if @lastState and doc\isClean @lastState
30 -- no changes since last event
31 return
32
33 @lastState = doc\changeGeneration true
34 value = doc\getValue!
35
36 @fileder.facets[@key] = value
37 BROWSER\refresh!
238
339 -- syntax-highlighted code
440 {
1248 pre languages[lang] val
1349 }
1450 }
51 editors: if MODE == 'CLIENT' then {
52 {
53 inp: 'text/([^ ]*).*'
54 out: 'mmm/dom'
55 cost: 0
56 transform: (value, fileder, key) =>
57 mode = @from\match @convert.inp
58 Editor value, mode, fileder, key
59 }
60 }
1561 }
33 import render from require '.layout'
44 import tohtml from require 'mmm.component'
55
6 keep = (var) ->
7 last = var\get!
8 var\map (val) ->
9 last = val or last
10 last
11
126 -- fix JS null values
137 js_fix = if MODE == 'CLIENT'
148 (arg) ->
2317 func = assert _load val, "#{fileder}##{key}"
2418 func!
2519
26 -- list of converts
20 -- list of converts, editors
2721 -- converts each have
2822 -- * inp - input type. can capture subtypes using `(.+)`
2923 -- * out - output type. can substitute subtypes from inp with %1, %2 etc.
3024 -- * cost - conversion cost
3125 -- * transform - function (val: inp, fileder) => val: out
3226 -- @convert, @from, @to contain the convert and the concrete types
27 editors = {}
3328 converts = {
3429 {
3530 inp: 'fn -> (.+)',
255250 for convert in *plugin.converts
256251 table.insert converts, convert
257252
253 if plugin.editors
254 for editor in *plugin.editors
255 table.insert editors, editor
256
258257 add_converts 'code'
259258 add_converts 'markdown'
260259 add_converts 'mermaid'
288287 f!
289288 }
290289
291 :converts
290 {
291 :converts
292 :editors
293 }
1414 &.inspector {
1515 top: 0;
1616 position: sticky;
17 max-height: 100vh;
17 max-height: calc(100vh - 3rem);
1818 color: #c5c8c6;
1919
2020 @include left-border;
00 footer {
11 display: flex;
22 padding: 1rem 2rem;
3 height: 1rem;
34
45 position: sticky;
56 bottom: 0;
0 /*
1 vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
2 */
3
4 /*background color*/
5 .CodeMirror.cm-s-hybrid {
6 color: #c5c8c6;
7 background: #1d1f21;
8
9 height: auto;
10
11 /*selection color*/
12 .CodeMirror-selected,
13 .CodeMirror-line::selection,
14 .CodeMirror-line > span::selection,
15 .CodeMirror-line > span > span::selection, {
16 background: #373b41;
17 }
18
19 /*foreground color*/
20 .CodeMirror-cursor {
21 border-color: #c5c8c6;
22 }
23
24 /*color: fg_yellow*/
25 .cm-keyword {
26 color: #f0c674;
27 }
28
29 /*color: fg_comment*/
30 .cm-comment,
31 .cm-meta {
32 color: #707880;
33 }
34
35 /*color: fg_red*/
36 .cm-number,
37 .cm-atom {
38 color: #cc6666
39 }
40
41 /*color: fg_green*/
42 .cm-string,
43 .cm-string-2,
44 .cm-operator {
45 color: #b5bd68;
46 }
47
48 /*color: fg_purple*/
49 .cm-attribute,
50 .cm-propery {
51 color: #b294bb;
52 }
53
54 /*color: fg_blue*/
55 .cm-tag,
56 .cm-qualifier {
57 color: #81a2be;
58 }
59
60 /*color: fg_aqua*/
61 .cm-link,
62 .cm-header,
63 .cm-hr {
64 color: #8abeb7;
65 }
66
67 /*color: fg_orange*/
68 .cm-builtin, {
69 color: #de935f;
70 }
71 }
00 @import 'defs';
11 @import 'reset';
22 @import 'hljs';
3 @import 'codemirror';
34 @import 'header';
45 @import 'footer';
56 @import 'browser';