mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-02 20:23:32 +08:00
132 lines
4.8 KiB
JavaScript
132 lines
4.8 KiB
JavaScript
import { createElement } from "../../lib/skeleton/index.js";
|
|
import rxjs, { effect, applyMutation, onClick } from "../../lib/rx.js";
|
|
import { animate, slideXIn, opacityOut } from "../../lib/animate.js";
|
|
import { qs, qsa } from "../../lib/dom.js";
|
|
import { loadCSS } from "../../helpers/loader.js";
|
|
import { createForm } from "../../lib/form.js";
|
|
import { formTmpl } from "../../components/form.js";
|
|
import ctrlError from "../ctrl_error.js";
|
|
|
|
import { transition } from "./common.js";
|
|
import { $ICON } from "./common_fab.js";
|
|
import { cat, save } from "./model_files.js";
|
|
|
|
import "../../components/icon.js";
|
|
import "../../components/menubar.js";
|
|
import "../../components/fab.js";
|
|
|
|
export default function(render) {
|
|
const $page = createElement(`
|
|
<div class="component_formviewer">
|
|
<component-menubar></component-menubar>
|
|
<div class="formviewer_container hidden">
|
|
<form class="sticky box"></form>
|
|
</div>
|
|
<button is="component-fab" data-options="download"></button>
|
|
</div>
|
|
`);
|
|
render($page);
|
|
|
|
const $container = qs($page, ".formviewer_container");
|
|
const $fab = qs($page, `[is="component-fab"]`);
|
|
const formState = () => [...new FormData(qs($page, "form"))].reduce((acc, el) => {
|
|
acc[el[0]] = el[1];
|
|
return acc;
|
|
}, {});
|
|
const file$ = new rxjs.ReplaySubject(1);
|
|
|
|
// feature1: setup the dom
|
|
effect(cat().pipe(
|
|
rxjs.map((content) => JSON.parse(content)),
|
|
rxjs.mergeMap((formSpec) => rxjs.from(createForm(formSpec, formTmpl({
|
|
renderLeaf: ({ label, format, description, required }) => createElement(`
|
|
<label class="no-select">
|
|
<div>
|
|
<span>
|
|
${format(label)}
|
|
` + (required === true ? `<span class="mandatory">*</span>`: "") +`
|
|
</span>
|
|
<div data-bind="children"></div>
|
|
</div>
|
|
<div>
|
|
<span class="nothing"></span>
|
|
<div class="description">${description || ""}</div>
|
|
</div>
|
|
</label>
|
|
`),
|
|
}))).pipe(
|
|
applyMutation(qs($page, "form"), "replaceChildren"),
|
|
rxjs.tap(() => {
|
|
$container.classList.remove("hidden");
|
|
transition($container);
|
|
}),
|
|
rxjs.mapTo(formSpec),
|
|
)),
|
|
rxjs.tap((formSpec) => file$.next(formObjToJSON(formSpec))),
|
|
rxjs.catchError(ctrlError()),
|
|
));
|
|
|
|
// feature2: display/hide save button
|
|
effect(rxjs.merge(
|
|
file$.asObservable(),
|
|
file$.pipe(
|
|
rxjs.first(),
|
|
rxjs.mergeMap((formSpec) => rxjs.from(qsa($page, "form [name]")).pipe(
|
|
rxjs.mergeMap(($el) => rxjs.fromEvent($el, "input")),
|
|
rxjs.mapTo(formSpec),
|
|
)),
|
|
),
|
|
).pipe(
|
|
rxjs.map((originalState) => {
|
|
const smod = (key, value) => value || undefined;
|
|
return JSON.stringify(originalState, smod) !== JSON.stringify(formState(), smod);
|
|
}),
|
|
rxjs.mergeMap(async(isSaveButtonVisible) => {
|
|
if (isSaveButtonVisible && $fab.classList.contains("hidden")) {
|
|
$fab.render($ICON.SAVING);
|
|
$fab.classList.remove("hidden");
|
|
await animate($fab, { time: 100, keyframes: slideXIn(40) });
|
|
} else if (!isSaveButtonVisible && !$fab.classList.contains("hidden")) {
|
|
await animate($fab, { time: 100, keyframes: opacityOut() });
|
|
$fab.classList.add("hidden");
|
|
}
|
|
}),
|
|
rxjs.catchError(ctrlError()),
|
|
));
|
|
|
|
// feature3: submit the form
|
|
effect(onClick($fab).pipe(
|
|
rxjs.tap(() => {
|
|
$fab.render($ICON.LOADING);
|
|
$fab.disabled = true;
|
|
}),
|
|
rxjs.mergeMap(($fab) => rxjs.of(JSON.stringify(formState())).pipe(
|
|
rxjs.tap((a) => console.log(a)),
|
|
// rxjs.mergeMap((content) => save(content)),
|
|
rxjs.mergeMap(() => cat().pipe(rxjs.tap((formSpec) => file$.next(JSON.parse(formSpec))))),
|
|
)),
|
|
rxjs.tap(() => {
|
|
$fab.render($ICON.SAVING);
|
|
$fab.removeAttribute("disabled");
|
|
}),
|
|
rxjs.catchError(ctrlError()),
|
|
));
|
|
}
|
|
|
|
export function init() {
|
|
return loadCSS(import.meta.url, "./application_form.css");
|
|
}
|
|
|
|
const formObjToJSON = (o, level = 0) => {
|
|
const obj = Object.assign({}, o);
|
|
Object.keys(obj).forEach((key) => {
|
|
const t = obj[key];
|
|
if ("label" in t && "type" in t && "default" in t && "value" in t) {
|
|
obj[key] = obj[key].value;
|
|
} else {
|
|
obj[key] = formObjToJSON(obj[key], level + 1);
|
|
}
|
|
});
|
|
return obj;
|
|
};
|