on master help sign in
Merge pull request #159 from Bradshaw/master
be1ef7fЛu Лinveгa
scripts/hallway.js+32−28
@@ -1,5 +1,10 @@
1'use strict'
1'use strict'
2
2
3+const re_channel = /(\s|^)\/([a-zA-Z0-9]+)/g
4+const re_user = /(\s|^)\@([a-zA-Z0-9]+)/g
5+const re_tag = /([^&]|^)\#([a-zA-Z0-9]+)/g
6+const re_url = /((https?):\/\/(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)([-a-zA-Z0-9@:%_\+.~#?&//=]*)))/g
7+
3function Hallway (sites) {
8function Hallway (sites) {
4 const feeds = {}
9 const feeds = {}
5 this.sites = sites
10 this.sites = sites
@@ -22,10 +27,11 @@ function Hallway (sites) {
22 const entries = this.findEntries(feeds)
27 const entries = this.findEntries(feeds)
23 const channels = this.findChannels(entries)
28 const channels = this.findChannels(entries)
24 const users = this.findUsers(entries)
29 const users = this.findUsers(entries)
30+ const tags = this.findTags(entries)
25
31
26 this.el.innerHTML = `
32 this.el.innerHTML = `
27 <ul id='entries'>
33 <ul id='entries'>
28− ${entries.filter((val, id) => { return !(this.filter && val.author !== this.filter && val.channel !== this.filter) }).filter((val, id) => { return id < 50 }).reduce((acc, val, id) => { return acc + this.templateEntry(val) + '\n' }, '')}
34+ ${entries.filter((val, id) => { return !this.filter || (val.author === this.filter || val.channel === this.filter || val.tags.includes(this.filter)) }).filter((val, id) => { return id < 50 }).reduce((acc, val, id) => { return acc + this.templateEntry(val) + '\n' }, '')}
29 </ul>
35 </ul>
30 <div id='sidebar'>
36 <div id='sidebar'>
31 <ul id='channels'>
37 <ul id='channels'>
@@ -35,6 +41,9 @@ function Hallway (sites) {
35 <ul id='users'>
41 <ul id='users'>
36 ${Object.keys(users).reduce((acc, val, id) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}' href='#${val}'>${val} <span class='right'>${users[val]}</span></li>\n` }, '')}
42 ${Object.keys(users).reduce((acc, val, id) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}' href='#${val}'>${val} <span class='right'>${users[val]}</span></li>\n` }, '')}
37 </ul>
43 </ul>
44+ <ul id='tags'>
45+ ${Object.keys(tags).reduce((acc, val, id) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}' href='#${val}'>#${val} <span class='right'>${tags[val]}</span></li>\n` }, '')}
46+ </ul>
38 </div>
47 </div>
39 <p>The <b>Hallway</b> is a decentralized forum, to join the conversation, simply create yourself a <a href="https://twtxt.readthedocs.io/en/stable/user/twtxtfile.html">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>`
48 <p>The <b>Hallway</b> is a decentralized forum, to join the conversation, simply create yourself a <a href="https://twtxt.readthedocs.io/en/stable/user/twtxtfile.html">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>`
40
49
@@ -63,6 +72,17 @@ function Hallway (sites) {
63 }
72 }
64 return users
73 return users
65 }
74 }
75+
76+ this.findTags = function (entries){
77+ const tags = {}
78+ for (const id in entries) {
79+ const entry = entries[id]
80+ entry.tags.map(tag => {
81+ tags[tag] = tags[tag] ? tags[tag] + 1 : 1
82+ })
83+ }
84+ return tags
85+ }
66
86
67 this.findEntries = function (feeds) {
87 this.findEntries = function (feeds) {
68 const a = []
88 const a = []
@@ -71,36 +91,23 @@ function Hallway (sites) {
71 a.push(feeds[id].content[i])
91 a.push(feeds[id].content[i])
72 }
92 }
73 }
93 }
74− return a.sort(compare)
94+ return a.sort( (a, b) => a.offset - b.offset )
75 }
95 }
76
96
77 this.templateEntry = function (entry) {
97 this.templateEntry = function (entry) {
78− const words = entry.body.split(' ')
98+ entry.html = entry.body
79− const users = []
99+ .replace(re_channel, `$1<span class='channel'>/$2</span>`)
80− const channels = []
100+ .replace(re_user, `$1<span class='user'>@$2</span>`)
81− const tags = []
82− const links = []
83−
84− // Channels
85− for (const id in words) {
86− if (words[id].substr(0, 1) === '@') { users.push(words[id]) }
87− if (words[id].substr(0, 1) === '/') { channels.push(words[id]) }
88− if (words[id].substr(0, 1) === '#') { tags.push(words[id]) }
89− if (words[id].substr(0, 4) === 'http') { links.push(words[id]) }
90− }
91−
92− for (const id in users) { entry.body = entry.body.replace(users[id], `<span class='user'>${users[id]}</span>`) }
93− for (const id in channels) { entry.body = entry.body.replace(channels[id], `<span class='channel'>${channels[id]}</span>`) }
94− for (const id in tags) { entry.body = entry.body.replace(tags[id], `<span class='tag'>${tags[id]}</span>`) }
101+ .replace(re_tag, `$1<span class='tag'>#$2</span>`)
95− for (const id in links) { entry.body = entry.body.replace(links[id], `<a href='${links[id]}'>${links[id].replace('https://', '').replace('http://', '')}</a>`) }
102+ .replace(re_url, `<a target="_blank" href='$1'>$1</a>`)
96−
103+
97 const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
104 const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
98 const highlight = filter === entry.author.toLowerCase()
105 const highlight = filter === entry.author.toLowerCase()
99 const origin = feeds[entry.author].path
106 const origin = feeds[entry.author].path
100
107
101− return `<li class='entry ${highlight ? 'highlight' : ''}'><span class='date'>${timeAgo(Date.parse(entry.date))}</span> <a class='author' href='${origin}' target='_blank'>${entry.author}</a> <span class='body'>${entry.body}</span></li>`
108+ return `<li class='entry ${highlight ? 'highlight' : ''}'><span class='date'>${timeAgo(Date.parse(entry.date))}</span> <a class='author' href='${origin}' target='_blank'>${entry.author}</a> <span class='body'>${entry.html}</span></li>`
102 }
109 }
103−
110+
104 // Feeds
111 // Feeds
105
112
106 this.findFeeds = function () {
113 this.findFeeds = function () {
@@ -133,10 +140,6 @@ function Hallway (sites) {
133
140
134 // Utils
141 // Utils
135
142
136− function compare (a, b) {
137− return a.offset < b.offset ? -1 : a.offset > b.offset ? 1 : 0
138− }
139−
140 function parseFeed (author, feed) {
143 function parseFeed (author, feed) {
141 const lines = feed.split('\n')
144 const lines = feed.split('\n')
142 const entries = []
145 const entries = []
@@ -147,8 +150,9 @@ function Hallway (sites) {
147 const date = parts[0].trim()
150 const date = parts[0].trim()
148 const body = escapeHtml(parts[1].trim()).trim()
151 const body = escapeHtml(parts[1].trim()).trim()
149 const channel = body.substr(0, 1) === '/' ? body.split(' ')[0].substr(1).toLowerCase() : body.substr(0, 1) === '@' ? 'veranda' : 'lobby'
152 const channel = body.substr(0, 1) === '/' ? body.split(' ')[0].substr(1).toLowerCase() : body.substr(0, 1) === '@' ? 'veranda' : 'lobby'
153+ const tags = (body.match(re_tag)||[]).map(a => a.substr(a.indexOf('#')+1).toLowerCase())
150 const offset = new Date() - new Date(date)
154 const offset = new Date() - new Date(date)
151− entries.push({ date, body, author, offset, channel })
155+ entries.push({ date, body, author, offset, channel, tags })
152 }
156 }
153 return entries
157 return entries
154 }
158 }