SandpointsEditPage/src/App.svelte
2021-08-25 02:31:34 +02:00

359 lines
11 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
import SpTitle from "./SpTitle.svelte";
import SpTiers from "./SpTiers.svelte";
import SpKeys from "./SpKeys.svelte";
import SpCandidates from "./SpCandidates.svelte";
import SpJournal from "./SpJournal.svelte";
import SpNotsand from "./SpNotsand.svelte";
import { onMount } from "svelte";
let v = "loading...";
let relpath = "";
let relpermalink = "";
let protocol = "";
let title = "Foo bar";
let hases = [];
let hasesCandidates = [];
let frontmatter = {};
let formaction = "edit";
frontmatter["triad"] = [];
frontmatter["ascription"] = [];
frontmatter["journal"] = [];
frontmatter["notsand"] = [];
function keyUp(e) {
if (e.key == "Escape") {
window.history.back();
}
}
function reckonHasesCandidates() {
return diffArrr(hases, [
...frontmatter["triad"].map((t) => {
return t.fmKey;
}),
...frontmatter["ascription"].map((t) => {
return t.fmKey;
}),
]);
}
function diffArrr(arr, arrr) {
let diff = new Set(arr);
for (let e of arrr) {
diff.delete(e);
}
return Array.from(diff);
}
function newFmItem(fmKeyType, fmKey, fmValue) {
if (["abstract", "keywords"].includes(fmKey.toLowerCase())) {
fmKeyType = "journal";
}
if (fmKey == "_new") {
fmKey = `_new${Math.random()}`;
}
if (Array.isArray(fmValue)) {
let fmValueArray = [];
fmValue.forEach((v) => fmValueArray.push(v));
frontmatter[fmKeyType].push({ fmKey: fmKey, fmValue: fmValueArray });
} else {
frontmatter[fmKeyType].push({ fmKey: fmKey, fmValue: fmValue });
}
console.log("newFmItem", { frontmatter });
hasesCandidates = [...new Set(reckonHasesCandidates())];
toggleNewTiersButtons();
}
function swapTier(arrg) {
const [fmKeyType, fmKey, oldFmKey] = arrg.detail;
removeTier(fmKeyType, oldFmKey);
newTier(fmKeyType, fmKey, null);
}
function newTier(fmKeyType, fmKey, fmValue) {
let tiers = [];
let candidates = [];
if (fmKey == "_new") {
hasesCandidates = [...new Set(reckonHasesCandidates())];
if (hasesCandidates.length > 0) {
fmKey = hasesCandidates[0];
}
}
if (fmKey != "_new") {
if (fmValue) {
METASP[fmKey].tiers.forEach((t) => {
if (fmValue.includes(t.file)) {
tiers.push(t);
} else {
candidates.push(t);
}
});
} else {
tiers = [];
candidates = METASP[fmKey].tiers;
}
frontmatter[fmKeyType].push({
fmKey: fmKey,
tiers: tiers,
candidates: [...new Set(candidates)],
});
frontmatter = { ...frontmatter };
}
hasesCandidates = [...new Set(reckonHasesCandidates())];
toggleNewTiersButtons();
}
function loadHugoPageMetadata(editHash) {
let el = document.createElement("script");
el.onload = () => {
v = repo.content;
if (v.startsWith("\n")) {
v = v.substring(1);
}
relpath = repo.path;
relpermalink = repo.relpermalink;
const notSelf = Object.entries(METASP).filter((n) => n[1].singular == relpath.split("/")[0])[0][0];
hases = Object.keys(METASP).filter((k) => k != notSelf);
Object.entries(repo.frontmatter).forEach(([fmKey, fmValue]) => {
let fmKeyType = "";
if (fmKey.toLowerCase().startsWith("has_")) {
if (hases.includes(fmKey.substr(4))) {
fmKeyType = "triad";
fmKey = fmKey.substr(4);
}
} else if (hases.includes(fmKey.toLowerCase())) {
fmKeyType = "ascription";
} else if (["abstract", "keywords"].includes(fmKey.toLowerCase())) {
fmKeyType = "journal";
} else {
fmKeyType = "notsand";
}
if (["triad", "ascription"].includes(fmKeyType)) {
if (Array.isArray(fmValue)) {
newTier(fmKeyType, fmKey, fmValue);
}
} else if (!["draft", "iscjklanguage", "title"].includes(fmKey)) {
newFmItem(fmKeyType, fmKey, fmValue);
}
});
const tkey = Object.keys(repo.frontmatter).filter((t) => t.toLowerCase() == "title")[0];
title = repo.frontmatter[tkey];
toggleNewTiersButtons();
};
el.src = `../js/repo/${editHash}.js`;
document.body.appendChild(el);
}
function addToCandidatesRemoveFromTiers(arrgs) {
const [fmKeyType, index, fmKey, tier] = arrgs.detail;
frontmatter[fmKeyType][index]["fmKey"] = fmKey;
frontmatter[fmKeyType][index]["tiers"] = frontmatter[fmKeyType][index]["tiers"].filter(
(t) => t !== tier
);
frontmatter[fmKeyType][index]["candidates"] = [...frontmatter[fmKeyType][index]["candidates"], tier];
}
function addToTiersRemoveFromCandidates(arrgs) {
const [fmKeyType, index, , value] = arrgs.detail;
const tier = frontmatter[fmKeyType][index]["candidates"].filter((t) => t.file == value);
if (tier.length > 0) {
frontmatter[fmKeyType][index]["tiers"] = [...frontmatter[fmKeyType][index]["tiers"], tier[0]];
frontmatter[fmKeyType][index]["candidates"] = frontmatter[fmKeyType][index]["candidates"].filter(
(t) => t != tier[0]
);
}
}
function fmItemDottedBorder(e) {
e.target.parentNode.parentNode.style.border = "2px #ff000075 dotted";
}
function fmItemNoBorder(e) {
e.target.parentNode.parentNode.style.border = "0px";
}
function removeTier(fmKey, fmValue) {
frontmatter[fmKey] = frontmatter[fmKey].filter((v) => v["fmKey"] != fmValue["fmKey"]);
toggleNewTiersButtons();
}
function toggleFold() {
let e = document.getElementById("frontmatter");
if (e && e.classList.contains("fmHidden")) {
e.classList.remove("fmHidden");
e.classList.add("fmShown");
} else if (e && e.classList.contains("fmShown")) {
e.classList.remove("fmShown");
e.classList.add("fmHidden");
}
let i = document.getElementById("fmicon");
if (i && i.classList.contains("fmCollapse")) {
i.classList.remove("fmCollapse");
i.classList.add("fmExpand");
} else if (i && i.classList.contains("fmExpand")) {
i.classList.remove("fmExpand");
i.classList.add("fmCollapse");
}
}
function toggleNewTiersButtons() {
hasesCandidates = [...new Set(reckonHasesCandidates())];
if (hasesCandidates.length == 0) {
document.querySelectorAll(".newtiers").forEach((button) => {
button.style.display = "none";
});
} else {
document.querySelectorAll(".newtiers").forEach((button) => {
button.style.display = "block";
});
}
const ct = Object.entries(frontmatter).filter((i) => i[1].length == 0 && i[0] == "triad")[0];
if (!ct) {
document.getElementById("newtriad").style.display = "none";
}
}
function dispatchHash() {
protocol = document.location.protocol.substring(0, 4);
const searchParams = new URLSearchParams(location.search);
const editHash = searchParams.get("edit");
if (editHash) {
loadHugoPageMetadata(editHash);
} else {
let newPage = searchParams.get("new");
formaction = "new";
v = "waiting for your input here...";
title = "Please, change this title...";
relpath = `${newPage}/newfile.md`;
hases = Object.keys(METASP).filter((k) => k != newPage);
toggleNewTiersButtons();
}
}
onMount(() => {
dispatchHash();
// loadHugoPageMetadata();
console.dir({ frontmatter });
});
$: hashChanged = () => dispatchHash();
</script>
<svelte:window on:keyup={keyUp} on:hashchange={hashChanged} />
<main id="sandpoints">
<form>
<div class="formgrid">
<SpTitle {relpath} {title} {formaction} />
</div>
<div id="fmicon" on:click={toggleFold} class="fmCollapse">Frontmatter</div>
<span id="frontmatter" class="fmHidden">
{#each Object.entries(frontmatter) as fmItems}
{#each fmItems[1] as fmItem, i}
{#if ["ascription", "triad"].includes(fmItems[0])}
<div class="fmMeta">
<div class="fmMetaTitle">
{fmItems[0]}<button
type="button"
on:click={() => removeTier(fmItems[0], fmItem)}
on:mouseover={fmItemDottedBorder}
on:mouseout={fmItemNoBorder}>×</button
>
</div>
<div class="fmItem">
<SpKeys
fmKeyType={fmItems[0]}
{fmItem}
{hases}
{hasesCandidates}
on:hasTiersSelected={swapTier}
/>
<SpTiers
on:addToCandidatesRemoveFromTiers={addToCandidatesRemoveFromTiers}
index={i}
fmKeyType={fmItems[0]}
{fmItem}
/>
<SpCandidates
on:addToTiersRemoveFromCandidates={addToTiersRemoveFromCandidates}
index={i}
fmKeyType={fmItems[0]}
{fmItem}
/>
</div>
</div>
{:else if fmItems[0] == "journal"}
<div class="fmMeta">
<div class="fmMetaTitle">
{fmItems[0]}<button
type="button"
on:click={() => removeTier(fmItems[0], fmItem)}
on:mouseover={fmItemDottedBorder}
on:mouseout={fmItemNoBorder}>×</button
>
</div>
<div class="fmItem">
<SpJournal {fmItem} />
</div>
</div>
{:else if fmItems[0] == "notsand"}
<div class="fmMeta">
<div class="fmMetaTitle">
Not Sandpoints<button
type="button"
on:click={() => removeTier(fmItems[0], fmItem)}
on:mouseover={fmItemDottedBorder}
on:mouseout={fmItemNoBorder}>×</button
>
</div>
<div class="fmItem">
<SpNotsand {fmItem} />
</div>
</div>
{/if}
{/each}
{/each}
<div class="newtiersbar">
<div id="newtierstitle">Add new:</div>
<div id="newtriad" class="newtiers newtierbutton" on:click={() => newTier("triad", "_new", null)}>
TRIAD TIER
</div>
<div
id="newascription"
class="newtiers newtierbutton"
on:click={() => newTier("ascription", "_new", null)}
>
ASCRIPTION
</div>
<div id="newfmitem" class="newtierbutton" on:click={() => newFmItem("notsand", "_new", null)}>
MISC
</div>
</div>
</span>
<div class="formgrid">
<label for="pagecontent" class="labelcontent">Content:</label>
<textarea
id="pagecontent"
bind:value={v}
oninput="this.style.height = '';this.style.height = this.scrollHeight + 3 + 'px'"
/>
{#if document.location.protocol.substring(0, 4) != "file"}
<label for="publish">Publish</label>
<input type="checkbox" id="publish" name="publish" />
{/if}
<label for="offline" class="labeloffline">Offline</label>
<input type="checkbox" id="offline" name="offline" checked={protocol == "file" ? true : false} />
<input type="hidden" name="relpermalink" bind:value={relpermalink} />
<input type="hidden" name="protocol" bind:value={protocol} />
<button id="sandpointsButton">COMMIT/SAVE</button>
</div>
</form>
</main>