Skip to content

Instantly share code, notes, and snippets.

@alexiglesias93
Last active October 7, 2021 06:41
Show Gist options
  • Save alexiglesias93/e330dc3703fe7a9920a8f4cc926e098a to your computer and use it in GitHub Desktop.
Save alexiglesias93/e330dc3703fe7a9920a8f4cc926e098a to your computer and use it in GitHub Desktop.
CMS Nesting
document.addEventListener('DOMContentLoaded', async () => {
initNesting({
mainCollectionSelector: '#blog-posts',
nestedCollectionsSelectors: ['#categories', '#authors', '#tags'],
});
});
/**
* Init the nesting
* @param mainCollectionSelector The selector of the collection where the children will be nested
* @param nestedCollectionsSelectors Array of selectors of the the collections that will be nested in the main collection
*/
const initNesting = async ({
mainCollectionSelector,
nestedCollectionsSelectors,
}: {
mainCollectionSelector: string;
nestedCollectionsSelectors: string[];
}) => {
// Get the main collection's items
const mainCollectionItems = document.querySelectorAll<HTMLDivElement>(`${mainCollectionSelector} .w-dyn-item`);
// Store the nested collections' elements and data. The linksMap binds each collection's item with its correspondent URL.
const nestedCollections = nestedCollectionsSelectors.map((selector) => {
const list = document.querySelector(`${selector} .w-dyn-items`) as HTMLDivElement;
const items = list.querySelectorAll<HTMLDivElement>('.w-dyn-item');
const linksMap = mapCollectionLinks(items);
list.remove();
return { selector, list, linksMap };
});
// Create new DOMParser
const domParser = new DOMParser();
// Fetch each collection item's page to discover the correspondent nested collection items
mainCollectionItems.forEach(async (mainCollectionItem) => {
const link = mainCollectionItem.querySelector('a')?.href;
if (!link) return;
// Get the page and parse it
const pageResponse = await fetch(link);
const pageHTML = await pageResponse.text();
const page = domParser.parseFromString(pageHTML, 'text/html');
nestedCollections.forEach((nestedCollection) => {
// Get all the items of the collection and their URLs
const nestedCollectionItems = page.querySelectorAll<HTMLDivElement>(`${nestedCollection.selector} .w-dyn-item`);
const nestedCollectionLinks = getCollectionLinks(nestedCollectionItems);
if (!nestedCollectionLinks.length) return;
// Create a new nested collection list element
const newNestedCollectionList = cloneNode(nestedCollection.list, false);
// Populate the new nested collection list with the correspondent items that were found in the external page
nestedCollectionLinks.forEach((link) => {
const nestedCollectionItem = nestedCollection.linksMap.get(link);
if (!nestedCollectionItem) return;
const newNestedCollectionItem = cloneNode(nestedCollectionItem, true);
newNestedCollectionList.appendChild(newNestedCollectionItem);
});
mainCollectionItem.appendChild(newNestedCollectionList);
});
});
};
/**
* @param collection
* @returns A map that binds a URL to a specific collection item
*/
const mapCollectionLinks = (collection: NodeListOf<Element>) => {
const linksMap: Map<string, Element> = new Map();
collection.forEach((item) => {
const link = item.querySelector('a')?.href;
if (link) linksMap.set(link, item);
});
return linksMap;
};
/**
* @param collection
* @returns An array of the links to each item
*/
const getCollectionLinks = (collection: NodeListOf<Element>) => {
const linksArray = [...collection].reduce<string[]>((accumulated, item) => {
const link = item.querySelector('a')?.href;
if (link) accumulated.push(link);
return accumulated;
}, []);
return linksArray;
};
/**
* Clone a node that has the same type as the original one
* @param node
*/
const cloneNode = <T extends Node>(node: T, deep = true): T => <T>node.cloneNode(deep);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment