on 58ed1df help sign in
webring/scripts/wiki.js
141 lines 5.1 kB history raw
1'use strict'
3const Wiki = sites => {
4 const entries = {}
5 const main = document.getElementById('main')
6 const aside = document.getElementById('aside')
7 const authors = new Set()
8 const terms = new Set()
10 const storeEntry = (author, url, parent, cat, entry) => {
11 if (!(parent in entries)) {
12 entries[parent] = {}
13 entries[parent][cat] = [{ entry, author, url }]
14 } else if (!(cat in entries[parent])) {
15 entries[parent][cat] = [{ entry, author, url }]
16 } else {
17 entries[parent][cat].push({ entry, author, url })
18 }
19 terms.add(cat)
20 authors.add(author)
21 }
23 const storeEntries = (author, url, parent, entries) => {
24 Array.isArray(entries)
25 ? storeEntry(author, url, parent, 'list-definitions', entries)
26 : Object.keys(entries).forEach(entry => storeEntry(author, url, parent, entry, entries[entry]))
27 }
29 const transform = (author, url, ndtl) => {
30 Object.keys(ndtl).forEach(cat => storeEntries(author, url, cat, ndtl[cat]))
31 }
33 const parse = (site, content) => {
34 console.log('Wiki', 'Parsing ' + site.wiki)
35 const ndtl = indental(content)
36 transform(site.author, site.url, ndtl)
37 }
39 const selected = (key, category) => key.toLowerCase() === category.toLowerCase()
40 ? 'selected'
41 : ''
43 const randomTerm = () => {
44 const keys = Object.keys(entries)
45 return keys[Math.floor(Math.random() * keys.length)]
46 }
48 const formatSideBarCat = (key, entries) => (currentHtml, cat) => {
49 const catLength = Object.keys(entries[cat]).length
50 const newHtml = `<li class='${selected(key, cat)}'}'>
51 <a href='#${cat}' data-msgs='${catLength}'>${cat.toLowerCase()}</a>
52 </li>`
53 return `${currentHtml}${newHtml}`
54 }
56 const formatEntry = (definitions, definition) => {
57 const formatEntryList = entryList => entryList.reduce((items, item) => `${items}<li>${item}</li>`, '')
59 const newHtml = typeof definition.entry === 'string'
60 ? `<li>${definition.entry}
61 <a class='author' target='_blank' href='${definition.url}'> - @${definition.author}</a>
62 </li>`
63 : `<li><ul>${formatEntryList(definition.entry)}
64 <a class='author' target='_blank' href='${definition.url}'> — @${definition.author}</a>
65 </ul></li>`
67 return `${definitions}${newHtml}`
68 }
70 const formatEntries = entries => (currentHtml, category) => {
71 const definitions = entries[category].reduce(formatEntry, '')
72 const title = category === 'list-definitions'
73 ? ''
74 : `<li class='name'><strong>${category.toLowerCase()}</strong></li>`
75 return `${currentHtml}<ul class='term'>${title}${definitions}</ul>`
76 }
78 const findRelated = key => {
79 const searchOtherCategories = entry => {
80 return Object.keys(entries)
81 .filter(category => Object.keys(entries[category]).some(otherCat => otherCat === entry))
82 }
84 const foundMatches = Object.keys(entries[key])
85 .filter(entry => entry !== 'list-definitions')
86 .map(searchOtherCategories)
87 const flattened = [].concat.apply([], foundMatches)
88 return Array.from(new Set(flattened)).filter(related => related !== key)
89 }
91 const formatRelated = (allRelated, relatedCategory) => {
92 const newHtml = `<span><a href='#${relatedCategory}'>/${relatedCategory.toLowerCase()}</a> </span>`
93 return `${allRelated}${newHtml}`
94 }
96 const refresh = key => {
97 if (key) {
98 if (entries[key] === undefined) return
99 const items = Object.keys(entries[key]).sort().reduce(formatEntries(entries[key]), '')
100 const relatedCategories = findRelated(key)
101 const relatedHtml = relatedCategories.length > 0
102 ? relatedCategories.reduce(formatRelated, 'Related categories: ')
103 : ''
104 main.innerHTML = `<div class='related'><h1>${key}</h1>${relatedHtml}</div>${items}`
105 } else {
106 const html = `Click a /topic to get started, or try a <a href='#${randomTerm()}'>random page</a>`
107 const stats = `The wiki contains ${terms.size} terms in ${Object.keys(entries).length} categories, from ${authors.size} authors.`
108 main.innerHTML = `${html}<br />${stats}`
109 }
111 const homeCat = `<li class='${selected(key, '')}'>
112 <a href='#' data-msgs='${terms.size}'>home</a>
113 </li>`
114 const cats = Object.keys(entries).sort().reduce(formatSideBarCat(key, entries), homeCat)
115 aside.innerHTML = `<ul>${cats}</ul>`
116 }
118 return {
119 initialize: hash => {
120 console.log('Wiki', 'Fetching...')
121 sites.filter(site => site.wiki && site.author).forEach(site => {
122 fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then(content => {
123 parse(site, content)
124 refresh(stripHash(hash))
125 }).catch((err) => {
126 console.warn(`${site.wiki}`, err)
127 })
128 })
129 },
130 refresh: key => { refresh(key) }
131 }
134const stripHash = hash => {
135 const decoded = decodeURIComponent(hash)
136 return decoded.charAt(0) === '#' ? decoded.substring(1) : decoded
139window.addEventListener('hashchange', () => {
140 wiki.refresh(stripHash(window.location.hash).toUpperCase())
141})