on f45bfdb help sign in
webring/scripts/portal.js
121 lines 5.1 kB history raw
1'use strict'
3function Portal (sites) {
4 this.el = document.createElement('div')
5 this.el.id = 'portal'
6 this.sites = sites
8 // Templates
10 const _readme = '<p class="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 <b>diaries, wikis & portfolios</b>.</p><p>To add yourself to the ring, submit a <a href="https://github.com/XXIIVV/webring/edit/master/scripts/sites.js" target="_blank">Pull Request</a>.<br />If you found a broken link, please <a href="https://github.com/XXIIVV/webring/issues/new" target="_blank">report it</a>.</p>'
11 const _buttons = '<p class="buttons"><a href="#random" onClick="portal.reload()">Random</a> | <a href="https://github.com/XXIIVV/webring">Information</a> <a id="icon" href="#random" onClick="portal.reload()"></a> | <a href="hallway.html">The Hallway</a> | <a href="wiki.html">The Wiki</a> | <a id="opml">OPML</a></p>'
13 function _directory (sites) {
14 const siteTypesArray = [...new Set(sites.map(site => site.type).filter(Boolean))]
15 const siteLangsArray = [...new Set(sites
16 .reduce((flattened, site) => flattened.concat(site.langs), [])
17 .sort())]
19 const siteTypes = siteTypesArray.reduce((output, siteType) =>
20 `${output}<a data-type="${siteType}" href="#" onclick="filterSites(event)">&lt;${siteType}&gt;</a>`,
21 '<a class="currentType" data-type="all" href="#" onclick="filterSites(event)">&lt;all&gt;</a>')
23 const siteLangs = siteLangsArray.reduce((output, siteLang) =>
24 `${output}<a data-lang="${siteLang}" href="#" onclick="filterSites(event)">&lt;${siteLang}&gt;</a>`,
25 '<a class="currentLang" data-lang="all" href="#" onclick="filterSites(event)">&lt;all&gt;</a>')
27 const listItems = sites.reduce((acc, site, id) =>
28 `${acc}<li ${_type(site)} ${_lang(site)} id='${id}'><a href='${site.url}'>${_name(site)}</a></li>`, '')
29 return `<nav>${siteTypes}</nav><nav>${siteLangs}</nav><main><ul>${listItems}</ul></main><footer>${_readme}${_buttons}</footer>`
30 }
32 function _name (site) {
33 return site.title || `${site.url.split('//')[1].replace(/\/+$/,'')}`
34 }
36 function _type (site) {
37 return site.type ? `data-type="${site.type} "` : ''
38 }
40 function _lang (site) {
41 return `data-lang="${site.langs.join(' ').trim()}"`
42 }
44 function _redirectView (site) {
45 return `<main><p>Redirecting to <a href="${site.url}">${site.url}</a></p></main>
46 <footer><p class='buttons'><a href='#' onClick="portal.reload('')">Directory</a> | <a href='#${site.url}' onClick="portal.reload()">Skip</a> | <a href='#random' onClick="portal.reload()">Random</a> | <a href='https://github.com/XXIIVV/webring'>Information</a> <a id='icon' href='#random' onClick="portal.reload()"></a></p>`
47 }
49 //
51 this.install = function (host) {
52 host.appendChild(this.el)
53 }
55 this.start = function () {
56 const hash = window.location.hash
57 if (hash && hash.length > 4) {
58 const site = this.getSite(hash.replace('#', '').trim())
59 this.el.innerHTML = _redirectView(site)
60 setTimeout(() => { window.location = site.url }, 3000)
61 } else {
62 this.el.innerHTML = _directory(this.sites)
63 }
64 }
66 this.reload = function () {
67 setTimeout(() => { window.location.reload() }, 500)
68 }
70 this.navigate = function (target) {
71 setTimeout(() => { window.location.href = target }, 3000)
72 }
74 this.navLangs = [... new Set(navigator.languages.map(lang => lang.split('-').shift()))]
76 this.sitesMatchingLangs = this.sites
77 .filter(site => site.langs && site.langs.some(lang => this.navLangs.includes(lang)))
79 this.nextSiteIndex = (ceiling, index) => index === ceiling ? 0 : index + 1
80 this.randomSite = this.sitesMatchingLangs[Math.floor(Math.random() * this.sitesMatchingLangs.length)]
82 this.getSite = function (hash) {
83 if (hash === 'random') {
84 return this.randomSite
85 } else {
86 const index = this.sitesMatchingLangs.findIndex(site => site.url.includes(hash))
87 return (index > -1)
88 ? this.sitesMatchingLangs[this.nextSiteIndex(this.sitesMatchingLangs.length, index)]
89 : this.randomSite
90 }
91 }
94function filterSites (e) {
95 e.preventDefault()
96 const navLink = e.target
97 const currentFilter = navLink.dataset.lang ? 'Lang' : 'Type'
99 document.querySelector(`nav a.current${currentFilter}`).classList.remove(`current${currentFilter}`)
100 navLink.classList.add(`current${currentFilter}`)
102 const typeFilter = document.querySelector('nav a.currentType').dataset.type
103 const langFilter = document.querySelector('nav a.currentLang').dataset.lang
105 const sites = document.querySelectorAll('main li')
106 sites.forEach(el => { el.style.display = 'block' })
108 sites.forEach(el => {
109 if (typeFilter !== 'all') {
110 if (el.dataset.type) {
111 if (el.dataset.type.trim() !== typeFilter) el.style.display = 'none'
112 } else {
113 el.style.display = 'none'
114 }
115 }
117 if (langFilter !== 'all') {
118 if (!el.dataset.lang.includes(langFilter)) el.style.display = 'none'
119 }
120 })