-
Notifications
You must be signed in to change notification settings - Fork 1
/
app.js
171 lines (143 loc) · 3.83 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
;(function() {
'use strict'
//
// Variables
//
const app = document.querySelector('#app')
const storageID = 'pirateCache'
const timestring = 1000 * 10 // expiration time: 10 seconds
//
// Helper functions
//
/**
* Dynamically vary the API endpoint
* @return {String} The API endpoint
*/
const getEndpoint = function() {
const endpoint = 'https://vanillajsacademy.com/api/'
const random = Math.random()
if (random < 0.5) return endpoint + 'pirates.json'
return endpoint + 'fail.json'
}
/**
* Sanitize and encode all HTML in a user-submitted string
* (c) 2018 Chris Ferdinandi, MIT License, https://gomakethings.com
* @param {String} str The user-submitted string
* @return {String} str The sanitized string
*/
const sanitizeHTML = function(str) {
const temp = document.createElement('div')
temp.textContent = str
return temp.innerHTML
}
/**
* Check if the data is valid
* @param {Object} saved The data to validate
* @param {Number} goodFor How long the data is good for
* @return {Boolean} If true, data has not yet expired
*/
const isDataValid = function(saved, goodFor) {
// Check that there's data, and a timestamp key
if (!saved || !saved.data || !saved.timestamp) return
// Get timestamp from cache
const { timestamp } = JSON.parse(localStorage.getItem(storageID))
// Get the difference between the timestamp and current time
const difference = new Date().getTime() - timestamp
return difference < goodFor
}
/**
* Save article data to localStorage
* @param {Object} data The article data
*/
const saveDataToLocalStorage = data => {
// Create a cache object with a timestamp
const cache = {
data: data,
timestamp: new Date().getTime()
}
// Stringify it and save it to localStorage
localStorage.setItem(storageID, JSON.stringify(cache))
}
/**
* Render articles into the UI
* @param {Object} articles The API response object
*/
const renderNews = data => {
const { articles } = data
// If there are no articles, render a message into the UI
if (articles.length < 1) {
renderNoArticles()
return
}
// Otherwise, render the UI
return (app.innerHTML =
articles
.map(
article =>
`<article>
<h2>${sanitizeHTML(article.title)}</h2>
<p><em>By ${sanitizeHTML(article.author)} on ${sanitizeHTML(
article.pubdate
)} </em></p>
<p>${sanitizeHTML(article.article)}</p>
</article>`
)
.join('') +
`<p><em>Articles from <a href="${sanitizeHTML(
data.attribution.url
)}">${sanitizeHTML(data.attribution.name)}</a></em></p>`)
}
/**
* Render a message into the UI when there are no articles to share
*/
const renderNoArticles = function() {
app.innerHTML =
'<p>There be no pirate news afoot, matey. Check back later.</p>'
}
//
// Methods
//
/**
* Get data from the API and save it to localStorage
*/
const fetchArticles = async () => {
try {
const response = await fetch(getEndpoint())
if (!response.ok) return
const data = await response.json()
await saveDataToLocalStorage(data)
return data
} catch (error) {
console.log('Something went wrong:', error)
}
}
/**
* Render content from API cache on failed request
*/
const renderFallback = () => {
const saved = JSON.parse(localStorage.getItem(storageID))
saved ? renderNews(saved.data) : renderNoArticles()
}
//
// Inits
//
const init = () => {
/**
* Get API data from localStorage
*/
const saved = JSON.parse(localStorage.getItem(storageID))
if (saved) {
// Check if the data is still good
if (isDataValid(saved, timestring)) {
// The data is still good, use it
console.log('loaded from cache')
const { data } = saved
return renderNews(data)
}
}
fetchArticles()
.then(data => renderNews(data))
.catch(renderFallback())
}
init()
})()