on 4e64a9c help sign in
webring/scripts/wiki.js
140 lines 5.2 kB history raw
1'use strict'
3function Wiki (sites) {
4 const feeds = {}
5 this.sites = sites
6 this._el = document.createElement('div')
7 this._el.id = 'wiki'
8 this._sidebar = document.createElement('div')
9 this._sidebar.id = 'sidebar'
10 this._categories = document.createElement('ul')
11 this._categories.id = 'categories'
12 this._entry = document.createElement('div')
13 this._entry.id = 'entry'
15 this._footer = document.createElement('p')
16 this._footer.id = 'footer'
17 this._footer.innerHTML = `The <b>Wiki</b> is a decentralized encyclopedia, to join the conversation, add a <a href="https://github.com/XXIIVV/webring#joining-the-wiki">wiki:</a> field to your entry in the <a href="https://github.com/XXIIVV/Webring/">webring</a>.`
19 this.loc = ''
20 this.byName = {}
21 this.byCat = {}
22 this.byAuthor = {}
24 this.install = (host) => {
25 this._el.appendChild(this._entry)
26 this._sidebar.appendChild(this._categories)
27 this._el.appendChild(this._sidebar)
28 this._el.appendChild(this._footer)
29 host.appendChild(this._el)
30 this.fetch()
31 }
33 this.start = () => {
34 this._entry.innerHTML = 'Loading..'
35 }
37 this.refresh = () => {
38 // Main
39 if (this.loc) {
40 if (this.byCat[this.loc]) {
41 let html = ''
42 for (const id in this.byCat[this.loc]) {
43 const name = this.byCat[this.loc][id].name
44 html += `${this.templateTerm(name, this.byName[name])}<br />`
45 }
46 this._entry.innerHTML = html
47 } else if (this.byName[this.loc]) {
48 let html = `${this.templateTerm(this.loc, this.byName[this.loc])}<br />${this.templateRelated(this.loc, this.byName[this.loc])}`
49 this._entry.innerHTML = html
50 } else {
51 let html = `Unknown: ${this.loc}. Retun <a onclick='wiki.go("")'>home</a>, or try a <a onclick='wiki.go("${this.random()}")'>random page</a>.`
52 this._entry.innerHTML = html
53 }
54 } else {
55 const random = this.random()
56 this._entry.innerHTML = `Click a /topic to get started, or try a <a href='#${random.toUrl()}' onclick='wiki.go("${random}")'>random page</a>.<br />The wiki contains ${Object.keys(this.byName).length} terms, in ${Object.keys(this.byCat).length} categories, by ${Object.keys(this.byAuthor).length} authors.`
57 }
58 // Sidebar
59 this._categories.innerHTML = Object.keys(this.byCat).reduce((acc, id) => { return this.byCat[id].length > 5 ? `${acc}<li onclick='wiki.go("${id}")' class='${wiki.at(id) ? 'selected' : ''}'>${id.substr(0, 20)} <span class='right'>${this.byCat[id].length}</span></li>` : acc }, `<li onclick='wiki.go("")' class='${wiki.at() ? 'selected' : ''}'>home <span class='right'>${Object.keys(this.byName).length}</span></li>`)
60 }
62 this.go = (q = window.location.hash.substr(1).replace(/\+/g, ' ').toUpperCase()) => {
63 this.loc = q
64 window.location.hash = q.toUrl()
65 this.refresh()
66 }
68 this.at = (q = '') => {
69 return this.loc.toUpperCase() === q.toUpperCase() || (this.cat(this.loc).toUpperCase() === q.toUpperCase() && q !== '')
70 }
72 this.random = () => {
73 const keys = Object.keys(this.byCat)
74 return keys[Math.floor(Math.random() * keys.length)]
75 }
77 this.related = (name) => {
78 return this.byCat[this.cat(name)]
79 }
81 this.cat = (name) => {
82 return this.byName[name] ? this.byName[name][0].cat : ''
83 }
85 this.templateRelated = (name, entry) => {
86 let html = ''
87 const cat = entry.cat
88 const relatedWords = this.related(name)
89 html += `<ul class='col3'>${relatedWords.reduce((acc, item, id) => { return `${acc}<li onclick='wiki.go("${item.name}")' class='${wiki.at(item.name) ? 'selected' : ''}'>${item.name.toLowerCase()}</li>` }, '')}</ul>`
90 return html
91 }
93 this.templateTerm = (name, entry) => {
94 return '<ul class="term"><li class="name"><b>' + name.toLowerCase() + '</b></li>' + entry.reduce((acc, item) => { return `${acc}<li>${item.value} <a class='author' target='_blank' href='${item.origin.url}'> — @${item.origin.author}</a></li>` }, '') + '</ul>'
95 }
97 this.fetch = () => {
98 console.log('Wiki', 'Fetching..')
99 for (const site of sites) {
100 if (!site.wiki || !site.author) { continue }
101 fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then((content) => {
102 this.parse(site, content)
103 this.refresh(feeds)
104 }).catch((err) => {
105 console.warn(`${site.wiki}`, err)
106 })
107 }
108 }
110 this.add = (name, value, cat, origin) => {
111 //
112 if (!this.byName[name]) {
113 this.byName[name] = []
114 }
115 this.byName[name].push({ name, value, cat, origin })
116 //
117 if (!this.byCat[cat]) {
118 this.byCat[cat] = []
119 }
120 this.byCat[cat].push({ name, value, cat, origin })
121 //
122 if (!this.byAuthor[origin.author]) {
123 this.byAuthor[origin.author] = []
124 }
125 this.byAuthor[origin.author].push({ name, value, cat, origin })
126 }
128 this.parse = (site, content) => {
129 console.log('Wiki', 'Parsing ' + site.wiki)
130 const cats = indental(content)
131 for (const cat in cats) {
132 const terms = cats[cat]
133 for (const name in terms) {
134 this.add(name, terms[name], cat, site)
135 }
136 }
137 }
139 String.prototype.toUrl = function () { return this.toLowerCase().replace(/ /g, '+').replace(/[^0-9a-z\+\:\-\.\/\~]/gi, '').trim() }