// Extract child nodes
Object.values(tale.passages).map(v => v.childPassages = [...v.processText().matchAll(/\[\[([^|]*?)\|([^|]*?)\]\]/g)]);
// Map tree of paths
mapTree = (passageTitle, path) => {
if (path.includes(passageTitle))
return;
let passage = tale.passages[passageTitle];
if (!passage)
return;
passage.parentPassages = [...path];
passage.childPassages.map(c=>c[2]).forEach(p => mapTree(p, [...path, passageTitle]));
};
// Start tree with `Start` passage
mapTree('Start', []);
// Determine max size of each passage, starting with deepest parts of tree
Object.values(tale.passages).filter(p => p.parentPassages).sort((l, r) => r.parentPassages.length - l.parentPassages.length).forEach(p => {
p.maxSize = [...p.processText().matchAll(/\w+/g)].length + 1 + ((p.childPassages ?? []).map(c=>c[2]).map(n => tale.passages[n]).filter(c => c && c.maxSize).sort((l, r) => r.maxSize - l.maxSize)[0]?.maxSize ?? 0);
});
// Add path to passage header
Object.values(tale.passages).filter(p => p.parentPassages).forEach(p => {
let path = [...p.parentPassages, p.title].map(n=>{
let np = tale.passages[n];
let pn = np.parentPassages[np.parentPassages.length-1];
if (pn === undefined) return '';
return tale.passages[pn].childPassages.find(c=>c[2]===n)[1];
});
p.text = path.join(' > ') + '<br/><br/>' + p.text;
});
// Add depth/word count to passage links
Object.values(tale.passages).filter(p => p.maxSize).forEach(p => {
p.text = p.text.replaceAll(/\[\[([^|]*?)\|([^|]*?)\]\]/g, (m0, m1, m2) => `[[${m1}${tale.passages[m2]?.maxSize?' ('+tale.passages[m2].maxSize+')':''}|${m2}]]`)
});
// Refresh the current passage
document.getElementById('passages').childNodes[0].replaceWith((() => {
let e = tale.passages[document.getElementById('passages').children[0].id.substr(7)].render();
e.style.visibility = 'visible';
return e;
})())