on 262cbf6 help sign in
webring/scripts/hallway.js
147 lines 4.4 kB history raw
1'use strict'
3function Hallway (sites) {
4 const feeds = {}
5 this.sites = sites
6 this.el = document.createElement('div')
7 this.el.id = 'hallway'
9 this.install = function (host) {
10 host.appendChild(this.el)
11 this.findFeeds()
12 }
14 this.start = function () {
15 this.el.innerHTML = 'hello'
16 this.fetchFeeds()
17 }
19 this.refresh = function () {
20 const entries = this.sortEntries()
21 let html = ''
22 for (const id in entries) {
23 html += `${this.templateEntry(entries[id])}\n`
24 }
25 this.el.innerHTML = `<ul>${html}</ul>${this._footer()}`
26 }
28 // Entries
30 this.sortEntries = function () {
31 const a = []
32 for (const id in feeds) {
33 const feed = feeds[id]
34 for (const i in feed.content) {
35 const entry = feed.content[i]
36 a.push(entry)
37 }
38 }
39 return a.sort(compare)
40 }
42 this.templateEntry = function (entry) {
43 // Find mention
44 if (entry.body.indexOf('@<') > -1) {
45 const data = entry.body.split('@<').pop().split('>')[0]
46 const mention = data.split(' ')
47 const name = mention[0]
48 const path = mention[1]
49 entry.body = entry.body.replace(`@<${data}>`, `<a href='${path}'>@${name}</a>`)
50 }
52 if (entry.body.substr(0, 1) === '/') {
53 const channel = entry.body.split(' ')[0]
54 entry.body = entry.body.replace(channel, `<span class='channel'>${channel}</span>`)
55 }
57 const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
58 const highlight = filter == entry.author.toLowerCase()
60 return `<li class='entry ${highlight ? 'highlight' : ''}'><span class='date'>${timeAgo(Date.parse(entry.date))}</span> <a class='author' href=''>${entry.author}</a> <span class='body'>${entry.body}</span></li>`
61 }
63 // Feeds
65 this.findFeeds = function () {
66 console.log('Finding feeds..')
67 for (const id in sites) {
68 const site = sites[id]
69 if (site.feed && site.author) {
70 feeds[site.author] = { path: site.feed }
71 }
72 }
73 console.log(`Found ${Object.keys(feeds).length} feeds.`)
74 }
76 this.fetchFeeds = function () {
77 console.log(`Fetching ${Object.keys(feeds).length} feeds..`)
78 for (const id in feeds) {
79 this.fetchFeed(id, feeds[id])
80 }
81 }
83 this.fetchFeed = function (id, feed) {
84 console.log(`Fetching ${id}(${feed.path})..`)
86 fetch(feed.path, { cache: 'no-store' }).then(x => x.text()).then((content) => {
87 feeds[id].content = parseFeed(id, content)
88 this.refresh()
89 }).catch((err) => {
90 console.warn(`${id}`, err)
91 })
92 }
94 // Extras
96 this._footer = function () {
97 return '<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>'
98 }
100 // Utils
102 function compare (a, b) {
103 return a.offset < b.offset ? -1 : a.offset > b.offset ? 1 : 0
104 }
106 function parseFeed (author, feed) {
107 const lines = feed.split('\n')
108 const entries = []
109 for (const id in lines) {
110 const line = lines[id].trim()
111 if (line === '') { continue }
112 const parts = line.replace(' ', '\t').split('\t')
113 const date = parts[0].trim()
114 const body = parts[1].trim()
115 const offset = new Date() - new Date(date)
116 entries.push({ date, body, author, offset })
117 }
118 return entries
119 }
121 function timeAgo (dateParam) {
122 const date = typeof dateParam === 'object' ? dateParam : new Date(dateParam)
123 const DAY_IN_MS = 86400000 // 24 * 60 * 60 * 1000
124 const today = new Date()
125 const yesterday = new Date(today - DAY_IN_MS)
126 const seconds = Math.round((today - date) / 1000)
127 const minutes = Math.round(seconds / 60)
128 const isToday = today.toDateString() === date.toDateString()
129 const isYesterday = yesterday.toDateString() === date.toDateString()
131 if (seconds < 5) {
132 return 'now'
133 } else if (seconds < 60) {
134 return `${seconds} seconds ago`
135 } else if (seconds < 90) {
136 return 'about a minute ago'
137 } else if (minutes < 60) {
138 return `${minutes} minutes ago`
139 } else if (isToday) {
140 return `${Math.floor(minutes / 60)} hours ago`
141 } else if (isYesterday) {
142 return 'yesterday'
143 }
145 return `${Math.floor(minutes / 1440)} days ago`
146 }