'use strict'
const Wiki = sites => {
const entries = {}
const main = document.getElementById('main')
const aside = document.getElementById('aside')
const progress = document.getElementById('progress')
const progressCounter = Progress(sites.map(site => site.wiki))
const authors = new Set()
const terms = new Set()
const storeEntry = (author, url, category, term, entry) => {
if (!(category in entries)) {
entries[category] = {}
entries[category][term] = [{ entry, authors: [{ author, url }] }]
} else if (!(term in entries[category])) {
entries[category][term] = [{ entry, authors: [{ author, url }] }]
} else {
const possibleIndex = entries[category][term].findIndex(existing => existing.entry === entry)
possibleIndex > -1
? entries[category][term][possibleIndex].authors.push({ author, url })
: entries[category][term].push({ entry, authors: [{ author, url }] })
}
terms.add(term)
authors.add(author)
}
const storeEntries = (author, url, category, entries) => {
Array.isArray(entries)
? storeEntry(author, url, category, 'list-definitions', entries)
: Object.keys(entries).forEach(entry => storeEntry(author, url, category, entry, entries[entry]))
}
const transform = (author, url, ndtl) => {
Object.keys(ndtl).forEach(category => storeEntries(author, url, category, ndtl[category]))
}
const parse = (site, content) => {
console.log('Wiki', 'Parsing ' + site.wiki)
const ndtl = indental(content)
transform(site.author, site.url, ndtl)
}
const selected = (key, category) => key.toLowerCase() === category.toLowerCase()
? 'selected'
: ''
const randomTerm = () => {
const keys = Object.keys(entries)
return keys[Math.floor(Math.random() * keys.length)]
}
const formatSideBarCat = (key, entries) => (currentHtml, cat) => {
const catLength = Object.keys(entries[cat]).length
const newHtml = `
${cat.toLowerCase()}
`
return `${currentHtml}${newHtml}`
}
const formatLinks = text => text.replace(
/\b((https?|dat):\/\/[^"\s]+)/g,
'$1'
)
const formatAuthor = (authors, author) => {
return `${authors} @${author.author}`
}
const formatEntry = (definitions, definition) => {
const formatEntryList = entryList => entryList.reduce((items, item) => `${items}${formatLinks(item)}`, '')
const newHtml = typeof definition.entry === 'string'
? `${formatLinks(definition.entry)}
- ${definition.authors.reduce(formatAuthor, '')}
`
: `${formatEntryList(definition.entry)}
- ${definition.authors.reduce(formatAuthor, '')}
`
return `${definitions}${newHtml}`
}
const formatEntries = entries => (currentHtml, category) => {
const definitions = entries[category].reduce(formatEntry, '')
const title = category === 'list-definitions'
? ''
: `${category.toLowerCase()}`
return `${currentHtml}`
}
const findRelated = key => {
const searchOtherCategories = entry => {
return Object.keys(entries)
.filter(category => Object.keys(entries[category]).some(otherCat => otherCat === entry))
}
const foundMatches = Object.keys(entries[key])
.filter(entry => entry !== 'list-definitions')
.map(searchOtherCategories)
const flattened = [].concat.apply([], foundMatches)
return Array.from(new Set(flattened)).filter(related => related !== key)
}
const formatRelated = (allRelated, relatedCategory) => {
const newHtml = `/${relatedCategory.toLowerCase()} `
return `${allRelated}${newHtml}`
}
const refresh = key => {
if (key) {
if (entries[key] === undefined) return
const items = Object.keys(entries[key]).sort().reduce(formatEntries(entries[key]), '')
const relatedCategories = findRelated(key)
const relatedHtml = relatedCategories.length > 0
? relatedCategories.reduce(formatRelated, 'Related categories: ')
: ''
main.innerHTML = `${key}
${relatedHtml}${items}`
} else {
const html = `Click a /topic to get started, or try a random page`
const stats = `The wiki contains ${terms.size} terms in ${Object.keys(entries).length} categories, from ${authors.size} authors.`
main.innerHTML = `WIKI
${html}
${stats}`
}
const homeCat = `
home
`
const cats = Object.keys(entries).sort().reduce(formatSideBarCat(key, entries), homeCat)
aside.innerHTML = ``
}
const refreshProgress = () => {
progress.innerHTML = `${progressCounter}`
}
return {
initialize: hash => {
console.log('Wiki', 'Fetching...')
refreshProgress()
sites.filter(site => site.wiki && site.author).forEach(site => {
fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then(content => {
parse(site, content)
refresh(stripHash(hash))
progressCounter.success(site.wiki).then(refreshProgress)
}).catch((err) => {
console.warn(`${site.wiki}`, err)
progressCounter.failure(site.wiki).then(refreshProgress)
})
})
},
refresh: key => { refresh(key) }
}
}
const stripHash = hash => {
const decoded = decodeURIComponent(hash)
return decoded.charAt(0) === '#' ? decoded.substring(1) : decoded
}
window.addEventListener('hashchange', () => {
wiki.refresh(stripHash(window.location.hash).toUpperCase())
})