Created
April 30, 2022 14:28
-
-
Save tyte/293a93d3bdd3cbd6bbba83142e252385 to your computer and use it in GitHub Desktop.
JS encode third party code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Dragon Trainer Monthly - Author Data</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<style type="text/css"> | |
body { | |
margin: 0 auto; | |
max-width: 40em; | |
width: 88%; | |
} | |
article { | |
margin-bottom: 3em; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Dragon Trainer Monthly - Author Data</h1> | |
<div id="app"></div> | |
<script> | |
// Get the app element | |
let app = document.querySelector('#app'); | |
/** | |
* Find the first matching author | |
* @param {String} name The author name | |
* @param {Array} authors The author details | |
* @return {Array} The author | |
*/ | |
function getAuthor (name, authors) { | |
return authors.find(function (author) { | |
return author.author === name; | |
}); | |
} | |
/** | |
* Render an error message if fetch fails | |
*/ | |
function renderFail () { | |
app.innerHTML = '<p>The dragons burned all the copies. Unable to get new articles at this time. Sorry!</p>'; | |
} | |
/** | |
* Render articles into the DOM | |
* @param {Array} articles The articles to render | |
* @param {Array} authors The author details | |
*/ | |
function render (articles, authors) { | |
// If there are no articles to show | |
if (!articles || articles.length < 1) { | |
renderFail(); | |
return; | |
} | |
// Create a new array of markup strings with array.map(), then | |
// Combine them into one string with array.join(), then | |
// Insert them into the DOM with innerHTML | |
app.innerHTML = articles.map(function (article) { | |
let author = getAuthor(article.author, authors); | |
return ` | |
<article> | |
<h2><a href="${encodeHTML(article.url)}">${encodeHTML(article.title)}</a></h2> | |
<p><em>By ${author ? `${encodeHTML(author.author)} - ${encodeHTML(author.bio)}` : encodeHTML(article.author)}</em></p> | |
<p>${article.article}</p> | |
</article>`; | |
}).join(''); | |
} | |
// Get articles | |
Promise.all([ | |
fetch('https://vanillajsacademy.com/api/dragons.json'), | |
fetch('https://vanillajsacademy.com/api/dragons-authors.json'), | |
]).then(function (responses) { | |
return Promise.all(responses.map(function (response) { | |
return response.json(); | |
})); | |
}).then(function (data) { | |
// Render them into the DOM | |
render(data[0].articles, data[1].authors); | |
}).catch(function (error) { | |
console.warn(error); | |
renderFail(); | |
}); | |
/** | |
* Encode the HTML in a user-submitted string | |
* https://portswigger.net/web-security/cross-site-scripting/preventing | |
* @param {String} str The user-submitted string | |
* @return {String} str The sanitized string | |
*/ | |
function encodeHTML (str) { | |
return str.replace(/data:/gi, '').replace(/javascript:/gi, '').replace(/[^\w-_. ]/gi, function (c) { | |
return `&#${c.charCodeAt(0)};`; | |
}); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment