Skip to content

Instantly share code, notes, and snippets.

@edjw
Last active August 29, 2023 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edjw/a552c59b2aa6b58914203074d184287b to your computer and use it in GitHub Desktop.
Save edjw/a552c59b2aa6b58914203074d184287b to your computer and use it in GitHub Desktop.
load-github-gists
<script>
/**
* A script to fetch and apply JS and CSS from GitHub gists and GitLab snippets.
* Use with the Gistpad extension in VS Code for easy updating:
* https://marketplace.visualstudio.com/items?itemName=vsls-contrib.gistfs
*
* Note: For GitLab, it's likely the content fetch will fail due to CORS restrictions.
* With GitHub, rate limiting can be strict unless the gist is public.
*
* For html gists, specify the target using the html selector of an element on your page.
* Then optionally use on of these placement options. If you don't specify one, beforeend will be used
* "beforebegin": Before the element itself.
* "afterbegin": Just inside the element, before its first child.
* "beforeend": Just inside the element, after its last child (default).
* "afterend": After the element itself.
*
* const resources = [
{ url: "https://gist.github.com/edjw/3b87206bd180598c1c715aff0bf79058", type: 'js' },
{ url: "https://gist.github.com/edjw/0899714f1b44129932c59d968899b0e6", type: 'css' },
{ url: "https://gist.github.com/edjw/07bd385fdd8d01d2e9c38bc5bf602526", type: 'html', target: 'a css selector for a html element' placement: "afterbegin"},
{ url: "https://gist.github.com/edjw/07bd385fdd8d01d2e9c38bc5bf602526", type: 'html', target: 'a css selector for a html element'}
];
*/
(async function () {
const resources = [
// { url: "https://gist.github.com/edjw/0899714f1b44129932c59d968899b0e6", type: "css" },
// { url: "https://gist.github.com/edjw/3b87206bd180598c1c715aff0bf79058", type: 'js' },
// // { url: "https://gist.github.com/edjw/07bd385fdd8d01d2e9c38bc5bf602526", type: 'html', target: "", placement: "afterbegin" }
];
const defaultISTMainBodySelector = `article.node > div.content > div.field > div.field-items > div.field-item`;
async function applyGitHubGist(gistId, type, target, placement) {
try {
if (!['js', 'css', 'html'].includes(type)) {
console.error(`Unknown resource type: ${type}`);
return;
}
if (type === 'html') {
const targetElement = document.querySelector(target || defaultISTMainBodySelector);
if (!targetElement) {
console.error(`Target element not found in the DOM for selector: ${target || defaultISTMainBodySelector}`);
return;
}
const placements = ["beforebegin", "afterbegin", "beforeend", "afterend"];
if (!placements.includes(placement)) {
console.error(`Invalid placement value: ${placement}`);
return;
}
}
const response = await fetch(`https://api.github.com/gists/${gistId}`);
if (!response.ok) {
console.error(`Error fetching GitHub gist ${gistId}: ${response.statusText}`);
return;
}
const data = await response.json();
if (!data.files || Object.keys(data.files).length === 0) {
console.error('No files found in gist response.');
return;
}
const fileContent = data.files[Object.keys(data.files)[0]].content;
if (type === 'js') {
eval(fileContent);
return;
}
if (type === 'css') {
const styleElem = document.createElement('style');
styleElem.textContent = fileContent;
document.head.appendChild(styleElem);
return;
}
if (type === 'html') {
const targetElement = document.querySelector(target || defaultISTMainBodySelector);
targetElement.insertAdjacentHTML(placement || 'beforeend', fileContent);
}
} catch (error) {
console.error(`Error processing GitHub gist ${gistId}:`, error);
}
}
async function processResources(resources) {
const validTypes = ['js', 'css', 'html'];
for (const resource of resources) {
try {
const { type, target, placement, url } = resource;
console.log(`Processing ${type} URL: `, url);
const parsedURL = new URL(url);
if (parsedURL.hostname !== "gist.github.com") {
console.error(`URL not from GitHub: ${url}`);
continue;
}
const gistId = parsedURL.pathname.split('/').pop();
if (!gistId) {
console.error(`Failed to extract gistId from URL: ${url}`);
continue;
}
if (!type) {
console.error(`Resource type is missing for URL: ${url}. Skipping resource.`);
continue;
}
if (!validTypes.includes(type)) {
console.error(`Invalid resource type: ${type}. Skipping resource.`);
continue;
}
if (type === 'html') {
const effectiveTarget = target || defaultISTMainBodySelector;
if (typeof effectiveTarget !== 'string' || !document.querySelector(effectiveTarget)) {
console.error(`Invalid or missing target for HTML resource URL: ${url}. Skipping resource.`);
continue;
}
if (placement && !["beforebegin", "afterbegin", "beforeend", "afterend"].includes(placement)) {
console.error(`Invalid placement value for HTML resource URL: ${url}. Skipping resource.`);
continue;
}
}
await applyGitHubGist(gistId, type, target, placement);
} catch (error) {
console.error(`Invalid URL: ${resource.url}`);
continue;
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => processResources(resources));
} else {
await processResources(resources);
}
})();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment