on master help sign in
finishing up rewrite of wiki
commitf181ace1bd42f0796dbd253745fecebadec0df16 authorckipp01 <ckipp@pm.me> dateSat 10 Aug 2019, 11:51 (7 years ago) parent6283183
5 files changed+223−22
links/main2.css+31−8 scripts/wiki.js+23−9 scripts/wiki2.js+136 wiki.html+13−5 wiki2.html+20
links/main2.css+31−8
@@ -6,6 +6,7 @@ body > div > ul { padding-bottom: 15px; margin-bottom:15px; }
66body div p { display:block; padding:0px 5px; line-height: 20px;}
77body footer { border-top: 2px solid white; padding-top: 15px; margin-top: 15px;}
88body footer a { text-decoration: underline; }
9+body strong { font-weight: normal; font-family: 'input_mono_medium' }
910body .selected { background: white; color:black; }
1011
1112/* portal */
@@ -20,16 +21,17 @@ body #portal ul li a { line-height: 20px; padding:0px 5px; text-decoration: none
2021body #portal ul li a:visited { color:#ccc; text-decoration: none;}
2122body #portal ul li a:hover { text-decoration: underline; }
2223
24+body aside { min-width: 200px; padding: 0 15px; line-height: 16px; display: none; }
25+body aside ul { margin-bottom: 15px; }
26+body aside #channels li:before, body #sidebar #categories li:before { content:'/'; }
27+body aside #users li:before { content:'@'; }
28+body aside span.right { color: #555; float: right; }
29+body aside li { text-transform: lowercase; cursor: pointer; }
30+
2331/* hallway */
2432
2533body #hallway #entries { display: flex; margin-top: 35px; }
2634body #hallway #entries > div { flex-grow: 1; }
27−body #entries aside { min-width: 200px; padding: 0 15px; line-height: 16px; display: none; }
28−body #entries aside ul { margin-bottom: 15px; }
29−body #entries aside #channels li:before, body #sidebar #categories li:before { content:'/'; }
30−body #entries aside #users li:before { content:'@'; }
31−body #entries aside span.right { color: #555; float: right; }
32−body #entries aside li { text-transform: lowercase; cursor: pointer; }
3335body #hallway #showbar { position: absolute;top: 0px;width: 92%;height: 50px; background-image: url("data:image/svg+xml; utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='22'><path d='M11,4 L11,18 M4,4 L 4,18 M18,4 L18,18' stroke='%23555' fill='none' stroke-width='2' stroke-linecap='round'/></svg>");background-repeat: no-repeat;background-position: right;background-size: 25px; }
3436body #hallway #hidebar { position: absolute;top: 0px;width: 100%;height: 50px;background-image: url("data:image/svg+xml; utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='22'><path d='M5,5 L17,17 M17,5 L5,17' stroke='%23555' fill='none' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");background-repeat: no-repeat;background-position: left;background-size: 25px; }
3537body #hallway .entry { line-height: 16px; display: block; position: relative; padding-left:100px; }
@@ -46,16 +48,37 @@ body #hallway .entry.highlight .author { color:#555; }
4648body #hallway .entry:hover .author { color:#ccc; }
4749body #hallway .entry:hover .date { color:#ccc; }
4850body #hallway .entry:hover .body { color:#ccc; border-bottom-color: #555 }
49−body #hallway #footer { padding-left: 60px; background-image: url(../icon.white.svg); background-size: 40px; background-repeat: no-repeat; background-position: 0px 10px; border-top: 2px solid white; padding-top: 15px; margin-top: 15px; max-width: calc(100% - 300px); min-height: 45px; line-height: 15px;}
51+body #hallway #footer { padding-left: 60px; background-image: url(../icon.white.svg); background-size: 40px; background-repeat: no-repeat; background-position: 0px 10px; border-top: 2px solid white; padding-top: 20px; margin-top: 15px; max-width: calc(100% - 300px); min-height: 45px; line-height: 15px;}
5052
5153body #hallway #pagination { margin: 10px; text-align: center; }
5254body #hallway #pagination span { padding: 3px; margin: 2px; cursor: pointer; }
5355
56+/* wiki */
57+body #wiki { background: #ccc; color:#333; }
58+body #wiki main { display: flex; }
59+body #wiki main { flex: 1; }
60+body #wiki main { max-width: calc(100% - 230px); }
61+body #wiki main h1 { font-size: 1.3em; margin: 5px 0; font-weight: bold; }
62+body #wiki main div.related { border-bottom: 1px solid white; margin-bottom: 10px; }
63+body #wiki #main { width: 100%; }
64+body #wiki #main ul li { line-height: 15px; }
65+body #wiki aside { min-width: 220px; }
66+body #wiki aside { overflow-y: scroll; height: calc(100% - 15px); position: absolute; right: 0;}
67+body #wiki aside a { display: inline-block; width: 135px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; padding: 7px; }
68+body #wiki aside li { line-height: 7px; }
69+body #wiki aside li:before { display: none; }
70+body #wiki aside a:before { content: '/'; }
71+body #wiki aside a:after { content: attr(data-msgs) " msgs"; position: absolute; right: 20px; color:#555; }
72+body #wiki ul.term { margin-bottom: 15px; }
73+body #wiki ul.term li.name { margin-bottom: 5px; }
74+body #wiki #footer { padding-left: 60px; background-image: url(../icon.white.svg); background-size: 40px; background-repeat: no-repeat; background-position: 0px 10px; border-top: 2px solid white; padding-top: 22px; margin-top: 15px; max-width: calc(100% - 300px); min-height: 45px; line-height: 15px;}
75+
5476@media (min-width: 630px) {
77+ body aside { display: block; }
5578 body #portal ul { columns: 3;}
5679 body #hallway #entries { margin-top: 0; }
57− body #hallway #entries aside { display: block; }
5880 body #hallway #showbar { display: none; }
5981 body #hallway #hidebar { display: none; }
82+ body #wiki footer { margin-right: 225px; }
6083}
6184
scripts/wiki.js+23−9
@@ -1,5 +1,4 @@
11'use strict'
2−
32function Wiki (sites) {
43 const feeds = {}
54 this.sites = sites
@@ -45,20 +44,27 @@ function Wiki (sites) {
4544 const html = `${this.templateTerm(this.loc, this.byName[this.loc])}<br />${this.templateRelated(this.loc)}`
4645 this._entry.innerHTML = html
4746 } else {
48− const html = `Unknown: ${this.loc}. Retun <a onclick='wiki.go("")'>home</a>, or try a <a onclick='wiki.go("${this.random()}")'>random page</a>.`
47+ const html = `Unknown: ${this.loc}. Return <a href='#'>home</a>, or try a <a href='${this.random()}'>random page</a>.`
4948 this._entry.innerHTML = html
5049 }
5150 } else {
52− const random = this.random()
53− 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.`
51+ this._entry.innerHTML = `Click a /topic to get started, or try a <a href='#${this.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.`
5452 }
5553 // Sidebar
56− 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>`)
54+ this._categories.innerHTML = Object.keys(this.byCat).reduce((acc, id) =>
55+ { return this.byCat[id].length > 5
56+ ? `${acc}<li ${wiki.at(id) ? 'class="selected"' : ''}>
57+ <a href='#${id}' data-msgs='${this.byCat[id].length}'>${id}</a>
58+ </li>`
59+ : acc
60+ } , `<li ${wiki.at() ? 'class="selected"' : ''}>
61+ <a href='#' data-msgs='${Object.keys(this.byName).length}'>home</a>
62+ </li>`
63+ )
5764 }
5865
59− this.go = (q = window.location.hash.substr(1).replace(/\+/g, ' ').toUpperCase()) => {
60− this.loc = q
61− window.location.hash = q.toUrl()
66+ this.go = () => {
67+ this.loc = decodeURIComponent( window.location.hash.substr(1) ).toUpperCase()
6268 this.refresh()
6369 }
6470
@@ -81,7 +87,12 @@ function Wiki (sites) {
8187
8288 this.templateRelated = (name) => {
8389 const relatedWords = this.related(name)
84− const 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+ const html = `<ul class='col3'>${relatedWords.reduce( (acc, item, id) =>
91+ { return `${acc}<li ${wiki.at(item.name) ? 'class="selected"' : ''}>
92+ <a href='#${item.name.toLowerCase()}'>${item.name.toLowerCase()}</a>
93+ </li>`
94+ }, '') }
95+ </ul>`
8596 return html
8697 }
8798
@@ -135,4 +146,7 @@ function Wiki (sites) {
135146 }
136147
137148 String.prototype.toUrl = function () { return this.toLowerCase().replace(/ /g, '+').replace(/[^0-9a-z+:\-./~]/gi, '').trim() }
149+
150+ window.onload = this.go
151+ window.onhashchange = this.go
138152}
scripts/wiki2.jsnew file+136
@@ -0,0 +1,136 @@
1+'use strict'
2+
3+const 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()
9+
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+ }
22+
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+ }
28+
29+ const transform = (author, url, ndtl) => {
30+ Object.keys(ndtl).forEach(cat => storeEntries(author, url, cat, ndtl[cat]))
31+ }
32+
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+ }
38+
39+ const selected = (key, category) => key.toLowerCase() === category.toLowerCase()
40+ ? 'selected'
41+ : ''
42+
43+ const formatSideBarCat = (key, entries) => (currentHtml, cat) => {
44+ const catLength = Object.keys(entries[cat]).length
45+ const newHtml = `<li class='${selected(key, cat)}'}'>
46+ <a href='#${cat}' data-msgs='${catLength}'>${cat.toLowerCase()}</a>
47+ </li>`
48+ return `${currentHtml}${newHtml}`
49+ }
50+
51+ const formatEntry = (definitions, definition) => {
52+ const formatEntryList = entryList => entryList.reduce((items, item) => `${items}<li>${item}</li>`, '')
53+
54+ const newHtml = typeof definition.entry === 'string'
55+ ? `<li>${definition.entry}
56+ <a class='author' target='_blank' href='${definition.url}'> - @${definition.author}</a>
57+ </li>`
58+ : `<li><ul>${formatEntryList(definition.entry)}
59+ <a class='author' target='_blank' href='${definition.url}'> — @${definition.author}</a>
60+ </ul></li>`
61+
62+ return `${definitions}${newHtml}`
63+ }
64+
65+ const formatEntries = entries => (currentHtml, category) => {
66+ const definitions = entries[category].reduce(formatEntry, '')
67+ const title = category === 'list-definitions'
68+ ? ''
69+ : `<li class='name'><strong>${category.toLowerCase()}</strong></li>`
70+ return `${currentHtml}<ul class='term'>${title}${definitions}</ul>`
71+ }
72+
73+ const findRelated = key => {
74+ const searchOtherCategories = entry => {
75+ return Object.keys(entries)
76+ .filter(category => Object.keys(entries[category]).some(otherCat => otherCat === entry))
77+ }
78+
79+ const foundMatches = Object.keys(entries[key])
80+ .filter(entry => entry !== 'list-definitions')
81+ .map(searchOtherCategories)
82+ const flattened = [].concat.apply([], foundMatches)
83+ return Array.from(new Set(flattened)).filter(related => related !== key)
84+ }
85+
86+ const formatRelated = (allRelated, relatedCategory) => {
87+ const newHtml = `<span><a href='#${relatedCategory}'>/${relatedCategory.toLowerCase()}</a> </span>`
88+ return `${allRelated}${newHtml}`
89+ }
90+
91+ const refresh = key => {
92+ if (key) {
93+ if (entries[key] === undefined) return
94+ const items = Object.keys(entries[key]).sort().reduce(formatEntries(entries[key]), '')
95+ const relatedCategories = findRelated(key)
96+ const relatedHtml = relatedCategories.length > 0
97+ ? relatedCategories.reduce(formatRelated, 'Related categories: ')
98+ : ''
99+ main.innerHTML = `<div class='related'><h1>${key}</h1>${relatedHtml}</div>${items}`
100+ } else {
101+ const html = `Click a /topic to get started, or try a random page`
102+ const stats = `The wiki contains ${terms.size} terms in ${Object.keys(entries).length} categories, from ${authors.size} authors.`
103+ main.innerHTML = `${html}<br />${stats}`
104+ }
105+
106+ const homeCat = `<li class='${selected(key, '')}'>
107+ <a href='#' data-msgs='${terms.size}'>home</a>
108+ </li>`
109+ const cats = Object.keys(entries).sort().reduce(formatSideBarCat(key, entries), homeCat)
110+ aside.innerHTML = `<ul>${cats}</ul>`
111+ }
112+
113+ return {
114+ initialize: hash => {
115+ console.log('Wiki', 'Fetching...')
116+ sites.filter(site => site.wiki && site.author).forEach(site => {
117+ fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then(content => {
118+ parse(site, content)
119+ refresh(stripHash(hash))
120+ }).catch((err) => {
121+ console.warn(`${site.wiki}`, err)
122+ })
123+ })
124+ },
125+ refresh: key => { refresh(key) }
126+ }
127+}
128+
129+const stripHash = hash => {
130+ const decoded = decodeURIComponent(hash)
131+ return decoded.charAt(0) === '#' ? decoded.substring(1) : decoded
132+}
133+
134+window.addEventListener('hashchange', () => {
135+ wiki.refresh(stripHash(window.location.hash).toUpperCase())
136+})
wiki.html+13−5
@@ -4,17 +4,25 @@
44 <meta charset="utf-8">
55 <meta name="viewport" content="width=device-width, initial-scale=1.0">
66 <link rel="stylesheet" type="text/css" href="links/fonts.css"/>
7− <link rel="stylesheet" type="text/css" href="links/main.css"/>
8− <script src="scripts/wiki.js"></script>
7+ <link rel="stylesheet" type="text/css" href="links/main2.css"/>
8+ <script src="scripts/wiki2.js"></script>
99 <script src="scripts/sites.js"></script>
1010 <script src="scripts/indental.js"></script>
1111 <title>Wiki</title>
1212</head>
1313<body>
14+ <div id="wiki">
15+ <main>
16+ <div id="main"></div>
17+ <aside id="aside"></aside>
18+ </main>
19+ <footer id="footer">
20+ <p>The <strong>Wiki</strong> 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>.</p>
21+ </footer>
22+ </div>
1423 <script>
15− const wiki = new Wiki(sites);
16− wiki.install(document.body);
17− wiki.start();
24+ const wiki = Wiki(sites)
25+ wiki.initialize(window.location.hash)
1826 </script>
1927</body>
2028</html>
wiki2.htmlnew file+20
@@ -0,0 +1,20 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+<head>
4+ <meta charset="utf-8">
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6+ <link rel="stylesheet" type="text/css" href="links/fonts.css"/>
7+ <link rel="stylesheet" type="text/css" href="links/main.css"/>
8+ <script src="scripts/wiki.js"></script>
9+ <script src="scripts/sites.js"></script>
10+ <script src="scripts/indental.js"></script>
11+ <title>Wiki</title>
12+</head>
13+<body>
14+ <script>
15+ const wiki = new Wiki(sites);
16+ wiki.install(document.body);
17+ wiki.start();
18+ </script>
19+</body>
20+</html>