Blog auto generate directory

Posted by pleek on Sat, 25 Dec 2021 18:17:26 +0100

Blog auto generate directory

This article describes the function of adding automatic directory generation for blog posts.

Before talking about the functions, I'll talk about the general process of my blog post from writing to publishing to readers. All my articles are used locally markdown Grammar. After the article is written, it will be uploaded directly from the website management background to the server. At this time, readers can see the article I just published on my website. When a reader clicks on an article, the browser will send a request for the article to obtain the information of the article (including the markdown content). After the request is successful, the markdown will be converted to html format (I use this conversion) Showdown.js Library), with html code, you can display it directly on the page.

The function of automatically generating the directory is to analyze the html code of blog articles after conversion, get the title of each part, and use the title to form the directory.

You can click on me Blog website For each article, see the effect of the automatically generated directory.

code implementation

The function code is implemented as follows.

interface CatalogNode {
    title: string; // Directory name
    tag: string; // The tag "h1", "h2", "h3", "h4", "h5", "h6" of the title element indicates how many levels the title is
    childs: CatalogNode[]; // Subdirectories under this directory
    id: string; // The id attribute value of the title element, which is used to jump to the specified title position of the article
};

/**
 * Generate directory
 * @param htmlText html Content text
 */
const generateCatalog = (htmlText: string) => {
    const tags = ["h1", "h2", "h3", "h4", "h5", "h6"];
    const temEle = document.createElement("div");
    temEle.innerHTML = htmlText;

    const cmpContainer = [];
    const catalogNodes: CatalogNode[] = [];
    for (let i = 0; i < temEle.childNodes.length; i++) {
        const ele = temEle.childNodes[i] as HTMLElement;
        if (ele.tagName && tags.includes(ele.tagName.toLowerCase())) {
            const index1 = tags.indexOf(ele.tagName.toLowerCase());
            while (cmpContainer.length > 0) {
                const index2 = tags.indexOf(cmpContainer[cmpContainer.length - 1].tag);
                if (index1 > index2) {
                    break;
                }
                cmpContainer.pop();
            }
            let idStr = ele.id;
            if (!idStr) {
                idStr = ele.innerText.replaceAll(" ", "-");
                ele.setAttribute("id", idStr); // Use the article name as the attribute of element
            }
            if (cmpContainer.length > 0) {
                const node: CatalogNode = {
                    title: ele.innerText,
                    tag: ele.tagName.toLowerCase(),
                    childs: [],
                    id: idStr
                };
                cmpContainer[cmpContainer.length - 1].childs.push(node);
                cmpContainer.push(node);
            } else {
                const rootNode: CatalogNode = {
                    title: ele.innerText,
                    tag: ele.tagName.toLowerCase(),
                    childs: [],
                    id: idStr
                };
                catalogNodes.push(rootNode);
                cmpContainer.push(rootNode);
            }
        }
    }
    return {catalogNodes, htmlText: temEle.innerHTML};
};

The generateCatalog function accepts the original html code string parameter of the blog post and returns catalogNodes and htmlText, catalogNodes represents all directory information (title information in html source code), where children represents a subdirectory under a directory. The returned htmlText (hereinafter referred to as newHtmlText) is the html code of the new blog post corresponding to catalogNodes. All titles in newHtmlText have added the specified id attribute value, which is the same as the id field value of the corresponding title in catalogNodes. In this way, you can jump to the specified title position by following the hash field after the url.

Next, take newHtmlText as the rendering code of the article and generate the directory through catalogNodes.

The following code is the react code, which accepts catalogNodes and renders the directory list.

const renderList = (catalogNodes: CatalogNode[]) => {
    if (catalogNodes.length === 0) {
        return <></>;
    }
    return (
        <ul className="list-wrap">
            {
                catalogNodes.map((node) => (
                    <React.Fragment key={node.id}>
                        <li className="list">
                            <a href={`#${node.id}`}>{node.title}</a>
                        </li>
                        {renderList(node.childs)}
                    </React.Fragment>
                ))
            }
        </ul>
    );
}

< a href = {#${node. id} > {node. Title} < / a > this code sets the href of the directory to the id value of the corresponding title of the article, so you can click the directory to jump to the specified directory location.

(end)

Topics: html