/* global page, axios */
const newsfeed = {
lsKey: 'newsfeed',
feedUrl: 'https://blog.fiery.me/rss-newsfeed.xml',
maxItems: 3,
dismissed: {},
done: false
}
newsfeed.simpleParseDate = string => {
// For now limited to support the following examples (used in blog.fiery.me):
// Mon, 27 Jul 2020 18:30:00 GMT
// Sat, 16 May 2020 14:55:00 GMT
// Probably better to use a library if it needs to support other formats.
const months = { Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5, Jul: 6, Aug: 7, Sep: 8, Oct: 9, Nov: 10, Dec: 11 }
const match = string.match(/[a-zA-Z]*,\s(\d{2})\s([a-zA-Z]{3})\s(\d{4})\s(\d{2}):(\d{2}):(\d{2})\sGMT/)
if (match && (months[match[2]] !== undefined)) {
const date = new Date()
date.setUTCDate(match[1])
date.setUTCMonth(months[match[2]])
date.setUTCFullYear(match[3])
date.setUTCHours(match[4])
date.setUTCMinutes(match[5])
date.setUTCSeconds(match[6])
return date
}
}
newsfeed.formatRelativeDate = delta => {
// https://stackoverflow.com/a/7641812
const minute = 60
const hour = minute * 60
const day = hour * 24
const week = day * 7
let fuzzy
let unit
if (delta < minute) {
fuzzy = delta
unit = 'second'
} else if (delta < hour) {
fuzzy = Math.floor(delta / minute)
unit = 'minute'
} else if (delta < day) {
fuzzy = Math.floor(delta / hour)
unit = 'hour'
} else if (delta < week) {
fuzzy = Math.floor(delta / day)
unit = 'day'
} else {
fuzzy = Math.floor(delta / week)
unit = 'week'
}
return `${fuzzy} ${unit}${fuzzy !== 1 ? 's' : ''} ago`
}
newsfeed.formatNotification = item => {
const parsedDate = newsfeed.simpleParseDate(item.pubDate)
const dateDelta = Math.round((+new Date() - parsedDate) / 1000)
const isRecentWeek = dateDelta <= 604800
const element = document.createElement('a')
element.dataset.identifier = item.identifier
element.className = 'notification is-info'
element.href = item.link
element.target = '_blank'
element.innerHTML = `
${item.title || 'Untitled'}
${item.description
? `${item.description.slice(-1) === '…' ? `${item.description.slice(0, -1)} […]` : item.description}`
: 'N/A'}
${newsfeed.formatRelativeDate(dateDelta)}
`
return element
}
newsfeed.dismissNotification = element => {
if (!element || !element.dataset.identifier) return
newsfeed.dismissed[element.dataset.identifier] = 1
element.parentNode.removeChild(element)
const keys = Object.keys(newsfeed.dismissed)
if (keys.length > newsfeed.maxItems)
for (let i = 0; i < keys.length - newsfeed.maxItems; i++)
delete newsfeed.dismissed[keys[i]]
localStorage[newsfeed.lsKey] = JSON.stringify(newsfeed.dismissed)
}
newsfeed.do = () => {
return axios.get(newsfeed.feedUrl, {
responseType: 'document'
}).then(response => {
if (response && response.data && response.data.documentElement instanceof Element) {
const items = response.data.documentElement.querySelectorAll('item')
if (items.length) {
const dismissed = localStorage[newsfeed.lsKey]
if (dismissed)
newsfeed.dismissed = JSON.parse(dismissed)
const element = document.createElement('section')
element.id = 'newsfeed'
element.className = 'section'
element.innerHTML = `
`
const column = element.querySelector('.columns > .column:last-child')
for (let i = 0; i < Math.min(newsfeed.maxItems, items.length); i++) {
const titleElement = items[i].querySelector('title')
const descriptionElement = items[i].querySelector('description')
const pubDateElement = items[i].querySelector('pubDate')
const linkElement = items[i].querySelector('link')
const title = titleElement ? titleElement.textContent : ''
const description = descriptionElement ? descriptionElement.textContent : ''
const pubDate = pubDateElement ? pubDateElement.textContent : ''
const link = linkElement ? linkElement.textContent : ''
const identifier = title + '|' + description + '|' + pubDate + '|' + link
if (!newsfeed.dismissed[identifier]) {
const notificationElement = newsfeed.formatNotification({
title, description, pubDate, link, identifier
})
const dismissTrigger = notificationElement.querySelector('.delete')
if (dismissTrigger)
dismissTrigger.addEventListener('click', function () {
event.preventDefault()
newsfeed.dismissNotification(event.target.parentNode)
})
column.appendChild(notificationElement)
}
}
document.body.appendChild(element)
}
} else {
throw Error('response.data.documentElement is NOT an instance of Element')
}
}).catch(console.error)
}
newsfeed.onloaded = () => {
// If the main script had already done its API check, yet newsfeed haven't been triggered, do it
// This would only happen if this newsfeed script only gets loaded after the main script's API check
if (typeof page !== 'undefined' && page.apiChecked && !newsfeed.done)
newsfeed.do()
}
if (document.readyState === 'interactive' || document.readyState === 'complete')
newsfeed.onloaded()
else
window.addEventListener('DOMContentLoaded', () => newsfeed.onloaded())