Build a catalogue for your blog posts

Keywords: Javascript Hibernate Attribute REST

Build a catalogue for your blog posts

1. Write in front

This should be seen in the past few days. Hibernate User Manual Speaking of it.

This Handbook is really long, and it's all in English. For me who just passed CET-4, it's really hard to read. This "laborious" performance is that I often look at it and forget where I see it. The impression of what I have seen before is very vague, so I am thinking about why this is the case.

Are there many unknown words or grammars? It shouldn't be. As a matter of fact, general technical documents are basically common vocabulary except for some technical terms, and there is basically no more complicated grammar besides some agreed or allusive sentences.

Is the content of the article too professional? It doesn't seem to be. I read it all the way and didn't feel that there was something I couldn't understand. In fact, compared with some related Chinese blogs, the official documents of some technologies or projects I have seen in the course of my study are often easier to explain and richer in content.

Is the article too long? This seems to have something to do with it. Originally, I have just passed CET-4, but I still got it through 9 years of compulsory education and 3 years of high school education, which leads to the natural exclusion of English. It's good to read a short English article because I know I'll finish it if I stick to it. But when I see a large section of English articles that need to pull the scroll bar for a long time to see the bottom, my heart is complicated.

Finally, I think the most important reason is that I can't think in English. That is to say, we can't understand the meaning of a sentence directly. We must translate a sentence into Chinese in our head to think about the meaning it conveys. Plus, my translation speed is still slow. Although every sentence really understands its meaning when reading, when encountering a long article, I need to start a lot of translation operations in my brain, which leads to a great deal of energy spent on "translation" when reading English articles, and the logic of the whole article can not be controlled.

So I searched the relevant questions in my knowledge. Many people do have this question, and some people have explained it and given some solutions. such as thisthis.

Well, I've been talking nonsense for a long time. I mean, for a writer, it's very important to build a catalogue for an article besides a clear and orderly presentation of what he's expressing. And it's better fixed somewhere on the screen than scrolling along with the page. It's better to indicate which chapter the reader has read at the moment. Festival. In this way, readers will not be "lost" in "vast" articles.

So yesterday, I spent an hour or two to make a catalogue for my blog, and you should be able to see it by scrolling down a little.

Here I share the whole process records, hoping to help you with the same needs.

2. JS permission application

Directories need to be generated with JS, of course, the first step is to apply for JS privileges. This need to click on the application on my own management page. I have successfully applied here.

3. Create directories based on articles

Here's how to generate directories based on articles. The general idea of this is to extract the titles at all levels of the article, and then use the corresponding indentation in the catalog according to the series of the titles (e.g. the series of the h1 tag is 1).

Extracting the title is simple, using the document. querySelector All API directly, that is:

var aTitle = document.querySelectorAll('h1, h2, h3, h4, h5, h6');

Returns an array of dom objects corresponding to each h tag in exactly the same order as the titles in our article.

With the title array, we can traverse it and compare the series of the current title with that of the previous one in each traverse:

  1. If the current title series is large, then "indent to the right" once;
  2. If they are equal, they are inserted directly.
  3. If the current title series is small, it will be "indented to the left" once.

The right-to-right "indentation" is reflected in the code, that is, we insert a li tag into the current ul tag and nest another ul tag in it; the left-to-left "indentation" is reflected in the code that we "return" to the last ul tag; and the "direct insertion" means that only one li tag is inserted into the current ul tag.

Chestnut: If we have an article like this:

<h1>White night walk</h1>
<h2>Chapter 1</h2>
<h3>Section I</h3>
<h3>Second quarter</h3>
<h3>Third quarter</h3>
<h2>The second chapter</h2>
<h3>Section I</h3>
<h3>Second quarter</h3>
<h2>The third chapter</h2>
<h3>Section I</h3>
<h3>Second quarter</h3>

It's rendered like this:

Therefore, we need to get such a directory:

In the figure, a rectangle of color represents an ul. To illustrate and write code conveniently, we assign a level attribute to each ul, whose value is equal to the series of the title in it. For example, the level of the red UL in the picture above should be 1, because the series of the title "White Night Travel" in it is 1, and the series of the innermost pink UL should be 3, because the title "Section 1" and "Section 2" in it are three-level headings.

Based on the above analysis, we will go through the titles from top to bottom. But before traversing, we should create a root UL in advance. The first title we traverse is inserted directly into the "current ul", that is, the root ul, because there is no "previous title", and then traverse to the "first chapter", because the series of "first chapter" is larger than the series of "current ul" (red ul) (1), we need to indent the title to the right, that is, to say, to the root ul. Create a new li, create a new UL in li, put the "first chapter" into the new ul, and finally we need to update the "current ul" to the UL whose color is green; then go through the "first section", like the "first chapter", we need to create a new li, ul, and update the "current ul" to the blue ul; and then the "second section", because of the "second section". The series of "current ul" (3) is the same as the series of "current ul" (blue ul), so the "second section" is inserted directly into "current ul". When traversing to "Chapter 2" (2), the "current ul" is blue UL (3), and the UL series is larger. Therefore, the title of "current ul" needs to be indented to the left, that is to say, "current ul" and "retreat" to the previous "current ul" (green). Colour ul), and then insert a title into Current ul. These are all three cases, and the following traversal process is similar.

With the above analysis, we can quickly write the following code to build the directory:

function buildContents(rootId) {
    var aTitle = document.getElementById(rootId).querySelectorAll('h1, h2, h3, h4, h5, h6');
    var stack = [];
    var oRoot = document.createElement('ul');
    stack.push(oRoot);
    document.getElementById('contents').appendChild(oRoot);
    for (var i = 0; i < aTitle.length; i++) {
        var oTitle = aTitle[i];
        var level = parseInt(oTitle.nodeName.substring(1, 2)); // Series of current title
        var oTop = stack[stack.length - 1]; // Get the top element of the stack
        if (i == 0)
            oTop.level = level;

        while (level < oTop.level) {
            // Indent to the left
            stack.pop();
            oTop = stack[stack.length - 1];
        }

        var oLi = document.createElement('li');
        oTop.appendChild(oLi);
        if (level == oTop.level) {
            // Direct insertion
            oLi.textContent = oTitle.textContent;
            continue;
        } else if (level > oTop.level) {
            // Indent to the right
            var oUl = document.createElement('ul');
            oUl.level = level;
            oLi.appendChild(oUl);
            oLi.style.listStyle = 'none';
            var oChildLi = document.createElement('li');
            oChildLi.textContent = oTitle.textContent;
            oUl.appendChild(oChildLi);
            stack.push(oUl);
            oTop = oUl;
            continue;
        }
    }
    return oRoot;
}

In fact, the above code is bug gy, or it can only deal with the "standard" directory, for the "non-standard" directory, it is a problem. For example, if we delete "Chapter 1" from the above article, then the directory generated with it looks like this:

Obviously not, because it is supposed to be like this:

Consider the cause of the problem, because we assume by default that the next title must be under "current ul", but in fact this should also refer to the series of titles that appear later. For example, a three-level heading appears after the first level ul. Whether the three-level heading is placed directly under the UL depends on whether the following heading has two-level heading: if not, insert it directly; otherwise, an empty UL should be created, and then an UL should be built inside to put the current heading. This requires us to know the series of all titles in advance, so we can improve our code in this way:

function buildContents(rootId) {
    var aContents = [];
    var aTitle = document.getElementById(rootId).querySelectorAll("h1, h2, h3, h4, h5, h6");
    var checkArray = [false, false, false, false, false, false]; // Each location indicates whether there are h1, h2,..., H6 tags.
    // First traversal to collect relevant information
    for (var i = 0; i < aTitle.length; i++) {
        var level = parseInt(aTitle[i].tagName.substring(1, 2));
        checkArray[level - 1] = true;
    }
    // Second traversal to build a directory tree
    var oRoot = document.createElement('ul');
    for (var i = 0; i < 6; i++) {
        if (checkArray[i]) {
            oRoot.level = i + 1;
            break;
        }
    }
    var ulStack = [oRoot];
    ulStack.peek = function () {
        return this[ulStack.length - 1];
    };
    ulStack.level = function () {
        return this.peek().level;
    };
    for (var i = 0; i < aTitle.length; i++) {
        var titleLevel = parseInt(aTitle[i].tagName.substring(1, 2));
        while (titleLevel != ulStack.level()) {
            if (titleLevel > ulStack.level()) {
                var oLi = document.createElement('li');
                oLi.style.listStyle = 'none';
                var oChildUL = document.createElement('ul');
                oChildUL.level = ulStack.level() + 1;
                oLi.appendChild(oChildUL);
                if (ulStack.peek().childElementCount == 0) {
                    ulStack.peek().appendChild(document.createElement('li'));
                }
                ulStack.peek().appendChild(oLi);
                ulStack.push(oChildUL);
                while (!checkArray[oChildUL.level - 1] && titleLevel != ulStack.level()) {
                    oChildUL.level++;
                }
            } else {
                ulStack.pop();
            }
        }
        var oLi = document.createElement('li');
        var oLink = document.createElement('a');
        oLink.setAttribute('href', '#' + aTitle[i].getAttribute('id'));
        oLink.textContent = aTitle[i].textContent;
        oLi.appendChild(oLink);
        ulStack.peek().appendChild(oLi);
        aContents.push(oLink);
    }
    return oRoot;
}

The above code and previous code ideas are the same, but the way the code is organized is slightly different. In addition, we added links and anchors to each title, so that we can click on a title to locate the corresponding content directly.

4. Fixed catalogue

The next thing to do is to "fix" the directory. If your blog has enough space, you can fix the generated directory directly to a certain location using position: fixed. But if you don't have the right space, you can put the directory at the bottom of the sidebar, like me, and then, by listening for page scrolling, when you scroll to the directory column, you can "fix" it and stop scrolling. The code is probably like this:


function stickUp(){
    var stickUpOffset = oContents.offsetTop;// oContents is the outermost container dom object of your directory
    document.onscroll = function(){
        if(window.scrollY >= stickUpOffset){
            fix();
        }else{
            static();
        }
    };
    
    var fixed;
    function fix(){
        if(fixed) return;
        oSideBar.style.top = (oSideBar.offsetTop - oContents.offsetTop) + 'px'; // oSideBar is the sidebar dom object
        oSideBar.style.position = 'fixed';
        fixed = true;
    }

    function static(){
        oSideBar.style.position = 'static';
        fixed = false;
    }  
}

5. Indicate the current location

In order to indicate where the article scrolls in the catalog, we also need to listen to the article scroll, and then highlight the previous title nearest to the current scroll position in the catalog.

Write a highlighted css class first, and then add the class to the appropriate location.

.active{
    color: yellow;
}

class can be added as follows:

function stickUp(){
    var stickUpOffset = oContents.offsetTop// oContents is the outermost container DOM object of your directory
    document.onscroll = function(){
        if(window.scrollY >= stickUpOffset){
            fix();
        }else{
            static();
        }
    };
    
    // Add class
    var aLastActive = aContents[0]; // aContents is an array of a-label DOM objects where all titles in the directory are located
    for (var i = 0; i < aTitle.length; i++) {// aTitle is an array of all h-tag DOM objects in the article
          if (window.scrollY < aTitle[i].offsetTop) { 
              break;
          }
    }
    aLastActive.removeAttribute('class');
    aContents[i && i - 1].setAttribute('class', 'active');
    aLastActive = aContents[i && i - 1];
}

6. Write at the end

This is the whole process of creating a directory, and only about the code is posted, because each person's blog template may be different, the rest needs to be written according to their own template.

Posted by SirChick on Tue, 09 Apr 2019 13:03:31 -0700