Last active
October 7, 2021 06:41
-
-
Save alexiglesias93/e330dc3703fe7a9920a8f4cc926e098a to your computer and use it in GitHub Desktop.
CMS Nesting
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
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