on b372e31 help sign in
webring/scripts/wiki.js
127 lines 4.6 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.loc = ''
16 this.byName = {}
17 this.byCat = {}
18 this.byAuthor = {}
20 this.install = (host) => {
21 console.log('Wiki', 'Installing..')
22 this.fetch()
23 this._el.appendChild(this._entry)
24 this._sidebar.appendChild(this._categories)
25 this._el.appendChild(this._sidebar)
26 host.appendChild(this._el)
27 }
29 this.start = () => {
30 console.log('Wiki', 'Starting..')
31 this.loc = window.location.hash.substr(1).replace(/\+/g, ' ').toUpperCase()
32 this._entry.innerHTML = 'Loading..'
33 }
35 this.refresh = () => {
36 // Main
37 if (this.loc) {
38 if (this.byCat[this.byName]) {
39 let html = `term: ${this.loc}`
40 this._entry.innerHTML = html
41 } else if (this.byCat[this.loc]) {
42 let html = ''
43 for (const id in this.byCat[this.loc]) {
44 const name = this.byCat[this.loc][id].name
45 html += `${this.templateTerm(name, this.byName[name])}<br />`
46 }
47 this._entry.innerHTML = html
48 } else {
49 let html = `Unknown: ${this.loc}. Retun <a onclick='wiki.go("")'>home</a>, or try a <a onclick='wiki.go("${this.random()}")'>random page</a>.`
50 this._entry.innerHTML = html
51 }
52 } else {
53 const random = this.random()
54 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.`
55 }
56 // Sidebar
57 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 }, '')
58 this._entry.innerHTML += `<p id='footer'>The <b>Wiki</b> is a decentralized encyclopedia, to join the conversation, simply create yourself an <a href="https://wiki.xxiivv.com/Indental">twtxt</a> feed and <a href="https://github.com/XXIIVV/Webring/">add it</a> to your entry in the <a href="index.html">webring</a>.</p>`
59 }
61 this.go = (q = this.loc) => {
62 this.loc = q
63 window.location.hash = q.toUrl()
64 this.refresh()
65 }
67 this.at = (q = '') => {
68 return this.loc.toUpperCase() === q.toUpperCase()
69 }
71 this.random = () => {
72 const keys = Object.keys(this.byCat)
73 const target = Math.floor(Math.random() * keys.length)
74 return keys[target]
75 }
77 this.templateTerm = (name, entry) => {
78 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>'
79 }
81 this.fetch = () => {
82 console.log('Wiki', 'Fetching..')
83 for (const site of sites) {
84 if (!site.wiki || !site.author) { continue }
85 fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then((content) => {
86 this.parse(site, content)
87 this.refresh(feeds)
88 }).catch((err) => {
89 console.warn(`${site.wiki}`, err)
90 })
91 }
92 }
94 this.add = (name, value, cat, origin) => {
95 //
96 if (!this.byName[name]) {
97 this.byName[name] = []
98 }
99 this.byName[name].push({ name, value, cat, origin })
100 //
101 if (!this.byCat[cat]) {
102 this.byCat[cat] = []
103 }
104 this.byCat[cat].push({ name, value, cat, origin })
105 //
106 if (!this.byAuthor[origin.author]) {
107 this.byAuthor[origin.author] = []
108 }
109 this.byAuthor[origin.author].push({ name, value, cat, origin })
110 }
112 this.parse = (site, content) => {
113 console.log('Wiki', 'Parsing ' + site.wiki)
114 const cats = indental(this.filter(content))
115 for (const cat in cats) {
116 const terms = cats[cat]
117 for (const name in terms) {
118 this.add(name, terms[name], cat, site)
119 }
120 }
121 }
123 this.filter = (lines) => {
124 return lines.split('\n').filter((line) => { return line.indexOf(' = `') < 0 && line.trim().length > 1 }).join('\n')
125 }
126 String.prototype.toUrl = function () { return this.toLowerCase().replace(/ /g, '+').replace(/[^0-9a-z\+\:\-\.\/\~]/gi, '').trim() }