359 lines
11 KiB
Svelte
359 lines
11 KiB
Svelte
<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>
|