5 const main = document.getElementById('main')
6 const aside = document.getElementById('aside')
7 const progress = document.getElementById('progress')
8 const progressCounter = Progress(sites.map(site => site.wiki))
9 const authors = new Set()
10 const terms = new Set()
12 const storeEntry = (author, url, parent, cat, entry) => {
13 if (!(parent in entries)) {
15 entries[parent][cat] = [{ entry, author, url }]
16 } else if (!(cat in entries[parent])) {
17 entries[parent][cat] = [{ entry, author, url }]
19 entries[parent][cat].push({ entry, author, url })
25 const storeEntries = (author, url, parent, entries) => {
26 Array.isArray(entries)
27 ? storeEntry(author, url, parent, 'list-definitions', entries)
28 : Object.keys(entries).forEach(entry => storeEntry(author, url, parent, entry, entries[entry]))
31 const transform = (author, url, ndtl) => {
32 Object.keys(ndtl).forEach(cat => storeEntries(author, url, cat, ndtl[cat]))
35 const parse = (site, content) => {
36 console.log('Wiki', 'Parsing ' + site.wiki)
37 const ndtl = indental(content)
38 transform(site.author, site.url, ndtl)
41 const selected = (key, category) => key.toLowerCase() === category.toLowerCase()
45 const randomTerm = () => {
46 const keys = Object.keys(entries)
47 return keys[Math.floor(Math.random() * keys.length)]
50 const formatSideBarCat = (key, entries) => (currentHtml, cat) => {
51 const catLength = Object.keys(entries[cat]).length
52 const newHtml = `<li class='${selected(key, cat)}'}'>
53 <a href='#${cat}' data-msgs='${catLength}'>${cat.toLowerCase()}</a>
55 return `${currentHtml}${newHtml}`
58 const formatLinks = text => text.replace(
59 new RegExp('\\b(https?://[^."\\s]+\\.[^"\\s]+)', 'g'),
60 '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>'
63 const formatEntry = (definitions, definition) => {
64 const formatEntryList = entryList => entryList.reduce((items, item) => `${items}<li>${formatLinks(item)}</li>`, '')
66 const newHtml = typeof definition.entry === 'string'
67 ? `<li>${formatLinks(definition.entry)}
68 - <a class='author' target='_blank' href='${definition.url}'> @${definition.author}</a>
70 : `<li><ul>${formatEntryList(definition.entry)}
71 <a class='author' target='_blank' href='${definition.url}'> — @${definition.author}</a>
74 return `${definitions}${newHtml}`
77 const formatEntries = entries => (currentHtml, category) => {
78 const definitions = entries[category].reduce(formatEntry, '')
79 const title = category === 'list-definitions'
81 : `<li class='name'><strong>${category.toLowerCase()}</strong></li>`
82 return `${currentHtml}<ul class='term'>${title}${definitions}</ul>`
85 const findRelated = key => {
86 const searchOtherCategories = entry => {
87 return Object.keys(entries)
88 .filter(category => Object.keys(entries[category]).some(otherCat => otherCat === entry))
91 const foundMatches = Object.keys(entries[key])
92 .filter(entry => entry !== 'list-definitions')
93 .map(searchOtherCategories)
94 const flattened = [].concat.apply([], foundMatches)
95 return Array.from(new Set(flattened)).filter(related => related !== key)
98 const formatRelated = (allRelated, relatedCategory) => {
99 const newHtml = `<span><a href='#${relatedCategory}'>/${relatedCategory.toLowerCase()}</a> </span>`
100 return `${allRelated}${newHtml}`
103 const refresh = key => {
105 if (entries[key] === undefined) return
106 const items = Object.keys(entries[key]).sort().reduce(formatEntries(entries[key]), '')
107 const relatedCategories = findRelated(key)
108 const relatedHtml = relatedCategories.length > 0
109 ? relatedCategories.reduce(formatRelated, 'Related categories: ')
111 main.innerHTML = `<div class='related'><h1>${key}</h1>${relatedHtml}</div>${items}`
113 const html = `Click a /topic to get started, or try a <a href='#${randomTerm()}'>random page</a>`
114 const stats = `The wiki contains ${terms.size} terms in ${Object.keys(entries).length} categories, from ${authors.size} authors.`
115 main.innerHTML = `<h1>WIKI</h1>${html}<br />${stats}`
118 const homeCat = `<li class='${selected(key, '')}'>
119 <a href='#' data-msgs='${terms.size}'>home</a>
121 const cats = Object.keys(entries).sort().reduce(formatSideBarCat(key, entries), homeCat)
122 aside.innerHTML = `<ul>${cats}</ul>`
125 const refreshProgress = () => {
126 progress.innerHTML = progressCounter.render()
130 initialize: hash => {
131 console.log('Wiki', 'Fetching...')
133 sites.filter(site => site.wiki && site.author).forEach(site => {
134 fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then(content => {
136 refresh(stripHash(hash))
137 progressCounter.success(site.wiki).then(refreshProgress)
139 console.warn(`${site.wiki}`, err)
140 progressCounter.failure(site.wiki).then(refreshProgress)
144 refresh: key => { refresh(key) }
148const stripHash = hash => {
149 const decoded = decodeURIComponent(hash)
150 return decoded.charAt(0) === '#' ? decoded.substring(1) : decoded
153window.addEventListener('hashchange', () => {
154 wiki.refresh(stripHash(window.location.hash).toUpperCase())
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list