diff --git a/hallway.html b/hallway.html deleted file mode 100644 index 56b4194..0000000 --- a/hallway.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - Hallway - - - - - diff --git a/scripts/hallway.js b/scripts/hallway.js deleted file mode 100644 index 3f88979..0000000 --- a/scripts/hallway.js +++ /dev/null @@ -1,232 +0,0 @@ -'use strict' - -const reChannel = /(\s|^)\/([a-zA-Z0-9]+)/g -const reUser = /((\s|^)@<[a-zA-Z0-9./:\-_+~#= ]*>)/g -const reTag = /(^|\s)(#[a-z\d-]+)/ig -const reUrl = /((https?):\/\/(([-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b)([-a-zA-Z0-9@:%_+.~#?&//=]*)))/g - -function Hallway (sites) { - const feeds = {} - this.sites = sites - this._el = document.createElement('div') - this._el.id = 'hallway' - const filterAndPage = window.location.hash.split('^') - this.finder = { filter: stripHash(filterAndPage[0]), page: filterAndPage[1] || 1 } - this.cache = null - - this._main = document.createElement('main') - this._main.id = 'entries' - this._footer = document.createElement('footer') - this._footer.id = 'footer' - this.readme = '

The Hallway is a decentralized forum, to join the conversation, add a feed: field to your entry in the webring.

' - this.nav = '

Information | The Portal | The Wiki | OPML

' - this._footer.innerHTML = `${this.readme}${this.nav}` - - this.install = function (host) { - this._el.appendChild(this._main) - this._el.appendChild(this._footer) - host.appendChild(this._el) - this.findFeeds() - } - - this.start = function () { - this._main.innerHTML = 'Loading..' - this.fetchFeeds() - } - - this.refresh = function (feeds = this.cache) { - const entries = this.findEntries(feeds) - const localEntries = entries.filter(entry => this.filterExternals(entry)) - const channels = this.find(localEntries, 'channel') - const users = this.find(localEntries, 'author') - const tags = this.findTags(localEntries) - const relevantEntries = localEntries - .filter(entry => !this.finder.filter || (entry.author === this.finder.filter || entry.channel === this.finder.filter || entry.tags.includes(this.finder.filter) || entry.body.includes(this.finder.filter))) - - const mainHtml = ` -
- -
` - - const aside = ` - ` - - this._main.innerHTML = `${mainHtml}${aside}` - - if (feeds) { - this.cache = feeds - } - } - - // Entries - - this.filterExternals = function (entry) { - const matches = entry.body.match(reUser) - const locals = Object.keys(feeds) - return matches ? matches.some(match => locals.some(local => match.indexOf(feeds[local].path) !== -1)) : true - } - - this.find = function (entries, key) { - const h = {} - for (const entry of entries) { - if (entry && entry[key]) { - h[entry[key]] = h[entry[key]] ? h[entry[key]] + 1 : 1 - } - } - return h - } - - this.findTags = function (entries) { - const tags = {} - for (const entry of entries) { - entry.tags.map(tag => { - tags[tag] = tags[tag] ? tags[tag] + 1 : 1 - }) - } - return tags - } - - this.findEntries = function (feeds) { - const a = [] - for (const id in feeds) { - for (const i in feeds[id].content) { - a.push(feeds[id].content[i]) - } - } - return a.sort((a, b) => a.offset - b.offset) - } - - this.findMention = function (found) { - const mention = Object.keys(feeds).filter(user => found.indexOf(feeds[user].path) > -1) - return ` ${mention[0]}` - } - - this.templateEntry = function (entry) { - entry.html = entry.body - .replace(reChannel, '$1/$2') - .replace(reUser, this.findMention) - .replace(reTag, '$1$2') - .replace(reUrl, '$1') - - const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase() - const highlight = filter === entry.author.toLowerCase() - const origin = feeds[entry.author].path - - return `
  • ${timeAgo(Date.parse(entry.date))} ${entry.author} ${entry.html}
  • ` - } - - // Feeds - - this.findFeeds = function () { - console.log('Finding feeds..') - for (const site of sites) { - if (site.feed && site.author) { - feeds[site.author] = { path: site.feed } - } - } - console.log(`Found ${Object.keys(feeds).length} feeds.`) - } - - this.fetchFeeds = function () { - console.log(`Fetching ${Object.keys(feeds).length} feeds..`) - for (const id in feeds) { - this.fetchFeed(id, feeds[id]) - } - } - - this.fetchFeed = function (id, feed) { - console.log(`Fetching ${id}(${feed.path})..`) - fetch(feed.path, { cache: 'no-store' }).then(x => x.text()).then((content) => { - feeds[id].content = parseFeed(id, content) - this.refresh(feeds) - }).catch((err) => { - console.warn(`${id}`, err) - }) - } - - // Utils - - function parseFeed (author, feed) { - const lines = feed.split('\n').filter((line) => line.substr(0, 1) !== '#') - const entries = [] - for (const id in lines) { - const line = lines[id].trim() - if (line === '') { continue } - const parts = line.replace(' ', '\t').split('\t') - const date = parts[0].trim() - const body = escapeHtml(parts[1].trim()).trim() - const channel = body.substr(0, 1) === '/' ? cleanTags(body.split(' ')[0].substr(1).toLowerCase()) : body.substr(0, 1) === '@' ? 'veranda' : 'lobby' - const tags = (body.match(reTag) || []).map(a => cleanTags(a.substr(a.indexOf('#') + 1).toLowerCase())) - const offset = new Date() - new Date(date) - entries.push({ date, body, author, offset, channel, tags }) - } - return entries - } - - function timeAgo (dateParam) { - const date = typeof dateParam === 'object' ? dateParam : new Date(dateParam) - const today = new Date() - const yesterday = new Date(today - 86400000) - const seconds = Math.round((today - date) / 1000) - const minutes = Math.round(seconds / 60) - const isToday = today.toDateString() === date.toDateString() - const isYesterday = yesterday.toDateString() === date.toDateString() - - if (seconds < 5) { - return 'just now' - } else if (seconds < 60) { - return `${seconds} seconds ago` - } else if (seconds < 90) { - return 'a minute ago' - } else if (minutes < 60) { - return `${minutes} minutes ago` - } else if (isToday) { - return `${Math.floor(minutes / 60)} hours ago` - } else if (isYesterday) { - return 'yesterday' - } - - return `${Math.floor(minutes / 1440)} days ago` - } -} - -function toggleVisibility (id) { - const e = document.getElementById(id) - if (e.style.display === 'block') { e.style.display = 'none' } else { e.style.display = 'block' } -} - -function escapeHtml (unsafe) { - return unsafe.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''') -} - -function cleanTags (unsafe) { - return unsafe.replace(/([^a-z0-9]+)/gi, '-') -} - -function stripHash (hash) { - const decoded = decodeURIComponent(hash) - return decoded.charAt(0) === '#' ? decoded.substring(1) : decoded -} - -function filter (name) { - window.location.hash = name - const filterAndPage = window.location.hash.split('^') - hallway.finder = { filter: stripHash(filterAndPage[0]), page: filterAndPage[1] || 1 } - hallway.refresh() -} diff --git a/scripts/indental.js b/scripts/indental.js deleted file mode 100644 index 5193a08..0000000 --- a/scripts/indental.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict' - -function indental (data, Type) { - function formatLine (line) { - const a = [] - const h = {} - for (const child of line.children) { - if (child.key) { - if (h[child.key]) { console.warn(`Redefined key: ${child.key}.`) } - h[child.key] = child.value - } else if (child.children.length === 0 && child.content) { - a[a.length] = child.content - } else { - h[child.content.toUpperCase()] = formatLine(child) - } - } - return a.length > 0 ? a : h - } - - function makeLine (line) { - return line.indexOf(' : ') > -1 ? { - indent: line.search(/\S|$/), - content: line.trim(), - key: line.split(' : ')[0].trim().toUpperCase(), - value: line.split(' : ')[1].trim() - } : { - indent: line.search(/\S|$/), - content: line.trim(), - children: [] - } - } - - function skipLine (line) { - return line.trim() !== '' && line.trim().substr(0, 1) !== ';' && line.trim().slice(-1) !== '`' - } - - const lines = data.split('\n').filter(skipLine).map(makeLine) - - // Assoc - const stack = {} - for (const line of lines) { - const target = stack[line.indent - 2] - if (target) { target.children.push(line) } - stack[line.indent] = line - } - - // Format - const h = {} - for (const id in lines) { - const line = lines[id] - if (line.indent > 0) { continue } - const key = line.content.toUpperCase() - if (h[key]) { console.warn(`Redefined key: ${key}, line ${id}.`) } - h[key] = Type ? new Type(key, formatLine(line)) : formatLine(line) - } - return h -} diff --git a/scripts/opml.js b/scripts/opml.js deleted file mode 100644 index 5175225..0000000 --- a/scripts/opml.js +++ /dev/null @@ -1,13 +0,0 @@ -const outlines = sites.filter(site => site.rss).map(site => { - return `` -}) - -const template = `${outlines.join('')}` - -window.addEventListener('DOMContentLoaded', () => { - const a = document.getElementById('opml') - if (a) { - a.setAttribute('href', 'data:text/plain;charset=utf-8,' + window.encodeURIComponent(template)) - a.setAttribute('download', 'webring.opml') - } -}) diff --git a/scripts/portal.js b/scripts/portal.js deleted file mode 100644 index a8a9fc9..0000000 --- a/scripts/portal.js +++ /dev/null @@ -1,121 +0,0 @@ -'use strict' - -function Portal (sites) { - this.el = document.createElement('div') - this.el.id = 'portal' - this.sites = sites - - // Templates - - const _readme = '

    This webring is an attempt to inspire artists & developers to build their own website and share traffic among each other. The ring welcomes personalized websites such as diaries, wikis & portfolios.

    To add yourself to the ring, submit a Pull Request.
    If you found a broken link, please report it.

    ' - const _buttons = '

    Random | Information | The Hallway | The Wiki | OPML

    ' - - function _directory (sites) { - const siteTypesArray = [...new Set(sites.map(site => site.type).filter(Boolean))] - const siteLangsArray = [...new Set(sites - .reduce((flattened, site) => flattened.concat(site.langs), []) - .sort())] - - const siteTypes = siteTypesArray.reduce((output, siteType) => - `${output}<${siteType}>`, - '<all>') - - const siteLangs = siteLangsArray.reduce((output, siteLang) => - `${output}<${siteLang}>`, - '<all>') - - const listItems = sites.reduce((acc, site, id) => - `${acc}
  • ${_name(site)}
  • `, '') - return `
    ` - } - - function _name (site) { - return site.title || `${site.url.split('//')[1].replace(/\/+$/, '')}` - } - - function _type (site) { - return site.type ? `data-type="${site.type} "` : '' - } - - function _lang (site) { - return `data-lang="${site.langs.join(' ').trim()}"` - } - - function _redirectView (site) { - return `

    Redirecting to ${site.url}

    -