0 | |
local p = package.preload
|
1 | |
if not p["mmm.canvasapp"] then p["mmm.canvasapp"] = load("local window = js.global\
|
2 | |
local js = require('js')\
|
3 | |
local a, canvas, div, button, script\
|
4 | |
do\
|
5 | |
local _obj_0 = require('mmm.dom')\
|
6 | |
a, canvas, div, button, script = _obj_0.a, _obj_0.canvas, _obj_0.div, _obj_0.button, _obj_0.script\
|
7 | |
end\
|
8 | |
local CanvasApp\
|
9 | |
do\
|
10 | |
local _class_0\
|
11 | |
local _base_0 = {\
|
12 | |
width = 500,\
|
13 | |
height = 400,\
|
14 | |
update = function(self, dt)\
|
15 | |
self.time = self.time + dt\
|
16 | |
if self.length and self.time > self.length then\
|
17 | |
self.time = self.time - self.length\
|
18 | |
return true\
|
19 | |
end\
|
20 | |
end,\
|
21 | |
render = function(self, fps)\
|
22 | |
if fps == nil then\
|
23 | |
fps = 60\
|
24 | |
end\
|
25 | |
assert(self.length, 'cannot render CanvasApp without length set')\
|
26 | |
self.paused = true\
|
27 | |
local actual_render\
|
28 | |
actual_render = function()\
|
29 | |
local writer = js.new(window.Whammy.Video, fps)\
|
30 | |
local doFrame\
|
31 | |
doFrame = function()\
|
32 | |
local done = self:update(1 / fps)\
|
33 | |
self.ctx:resetTransform()\
|
34 | |
self:draw()\
|
35 | |
writer:add(self.canvas)\
|
36 | |
if done or self.time >= self.length then\
|
37 | |
local blob = writer:compile()\
|
38 | |
local name = tostring(self.__class.__name) .. \"_\" .. tostring(fps) .. \"fps.webm\"\
|
39 | |
return self.node.lastChild:appendChild(a(name, {\
|
40 | |
download = name,\
|
41 | |
href = window.URL:createObjectURL(blob)\
|
42 | |
}))\
|
43 | |
else\
|
44 | |
return window:setTimeout(doFrame)\
|
45 | |
end\
|
46 | |
end\
|
47 | |
self.time = 0\
|
48 | |
return doFrame()\
|
49 | |
end\
|
50 | |
if window.Whammy then\
|
51 | |
return actual_render()\
|
52 | |
else\
|
53 | |
window.global = window.global or window\
|
54 | |
return document.body:appendChild(script({\
|
55 | |
onload = actual_render,\
|
56 | |
src = 'https://cdn.jsdelivr.net/npm/whammy@0.0.1/whammy.min.js'\
|
57 | |
}))\
|
58 | |
end\
|
59 | |
end\
|
60 | |
}\
|
61 | |
_base_0.__index = _base_0\
|
62 | |
_class_0 = setmetatable({\
|
63 | |
__init = function(self, show_menu, paused)\
|
64 | |
if show_menu == nil then\
|
65 | |
show_menu = false\
|
66 | |
end\
|
67 | |
self.paused = paused\
|
68 | |
self.canvas = canvas({\
|
69 | |
width = self.width,\
|
70 | |
height = self.height\
|
71 | |
})\
|
72 | |
self.ctx = self.canvas:getContext('2d')\
|
73 | |
self.time = 0\
|
74 | |
self.canvas.tabIndex = 0\
|
75 | |
self.canvas:addEventListener('click', function(_, e)\
|
76 | |
return self.click and self:click(e.offsetX, e.offsetY, e.button)\
|
77 | |
end)\
|
78 | |
self.canvas:addEventListener('keydown', function(_, e)\
|
79 | |
return self.keydown and self:keydown(e.key, e.code)\
|
80 | |
end)\
|
81 | |
local lastMillis = window.performance:now()\
|
82 | |
local animationFrame\
|
83 | |
animationFrame = function(_, millis)\
|
84 | |
self:update((millis - lastMillis) / 1000)\
|
85 | |
self.ctx:resetTransform()\
|
86 | |
self:draw()\
|
87 | |
lastMillis = millis\
|
88 | |
if not self.paused then\
|
89 | |
return window:setTimeout((function()\
|
90 | |
return window:requestAnimationFrame(animationFrame)\
|
91 | |
end), 0)\
|
92 | |
end\
|
93 | |
end\
|
94 | |
window:requestAnimationFrame(animationFrame)\
|
95 | |
if show_menu then\
|
96 | |
self.node = div({\
|
97 | |
className = 'canvas_app',\
|
98 | |
self.canvas,\
|
99 | |
div({\
|
100 | |
className = 'overlay',\
|
101 | |
button('render 30fps', {\
|
102 | |
onclick = function()\
|
103 | |
return self:render(30)\
|
104 | |
end\
|
105 | |
}),\
|
106 | |
button('render 60fps', {\
|
107 | |
onclick = function()\
|
108 | |
return self:render(60)\
|
109 | |
end\
|
110 | |
})\
|
111 | |
})\
|
112 | |
})\
|
113 | |
else\
|
114 | |
self.node = self.canvas\
|
115 | |
end\
|
116 | |
end,\
|
117 | |
__base = _base_0,\
|
118 | |
__name = \"CanvasApp\"\
|
119 | |
}, {\
|
120 | |
__index = _base_0,\
|
121 | |
__call = function(cls, ...)\
|
122 | |
local _self_0 = setmetatable({}, _base_0)\
|
123 | |
cls.__init(_self_0, ...)\
|
124 | |
return _self_0\
|
125 | |
end\
|
126 | |
})\
|
127 | |
_base_0.__class = _class_0\
|
128 | |
CanvasApp = _class_0\
|
129 | |
end\
|
130 | |
return {\
|
131 | |
CanvasApp = CanvasApp\
|
132 | |
}\
|
133 | |
", "mmm/canvasapp.client.lua") end
|
134 | |
if not p["mmm.color"] then p["mmm.color"] = load("local rgb\
|
135 | |
rgb = function(r, g, b)\
|
136 | |
if 'table' == type(r) then\
|
137 | |
r, g, b = table.unpack(r)\
|
138 | |
end\
|
139 | |
return \"rgb(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \")\"\
|
140 | |
end\
|
141 | |
local rgba\
|
142 | |
rgba = function(r, g, b, a)\
|
143 | |
if 'table' == type(r) then\
|
144 | |
r, g, b, a = table.unpack(r)\
|
145 | |
end\
|
146 | |
return \"rgba(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \", \" .. tostring(a or 1) .. \")\"\
|
147 | |
end\
|
148 | |
local hsl\
|
149 | |
hsl = function(h, s, l)\
|
150 | |
if 'table' == type(h) then\
|
151 | |
h, s, l = table.unpack(h)\
|
152 | |
end\
|
153 | |
return \"hsl(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%)\"\
|
154 | |
end\
|
155 | |
local hsla\
|
156 | |
hsla = function(h, s, l, a)\
|
157 | |
if 'table' == type(h) then\
|
158 | |
h, s, l, a = table.unpack(h)\
|
159 | |
end\
|
160 | |
return \"hsla(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%, \" .. tostring(a or 1) .. \")\"\
|
161 | |
end\
|
162 | |
return {\
|
163 | |
rgb = rgb,\
|
164 | |
rgba = rgba,\
|
165 | |
hsl = hsl,\
|
166 | |
hsla = hsla\
|
167 | |
}\
|
168 | |
", "mmm/color.lua") end
|
169 | |
if not p["mmm.highlighting"] then p["mmm.highlighting"] = load("local code\
|
170 | |
code = require('mmm.dom').code\
|
171 | |
local highlight\
|
172 | |
local trim\
|
173 | |
trim = function(str)\
|
174 | |
return str:match('^ *(..-) *$')\
|
175 | |
end\
|
176 | |
if MODE == 'SERVER' then\
|
177 | |
highlight = function(lang, str)\
|
178 | |
assert(str, 'no string to highlight')\
|
179 | |
return code((trim(str)), {\
|
180 | |
class = \"hljs lang-\" .. tostring(lang)\
|
181 | |
})\
|
182 | |
end\
|
183 | |
else\
|
184 | |
highlight = function(lang, str)\
|
185 | |
assert(str, 'no string to highlight')\
|
186 | |
local result = window.hljs:highlight(lang, (trim(str)), true)\
|
187 | |
do\
|
188 | |
local _with_0 = code({\
|
189 | |
class = \"hljs lang-\" .. tostring(lang)\
|
190 | |
})\
|
191 | |
_with_0.innerHTML = result.value\
|
192 | |
return _with_0\
|
193 | |
end\
|
194 | |
end\
|
195 | |
end\
|
196 | |
local languages = setmetatable({ }, {\
|
197 | |
__index = function(self, name)\
|
198 | |
do\
|
199 | |
local val\
|
200 | |
val = function(str)\
|
201 | |
return highlight(name, str)\
|
202 | |
end\
|
203 | |
self[name] = val\
|
204 | |
return val\
|
205 | |
end\
|
206 | |
end\
|
207 | |
})\
|
208 | |
return {\
|
209 | |
highlight = highlight,\
|
210 | |
languages = languages\
|
211 | |
}\
|
212 | |
", "mmm/highlighting.lua") end
|
213 | |
if not p["mmm"] then p["mmm"] = load("window = js.global\
|
214 | |
local console\
|
215 | |
document, console = window.document, window.console\
|
216 | |
MODE = 'CLIENT'\
|
217 | |
local deep_tostring\
|
218 | |
deep_tostring = function(tbl, space)\
|
219 | |
if space == nil then\
|
220 | |
space = ''\
|
221 | |
end\
|
222 | |
if 'userdata' == type(tbl) then\
|
223 | |
return tbl\
|
224 | |
end\
|
225 | |
local buf = space .. tostring(tbl)\
|
226 | |
if not ('table' == type(tbl)) then\
|
227 | |
return buf\
|
228 | |
end\
|
229 | |
buf = buf .. ' {\\n'\
|
230 | |
for k, v in pairs(tbl) do\
|
231 | |
buf = buf .. tostring(space) .. \" [\" .. tostring(k) .. \"]: \" .. tostring(deep_tostring(v, space .. ' ')) .. \"\\n\"\
|
232 | |
end\
|
233 | |
buf = buf .. tostring(space) .. \"}\"\
|
234 | |
return buf\
|
235 | |
end\
|
236 | |
print = function(...)\
|
237 | |
local contents\
|
238 | |
do\
|
239 | |
local _accum_0 = { }\
|
240 | |
local _len_0 = 1\
|
241 | |
local _list_0 = {\
|
242 | |
...\
|
243 | |
}\
|
244 | |
for _index_0 = 1, #_list_0 do\
|
245 | |
local v = _list_0[_index_0]\
|
246 | |
_accum_0[_len_0] = deep_tostring(v)\
|
247 | |
_len_0 = _len_0 + 1\
|
248 | |
end\
|
249 | |
contents = _accum_0\
|
250 | |
end\
|
251 | |
return console:log(table.unpack(contents))\
|
252 | |
end\
|
253 | |
warn = function(...)\
|
254 | |
local contents\
|
255 | |
do\
|
256 | |
local _accum_0 = { }\
|
257 | |
local _len_0 = 1\
|
258 | |
local _list_0 = {\
|
259 | |
...\
|
260 | |
}\
|
261 | |
for _index_0 = 1, #_list_0 do\
|
262 | |
local v = _list_0[_index_0]\
|
263 | |
_accum_0[_len_0] = deep_tostring(v)\
|
264 | |
_len_0 = _len_0 + 1\
|
265 | |
end\
|
266 | |
contents = _accum_0\
|
267 | |
end\
|
268 | |
return console:warn(table.unpack(contents))\
|
269 | |
end\
|
270 | |
package.path = '/?.lua;/?/init.lua'\
|
271 | |
do\
|
272 | |
local _require = require\
|
273 | |
relative = function(base, sub)\
|
274 | |
if not ('number' == type(sub)) then\
|
275 | |
sub = 0\
|
276 | |
end\
|
277 | |
for i = 1, sub do\
|
278 | |
base = base:match('^(.*)%.%w+$')\
|
279 | |
end\
|
280 | |
return function(name, x)\
|
281 | |
if '.' == name:sub(1, 1) then\
|
282 | |
name = base .. name\
|
283 | |
end\
|
284 | |
return _require(name)\
|
285 | |
end\
|
286 | |
end\
|
287 | |
end\
|
288 | |
if on_load then\
|
289 | |
for _index_0 = 1, #on_load do\
|
290 | |
local f = on_load[_index_0]\
|
291 | |
f()\
|
292 | |
end\
|
293 | |
end\
|
294 | |
on_load = setmetatable({ }, {\
|
295 | |
__newindex = function(t, k, v)\
|
296 | |
rawset(t, k, v)\
|
297 | |
return v()\
|
298 | |
end\
|
299 | |
})\
|
300 | |
", "mmm/init.client.lua") end
|
301 | |
if not p["mmm.ordered"] then p["mmm.ordered"] = load("local sort\
|
302 | |
sort = function(t, order_fn, only_strings)\
|
303 | |
do\
|
304 | |
local index\
|
305 | |
do\
|
306 | |
local _accum_0 = { }\
|
307 | |
local _len_0 = 1\
|
308 | |
for k, v in pairs(t) do\
|
309 | |
if (not only_strings) or 'string' == type(k) then\
|
310 | |
_accum_0[_len_0] = k\
|
311 | |
_len_0 = _len_0 + 1\
|
312 | |
end\
|
313 | |
end\
|
314 | |
index = _accum_0\
|
315 | |
end\
|
316 | |
table.sort(index, order_fn)\
|
317 | |
return index\
|
318 | |
end\
|
319 | |
end\
|
320 | |
local onext\
|
321 | |
onext = function(state, key)\
|
322 | |
state.i = state.i + state.step\
|
323 | |
local t, index, i\
|
324 | |
t, index, i = state.t, state.index, state.i\
|
325 | |
do\
|
326 | |
key = index[i]\
|
327 | |
if key then\
|
328 | |
return key, t[key]\
|
329 | |
end\
|
330 | |
end\
|
331 | |
end\
|
332 | |
local opairs\
|
333 | |
opairs = function(t, order_fn, only_strings)\
|
334 | |
if only_strings == nil then\
|
335 | |
only_strings = false\
|
336 | |
end\
|
337 | |
local state = {\
|
338 | |
t = t,\
|
339 | |
i = 0,\
|
340 | |
step = 1,\
|
341 | |
index = sort(t, order_fn, only_strings)\
|
342 | |
}\
|
343 | |
return onext, state, nil\
|
344 | |
end\
|
345 | |
local ropairs\
|
346 | |
ropairs = function(t, order_fn, only_strings)\
|
347 | |
if only_strings == nil then\
|
348 | |
only_strings = false\
|
349 | |
end\
|
350 | |
local index = sort(t, order_fn, only_strings)\
|
351 | |
local state = {\
|
352 | |
t = t,\
|
353 | |
index = index,\
|
354 | |
i = #index + 1,\
|
355 | |
step = -1\
|
356 | |
}\
|
357 | |
return onext, state, nil\
|
358 | |
end\
|
359 | |
return {\
|
360 | |
onext = onext,\
|
361 | |
opairs = opairs,\
|
362 | |
ropairs = ropairs\
|
363 | |
}\
|
364 | |
", "mmm/ordered.lua") end
|
365 | |
if not p["mmm.mmmfs.browser"] then p["mmm.mmmfs.browser"] = load("local require = relative(..., 1)\
|
366 | |
local Key\
|
367 | |
Key = require('.fileder').Key\
|
368 | |
local converts, get_conversions, apply_conversions\
|
369 | |
do\
|
370 | |
local _obj_0 = require('.conversion')\
|
371 | |
converts, get_conversions, apply_conversions = _obj_0.converts, _obj_0.get_conversions, _obj_0.apply_conversions\
|
372 | |
end\
|
373 | |
local ReactiveVar, get_or_create, text, elements\
|
374 | |
do\
|
375 | |
local _obj_0 = require('mmm.component')\
|
376 | |
ReactiveVar, get_or_create, text, elements = _obj_0.ReactiveVar, _obj_0.get_or_create, _obj_0.text, _obj_0.elements\
|
377 | |
end\
|
378 | |
local pre, div, nav, span, button, a, code, select, option\
|
379 | |
pre, div, nav, span, button, a, code, select, option = elements.pre, elements.div, elements.nav, elements.span, elements.button, elements.a, elements.code, elements.select, elements.option\
|
380 | |
local languages\
|
381 | |
languages = require('mmm.highlighting').languages\
|
382 | |
local keep\
|
383 | |
keep = function(var)\
|
384 | |
local last = var:get()\
|
385 | |
return var:map(function(val)\
|
386 | |
last = val or last\
|
387 | |
return last\
|
388 | |
end)\
|
389 | |
end\
|
390 | |
local code_cast\
|
391 | |
code_cast = function(lang)\
|
392 | |
return {\
|
393 | |
inp = \"text/\" .. tostring(lang) .. \".*\",\
|
394 | |
out = 'mmm/dom',\
|
395 | |
transform = function(val)\
|
396 | |
return languages[lang](val)\
|
397 | |
end\
|
398 | |
}\
|
399 | |
end\
|
400 | |
local casts = {\
|
401 | |
code_cast('javascript'),\
|
402 | |
code_cast('moonscript'),\
|
403 | |
code_cast('lua'),\
|
404 | |
code_cast('markdown'),\
|
405 | |
code_cast('html'),\
|
406 | |
{\
|
407 | |
inp = 'text/plain',\
|
408 | |
out = 'mmm/dom',\
|
409 | |
transform = function(val)\
|
410 | |
return text(val)\
|
411 | |
end\
|
412 | |
},\
|
413 | |
{\
|
414 | |
inp = 'URL.*',\
|
415 | |
out = 'mmm/dom',\
|
416 | |
transform = function(href)\
|
417 | |
return span(a((code(href)), {\
|
418 | |
href = href\
|
419 | |
}))\
|
420 | |
end\
|
421 | |
}\
|
422 | |
}\
|
423 | |
for _index_0 = 1, #converts do\
|
424 | |
local convert = converts[_index_0]\
|
425 | |
table.insert(casts, convert)\
|
426 | |
end\
|
427 | |
local Browser\
|
428 | |
do\
|
429 | |
local _class_0\
|
430 | |
local err_and_trace, default_convert\
|
431 | |
local _base_0 = {\
|
432 | |
get_content = function(self, prop, err, convert)\
|
433 | |
if err == nil then\
|
434 | |
err = self.error\
|
435 | |
end\
|
436 | |
if convert == nil then\
|
437 | |
convert = default_convert\
|
438 | |
end\
|
439 | |
local clear_error\
|
440 | |
clear_error = function()\
|
441 | |
if MODE == 'CLIENT' then\
|
442 | |
return err:set()\
|
443 | |
end\
|
444 | |
end\
|
445 | |
local disp_error\
|
446 | |
disp_error = function(msg)\
|
447 | |
if MODE == 'CLIENT' then\
|
448 | |
err:set(pre(msg))\
|
449 | |
end\
|
450 | |
warn(\"ERROR rendering content: \" .. tostring(msg))\
|
451 | |
return nil\
|
452 | |
end\
|
453 | |
local active = self.active:get()\
|
454 | |
if not (active) then\
|
455 | |
return disp_error(\"fileder not found!\")\
|
456 | |
end\
|
457 | |
if not (prop) then\
|
458 | |
return disp_error(\"facet not found!\")\
|
459 | |
end\
|
460 | |
local ok, res = xpcall(convert, err_and_trace, active, prop)\
|
461 | |
if MODE == 'CLIENT' then\
|
462 | |
document.body.classList:remove('loading')\
|
463 | |
end\
|
464 | |
if ok and res then\
|
465 | |
clear_error()\
|
466 | |
return res\
|
467 | |
elseif ok then\
|
468 | |
return div(\"[no conversion path to \" .. tostring(prop.type) .. \"]\")\
|
469 | |
elseif res and res.msg.match and res.msg:match('%[nossr%]$') then\
|
470 | |
return div(\"[this page could not be pre-rendered on the server]\")\
|
471 | |
else\
|
472 | |
res = tostring(res.msg) .. \"\\n\" .. tostring(res.trace)\
|
473 | |
return disp_error(res)\
|
474 | |
end\
|
475 | |
end,\
|
476 | |
get_inspector = function(self)\
|
477 | |
self.inspect_prop = self.facet:map(function(prop)\
|
478 | |
local active = self.active:get()\
|
479 | |
local key = active and active:find(prop)\
|
480 | |
if key and key.original then\
|
481 | |
key = key.original\
|
482 | |
end\
|
483 | |
return key\
|
484 | |
end)\
|
485 | |
self.inspect_err = ReactiveVar()\
|
486 | |
do\
|
487 | |
local _with_0 = div({\
|
488 | |
class = 'view inspector'\
|
489 | |
})\
|
490 | |
_with_0:append(nav({\
|
491 | |
span('inspector'),\
|
492 | |
self.inspect_prop:map(function(current)\
|
493 | |
current = current and current:tostring()\
|
494 | |
local fileder = self.active:get()\
|
495 | |
local onchange\
|
496 | |
onchange = function(_, e)\
|
497 | |
if e.target.value == '' then\
|
498 | |
return \
|
499 | |
end\
|
500 | |
local name\
|
501 | |
name = self.facet:get().name\
|
502 | |
return self.inspect_prop:set(Key(e.target.value))\
|
503 | |
end\
|
504 | |
do\
|
505 | |
local _with_1 = select({\
|
506 | |
onchange = onchange\
|
507 | |
})\
|
508 | |
_with_1:append(option('(none)', {\
|
509 | |
value = '',\
|
510 | |
disabled = true,\
|
511 | |
selected = not value\
|
512 | |
}))\
|
513 | |
if fileder then\
|
514 | |
for key, _ in pairs(fileder.facets) do\
|
515 | |
local value = key:tostring()\
|
516 | |
_with_1:append(option(value, {\
|
517 | |
value = value,\
|
518 | |
selected = value == current\
|
519 | |
}))\
|
520 | |
end\
|
521 | |
end\
|
522 | |
return _with_1\
|
523 | |
end\
|
524 | |
end),\
|
525 | |
self.inspect:map(function(enabled)\
|
526 | |
if enabled then\
|
527 | |
return button('close', {\
|
528 | |
onclick = function(_, e)\
|
529 | |
return self.inspect:set(false)\
|
530 | |
end\
|
531 | |
})\
|
532 | |
end\
|
533 | |
end)\
|
534 | |
}))\
|
535 | |
_with_0:append((function()\
|
536 | |
do\
|
537 | |
local _with_1 = div({\
|
538 | |
class = self.inspect_err:map(function(e)\
|
539 | |
if e then\
|
540 | |
return 'error-wrap'\
|
541 | |
else\
|
542 | |
return 'error-wrap empty'\
|
543 | |
end\
|
544 | |
end)\
|
545 | |
})\
|
546 | |
_with_1:append(span(\"an error occured while rendering this view:\"))\
|
547 | |
_with_1:append(self.inspect_err)\
|
548 | |
return _with_1\
|
549 | |
end\
|
550 | |
end)())\
|
551 | |
_with_0:append((function()\
|
552 | |
do\
|
553 | |
local _with_1 = pre({\
|
554 | |
class = 'content'\
|
555 | |
})\
|
556 | |
_with_1:append(keep(self.inspect_prop:map(function(prop, old)\
|
557 | |
return self:get_content(prop, self.inspect_err, function(self, prop)\
|
558 | |
local value, key = self:get(prop)\
|
559 | |
assert(key, \"couldn't @get \" .. tostring(prop))\
|
560 | |
local conversions = get_conversions('mmm/dom', key.type, casts)\
|
561 | |
assert(conversions, \"cannot cast '\" .. tostring(key.type) .. \"'\")\
|
562 | |
return apply_conversions(conversions, value, self, prop)\
|
563 | |
end)\
|
564 | |
end)))\
|
565 | |
return _with_1\
|
566 | |
end\
|
567 | |
end)())\
|
568 | |
return _with_0\
|
569 | |
end\
|
570 | |
end,\
|
571 | |
navigate = function(self, new)\
|
572 | |
return self.path:set(new)\
|
573 | |
end\
|
574 | |
}\
|
575 | |
_base_0.__index = _base_0\
|
576 | |
_class_0 = setmetatable({\
|
577 | |
__init = function(self, root, path, rehydrate)\
|
578 | |
if rehydrate == nil then\
|
579 | |
rehydrate = false\
|
580 | |
end\
|
581 | |
self.root = root\
|
582 | |
assert(self.root, 'root fileder is nil')\
|
583 | |
self.path = ReactiveVar(path or '')\
|
584 | |
if MODE == 'CLIENT' then\
|
585 | |
local logo = document:querySelector('header h1 > svg')\
|
586 | |
local spin\
|
587 | |
spin = function()\
|
588 | |
logo.classList:add('spin')\
|
589 | |
local _ = logo.parentElement.offsetWidth\
|
590 | |
return logo.classList:remove('spin')\
|
591 | |
end\
|
592 | |
self.path:subscribe(function(path)\
|
593 | |
document.body.classList:add('loading')\
|
594 | |
spin()\
|
595 | |
if self.skip then\
|
596 | |
return \
|
597 | |
end\
|
598 | |
local vis_path = path .. ((function()\
|
599 | |
if '/' == path:sub(-1) then\
|
600 | |
return ''\
|
601 | |
else\
|
602 | |
return '/'\
|
603 | |
end\
|
604 | |
end)())\
|
605 | |
return window.history:pushState(path, '', vis_path)\
|
606 | |
end)\
|
607 | |
window.onpopstate = function(_, event)\
|
608 | |
if event.state and not event.state == js.null then\
|
609 | |
self.skip = true\
|
610 | |
self.path:set(event.state)\
|
611 | |
self.skip = nil\
|
612 | |
end\
|
613 | |
end\
|
614 | |
end\
|
615 | |
self.active = self.path:map((function()\
|
616 | |
local _base_1 = self.root\
|
617 | |
local _fn_0 = _base_1.walk\
|
618 | |
return function(...)\
|
619 | |
return _fn_0(_base_1, ...)\
|
620 | |
end\
|
621 | |
end)())\
|
622 | |
self.facet = self.active:map(function(fileder)\
|
623 | |
if not (fileder) then\
|
624 | |
return \
|
625 | |
end\
|
626 | |
local last = self.facet and self.facet:get()\
|
627 | |
return Key((function()\
|
628 | |
if last then\
|
629 | |
return last.type\
|
630 | |
else\
|
631 | |
return 'mmm/dom'\
|
632 | |
end\
|
633 | |
end)())\
|
634 | |
end)\
|
635 | |
self.inspect = ReactiveVar((MODE == 'CLIENT' and window.location.search:match('[?&]inspect')))\
|
636 | |
local main = get_or_create('div', 'browser-root', {\
|
637 | |
class = 'main view'\
|
638 | |
})\
|
639 | |
if MODE == 'SERVER' then\
|
640 | |
main:append(nav({\
|
641 | |
id = 'browser-navbar',\
|
642 | |
span('please stand by... interactivity loading :)')\
|
643 | |
}))\
|
644 | |
else\
|
645 | |
main:prepend((function()\
|
646 | |
do\
|
647 | |
local _with_0 = get_or_create('nav', 'browser-navbar')\
|
648 | |
_with_0.node.innerHTML = ''\
|
649 | |
_with_0:append(span('path: ', self.path:map(function(path)\
|
650 | |
do\
|
651 | |
local _with_1 = div({\
|
652 | |
class = 'path',\
|
653 | |
style = {\
|
654 | |
display = 'inline-block'\
|
655 | |
}\
|
656 | |
})\
|
657 | |
local path_segment\
|
658 | |
path_segment = function(name, href)\
|
659 | |
return a(name, {\
|
660 | |
href = href,\
|
661 | |
onclick = function(_, e)\
|
662 | |
e:preventDefault()\
|
663 | |
return self:navigate(href)\
|
664 | |
end\
|
665 | |
})\
|
666 | |
end\
|
667 | |
local href = ''\
|
668 | |
path = path:match('^/(.*)')\
|
669 | |
_with_1:append(path_segment('root', ''))\
|
670 | |
while path do\
|
671 | |
local name, rest = path:match('^([%w%-_%.]+)/(.*)')\
|
672 | |
if not name then\
|
673 | |
name = path\
|
674 | |
end\
|
675 | |
path = rest\
|
676 | |
href = tostring(href) .. \"/\" .. tostring(name)\
|
677 | |
_with_1:append('/')\
|
678 | |
_with_1:append(path_segment(name, href))\
|
679 | |
end\
|
680 | |
return _with_1\
|
681 | |
end\
|
682 | |
end)))\
|
683 | |
_with_0:append(span('view facet:', {\
|
684 | |
style = {\
|
685 | |
['margin-right'] = '0'\
|
686 | |
}\
|
687 | |
}))\
|
688 | |
_with_0:append(self.active:map(function(fileder)\
|
689 | |
local onchange\
|
690 | |
onchange = function(_, e)\
|
691 | |
local type\
|
692 | |
type = self.facet:get().type\
|
693 | |
return self.facet:set(Key({\
|
694 | |
name = e.target.value,\
|
695 | |
type = type\
|
696 | |
}))\
|
697 | |
end\
|
698 | |
local current = self.facet:get()\
|
699 | |
current = current and current.name\
|
700 | |
do\
|
701 | |
local _with_1 = select({\
|
702 | |
onchange = onchange,\
|
703 | |
disabled = not fileder\
|
704 | |
})\
|
705 | |
local has_main = fileder and fileder:find(current.name, '.*')\
|
706 | |
_with_1:append(option('(main)', {\
|
707 | |
value = '',\
|
708 | |
disabled = not has_main,\
|
709 | |
selected = current == ''\
|
710 | |
}))\
|
711 | |
if fileder then\
|
712 | |
for i, value in ipairs(fileder:get_facets()) do\
|
713 | |
local _continue_0 = false\
|
714 | |
repeat\
|
715 | |
if value == '' then\
|
716 | |
_continue_0 = true\
|
717 | |
break\
|
718 | |
end\
|
719 | |
_with_1:append(option(value, {\
|
720 | |
value = value,\
|
721 | |
selected = value == current\
|
722 | |
}))\
|
723 | |
_continue_0 = true\
|
724 | |
until true\
|
725 | |
if not _continue_0 then\
|
726 | |
break\
|
727 | |
end\
|
728 | |
end\
|
729 | |
end\
|
730 | |
return _with_1\
|
731 | |
end\
|
732 | |
end))\
|
733 | |
_with_0:append(self.inspect:map(function(enabled)\
|
734 | |
if not enabled then\
|
735 | |
return button('inspect', {\
|
736 | |
onclick = function(_, e)\
|
737 | |
return self.inspect:set(true)\
|
738 | |
end\
|
739 | |
})\
|
740 | |
end\
|
741 | |
end))\
|
742 | |
return _with_0\
|
743 | |
end\
|
744 | |
end)())\
|
745 | |
end\
|
746 | |
self.error = ReactiveVar()\
|
747 | |
main:append((function()\
|
748 | |
do\
|
749 | |
local _with_0 = get_or_create('div', 'browser-error', {\
|
750 | |
class = self.error:map(function(e)\
|
751 | |
if e then\
|
752 | |
return 'error-wrap'\
|
753 | |
else\
|
754 | |
return 'error-wrap empty'\
|
755 | |
end\
|
756 | |
end)\
|
757 | |
})\
|
758 | |
_with_0:append((span(\"an error occured while rendering this view:\")), (rehydrate and _with_0.node.firstChild))\
|
759 | |
_with_0:append(self.error)\
|
760 | |
return _with_0\
|
761 | |
end\
|
762 | |
end)())\
|
763 | |
main:append((function()\
|
764 | |
do\
|
765 | |
local _with_0 = get_or_create('div', 'browser-content', {\
|
766 | |
class = 'content'\
|
767 | |
})\
|
768 | |
local content = ReactiveVar((function()\
|
769 | |
if rehydrate then\
|
770 | |
return _with_0.node.lastChild\
|
771 | |
else\
|
772 | |
return self:get_content(self.facet:get())\
|
773 | |
end\
|
774 | |
end)())\
|
775 | |
_with_0:append(keep(content))\
|
776 | |
if MODE == 'CLIENT' then\
|
777 | |
self.facet:subscribe(function(p)\
|
778 | |
return window:setTimeout((function()\
|
779 | |
return content:set(self:get_content(p))\
|
780 | |
end), 150)\
|
781 | |
end)\
|
782 | |
end\
|
783 | |
return _with_0\
|
784 | |
end\
|
785 | |
end)())\
|
786 | |
if rehydrate then\
|
787 | |
self.facet:set(self.facet:get())\
|
788 | |
end\
|
789 | |
local inspector = self.inspect:map(function(enabled)\
|
790 | |
if enabled then\
|
791 | |
return self:get_inspector()\
|
792 | |
end\
|
793 | |
end)\
|
794 | |
local wrapper = get_or_create('div', 'browser-wrapper', main, inspector, {\
|
795 | |
class = 'browser'\
|
796 | |
})\
|
797 | |
self.node = wrapper.node\
|
798 | |
do\
|
799 | |
local _base_1 = wrapper\
|
800 | |
local _fn_0 = _base_1.render\
|
801 | |
self.render = function(...)\
|
802 | |
return _fn_0(_base_1, ...)\
|
803 | |
end\
|
804 | |
end\
|
805 | |
end,\
|
806 | |
__base = _base_0,\
|
807 | |
__name = \"Browser\"\
|
808 | |
}, {\
|
809 | |
__index = _base_0,\
|
810 | |
__call = function(cls, ...)\
|
811 | |
local _self_0 = setmetatable({}, _base_0)\
|
812 | |
cls.__init(_self_0, ...)\
|
813 | |
return _self_0\
|
814 | |
end\
|
815 | |
})\
|
816 | |
_base_0.__class = _class_0\
|
817 | |
local self = _class_0\
|
818 | |
err_and_trace = function(msg)\
|
819 | |
return {\
|
820 | |
msg = msg,\
|
821 | |
trace = debug.traceback()\
|
822 | |
}\
|
823 | |
end\
|
824 | |
default_convert = function(self, key)\
|
825 | |
return self:get(key.name, 'mmm/dom')\
|
826 | |
end\
|
827 | |
default_convert = function(self, key)\
|
828 | |
return self:get(key.name, 'mmm/dom')\
|
829 | |
end\
|
830 | |
Browser = _class_0\
|
831 | |
end\
|
832 | |
return {\
|
833 | |
Browser = Browser\
|
834 | |
}\
|
835 | |
", "mmm/mmmfs/browser.lua") end
|
836 | |
if not p["mmm.mmmfs.conversion"] then p["mmm.mmmfs.conversion"] = load("local require = relative(..., 1)\
|
837 | |
local converts = require('.converts')\
|
838 | |
local count\
|
839 | |
count = function(base, pattern)\
|
840 | |
if pattern == nil then\
|
841 | |
pattern = '->'\
|
842 | |
end\
|
843 | |
return select(2, base:gsub(pattern, ''))\
|
844 | |
end\
|
845 | |
local escape_pattern\
|
846 | |
escape_pattern = function(inp)\
|
847 | |
return \"^\" .. tostring(inp:gsub('([^%w])', '%%%1')) .. \"$\"\
|
848 | |
end\
|
849 | |
local escape_inp\
|
850 | |
escape_inp = function(inp)\
|
851 | |
return \"^\" .. tostring(inp:gsub('([-/])', '%%%1')) .. \"$\"\
|
852 | |
end\
|
853 | |
local get_conversions\
|
854 | |
get_conversions = function(want, have, _converts, limit)\
|
855 | |
if _converts == nil then\
|
856 | |
_converts = converts\
|
857 | |
end\
|
858 | |
if limit == nil then\
|
859 | |
limit = 5\
|
860 | |
end\
|
861 | |
assert(have, 'need starting type(s)')\
|
862 | |
if 'string' == type(have) then\
|
863 | |
have = {\
|
864 | |
have\
|
865 | |
}\
|
866 | |
end\
|
867 | |
assert(#have > 0, 'need starting type(s) (list was empty)')\
|
868 | |
want = escape_pattern(want)\
|
869 | |
local iterations = limit + math.max(table.unpack((function()\
|
870 | |
local _accum_0 = { }\
|
871 | |
local _len_0 = 1\
|
872 | |
for _index_0 = 1, #have do\
|
873 | |
local type = have[_index_0]\
|
874 | |
_accum_0[_len_0] = count(type)\
|
875 | |
_len_0 = _len_0 + 1\
|
876 | |
end\
|
877 | |
return _accum_0\
|
878 | |
end)()))\
|
879 | |
do\
|
880 | |
local _accum_0 = { }\
|
881 | |
local _len_0 = 1\
|
882 | |
for _index_0 = 1, #have do\
|
883 | |
local start = have[_index_0]\
|
884 | |
_accum_0[_len_0] = {\
|
885 | |
start = start,\
|
886 | |
rest = start,\
|
887 | |
conversions = { }\
|
888 | |
}\
|
889 | |
_len_0 = _len_0 + 1\
|
890 | |
end\
|
891 | |
have = _accum_0\
|
892 | |
end\
|
893 | |
for i = 1, iterations do\
|
894 | |
local next_have, c = { }, 1\
|
895 | |
for _index_0 = 1, #have do\
|
896 | |
local _des_0 = have[_index_0]\
|
897 | |
local start, rest, conversions\
|
898 | |
start, rest, conversions = _des_0.start, _des_0.rest, _des_0.conversions\
|
899 | |
if rest:match(want) then\
|
900 | |
return conversions, start\
|
901 | |
else\
|
902 | |
for _index_1 = 1, #_converts do\
|
903 | |
local _continue_0 = false\
|
904 | |
repeat\
|
905 | |
local convert = _converts[_index_1]\
|
906 | |
local inp = escape_inp(convert.inp)\
|
907 | |
if not (rest:match(inp)) then\
|
908 | |
_continue_0 = true\
|
909 | |
break\
|
910 | |
end\
|
911 | |
local result = rest:gsub(inp, convert.out)\
|
912 | |
if result then\
|
913 | |
next_have[c] = {\
|
914 | |
start = start,\
|
915 | |
rest = result,\
|
916 | |
conversions = {\
|
917 | |
{\
|
918 | |
convert = convert,\
|
919 | |
from = rest,\
|
920 | |
to = result\
|
921 | |
},\
|
922 | |
table.unpack(conversions)\
|
923 | |
}\
|
924 | |
}\
|
925 | |
c = c + 1\
|
926 | |
end\
|
927 | |
_continue_0 = true\
|
928 | |
until true\
|
929 | |
if not _continue_0 then\
|
930 | |
break\
|
931 | |
end\
|
932 | |
end\
|
933 | |
end\
|
934 | |
end\
|
935 | |
have = next_have\
|
936 | |
if not (#have > 0) then\
|
937 | |
return \
|
938 | |
end\
|
939 | |
end\
|
940 | |
end\
|
941 | |
local apply_conversions\
|
942 | |
apply_conversions = function(conversions, value, ...)\
|
943 | |
for i = #conversions, 1, -1 do\
|
944 | |
local step = conversions[i]\
|
945 | |
value = step.convert.transform(step, value, ...)\
|
946 | |
end\
|
947 | |
return value\
|
948 | |
end\
|
949 | |
return {\
|
950 | |
converts = converts,\
|
951 | |
get_conversions = get_conversions,\
|
952 | |
apply_conversions = apply_conversions\
|
953 | |
}\
|
954 | |
", "mmm/mmmfs/conversion.lua") end
|
955 | |
if not p["mmm.mmmfs.fileder"] then p["mmm.mmmfs.fileder"] = load("local require = relative(..., 1)\
|
956 | |
local get_conversions, apply_conversions\
|
957 | |
do\
|
958 | |
local _obj_0 = require('.conversion')\
|
959 | |
get_conversions, apply_conversions = _obj_0.get_conversions, _obj_0.apply_conversions\
|
960 | |
end\
|
961 | |
local Key\
|
962 | |
do\
|
963 | |
local _class_0\
|
964 | |
local _base_0 = {\
|
965 | |
tostring = function(self)\
|
966 | |
if self.name == '' then\
|
967 | |
return self.type\
|
968 | |
else\
|
969 | |
return tostring(self.name) .. \": \" .. tostring(self.type)\
|
970 | |
end\
|
971 | |
end,\
|
972 | |
__tostring = function(self)\
|
973 | |
return self:tostring()\
|
974 | |
end\
|
975 | |
}\
|
976 | |
_base_0.__index = _base_0\
|
977 | |
_class_0 = setmetatable({\
|
978 | |
__init = function(self, opts, second)\
|
979 | |
if 'string' == type(second) then\
|
980 | |
self.name, self.type = (opts or ''), second\
|
981 | |
elseif 'string' == type(opts) then\
|
982 | |
self.name, self.type = opts:match('^([%w-_]+): *(.+)$')\
|
983 | |
if not self.name then\
|
984 | |
self.name = ''\
|
985 | |
self.type = opts\
|
986 | |
end\
|
987 | |
elseif 'table' == type(opts) then\
|
988 | |
self.name = opts.name\
|
989 | |
self.type = opts.type\
|
990 | |
self.original = opts.original\
|
991 | |
self.filename = opts.filename\
|
992 | |
else\
|
993 | |
return error(\"wrong argument type: \" .. tostring(type(opts)) .. \", \" .. tostring(type(second)))\
|
994 | |
end\
|
995 | |
end,\
|
996 | |
__base = _base_0,\
|
997 | |
__name = \"Key\"\
|
998 | |
}, {\
|
999 | |
__index = _base_0,\
|
1000 | |
__call = function(cls, ...)\
|
1001 | |
local _self_0 = setmetatable({}, _base_0)\
|
1002 | |
cls.__init(_self_0, ...)\
|
1003 | |
return _self_0\
|
1004 | |
end\
|
1005 | |
})\
|
1006 | |
_base_0.__class = _class_0\
|
1007 | |
Key = _class_0\
|
1008 | |
end\
|
1009 | |
local Fileder\
|
1010 | |
do\
|
1011 | |
local _class_0\
|
1012 | |
local _base_0 = {\
|
1013 | |
walk = function(self, path)\
|
1014 | |
if path == '' then\
|
1015 | |
return self\
|
1016 | |
end\
|
1017 | |
if '/' ~= path:sub(1, 1) then\
|
1018 | |
path = tostring(self.path) .. \"/\" .. tostring(path)\
|
1019 | |
end\
|
1020 | |
if not (self.path == path:sub(1, #self.path)) then\
|
1021 | |
return \
|
1022 | |
end\
|
1023 | |
if #path == #self.path then\
|
1024 | |
return self\
|
1025 | |
end\
|
1026 | |
local _list_0 = self.children\
|
1027 | |
for _index_0 = 1, #_list_0 do\
|
1028 | |
local child = _list_0[_index_0]\
|
1029 | |
do\
|
1030 | |
local match = child:walk(path)\
|
1031 | |
if match then\
|
1032 | |
return match\
|
1033 | |
end\
|
1034 | |
end\
|
1035 | |
end\
|
1036 | |
end,\
|
1037 | |
mount = function(self, path, mount_as)\
|
1038 | |
if not mount_as then\
|
1039 | |
path = path .. self:gett('name: alpha')\
|
1040 | |
end\
|
1041 | |
assert(not self.path or self.path == path, \"mounted twice: \" .. tostring(self.path) .. \" and now \" .. tostring(path))\
|
1042 | |
self.path = path\
|
1043 | |
local _list_0 = self.children\
|
1044 | |
for _index_0 = 1, #_list_0 do\
|
1045 | |
local child = _list_0[_index_0]\
|
1046 | |
child:mount(self.path .. '/')\
|
1047 | |
end\
|
1048 | |
end,\
|
1049 | |
iterate = function(self, depth)\
|
1050 | |
if depth == nil then\
|
1051 | |
depth = 0\
|
1052 | |
end\
|
1053 | |
coroutine.yield(self)\
|
1054 | |
if depth == 1 then\
|
1055 | |
return \
|
1056 | |
end\
|
1057 | |
local _list_0 = self.children\
|
1058 | |
for _index_0 = 1, #_list_0 do\
|
1059 | |
local child = _list_0[_index_0]\
|
1060 | |
child:iterate(depth - 1)\
|
1061 | |
end\
|
1062 | |
end,\
|
1063 | |
get_facets = function(self)\
|
1064 | |
local names = { }\
|
1065 | |
for key in pairs(self.facets) do\
|
1066 | |
names[key.name] = true\
|
1067 | |
end\
|
1068 | |
local _accum_0 = { }\
|
1069 | |
local _len_0 = 1\
|
1070 | |
for name in pairs(names) do\
|
1071 | |
_accum_0[_len_0] = name\
|
1072 | |
_len_0 = _len_0 + 1\
|
1073 | |
end\
|
1074 | |
return _accum_0\
|
1075 | |
end,\
|
1076 | |
has = function(self, ...)\
|
1077 | |
local want = Key(...)\
|
1078 | |
for key in pairs(self.facets) do\
|
1079 | |
local _continue_0 = false\
|
1080 | |
repeat\
|
1081 | |
if key.original then\
|
1082 | |
_continue_0 = true\
|
1083 | |
break\
|
1084 | |
end\
|
1085 | |
if key.name == want.name and key.type == want.type then\
|
1086 | |
return key\
|
1087 | |
end\
|
1088 | |
_continue_0 = true\
|
1089 | |
until true\
|
1090 | |
if not _continue_0 then\
|
1091 | |
break\
|
1092 | |
end\
|
1093 | |
end\
|
1094 | |
end,\
|
1095 | |
has_facet = function(self, want)\
|
1096 | |
for key in pairs(self.facets) do\
|
1097 | |
local _continue_0 = false\
|
1098 | |
repeat\
|
1099 | |
if key.original then\
|
1100 | |
_continue_0 = true\
|
1101 | |
break\
|
1102 | |
end\
|
1103 | |
if key.name == want then\
|
1104 | |
return key\
|
1105 | |
end\
|
1106 | |
_continue_0 = true\
|
1107 | |
until true\
|
1108 | |
if not _continue_0 then\
|
1109 | |
break\
|
1110 | |
end\
|
1111 | |
end\
|
1112 | |
end,\
|
1113 | |
find = function(self, ...)\
|
1114 | |
local want = Key(...)\
|
1115 | |
local matching\
|
1116 | |
do\
|
1117 | |
local _accum_0 = { }\
|
1118 | |
local _len_0 = 1\
|
1119 | |
for key in pairs(self.facets) do\
|
1120 | |
if key.name == want.name then\
|
1121 | |
_accum_0[_len_0] = key\
|
1122 | |
_len_0 = _len_0 + 1\
|
1123 | |
end\
|
1124 | |
end\
|
1125 | |
matching = _accum_0\
|
1126 | |
end\
|
1127 | |
if not (#matching > 0) then\
|
1128 | |
return \
|
1129 | |
end\
|
1130 | |
local shortest_path, start = get_conversions(want.type, (function()\
|
1131 | |
local _accum_0 = { }\
|
1132 | |
local _len_0 = 1\
|
1133 | |
for _index_0 = 1, #matching do\
|
1134 | |
local key = matching[_index_0]\
|
1135 | |
_accum_0[_len_0] = key.type\
|
1136 | |
_len_0 = _len_0 + 1\
|
1137 | |
end\
|
1138 | |
return _accum_0\
|
1139 | |
end)())\
|
1140 | |
if start then\
|
1141 | |
for _index_0 = 1, #matching do\
|
1142 | |
local key = matching[_index_0]\
|
1143 | |
if key.type == start then\
|
1144 | |
return key, shortest_path\
|
1145 | |
end\
|
1146 | |
end\
|
1147 | |
return error(\"couldn't find key after resolution?\")\
|
1148 | |
end\
|
1149 | |
end,\
|
1150 | |
get = function(self, ...)\
|
1151 | |
local want = Key(...)\
|
1152 | |
local key, conversions = self:find(want)\
|
1153 | |
if key then\
|
1154 | |
local value = apply_conversions(conversions, self.facets[key], self, key)\
|
1155 | |
return value, key\
|
1156 | |
end\
|
1157 | |
end,\
|
1158 | |
gett = function(self, ...)\
|
1159 | |
local want = Key(...)\
|
1160 | |
local value, key = self:get(want)\
|
1161 | |
assert(value, tostring(self) .. \" doesn't have value for '\" .. tostring(want) .. \"'\")\
|
1162 | |
return value, key\
|
1163 | |
end,\
|
1164 | |
__tostring = function(self)\
|
1165 | |
return \"Fileder:\" .. tostring(self.path)\
|
1166 | |
end\
|
1167 | |
}\
|
1168 | |
_base_0.__index = _base_0\
|
1169 | |
_class_0 = setmetatable({\
|
1170 | |
__init = function(self, facets, children)\
|
1171 | |
if not children then\
|
1172 | |
do\
|
1173 | |
local _accum_0 = { }\
|
1174 | |
local _len_0 = 1\
|
1175 | |
for i, child in ipairs(facets) do\
|
1176 | |
facets[i] = nil\
|
1177 | |
local _value_0 = child\
|
1178 | |
_accum_0[_len_0] = _value_0\
|
1179 | |
_len_0 = _len_0 + 1\
|
1180 | |
end\
|
1181 | |
children = _accum_0\
|
1182 | |
end\
|
1183 | |
end\
|
1184 | |
self.children = setmetatable({ }, {\
|
1185 | |
__index = function(t, k)\
|
1186 | |
if not ('string' == type(k)) then\
|
1187 | |
return rawget(t, k)\
|
1188 | |
end\
|
1189 | |
return self:walk(tostring(self.path) .. \"/\" .. tostring(k))\
|
1190 | |
end,\
|
1191 | |
__newindex = function(t, k, child)\
|
1192 | |
rawset(t, k, child)\
|
1193 | |
if self.path == '/' then\
|
1194 | |
return child:mount('/')\
|
1195 | |
elseif self.path then\
|
1196 | |
return child:mount(self.path .. '/')\
|
1197 | |
end\
|
1198 | |
end\
|
1199 | |
})\
|
1200 | |
for i, child in ipairs(children) do\
|
1201 | |
self.children[i] = child\
|
1202 | |
end\
|
1203 | |
self.facets = setmetatable({ }, {\
|
1204 | |
__newindex = function(t, key, v)\
|
1205 | |
return rawset(t, (Key(key)), v)\
|
1206 | |
end\
|
1207 | |
})\
|
1208 | |
for k, v in pairs(facets) do\
|
1209 | |
self.facets[k] = v\
|
1210 | |
end\
|
1211 | |
end,\
|
1212 | |
__base = _base_0,\
|
1213 | |
__name = \"Fileder\"\
|
1214 | |
}, {\
|
1215 | |
__index = _base_0,\
|
1216 | |
__call = function(cls, ...)\
|
1217 | |
local _self_0 = setmetatable({}, _base_0)\
|
1218 | |
cls.__init(_self_0, ...)\
|
1219 | |
return _self_0\
|
1220 | |
end\
|
1221 | |
})\
|
1222 | |
_base_0.__class = _class_0\
|
1223 | |
Fileder = _class_0\
|
1224 | |
end\
|
1225 | |
local dir_base\
|
1226 | |
dir_base = function(path)\
|
1227 | |
local dir, base = path:match('(.-)([^/]-)$')\
|
1228 | |
if dir and #dir > 0 then\
|
1229 | |
dir = dir:sub(1, #dir - 1)\
|
1230 | |
end\
|
1231 | |
return dir, base\
|
1232 | |
end\
|
1233 | |
local load_tree\
|
1234 | |
load_tree = function(store, root)\
|
1235 | |
if root == nil then\
|
1236 | |
root = ''\
|
1237 | |
end\
|
1238 | |
local fileders = setmetatable({ }, {\
|
1239 | |
__index = function(self, path)\
|
1240 | |
do\
|
1241 | |
local val = Fileder({ })\
|
1242 | |
val.path = path\
|
1243 | |
rawset(self, path, val)\
|
1244 | |
return val\
|
1245 | |
end\
|
1246 | |
end\
|
1247 | |
})\
|
1248 | |
root = fileders[root]\
|
1249 | |
root.facets['name: alpha'] = ''\
|
1250 | |
for fn, ft in store:list_facets(root.path) do\
|
1251 | |
local val = store:load_facet(root.path, fn, ft)\
|
1252 | |
root.facets[Key(fn, ft)] = val\
|
1253 | |
end\
|
1254 | |
for path in store:list_all_fileders(root.path) do\
|
1255 | |
local fileder = fileders[path]\
|
1256 | |
local parent, name = dir_base(path)\
|
1257 | |
fileder.facets['name: alpha'] = name\
|
1258 | |
table.insert(fileders[parent].children, fileder)\
|
1259 | |
for fn, ft in store:list_facets(path) do\
|
1260 | |
local val = store:load_facet(path, fn, ft)\
|
1261 | |
fileder.facets[Key(fn, ft)] = val\
|
1262 | |
end\
|
1263 | |
end\
|
1264 | |
return root\
|
1265 | |
end\
|
1266 | |
return {\
|
1267 | |
Key = Key,\
|
1268 | |
Fileder = Fileder,\
|
1269 | |
dir_base = dir_base,\
|
1270 | |
load_tree = load_tree\
|
1271 | |
}\
|
1272 | |
", "mmm/mmmfs/fileder.lua") end
|
1273 | |
if not p["mmm.mmmfs"] then p["mmm.mmmfs"] = load("local require = relative(...)\
|
1274 | |
local Key, Fileder\
|
1275 | |
do\
|
1276 | |
local _obj_0 = require('.fileder')\
|
1277 | |
Key, Fileder = _obj_0.Key, _obj_0.Fileder\
|
1278 | |
end\
|
1279 | |
local Browser\
|
1280 | |
Browser = require('.browser').Browser\
|
1281 | |
return {\
|
1282 | |
Key = Key,\
|
1283 | |
Fileder = Fileder,\
|
1284 | |
Browser = Browser\
|
1285 | |
}\
|
1286 | |
", "mmm/mmmfs/init.lua") end
|
1287 | |
if not p["mmm.mmmfs.util"] then p["mmm.mmmfs.util"] = load("local merge\
|
1288 | |
merge = function(orig, extra)\
|
1289 | |
if orig == nil then\
|
1290 | |
orig = { }\
|
1291 | |
end\
|
1292 | |
do\
|
1293 | |
local attr\
|
1294 | |
do\
|
1295 | |
local _tbl_0 = { }\
|
1296 | |
for k, v in pairs(orig) do\
|
1297 | |
_tbl_0[k] = v\
|
1298 | |
end\
|
1299 | |
attr = _tbl_0\
|
1300 | |
end\
|
1301 | |
for k, v in pairs(extra) do\
|
1302 | |
attr[k] = v\
|
1303 | |
end\
|
1304 | |
return attr\
|
1305 | |
end\
|
1306 | |
end\
|
1307 | |
local tourl\
|
1308 | |
tourl = function(path)\
|
1309 | |
if STATIC then\
|
1310 | |
return path .. '/'\
|
1311 | |
else\
|
1312 | |
return path .. '/'\
|
1313 | |
end\
|
1314 | |
end\
|
1315 | |
return function(elements)\
|
1316 | |
local a, div, pre\
|
1317 | |
a, div, pre = elements.a, elements.div, elements.pre\
|
1318 | |
local find_fileder\
|
1319 | |
find_fileder = function(fileder, origin)\
|
1320 | |
if 'string' == type(fileder) then\
|
1321 | |
assert(origin, \"cannot resolve path '\" .. tostring(fileder) .. \"' without origin!\")\
|
1322 | |
return assert((origin:walk(fileder)), \"couldn't resolve path '\" .. tostring(fileder) .. \"' from \" .. tostring(origin))\
|
1323 | |
else\
|
1324 | |
return assert(fileder, \"no fileder passed.\")\
|
1325 | |
end\
|
1326 | |
end\
|
1327 | |
local navigate_to\
|
1328 | |
navigate_to = function(path, name, opts)\
|
1329 | |
if opts == nil then\
|
1330 | |
opts = { }\
|
1331 | |
end\
|
1332 | |
opts.href = tourl(path)\
|
1333 | |
if MODE == 'CLIENT' then\
|
1334 | |
opts.onclick = function(self, e)\
|
1335 | |
e:preventDefault()\
|
1336 | |
return BROWSER:navigate(path)\
|
1337 | |
end\
|
1338 | |
end\
|
1339 | |
return a(name, opts)\
|
1340 | |
end\
|
1341 | |
local link_to\
|
1342 | |
link_to = function(fileder, name, origin, attr)\
|
1343 | |
fileder = find_fileder(fileder, origin)\
|
1344 | |
name = name or fileder:get('title: mmm/dom')\
|
1345 | |
name = name or fileder:gett('name: alpha')\
|
1346 | |
do\
|
1347 | |
local href = fileder:get('link: URL.*')\
|
1348 | |
if href then\
|
1349 | |
return a(name, merge(attr, {\
|
1350 | |
href = href,\
|
1351 | |
target = '_blank'\
|
1352 | |
}))\
|
1353 | |
else\
|
1354 | |
return a(name, merge(attr, {\
|
1355 | |
href = tourl(fileder.path),\
|
1356 | |
onclick = (function()\
|
1357 | |
if MODE == 'CLIENT' then\
|
1358 | |
return function(self, e)\
|
1359 | |
e:preventDefault()\
|
1360 | |
return BROWSER:navigate(fileder.path)\
|
1361 | |
end\
|
1362 | |
end\
|
1363 | |
end)()\
|
1364 | |
}))\
|
1365 | |
end\
|
1366 | |
end\
|
1367 | |
end\
|
1368 | |
local embed\
|
1369 | |
embed = function(fileder, name, origin, opts)\
|
1370 | |
if name == nil then\
|
1371 | |
name = ''\
|
1372 | |
end\
|
1373 | |
if opts == nil then\
|
1374 | |
opts = { }\
|
1375 | |
end\
|
1376 | |
fileder = find_fileder(fileder, origin)\
|
1377 | |
local ok, node = pcall(fileder.gett, fileder, name, 'mmm/dom')\
|
1378 | |
if not ok then\
|
1379 | |
return div(\"couldn't embed \" .. tostring(fileder) .. \" \" .. tostring(name), (pre(node)), {\
|
1380 | |
style = {\
|
1381 | |
background = 'var(--gray-fail)',\
|
1382 | |
padding = '1em'\
|
1383 | |
}\
|
1384 | |
})\
|
1385 | |
end\
|
1386 | |
local klass = 'embed'\
|
1387 | |
if opts.desc then\
|
1388 | |
klass = klass .. ' desc'\
|
1389 | |
end\
|
1390 | |
if opts.inline then\
|
1391 | |
klass = klass .. ' inline'\
|
1392 | |
end\
|
1393 | |
node = div({\
|
1394 | |
class = klass,\
|
1395 | |
node,\
|
1396 | |
(function()\
|
1397 | |
if opts.desc then\
|
1398 | |
return div(opts.desc, {\
|
1399 | |
class = 'description'\
|
1400 | |
})\
|
1401 | |
end\
|
1402 | |
end)()\
|
1403 | |
})\
|
1404 | |
if opts.nolink then\
|
1405 | |
return node\
|
1406 | |
end\
|
1407 | |
return link_to(fileder, node, nil, opts.attr)\
|
1408 | |
end\
|
1409 | |
return {\
|
1410 | |
find_fileder = find_fileder,\
|
1411 | |
link_to = link_to,\
|
1412 | |
navigate_to = navigate_to,\
|
1413 | |
embed = embed\
|
1414 | |
}\
|
1415 | |
end\
|
1416 | |
", "mmm/mmmfs/util.lua") end
|
1417 | |
if not p["mmm.mmmfs.converts"] then p["mmm.mmmfs.converts"] = load("local require = relative(..., 1)\
|
1418 | |
local div, code, img, video, blockquote, a, span, source, iframe\
|
1419 | |
do\
|
1420 | |
local _obj_0 = require('mmm.dom')\
|
1421 | |
div, code, img, video, blockquote, a, span, source, iframe = _obj_0.div, _obj_0.code, _obj_0.img, _obj_0.video, _obj_0.blockquote, _obj_0.a, _obj_0.span, _obj_0.source, _obj_0.iframe\
|
1422 | |
end\
|
1423 | |
local find_fileder, link_to, embed\
|
1424 | |
do\
|
1425 | |
local _obj_0 = (require('mmm.mmmfs.util'))(require('mmm.dom'))\
|
1426 | |
find_fileder, link_to, embed = _obj_0.find_fileder, _obj_0.link_to, _obj_0.embed\
|
1427 | |
end\
|
1428 | |
local render\
|
1429 | |
render = require('.layout').render\
|
1430 | |
local tohtml\
|
1431 | |
tohtml = require('mmm.component').tohtml\
|
1432 | |
local js_fix\
|
1433 | |
if MODE == 'CLIENT' then\
|
1434 | |
js_fix = function(arg)\
|
1435 | |
if arg == js.null then\
|
1436 | |
return \
|
1437 | |
end\
|
1438 | |
return arg\
|
1439 | |
end\
|
1440 | |
end\
|
1441 | |
local single\
|
1442 | |
single = function(func)\
|
1443 | |
return function(self, val)\
|
1444 | |
return func(val)\
|
1445 | |
end\
|
1446 | |
end\
|
1447 | |
local loadwith\
|
1448 | |
loadwith = function(_load)\
|
1449 | |
return function(self, val, fileder, key)\
|
1450 | |
local func = assert(_load(val, tostring(fileder) .. \"#\" .. tostring(key)))\
|
1451 | |
return func()\
|
1452 | |
end\
|
1453 | |
end\
|
1454 | |
local converts = {\
|
1455 | |
{\
|
1456 | |
inp = 'fn -> (.+)',\
|
1457 | |
out = '%1',\
|
1458 | |
transform = function(self, val, fileder)\
|
1459 | |
return val(fileder)\
|
1460 | |
end\
|
1461 | |
},\
|
1462 | |
{\
|
1463 | |
inp = 'mmm/component',\
|
1464 | |
out = 'mmm/dom',\
|
1465 | |
transform = single(tohtml)\
|
1466 | |
},\
|
1467 | |
{\
|
1468 | |
inp = 'mmm/dom',\
|
1469 | |
out = 'text/html+frag',\
|
1470 | |
transform = function(self, node)\
|
1471 | |
if MODE == 'SERVER' then\
|
1472 | |
return node\
|
1473 | |
else\
|
1474 | |
return node.outerHTML\
|
1475 | |
end\
|
1476 | |
end\
|
1477 | |
},\
|
1478 | |
{\
|
1479 | |
inp = 'mmm/dom',\
|
1480 | |
out = 'text/html',\
|
1481 | |
transform = function(self, html, fileder)\
|
1482 | |
return render(html, fileder)\
|
1483 | |
end\
|
1484 | |
},\
|
1485 | |
{\
|
1486 | |
inp = 'text/html%+frag',\
|
1487 | |
out = 'mmm/dom',\
|
1488 | |
transform = (function()\
|
1489 | |
if MODE == 'SERVER' then\
|
1490 | |
return function(self, html, fileder)\
|
1491 | |
html = html:gsub('<mmm%-link%s+(.-)>(.-)</mmm%-link>', function(attrs, text)\
|
1492 | |
if #text == 0 then\
|
1493 | |
text = nil\
|
1494 | |
end\
|
1495 | |
local path = ''\
|
1496 | |
while attrs and attrs ~= '' do\
|
1497 | |
local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\
|
1498 | |
if not key then\
|
1499 | |
key, _attrs = attrs:match('^(%w+)%s*(.*)$')\
|
1500 | |
val = true\
|
1501 | |
end\
|
1502 | |
attrs = _attrs\
|
1503 | |
local _exp_0 = key\
|
1504 | |
if 'path' == _exp_0 then\
|
1505 | |
path = val\
|
1506 | |
else\
|
1507 | |
warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in <mmm-link>\")\
|
1508 | |
end\
|
1509 | |
end\
|
1510 | |
return link_to(path, text, fileder)\
|
1511 | |
end)\
|
1512 | |
html = html:gsub('<mmm%-embed%s+(.-)>(.-)</mmm%-embed>', function(attrs, desc)\
|
1513 | |
local path, facet = '', ''\
|
1514 | |
local opts = { }\
|
1515 | |
if #desc ~= 0 then\
|
1516 | |
opts.desc = desc\
|
1517 | |
end\
|
1518 | |
while attrs and attrs ~= '' do\
|
1519 | |
local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\
|
1520 | |
if not key then\
|
1521 | |
key, _attrs = attrs:match('^(%w+)%s*(.*)$')\
|
1522 | |
val = true\
|
1523 | |
end\
|
1524 | |
attrs = _attrs\
|
1525 | |
local _exp_0 = key\
|
1526 | |
if 'path' == _exp_0 then\
|
1527 | |
path = val\
|
1528 | |
elseif 'facet' == _exp_0 then\
|
1529 | |
facet = val\
|
1530 | |
elseif 'nolink' == _exp_0 then\
|
1531 | |
opts.nolink = true\
|
1532 | |
elseif 'inline' == _exp_0 then\
|
1533 | |
opts.inline = true\
|
1534 | |
else\
|
1535 | |
warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in <mmm-embed>\")\
|
1536 | |
end\
|
1537 | |
end\
|
1538 | |
return embed(path, facet, fileder, opts)\
|
1539 | |
end)\
|
1540 | |
return html\
|
1541 | |
end\
|
1542 | |
else\
|
1543 | |
return function(self, html, fileder)\
|
1544 | |
local parent\
|
1545 | |
do\
|
1546 | |
local _with_0 = document:createElement('div')\
|
1547 | |
_with_0.innerHTML = html\
|
1548 | |
local embeds = _with_0:getElementsByTagName('mmm-embed')\
|
1549 | |
do\
|
1550 | |
local _accum_0 = { }\
|
1551 | |
local _len_0 = 1\
|
1552 | |
for i = 0, embeds.length - 1 do\
|
1553 | |
_accum_0[_len_0] = embeds[i]\
|
1554 | |
_len_0 = _len_0 + 1\
|
1555 | |
end\
|
1556 | |
embeds = _accum_0\
|
1557 | |
end\
|
1558 | |
for _index_0 = 1, #embeds do\
|
1559 | |
local element = embeds[_index_0]\
|
1560 | |
local path = js_fix(element:getAttribute('path'))\
|
1561 | |
local facet = js_fix(element:getAttribute('facet'))\
|
1562 | |
local nolink = js_fix(element:getAttribute('nolink'))\
|
1563 | |
local inline = js_fix(element:getAttribute('inline'))\
|
1564 | |
local desc = js_fix(element.innerText)\
|
1565 | |
element:replaceWith(embed(path or '', facet or '', fileder, {\
|
1566 | |
nolink = nolink,\
|
1567 | |
inline = inline,\
|
1568 | |
desc = desc\
|
1569 | |
}))\
|
1570 | |
end\
|
1571 | |
embeds = _with_0:getElementsByTagName('mmm-link')\
|
1572 | |
do\
|
1573 | |
local _accum_0 = { }\
|
1574 | |
local _len_0 = 1\
|
1575 | |
for i = 0, embeds.length - 1 do\
|
1576 | |
_accum_0[_len_0] = embeds[i]\
|
1577 | |
_len_0 = _len_0 + 1\
|
1578 | |
end\
|
1579 | |
embeds = _accum_0\
|
1580 | |
end\
|
1581 | |
for _index_0 = 1, #embeds do\
|
1582 | |
local element = embeds[_index_0]\
|
1583 | |
local text = js_fix(element.innerText)\
|
1584 | |
local path = js_fix(element:getAttribute('path'))\
|
1585 | |
element:replaceWith(link_to(path or '', text, fileder))\
|
1586 | |
end\
|
1587 | |
parent = _with_0\
|
1588 | |
end\
|
1589 | |
assert(1 == parent.childElementCount, \"text/html with more than one child!\")\
|
1590 | |
return parent.firstElementChild\
|
1591 | |
end\
|
1592 | |
end\
|
1593 | |
end)()\
|
1594 | |
},\
|
1595 | |
{\
|
1596 | |
inp = 'text/lua -> (.+)',\
|
1597 | |
out = '%1',\
|
1598 | |
transform = loadwith(load or loadstring)\
|
1599 | |
},\
|
1600 | |
{\
|
1601 | |
inp = 'mmm/tpl -> (.+)',\
|
1602 | |
out = '%1',\
|
1603 | |
transform = function(self, source, fileder)\
|
1604 | |
return source:gsub('{{(.-)}}', function(expr)\
|
1605 | |
local path, facet = expr:match('^([%w%-_%./]*)%+(.*)')\
|
1606 | |
assert(path, \"couldn't match TPL expression '\" .. tostring(expr) .. \"'\")\
|
1607 | |
return (find_fileder(path, fileder)):gett(facet)\
|
1608 | |
end)\
|
1609 | |
end\
|
1610 | |
},\
|
1611 | |
{\
|
1612 | |
inp = 'time/iso8601-date',\
|
1613 | |
out = 'time/unix',\
|
1614 | |
transform = function(self, val)\
|
1615 | |
local year, _, month, day = val:match('^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$')\
|
1616 | |
assert(year, \"failed to parse ISO 8601 date: '\" .. tostring(val) .. \"'\")\
|
1617 | |
return os.time({\
|
1618 | |
year = year,\
|
1619 | |
month = month,\
|
1620 | |
day = day\
|
1621 | |
})\
|
1622 | |
end\
|
1623 | |
},\
|
1624 | |
{\
|
1625 | |
inp = 'URL -> twitter/tweet',\
|
1626 | |
out = 'mmm/dom',\
|
1627 | |
transform = function(self, href)\
|
1628 | |
local id = assert((href:match('twitter.com/[^/]-/status/(%d*)')), \"couldn't parse twitter/tweet URL: '\" .. tostring(href) .. \"'\")\
|
1629 | |
if MODE == 'CLIENT' then\
|
1630 | |
do\
|
1631 | |
local parent = div()\
|
1632 | |
window.twttr.widgets:createTweet(id, parent)\
|
1633 | |
return parent\
|
1634 | |
end\
|
1635 | |
else\
|
1636 | |
return div(blockquote({\
|
1637 | |
class = 'twitter-tweet',\
|
1638 | |
['data-lang'] = 'en',\
|
1639 | |
a('(linked tweet)', {\
|
1640 | |
href = href\
|
1641 | |
})\
|
1642 | |
}))\
|
1643 | |
end\
|
1644 | |
end\
|
1645 | |
},\
|
1646 | |
{\
|
1647 | |
inp = 'URL -> youtube/video',\
|
1648 | |
out = 'mmm/dom',\
|
1649 | |
transform = function(self, link)\
|
1650 | |
local id = link:match('youtu%.be/([^/]+)')\
|
1651 | |
id = id or link:match('youtube.com/watch.*[?&]v=([^&]+)')\
|
1652 | |
id = id or link:match('youtube.com/[ev]/([^/]+)')\
|
1653 | |
id = id or link:match('youtube.com/embed/([^/]+)')\
|
1654 | |
assert(id, \"couldn't parse youtube URL: '\" .. tostring(link) .. \"'\")\
|
1655 | |
return iframe({\
|
1656 | |
width = 560,\
|
1657 | |
height = 315,\
|
1658 | |
frameborder = 0,\
|
1659 | |
allowfullscreen = true,\
|
1660 | |
frameBorder = 0,\
|
1661 | |
src = \"//www.youtube.com/embed/\" .. tostring(id)\
|
1662 | |
})\
|
1663 | |
end\
|
1664 | |
},\
|
1665 | |
{\
|
1666 | |
inp = 'URL -> image/.+',\
|
1667 | |
out = 'mmm/dom',\
|
1668 | |
transform = function(self, src, fileder)\
|
1669 | |
return img({\
|
1670 | |
src = src\
|
1671 | |
})\
|
1672 | |
end\
|
1673 | |
},\
|
1674 | |
{\
|
1675 | |
inp = 'URL -> video/.+',\
|
1676 | |
out = 'mmm/dom',\
|
1677 | |
transform = function(self, src)\
|
1678 | |
return video((source({\
|
1679 | |
src = src\
|
1680 | |
})), {\
|
1681 | |
controls = true,\
|
1682 | |
loop = true\
|
1683 | |
})\
|
1684 | |
end\
|
1685 | |
},\
|
1686 | |
{\
|
1687 | |
inp = 'text/plain',\
|
1688 | |
out = 'mmm/dom',\
|
1689 | |
transform = function(self, val)\
|
1690 | |
return span(val)\
|
1691 | |
end\
|
1692 | |
},\
|
1693 | |
{\
|
1694 | |
inp = 'alpha',\
|
1695 | |
out = 'mmm/dom',\
|
1696 | |
transform = single(code)\
|
1697 | |
},\
|
1698 | |
{\
|
1699 | |
inp = '(.+)',\
|
1700 | |
out = 'URL -> %1',\
|
1701 | |
transform = function(self, _, fileder, key)\
|
1702 | |
return tostring(fileder.path) .. \"/\" .. tostring(key.name) .. \":\" .. tostring(self.from)\
|
1703 | |
end\
|
1704 | |
}\
|
1705 | |
}\
|
1706 | |
if MODE == 'SERVER' then\
|
1707 | |
local ok, moon = pcall(require, 'moonscript.base')\
|
1708 | |
if ok then\
|
1709 | |
local _load = moon.load or moon.loadstring\
|
1710 | |
table.insert(converts, {\
|
1711 | |
inp = 'text/moonscript -> (.+)',\
|
1712 | |
out = '%1',\
|
1713 | |
transform = loadwith(moon.load or moon.loadstring)\
|
1714 | |
})\
|
1715 | |
table.insert(converts, {\
|
1716 | |
inp = 'text/moonscript -> (.+)',\
|
1717 | |
out = 'text/lua -> %1',\
|
1718 | |
transform = single(moon.to_lua)\
|
1719 | |
})\
|
1720 | |
end\
|
1721 | |
else\
|
1722 | |
table.insert(converts, {\
|
1723 | |
inp = 'text/javascript -> (.+)',\
|
1724 | |
out = '%1',\
|
1725 | |
transform = function(self, source)\
|
1726 | |
local f = js.new(window.Function, source)\
|
1727 | |
return f()\
|
1728 | |
end\
|
1729 | |
})\
|
1730 | |
end\
|
1731 | |
do\
|
1732 | |
local markdown\
|
1733 | |
if MODE == 'SERVER' then\
|
1734 | |
local success, discount = pcall(require, 'discount')\
|
1735 | |
if not success then\
|
1736 | |
warn(\"NO MARKDOWN SUPPORT!\", discount)\
|
1737 | |
end\
|
1738 | |
markdown = success and function(md)\
|
1739 | |
local res = assert(discount.compile(md, 'githubtags'))\
|
1740 | |
return res.body\
|
1741 | |
end\
|
1742 | |
else\
|
1743 | |
markdown = window and window.marked and (function()\
|
1744 | |
local _base_0 = window\
|
1745 | |
local _fn_0 = _base_0.marked\
|
1746 | |
return function(...)\
|
1747 | |
return _fn_0(_base_0, ...)\
|
1748 | |
end\
|
1749 | |
end)()\
|
1750 | |
end\
|
1751 | |
if markdown then\
|
1752 | |
table.insert(converts, {\
|
1753 | |
inp = 'text/markdown',\
|
1754 | |
out = 'text/html+frag',\
|
1755 | |
transform = function(self, md)\
|
1756 | |
return \"<div class=\\\"markdown\\\">\" .. tostring(markdown(md)) .. \"</div>\"\
|
1757 | |
end\
|
1758 | |
})\
|
1759 | |
table.insert(converts, {\
|
1760 | |
inp = 'text/markdown%+span',\
|
1761 | |
out = 'mmm/dom',\
|
1762 | |
transform = (function()\
|
1763 | |
if MODE == 'SERVER' then\
|
1764 | |
return function(self, source)\
|
1765 | |
local html = markdown(source)\
|
1766 | |
html = html:gsub('^<p', '<span')\
|
1767 | |
return html:gsub('/p>$', '/span>')\
|
1768 | |
end\
|
1769 | |
else\
|
1770 | |
return function(self, source)\
|
1771 | |
local html = markdown(source)\
|
1772 | |
html = html:gsub('^%s*<p>%s*', '')\
|
1773 | |
html = html:gsub('%s*</p>%s*$', '')\
|
1774 | |
do\
|
1775 | |
local _with_0 = document:createElement('span')\
|
1776 | |
_with_0.innerHTML = html\
|
1777 | |
return _with_0\
|
1778 | |
end\
|
1779 | |
end\
|
1780 | |
end\
|
1781 | |
end)()\
|
1782 | |
})\
|
1783 | |
end\
|
1784 | |
end\
|
1785 | |
return converts\
|
1786 | |
", "mmm/mmmfs/converts.lua") end
|
1787 | |
if not p["mmm.mmmfs.layout"] then p["mmm.mmmfs.layout"] = load("local require = relative(..., 1)\
|
1788 | |
local header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img\
|
1789 | |
do\
|
1790 | |
local _obj_0 = require('mmm.dom')\
|
1791 | |
header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img = _obj_0.header, _obj_0.aside, _obj_0.footer, _obj_0.div, _obj_0.svg, _obj_0.script, _obj_0.g, _obj_0.circle, _obj_0.h1, _obj_0.span, _obj_0.b, _obj_0.a, _obj_0.img\
|
1792 | |
end\
|
1793 | |
local navigate_to\
|
1794 | |
navigate_to = (require('mmm.mmmfs.util'))(require('mmm.dom')).navigate_to\
|
1795 | |
local pick\
|
1796 | |
pick = function(...)\
|
1797 | |
local num = select('#', ...)\
|
1798 | |
local i = math.ceil(math.random() * num)\
|
1799 | |
return (select(i, ...))\
|
1800 | |
end\
|
1801 | |
local iconlink\
|
1802 | |
iconlink = function(href, src, alt, style)\
|
1803 | |
return a({\
|
1804 | |
class = 'iconlink',\
|
1805 | |
target = '_blank',\
|
1806 | |
rel = 'me',\
|
1807 | |
href = href,\
|
1808 | |
img({\
|
1809 | |
src = src,\
|
1810 | |
alt = alt,\
|
1811 | |
style = style\
|
1812 | |
})\
|
1813 | |
})\
|
1814 | |
end\
|
1815 | |
local logo = svg({\
|
1816 | |
class = 'sun',\
|
1817 | |
viewBox = '-0.75 -1 1.5 2',\
|
1818 | |
xmlns = 'http://www.w3.org/2000/svg',\
|
1819 | |
baseProfile = 'full',\
|
1820 | |
version = '1.1',\
|
1821 | |
g({\
|
1822 | |
transform = 'translate(0 .18)',\
|
1823 | |
g({\
|
1824 | |
class = 'circle out',\
|
1825 | |
circle({\
|
1826 | |
r = '.6',\
|
1827 | |
fill = 'none',\
|
1828 | |
['stroke-width'] = '.12'\
|
1829 | |
})\
|
1830 | |
}),\
|
1831 | |
g({\
|
1832 | |
class = 'circle in',\
|
1833 | |
circle({\
|
1834 | |
r = '.2',\
|
1835 | |
stroke = 'none'\
|
1836 | |
})\
|
1837 | |
})\
|
1838 | |
})\
|
1839 | |
})\
|
1840 | |
local gen_header\
|
1841 | |
gen_header = function()\
|
1842 | |
return header({\
|
1843 | |
div({\
|
1844 | |
h1({\
|
1845 | |
navigate_to('', logo),\
|
1846 | |
span({\
|
1847 | |
span('mmm', {\
|
1848 | |
class = 'bold'\
|
1849 | |
}),\
|
1850 | |
'​',\
|
1851 | |
'.s‑ol.nu'\
|
1852 | |
})\
|
1853 | |
}),\
|
1854 | |
table.concat({\
|
1855 | |
pick('fun', 'cool', 'weird', 'interesting', 'new', 'pleasant'),\
|
1856 | |
pick('stuff', 'things', 'projects', 'experiments', 'visuals', 'ideas'),\
|
1857 | |
pick(\"with\", 'and'),\
|
1858 | |
pick('mostly code', 'code and wires', 'silicon', 'electronics', 'shaders', 'oscilloscopes', 'interfaces', 'hardware', 'FPGAs')\
|
1859 | |
}, ' ')\
|
1860 | |
}),\
|
1861 | |
aside({\
|
1862 | |
navigate_to('/about', 'about me'),\
|
1863 | |
navigate_to('/games', 'games'),\
|
1864 | |
navigate_to('/projects', 'other'),\
|
1865 | |
a({\
|
1866 | |
href = 'mailto:s%20[removethis]%20[at]%20s-ol.nu',\
|
1867 | |
'contact',\
|
1868 | |
script(\"\\n var l = document.currentScript.parentElement;\\n l.href = l.href.replace('%20[at]%20', '@');\\n l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)';\\n \")\
|
1869 | |
})\
|
1870 | |
})\
|
1871 | |
})\
|
1872 | |
end\
|
1873 | |
footer = footer({\
|
1874 | |
span({\
|
1875 | |
'made with \\xe2\\x98\\xbd by ',\
|
1876 | |
a('s-ol', {\
|
1877 | |
href = 'https://twitter.com/S0lll0s'\
|
1878 | |
}),\
|
1879 | |
\", \" .. tostring(os.date('%Y'))\
|
1880 | |
}),\
|
1881 | |
div({\
|
1882 | |
class = 'icons',\
|
1883 | |
iconlink('https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github'),\
|
1884 | |
iconlink('https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon'),\
|
1885 | |
iconlink('https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter'),\
|
1886 | |
iconlink('https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', {\
|
1887 | |
height = '1.3em',\
|
1888 | |
['margin-left'] = '.3em',\
|
1889 | |
['margin-top'] = '-0.12em'\
|
1890 | |
})\
|
1891 | |
})\
|
1892 | |
})\
|
1893 | |
local get_meta\
|
1894 | |
get_meta = function(self)\
|
1895 | |
local title = (self:get('title: text/plain')) or self:gett('name: alpha')\
|
1896 | |
local l\
|
1897 | |
l = function(str)\
|
1898 | |
str = str:gsub('[%s\\\\n]+$', '')\
|
1899 | |
return str:gsub('\\\\n', ' ')\
|
1900 | |
end\
|
1901 | |
local e\
|
1902 | |
e = function(str)\
|
1903 | |
return string.format('%q', l(str))\
|
1904 | |
end\
|
1905 | |
local meta = \"\\n <meta charset=\\\"UTF-8\\\">\\n <title>\" .. tostring(l(title)) .. \"</title>\\n \"\
|
1906 | |
do\
|
1907 | |
local page_meta = self:get('_meta: mmm/dom')\
|
1908 | |
if page_meta then\
|
1909 | |
meta = meta .. page_meta\
|
1910 | |
else\
|
1911 | |
meta = meta .. \"\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\">\\n\\n <meta property=\\\"og:title\\\" content=\" .. tostring(e(title)) .. \" />\\n <meta property=\\\"og:type\\\" content=\\\"website\\\" />\\n <meta property=\\\"og:url\\\" content=\\\"https://mmm.s-ol.nu\" .. tostring(self.path) .. \"/\\\" />\\n <meta property=\\\"og:site_name\\\" content=\\\"mmm\\\" />\"\
|
1912 | |
do\
|
1913 | |
local desc = self:get('description: text/plain')\
|
1914 | |
if desc then\
|
1915 | |
meta = meta .. \"\\n <meta property=\\\"og:description\\\" content=\" .. tostring(e(desc)) .. \" />\"\
|
1916 | |
end\
|
1917 | |
end\
|
1918 | |
end\
|
1919 | |
end\
|
1920 | |
return meta\
|
1921 | |
end\
|
1922 | |
local render\
|
1923 | |
render = function(content, fileder, opts)\
|
1924 | |
if opts == nil then\
|
1925 | |
opts = { }\
|
1926 | |
end\
|
1927 | |
opts.meta = opts.meta or get_meta(fileder)\
|
1928 | |
opts.scripts = opts.scripts or ''\
|
1929 | |
if not (opts.noview) then\
|
1930 | |
content = [[ <div class=\"view main\">\
|
1931 | |
<div class=\"content\">\
|
1932 | |
]] .. content .. [[ </div>\
|
1933 | |
</div>\
|
1934 | |
]]\
|
1935 | |
end\
|
1936 | |
local buf = [[<!DOCTYPE html>\
|
1937 | |
<html>\
|
1938 | |
<head>\
|
1939 | |
<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/style/:text/css\" />\
|
1940 | |
<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,600\" />\
|
1941 | |
]]\
|
1942 | |
buf = buf .. \"\\n \" .. tostring(get_meta(fileder)) .. \"\\n </head>\\n <body>\\n \" .. tostring(gen_header()) .. \"\\n\\n \" .. tostring(content) .. \"\\n\\n \" .. tostring(footer) .. \"\\n \"\
|
1943 | |
buf = buf .. [[ <script type=\"application/javascript\" src=\"/static/highlight-pack/:application/javascript\"></script>\
|
1944 | |
<script type=\"application/javascript\" src=\"//cdnjs.cloudflare.com/ajax/libs/marked/0.5.1/marked.min.js\"></script>\
|
1945 | |
<script type=\"application/javascript\" src=\"//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js\"></script>\
|
1946 | |
<script type=\"application/javascript\" src=\"//platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\
|
1947 | |
<script type=\"application/javascript\" src=\"/static/fengari-web/:application/javascript\"></script>\
|
1948 | |
<script type=\"application/lua\" src=\"/static/mmm/:application/lua\"></script>\
|
1949 | |
<script type=\"application/lua\">require 'mmm'</script>\
|
1950 | |
]]\
|
1951 | |
buf = buf .. opts.scripts\
|
1952 | |
buf = buf .. \"\\n </body>\\n</html>\\n \"\
|
1953 | |
return buf\
|
1954 | |
end\
|
1955 | |
return {\
|
1956 | |
render = render\
|
1957 | |
}\
|
1958 | |
", "mmm/mmmfs/layout.lua") end
|
1959 | |
if not p["mmm.mmmfs.stores.fs"] then p["mmm.mmmfs.stores.fs"] = load("local lfs = require('lfs')\
|
1960 | |
local dir_base\
|
1961 | |
dir_base = function(path)\
|
1962 | |
local dir, base = path:match('(.-)([^/]-)$')\
|
1963 | |
if dir and #dir > 0 then\
|
1964 | |
dir = dir:sub(1, #dir - 1)\
|
1965 | |
end\
|
1966 | |
return dir, base\
|
1967 | |
end\
|
1968 | |
local FSStore\
|
1969 | |
do\
|
1970 | |
local _class_0\
|
1971 | |
local _base_0 = {\
|
1972 | |
log = function(self, ...)\
|
1973 | |
return print(\"[DB]\", ...)\
|
1974 | |
end,\
|
1975 | |
list_fileders_in = function(self, path)\
|
1976 | |
if path == nil then\
|
1977 | |
path = ''\
|
1978 | |
end\
|
1979 | |
return coroutine.wrap(function()\
|
1980 | |
for entry_name in lfs.dir(self.root .. path) do\
|
1981 | |
local _continue_0 = false\
|
1982 | |
repeat\
|
1983 | |
if '.' == entry_name:sub(1, 1) then\
|
1984 | |
_continue_0 = true\
|
1985 | |
break\
|
1986 | |
end\
|
1987 | |
local entry_path = self.root .. tostring(path) .. \"/\" .. tostring(entry_name)\
|
1988 | |
if 'directory' == lfs.attributes(entry_path, 'mode') then\
|
1989 | |
coroutine.yield(tostring(path) .. \"/\" .. tostring(entry_name))\
|
1990 | |
end\
|
1991 | |
_continue_0 = true\
|
1992 | |
until true\
|
1993 | |
if not _continue_0 then\
|
1994 | |
break\
|
1995 | |
end\
|
1996 | |
end\
|
1997 | |
end)\
|
1998 | |
end,\
|
1999 | |
list_all_fileders = function(self, path)\
|
2000 | |
if path == nil then\
|
2001 | |
path = ''\
|
2002 | |
end\
|
2003 | |
return coroutine.wrap(function()\
|
2004 | |
for path in self:list_fileders_in(path) do\
|
2005 | |
coroutine.yield(path)\
|
2006 | |
for p in self:list_all_fileders(path) do\
|
2007 | |
coroutine.yield(p)\
|
2008 | |
end\
|
2009 | |
end\
|
2010 | |
end)\
|
2011 | |
end,\
|
2012 | |
create_fileder = function(self, parent, name)\
|
2013 | |
self:log(\"creating fileder \" .. tostring(path))\
|
2014 | |
local path = tostring(parent) .. \"/\" .. tostring(name)\
|
2015 | |
assert(lfs.mkdir(self.root .. path))\
|
2016 | |
return path\
|
2017 | |
end,\
|
2018 | |
remove_fileder = function(self, path)\
|
2019 | |
self:log(\"removing fileder \" .. tostring(path))\
|
2020 | |
local rmdir\
|
2021 | |
rmdir = function(path)\
|
2022 | |
for file in lfs.dir(path) do\
|
2023 | |
local _continue_0 = false\
|
2024 | |
repeat\
|
2025 | |
if '.' == file:sub(1, 1) then\
|
2026 | |
_continue_0 = true\
|
2027 | |
break\
|
2028 | |
end\
|
2029 | |
local file_path = tostring(path) .. \"/\" .. tostring(file)\
|
2030 | |
local _exp_0 = lfs.attributes(file_path, 'mode')\
|
2031 | |
if 'file' == _exp_0 then\
|
2032 | |
assert(os.remove(file_path))\
|
2033 | |
elseif 'directory' == _exp_0 then\
|
2034 | |
assert(rmdir(file_path))\
|
2035 | |
end\
|
2036 | |
_continue_0 = true\
|
2037 | |
until true\
|
2038 | |
if not _continue_0 then\
|
2039 | |
break\
|
2040 | |
end\
|
2041 | |
end\
|
2042 | |
return lfs.rmdir(path)\
|
2043 | |
end\
|
2044 | |
return rmdir(self.root .. path)\
|
2045 | |
end,\
|
2046 | |
rename_fileder = function(self, path, next_name)\
|
2047 | |
self:log(\"renaming fileder \" .. tostring(path) .. \" -> '\" .. tostring(next_name) .. \"'\")\
|
2048 | |
local parent, name = dir_base(path)\
|
2049 | |
return assert(os.rename(path, self.root .. tostring(parent) .. \"/\" .. tostring(next_name)))\
|
2050 | |
end,\
|
2051 | |
move_fileder = function(self, path, next_parent)\
|
2052 | |
self:log(\"moving fileder \" .. tostring(path) .. \" -> \" .. tostring(next_parent) .. \"/\")\
|
2053 | |
local parent, name = dir_base(path)\
|
2054 | |
return assert(os.rename(self.root .. path, self.root .. tostring(next_parent) .. \"/\" .. tostring(name)))\
|
2055 | |
end,\
|
2056 | |
list_facets = function(self, path)\
|
2057 | |
return coroutine.wrap(function()\
|
2058 | |
for entry_name in lfs.dir(self.root .. path) do\
|
2059 | |
local entry_path = tostring(self.root .. path) .. \"/\" .. tostring(entry_name)\
|
2060 | |
if 'file' == lfs.attributes(entry_path, 'mode') then\
|
2061 | |
entry_name = (entry_name:match('(.*)%.%w+')) or entry_name\
|
2062 | |
entry_name = entry_name:gsub('%$', '/')\
|
2063 | |
local name, type = entry_name:match('([%w-_]+): *(.+)')\
|
2064 | |
if not name then\
|
2065 | |
name = ''\
|
2066 | |
type = entry_name\
|
2067 | |
end\
|
2068 | |
coroutine.yield(name, type)\
|
2069 | |
end\
|
2070 | |
end\
|
2071 | |
end)\
|
2072 | |
end,\
|
2073 | |
tofp = function(self, path, name, type)\
|
2074 | |
if #name > 0 then\
|
2075 | |
type = tostring(name) .. \": \" .. tostring(type)\
|
2076 | |
end\
|
2077 | |
type = type:gsub('%/', '$')\
|
2078 | |
return self.root .. tostring(path) .. \"/\" .. tostring(type)\
|
2079 | |
end,\
|
2080 | |
locate = function(self, path, name, type)\
|
2081 | |
if not (lfs.attributes(self.root .. path, 'mode')) then\
|
2082 | |
return \
|
2083 | |
end\
|
2084 | |
type = type:gsub('%/', '$')\
|
2085 | |
if #name > 0 then\
|
2086 | |
name = tostring(name) .. \": \"\
|
2087 | |
end\
|
2088 | |
name = name .. type\
|
2089 | |
name = name:gsub('([^%w])', '%%%1')\
|
2090 | |
local file_name\
|
2091 | |
for entry_name in lfs.dir(self.root .. path) do\
|
2092 | |
if (entry_name:match(\"^\" .. tostring(name) .. \"$\")) or entry_name:match(\"^\" .. tostring(name) .. \"%.%w+$\") then\
|
2093 | |
if file_name then\
|
2094 | |
error(\"two files match \" .. tostring(name) .. \": \" .. tostring(file_name) .. \" and \" .. tostring(entry_name) .. \"!\")\
|
2095 | |
end\
|
2096 | |
file_name = entry_name\
|
2097 | |
end\
|
2098 | |
end\
|
2099 | |
return file_name and self.root .. tostring(path) .. \"/\" .. tostring(file_name)\
|
2100 | |
end,\
|
2101 | |
load_facet = function(self, path, name, type)\
|
2102 | |
local filepath = self:locate(path, name, type)\
|
2103 | |
if not (filepath) then\
|
2104 | |
return \
|
2105 | |
end\
|
2106 | |
local file = assert((io.open(filepath, 'rb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\
|
2107 | |
do\
|
2108 | |
local _with_0 = file:read('*all')\
|
2109 | |
file:close()\
|
2110 | |
return _with_0\
|
2111 | |
end\
|
2112 | |
end,\
|
2113 | |
create_facet = function(self, path, name, type, blob)\
|
2114 | |
self:log(\"creating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\
|
2115 | |
assert(blob, \"cant create facet without value!\")\
|
2116 | |
local filepath = self:tofp(path, name, type)\
|
2117 | |
if lfs.attributes(filepath, 'mode') then\
|
2118 | |
error(\"facet file already exists!\")\
|
2119 | |
end\
|
2120 | |
local file = assert((io.open(filepath, 'wb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\
|
2121 | |
file:write(blob)\
|
2122 | |
return file:close()\
|
2123 | |
end,\
|
2124 | |
remove_facet = function(self, path, name, type)\
|
2125 | |
self:log(\"removing facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\
|
2126 | |
local filepath = self:locate(path, name, type)\
|
2127 | |
assert(filepath, \"couldn't locate facet!\")\
|
2128 | |
return assert(os.remove(filepath))\
|
2129 | |
end,\
|
2130 | |
rename_facet = function(self, path, name, type, next_name)\
|
2131 | |
self:log(\"renaming facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type) .. \" -> \" .. tostring(next_name))\
|
2132 | |
local filepath = self:locate(path, name, type)\
|
2133 | |
assert(filepath, \"couldn't locate facet!\")\
|
2134 | |
return assert(os.rename(filepath, self:tofp(path, next_name, type)))\
|
2135 | |
end,\
|
2136 | |
update_facet = function(self, path, name, type, blob)\
|
2137 | |
self:log(\"updating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\
|
2138 | |
local filepath = self:locate(path, name, type)\
|
2139 | |
assert(filepath, \"couldn't locate facet!\")\
|
2140 | |
local file = assert((io.open(filepath, 'wb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\
|
2141 | |
file:write(blob)\
|
2142 | |
return file:close()\
|
2143 | |
end\
|
2144 | |
}\
|
2145 | |
_base_0.__index = _base_0\
|
2146 | |
_class_0 = setmetatable({\
|
2147 | |
__init = function(self, opts)\
|
2148 | |
if opts == nil then\
|
2149 | |
opts = { }\
|
2150 | |
end\
|
2151 | |
opts.root = opts.root or 'root'\
|
2152 | |
opts.verbose = opts.verbose or false\
|
2153 | |
if not opts.verbose then\
|
2154 | |
self.log = function() end\
|
2155 | |
end\
|
2156 | |
self.root = opts.root:match('^(.-)/?$')\
|
2157 | |
return self:log(\"opening '\" .. tostring(opts.root) .. \"'...\")\
|
2158 | |
end,\
|
2159 | |
__base = _base_0,\
|
2160 | |
__name = \"FSStore\"\
|
2161 | |
}, {\
|
2162 | |
__index = _base_0,\
|
2163 | |
__call = function(cls, ...)\
|
2164 | |
local _self_0 = setmetatable({}, _base_0)\
|
2165 | |
cls.__init(_self_0, ...)\
|
2166 | |
return _self_0\
|
2167 | |
end\
|
2168 | |
})\
|
2169 | |
_base_0.__class = _class_0\
|
2170 | |
FSStore = _class_0\
|
2171 | |
end\
|
2172 | |
return {\
|
2173 | |
FSStore = FSStore\
|
2174 | |
}\
|
2175 | |
", "mmm/mmmfs/stores/fs.lua") end
|
2176 | |
if not p["mmm.mmmfs.stores"] then p["mmm.mmmfs.stores"] = load("local require = relative(..., 0)\
|
2177 | |
local get_store\
|
2178 | |
get_store = function(args, opts)\
|
2179 | |
if args == nil then\
|
2180 | |
args = 'sql'\
|
2181 | |
end\
|
2182 | |
if opts == nil then\
|
2183 | |
opts = {\
|
2184 | |
verbose = true\
|
2185 | |
}\
|
2186 | |
end\
|
2187 | |
local type, arg = args:match('(%w+):(.*)')\
|
2188 | |
if not (type) then\
|
2189 | |
type = args\
|
2190 | |
end\
|
2191 | |
local _exp_0 = type:lower()\
|
2192 | |
if 'sql' == _exp_0 then\
|
2193 | |
local SQLStore\
|
2194 | |
SQLStore = require('.sql').SQLStore\
|
2195 | |
if arg == 'MEMORY' then\
|
2196 | |
opts.memory = true\
|
2197 | |
else\
|
2198 | |
opts.file = arg\
|
2199 | |
end\
|
2200 | |
return SQLStore(opts)\
|
2201 | |
elseif 'fs' == _exp_0 then\
|
2202 | |
local FSStore\
|
2203 | |
FSStore = require('.fs').FSStore\
|
2204 | |
opts.root = arg\
|
2205 | |
return FSStore(opts)\
|
2206 | |
else\
|
2207 | |
warn(\"unknown or missing value for STORE: valid types values are sql, fs\")\
|
2208 | |
return os.exit(1)\
|
2209 | |
end\
|
2210 | |
end\
|
2211 | |
return {\
|
2212 | |
get_store = get_store\
|
2213 | |
}\
|
2214 | |
", "mmm/mmmfs/stores/init.lua") end
|
2215 | |
if not p["mmm.mmmfs.stores.sql"] then p["mmm.mmmfs.stores.sql"] = load("local sqlite = require('sqlite3')\
|
2216 | |
local root = os.tmpname()\
|
2217 | |
local SQLStore\
|
2218 | |
do\
|
2219 | |
local _class_0\
|
2220 | |
local _base_0 = {\
|
2221 | |
log = function(self, ...)\
|
2222 | |
return print(\"[DB]\", ...)\
|
2223 | |
end,\
|
2224 | |
close = function(self)\
|
2225 | |
return self.db:close()\
|
2226 | |
end,\
|
2227 | |
fetch = function(self, q, ...)\
|
2228 | |
local stmt = assert(self.db:prepare(q))\
|
2229 | |
if 0 < select('#', ...) then\
|
2230 | |
stmt:bind(...)\
|
2231 | |
end\
|
2232 | |
return stmt:irows()\
|
2233 | |
end,\
|
2234 | |
fetch_one = function(self, q, ...)\
|
2235 | |
local stmt = assert(self.db:prepare(q))\
|
2236 | |
if 0 < select('#', ...) then\
|
2237 | |
stmt:bind(...)\
|
2238 | |
end\
|
2239 | |
return stmt:first_irow()\
|
2240 | |
end,\
|
2241 | |
exec = function(self, q, ...)\
|
2242 | |
local stmt = assert(self.db:prepare(q))\
|
2243 | |
if 0 < select('#', ...) then\
|
2244 | |
stmt:bind(...)\
|
2245 | |
end\
|
2246 | |
local res = assert(stmt:exec())\
|
2247 | |
end,\
|
2248 | |
list_fileders_in = function(self, path)\
|
2249 | |
if path == nil then\
|
2250 | |
path = ''\
|
2251 | |
end\
|
2252 | |
return coroutine.wrap(function()\
|
2253 | |
for _des_0 in self:fetch('SELECT path\\n FROM fileder WHERE parent IS ?', path) do\
|
2254 | |
path = _des_0[1]\
|
2255 | |
coroutine.yield(path)\
|
2256 | |
end\
|
2257 | |
end)\
|
2258 | |
end,\
|
2259 | |
list_all_fileders = function(self, path)\
|
2260 | |
if path == nil then\
|
2261 | |
path = ''\
|
2262 | |
end\
|
2263 | |
return coroutine.wrap(function()\
|
2264 | |
for path in self:list_fileders_in(path) do\
|
2265 | |
coroutine.yield(path)\
|
2266 | |
for p in self:list_all_fileders(path) do\
|
2267 | |
coroutine.yield(p)\
|
2268 | |
end\
|
2269 | |
end\
|
2270 | |
end)\
|
2271 | |
end,\
|
2272 | |
create_fileder = function(self, parent, name)\
|
2273 | |
local path = tostring(parent) .. \"/\" .. tostring(name)\
|
2274 | |
self:log(\"creating fileder \" .. tostring(path))\
|
2275 | |
self:exec('INSERT INTO fileder (path, parent)\\n VALUES (:path, :parent)', {\
|
2276 | |
path = path,\
|
2277 | |
parent = parent\
|
2278 | |
})\
|
2279 | |
local changes = self:fetch_one('SELECT changes()')\
|
2280 | |
assert(changes[1] == 1, \"couldn't create fileder - parent missing?\")\
|
2281 | |
return path\
|
2282 | |
end,\
|
2283 | |
remove_fileder = function(self, path)\
|
2284 | |
self:log(\"removing fileder \" .. tostring(path))\
|
2285 | |
return self:exec('DELETE FROM fileder\\n WHERE path LIKE :path || \"/%\"\\n OR path = :path', path)\
|
2286 | |
end,\
|
2287 | |
rename_fileder = function(self, path, next_name)\
|
2288 | |
self:log(\"renaming fileder \" .. tostring(path) .. \" -> '\" .. tostring(next_name) .. \"'\")\
|
2289 | |
error('not implemented')\
|
2290 | |
return self:exec('UPDATE fileder\\n SET path = parent || \"/\" || :next_name\\n WHERE path = :path', {\
|
2291 | |
path = path,\
|
2292 | |
next_name = next_name\
|
2293 | |
})\
|
2294 | |
end,\
|
2295 | |
move_fileder = function(self, path, next_parent)\
|
2296 | |
self:log(\"moving fileder \" .. tostring(path) .. \" -> \" .. tostring(next_parent) .. \"/\")\
|
2297 | |
return error('not implemented')\
|
2298 | |
end,\
|
2299 | |
list_facets = function(self, path)\
|
2300 | |
return coroutine.wrap(function()\
|
2301 | |
for _des_0 in self:fetch('SELECT facet.name, facet.type\\n FROM facet\\n INNER JOIN fileder ON facet.fileder_id = fileder.id\\n WHERE fileder.path = ?', path) do\
|
2302 | |
local name, type\
|
2303 | |
name, type = _des_0[1], _des_0[2]\
|
2304 | |
coroutine.yield(name, type)\
|
2305 | |
end\
|
2306 | |
end)\
|
2307 | |
end,\
|
2308 | |
load_facet = function(self, path, name, type)\
|
2309 | |
local v = self:fetch_one('SELECT facet.value\\n FROM facet\\n INNER JOIN fileder ON facet.fileder_id = fileder.id\\n WHERE fileder.path = :path\\n AND facet.name = :name\\n AND facet.type = :type', {\
|
2310 | |
path = path,\
|
2311 | |
name = name,\
|
2312 | |
type = type\
|
2313 | |
})\
|
2314 | |
return v and v[1]\
|
2315 | |
end,\
|
2316 | |
create_facet = function(self, path, name, type, blob)\
|
2317 | |
self:log(\"creating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\
|
2318 | |
self:exec('INSERT INTO facet (fileder_id, name, type, value)\\n SELECT id, :name, :type, :blob\\n FROM fileder\\n WHERE fileder.path = :path', {\
|
2319 | |
path = path,\
|
2320 | |
name = name,\
|
2321 | |
type = type,\
|
2322 | |
blob = blob\
|
2323 | |
})\
|
2324 | |
local changes = self:fetch_one('SELECT changes()')\
|
2325 | |
return assert(changes[1] == 1, \"couldn't create facet - fileder missing?\")\
|
2326 | |
end,\
|
2327 | |
remove_facet = function(self, path, name, type)\
|
2328 | |
self:log(\"removing facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\
|
2329 | |
self:exec('DELETE FROM facet\\n WHERE name = :name\\n AND type = :type\\n AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\
|
2330 | |
path = path,\
|
2331 | |
name = name,\
|
2332 | |
type = type\
|
2333 | |
})\
|
2334 | |
local changes = self:fetch_one('SELECT changes()')\
|
2335 | |
return assert(changes[1] == 1, \"no such facet\")\
|
2336 | |
end,\
|
2337 | |
rename_facet = function(self, path, name, type, next_name)\
|
2338 | |
self:log(\"renaming facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type) .. \" -> \" .. tostring(next_name))\
|
2339 | |
self:exec('UPDATE facet\\n SET name = :next_name\\n WHERE name = :name\\n AND type = :type\\n AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\
|
2340 | |
path = path,\
|
2341 | |
name = name,\
|
2342 | |
next_name = next_name,\
|
2343 | |
type = type\
|
2344 | |
})\
|
2345 | |
local changes = self:fetch_one('SELECT changes()')\
|
2346 | |
return assert(changes[1] == 1, \"no such facet\")\
|
2347 | |
end,\
|
2348 | |
update_facet = function(self, path, name, type, blob)\
|
2349 | |
self:log(\"updating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\
|
2350 | |
self:exec('UPDATE facet\\n SET value = :blob\\n WHERE facet.name = :name\\n AND facet.type = :type\\n AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\
|
2351 | |
path = path,\
|
2352 | |
name = name,\
|
2353 | |
type = type,\
|
2354 | |
blob = blob\
|
2355 | |
})\
|
2356 | |
local changes = self:fetch_one('SELECT changes()')\
|
2357 | |
return assert(changes[1] == 1, \"no such facet\")\
|
2358 | |
end\
|
2359 | |
}\
|
2360 | |
_base_0.__index = _base_0\
|
2361 | |
_class_0 = setmetatable({\
|
2362 | |
__init = function(self, opts)\
|
2363 | |
if opts == nil then\
|
2364 | |
opts = { }\
|
2365 | |
end\
|
2366 | |
opts.file = opts.file or 'db.sqlite3'\
|
2367 | |
opts.verbose = opts.verbose or false\
|
2368 | |
opts.memory = opts.memory or false\
|
2369 | |
if not opts.verbose then\
|
2370 | |
self.log = function() end\
|
2371 | |
end\
|
2372 | |
if opts.memory then\
|
2373 | |
self:log(\"opening in-memory DB...\")\
|
2374 | |
self.db = sqlite.open_memory()\
|
2375 | |
else\
|
2376 | |
self:log(\"opening '\" .. tostring(opts.file) .. \"'...\")\
|
2377 | |
self.db = sqlite.open(opts.file)\
|
2378 | |
end\
|
2379 | |
return assert(self.db:exec([[ PRAGMA foreign_keys = ON;\
|
2380 | |
PRAGMA case_sensitive_like = ON;\
|
2381 | |
CREATE TABLE IF NOT EXISTS fileder (\
|
2382 | |
id INTEGER NOT NULL PRIMARY KEY,\
|
2383 | |
path TEXT NOT NULL UNIQUE,\
|
2384 | |
parent TEXT REFERENCES fileder(path)\
|
2385 | |
ON DELETE CASCADE\
|
2386 | |
ON UPDATE CASCADE\
|
2387 | |
);\
|
2388 | |
INSERT OR IGNORE INTO fileder (path, parent) VALUES (\"\", NULL);\
|
2389 | |
\
|
2390 | |
CREATE TABLE IF NOT EXISTS facet (\
|
2391 | |
fileder_id INTEGER NOT NULL\
|
2392 | |
REFERENCES fileder\
|
2393 | |
ON UPDATE CASCADE\
|
2394 | |
ON DELETE CASCADE,\
|
2395 | |
name TEXT NOT NULL,\
|
2396 | |
type TEXT NOT NULL,\
|
2397 | |
value BLOB NOT NULL,\
|
2398 | |
PRIMARY KEY (fileder_id, name, type)\
|
2399 | |
);\
|
2400 | |
CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id);\
|
2401 | |
CREATE INDEX IF NOT EXISTS facet_name ON facet(name);\
|
2402 | |
]]))\
|
2403 | |
end,\
|
2404 | |
__base = _base_0,\
|
2405 | |
__name = \"SQLStore\"\
|
2406 | |
}, {\
|
2407 | |
__index = _base_0,\
|
2408 | |
__call = function(cls, ...)\
|
2409 | |
local _self_0 = setmetatable({}, _base_0)\
|
2410 | |
cls.__init(_self_0, ...)\
|
2411 | |
return _self_0\
|
2412 | |
end\
|
2413 | |
})\
|
2414 | |
_base_0.__class = _class_0\
|
2415 | |
SQLStore = _class_0\
|
2416 | |
end\
|
2417 | |
return {\
|
2418 | |
SQLStore = SQLStore\
|
2419 | |
}\
|
2420 | |
", "mmm/mmmfs/stores/sql.lua") end
|
2421 | |
if not p["mmm.dom"] then p["mmm.dom"] = load("local element\
|
2422 | |
element = function(element)\
|
2423 | |
return function(...)\
|
2424 | |
local children = {\
|
2425 | |
...\
|
2426 | |
}\
|
2427 | |
local attributes = children[#children]\
|
2428 | |
if 'table' == (type(attributes)) and not attributes.node then\
|
2429 | |
table.remove(children)\
|
2430 | |
else\
|
2431 | |
attributes = { }\
|
2432 | |
end\
|
2433 | |
do\
|
2434 | |
local e = document:createElement(element)\
|
2435 | |
for k, v in pairs(attributes) do\
|
2436 | |
if k == 'class' then\
|
2437 | |
k = 'className'\
|
2438 | |
end\
|
2439 | |
if k == 'style' and 'table' == type(v) then\
|
2440 | |
for kk, vv in pairs(v) do\
|
2441 | |
e.style[kk] = vv\
|
2442 | |
end\
|
2443 | |
elseif 'string' == type(k) then\
|
2444 | |
e[k] = v\
|
2445 | |
end\
|
2446 | |
end\
|
2447 | |
if #children == 0 then\
|
2448 | |
children = attributes\
|
2449 | |
end\
|
2450 | |
for _index_0 = 1, #children do\
|
2451 | |
local child = children[_index_0]\
|
2452 | |
if 'string' == type(child) then\
|
2453 | |
child = document:createTextNode(child)\
|
2454 | |
end\
|
2455 | |
e:appendChild(child)\
|
2456 | |
end\
|
2457 | |
return e\
|
2458 | |
end\
|
2459 | |
end\
|
2460 | |
end\
|
2461 | |
return setmetatable({ }, {\
|
2462 | |
__index = function(self, name)\
|
2463 | |
do\
|
2464 | |
local val = element(name)\
|
2465 | |
self[name] = val\
|
2466 | |
return val\
|
2467 | |
end\
|
2468 | |
end\
|
2469 | |
})\
|
2470 | |
", "mmm/dom/init.client.lua") end
|
2471 | |
if not p["mmm.component"] then p["mmm.component"] = load("local tohtml\
|
2472 | |
tohtml = function(val)\
|
2473 | |
if 'string' == type(val) then\
|
2474 | |
return document:createTextNode(val)\
|
2475 | |
end\
|
2476 | |
if 'table' == type(val) then\
|
2477 | |
assert(val.node, \"Table doesn't have .node\")\
|
2478 | |
val = val.node\
|
2479 | |
end\
|
2480 | |
if 'userdata' == type(val) then\
|
2481 | |
assert((js.instanceof(val, js.global.Node)), \"userdata is not a Node\")\
|
2482 | |
return val\
|
2483 | |
else\
|
2484 | |
return error(\"not a Node: \" .. tostring(val) .. \", \" .. tostring(type(val)))\
|
2485 | |
end\
|
2486 | |
end\
|
2487 | |
local text\
|
2488 | |
text = function(str)\
|
2489 | |
return document:createTextNode(tostring(str))\
|
2490 | |
end\
|
2491 | |
local ReactiveVar\
|
2492 | |
do\
|
2493 | |
local _class_0\
|
2494 | |
local _base_0 = {\
|
2495 | |
set = function(self, value)\
|
2496 | |
local old = self.value\
|
2497 | |
self.value = value\
|
2498 | |
for k, callback in pairs(self.listeners) do\
|
2499 | |
callback(self.value, old)\
|
2500 | |
end\
|
2501 | |
end,\
|
2502 | |
get = function(self)\
|
2503 | |
return self.value\
|
2504 | |
end,\
|
2505 | |
transform = function(self, transform)\
|
2506 | |
return self:set(transform(self:get()))\
|
2507 | |
end,\
|
2508 | |
subscribe = function(self, callback)\
|
2509 | |
do\
|
2510 | |
local _with_0\
|
2511 | |
_with_0 = function()\
|
2512 | |
self.listeners[callback] = nil\
|
2513 | |
end\
|
2514 | |
self.listeners[callback] = callback\
|
2515 | |
return _with_0\
|
2516 | |
end\
|
2517 | |
end,\
|
2518 | |
map = function(self, transform)\
|
2519 | |
do\
|
2520 | |
local _with_0 = ReactiveVar(transform(self.value))\
|
2521 | |
_with_0.upstream = self:subscribe(function(...)\
|
2522 | |
return _with_0:set(transform(...))\
|
2523 | |
end)\
|
2524 | |
return _with_0\
|
2525 | |
end\
|
2526 | |
end\
|
2527 | |
}\
|
2528 | |
_base_0.__index = _base_0\
|
2529 | |
_class_0 = setmetatable({\
|
2530 | |
__init = function(self, value)\
|
2531 | |
self.value = value\
|
2532 | |
self.listeners = setmetatable({ }, {\
|
2533 | |
__mode = 'kv'\
|
2534 | |
})\
|
2535 | |
end,\
|
2536 | |
__base = _base_0,\
|
2537 | |
__name = \"ReactiveVar\"\
|
2538 | |
}, {\
|
2539 | |
__index = _base_0,\
|
2540 | |
__call = function(cls, ...)\
|
2541 | |
local _self_0 = setmetatable({}, _base_0)\
|
2542 | |
cls.__init(_self_0, ...)\
|
2543 | |
return _self_0\
|
2544 | |
end\
|
2545 | |
})\
|
2546 | |
_base_0.__class = _class_0\
|
2547 | |
local self = _class_0\
|
2548 | |
self.isinstance = function(val)\
|
2549 | |
return 'table' == (type(val)) and val.subscribe\
|
2550 | |
end\
|
2551 | |
ReactiveVar = _class_0\
|
2552 | |
end\
|
2553 | |
local ReactiveElement\
|
2554 | |
do\
|
2555 | |
local _class_0\
|
2556 | |
local _base_0 = {\
|
2557 | |
destroy = function(self)\
|
2558 | |
local _list_0 = self._subscriptions\
|
2559 | |
for _index_0 = 1, #_list_0 do\
|
2560 | |
local unsub = _list_0[_index_0]\
|
2561 | |
unsub()\
|
2562 | |
end\
|
2563 | |
end,\
|
2564 | |
set = function(self, attr, value)\
|
2565 | |
if attr == 'class' then\
|
2566 | |
attr = 'className'\
|
2567 | |
end\
|
2568 | |
if 'table' == (type(value)) and ReactiveVar.isinstance(value) then\
|
2569 | |
table.insert(self._subscriptions, value:subscribe(function(...)\
|
2570 | |
return self:set(attr, ...)\
|
2571 | |
end))\
|
2572 | |
value = value:get()\
|
2573 | |
end\
|
2574 | |
if attr == 'style' and 'table' == type(value) then\
|
2575 | |
for k, v in pairs(value) do\
|
2576 | |
self.node.style[k] = v\
|
2577 | |
end\
|
2578 | |
return \
|
2579 | |
end\
|
2580 | |
self.node[attr] = value\
|
2581 | |
end,\
|
2582 | |
prepend = function(self, child, last)\
|
2583 | |
return self:append(child, last, 'prepend')\
|
2584 | |
end,\
|
2585 | |
append = function(self, child, last, mode)\
|
2586 | |
if mode == nil then\
|
2587 | |
mode = 'append'\
|
2588 | |
end\
|
2589 | |
if ReactiveVar.isinstance(child) then\
|
2590 | |
table.insert(self._subscriptions, child:subscribe(function(...)\
|
2591 | |
return self:append(...)\
|
2592 | |
end))\
|
2593 | |
child = child:get()\
|
2594 | |
end\
|
2595 | |
if 'string' == type(last) then\
|
2596 | |
error('cannot replace string node')\
|
2597 | |
end\
|
2598 | |
if child == nil then\
|
2599 | |
if last then\
|
2600 | |
self:remove(last)\
|
2601 | |
end\
|
2602 | |
return \
|
2603 | |
end\
|
2604 | |
child = tohtml(child)\
|
2605 | |
if last then\
|
2606 | |
return self.node:replaceChild(child, tohtml(last))\
|
2607 | |
else\
|
2608 | |
local _exp_0 = mode\
|
2609 | |
if 'append' == _exp_0 then\
|
2610 | |
return self.node:appendChild(child)\
|
2611 | |
elseif 'prepend' == _exp_0 then\
|
2612 | |
return self.node:insertBefore(child, self.node.firstChild)\
|
2613 | |
end\
|
2614 | |
end\
|
2615 | |
end,\
|
2616 | |
remove = function(self, child)\
|
2617 | |
self.node:removeChild(tohtml(child))\
|
2618 | |
if 'table' == (type(child)) and child.destroy then\
|
2619 | |
return child:destroy()\
|
2620 | |
end\
|
2621 | |
end\
|
2622 | |
}\
|
2623 | |
_base_0.__index = _base_0\
|
2624 | |
_class_0 = setmetatable({\
|
2625 | |
__init = function(self, element, ...)\
|
2626 | |
if 'userdata' == type(element) then\
|
2627 | |
self.node = element\
|
2628 | |
else\
|
2629 | |
self.node = document:createElement(element)\
|
2630 | |
end\
|
2631 | |
self._subscriptions = { }\
|
2632 | |
local children = {\
|
2633 | |
...\
|
2634 | |
}\
|
2635 | |
local attributes = children[#children]\
|
2636 | |
if 'table' == (type(attributes)) and (not ReactiveElement.isinstance(attributes)) and (not ReactiveVar.isinstance(attributes)) then\
|
2637 | |
table.remove(children)\
|
2638 | |
else\
|
2639 | |
attributes = { }\
|
2640 | |
end\
|
2641 | |
for k, v in pairs(attributes) do\
|
2642 | |
if 'string' == type(k) then\
|
2643 | |
self:set(k, v)\
|
2644 | |
end\
|
2645 | |
end\
|
2646 | |
if #children == 0 then\
|
2647 | |
children = attributes\
|
2648 | |
end\
|
2649 | |
for _index_0 = 1, #children do\
|
2650 | |
local child = children[_index_0]\
|
2651 | |
self:append(child)\
|
2652 | |
end\
|
2653 | |
end,\
|
2654 | |
__base = _base_0,\
|
2655 | |
__name = \"ReactiveElement\"\
|
2656 | |
}, {\
|
2657 | |
__index = _base_0,\
|
2658 | |
__call = function(cls, ...)\
|
2659 | |
local _self_0 = setmetatable({}, _base_0)\
|
2660 | |
cls.__init(_self_0, ...)\
|
2661 | |
return _self_0\
|
2662 | |
end\
|
2663 | |
})\
|
2664 | |
_base_0.__class = _class_0\
|
2665 | |
local self = _class_0\
|
2666 | |
self.isinstance = function(val)\
|
2667 | |
return 'table' == (type(val)) and val.node\
|
2668 | |
end\
|
2669 | |
ReactiveElement = _class_0\
|
2670 | |
end\
|
2671 | |
local get_or_create\
|
2672 | |
get_or_create = function(elem, id, ...)\
|
2673 | |
elem = (document:getElementById(id)) or elem\
|
2674 | |
do\
|
2675 | |
local _with_0 = ReactiveElement(elem, ...)\
|
2676 | |
_with_0:set('id', id)\
|
2677 | |
return _with_0\
|
2678 | |
end\
|
2679 | |
end\
|
2680 | |
local elements = setmetatable({ }, {\
|
2681 | |
__index = function(self, name)\
|
2682 | |
do\
|
2683 | |
local val\
|
2684 | |
val = function(...)\
|
2685 | |
return ReactiveElement(name, ...)\
|
2686 | |
end\
|
2687 | |
self[name] = val\
|
2688 | |
return val\
|
2689 | |
end\
|
2690 | |
end\
|
2691 | |
})\
|
2692 | |
return {\
|
2693 | |
ReactiveVar = ReactiveVar,\
|
2694 | |
ReactiveElement = ReactiveElement,\
|
2695 | |
get_or_create = get_or_create,\
|
2696 | |
tohtml = tohtml,\
|
2697 | |
text = text,\
|
2698 | |
elements = elements\
|
2699 | |
}\
|
2700 | |
", "mmm/component/init.client.lua") end
|