@@ -1,7 +1,7 @@
1'use strict'
1'use strict'
3const re_channel = /(\s|^)\/([a-zA-Z0-9]+)/g
3const re_channel = /(\s|^)\/([a-zA-Z0-9]+)/g
4−const re_user = /(\s|^)\@([a-zA-Z0-9]+)/g
4+const re_user = /((\s|^)@<[a-zA-Z0-9./:\-_\+~#= ]*>)/g
5const re_tag = /([^&]|^)\#([a-zA-Z0-9]+)/g
5const re_tag = /([^&]|^)\#([a-zA-Z0-9]+)/g
6const re_url = /((https?):\/\/(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)([-a-zA-Z0-9@:%_\+.~#?&//=]*)))/g
6const re_url = /((https?):\/\/(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)([-a-zA-Z0-9@:%_\+.~#?&//=]*)))/g
@@ -31,18 +31,18 @@ function Hallway (sites) {
32 this.el.innerHTML = `
32 this.el.innerHTML = `
33 <ul id='entries'>
33 <ul id='entries'>
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' }, '')}
34+ ${entries.filter((val) => { return !this.filter || (val.author === this.filter || val.channel === this.filter || val.tags.includes(this.filter)) }).filter((_, id) => { return id < 50 }).reduce((acc, val) => { return acc + this.templateEntry(val) + '\n' }, '')}
36 <div id='sidebar'>
36 <div id='sidebar'>
37 <ul id='channels'>
37 <ul id='channels'>
38 <li onclick='filter("")' class='${hallway.filter === '' ? 'selected' : ''}'><a href='#'>hallway <span class='right'>${entries.length}</span></a></li>
38 <li onclick='filter("")' class='${hallway.filter === '' ? 'selected' : ''}'><a href='#'>hallway <span class='right'>${entries.length}</span></a></li>
39− ${Object.keys(channels).reduce((acc, val, id) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}'><a href='#${val}'>${val} <span class='right'>${channels[val]}</span></a></li>\n` }, '')}
39+ ${Object.keys(channels).reduce((acc, val) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}'><a href='#${val}'>${val} <span class='right'>${channels[val]}</span></a></li>\n` }, '')}
41 <ul id='users'>
41 <ul id='users'>
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` }, '')}
42+ ${Object.keys(users).reduce((acc, val) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}' href='#${val}'>${val} <span class='right'>${users[val]}</span></li>\n` }, '')}
44 <ul id='tags'>
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` }, '')}
45+ ${Object.keys(tags).reduce((acc, val) => { return acc + `<li onclick='filter("${val}")' class='${hallway.filter === val ? 'selected' : ''}' href='#${val}'>#${val} <span class='right'>${tags[val]}</span></li>\n` }, '')}
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>`
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>`
@@ -72,7 +72,7 @@ function Hallway (sites) {
73 return users
73 return users
76 this.findTags = function (entries){
76 this.findTags = function (entries){
77 const tags = {}
77 const tags = {}
78 for (const id in entries) {
78 for (const id in entries) {
@@ -94,20 +94,27 @@ function Hallway (sites) {
94 return a.sort( (a, b) => a.offset - b.offset )
94 return a.sort( (a, b) => a.offset - b.offset )
97+ this.findMention = function (found) {
98+ const mention = Object.keys(feeds).filter(user => found.indexOf(feeds[user].path) > -1)
99+ return mention.length === 1
100+ ? ` <span class='user'>@${mention[0]}</span>`
101+ : ` <span class='user'>${found}</span>`
97 this.templateEntry = function (entry) {
104 this.templateEntry = function (entry) {
98 entry.html = entry.body
105 entry.html = entry.body
99 .replace(re_channel, `$1<span class='channel'>/$2</span>`)
106 .replace(re_channel, `$1<span class='channel'>/$2</span>`)
100− .replace(re_user, `$1<span class='user'>@$2</span>`)
107+ .replace(re_user, this.findMention)
101 .replace(re_tag, `$1<span class='tag'>#$2</span>`)
108 .replace(re_tag, `$1<span class='tag'>#$2</span>`)
102 .replace(re_url, `<a target="_blank" href='$1'>$1</a>`)
109 .replace(re_url, `<a target="_blank" href='$1'>$1</a>`)
104 const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
111 const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
105 const highlight = filter === entry.author.toLowerCase()
112 const highlight = filter === entry.author.toLowerCase()
106 const origin = feeds[entry.author].path
113 const origin = feeds[entry.author].path
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>`
115 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>`
113 this.findFeeds = function () {
120 this.findFeeds = function () {