六一的部落格


关关难过关关过,前路漫漫亦灿灿。




思路

  1. 目前标题id唯一. 由于需要数组存放标题高亮状态, 仍旧为标题进行编号, 使用编号读取数组值
  2. 文章目录标题项和正文标题项均使用li元素定位
  3. 出现在页面的所有标题高亮

框架


获取文章目录标题数和正文标题数, 判等

 1const toc = document.querySelector('.toc-panel');
 2if (!toc)
 3{
 4    console.log("toc is null", toc);
 5    return;
 6}
 7
 8const headings = Array.apply(null, document.querySelectorAll('h2[id], h3[id], h4[id]'))
 9                     .filter(function(value, index, arr) { return arr[index].querySelector('.anchor'); });
10const tocHeadings = toc.querySelectorAll('li');
11
12if (tocHeadings.length !== headings.length)
13{
14    console.log(headings);
15    console.log(tocHeadings);
16    return;
17}

为文章目录标题和正文标题添加关联编号, 创建标题高亮数组

 1function addHeadingIdx(list)
 2{
 3    let i = 0;
 4    list.forEach((item) => { item.setAttribute('headingIdx', i++); });
 5}
 6
 7let HeadingFlag;
 8
 9addHeadingIdx(tocHeadings);
10addHeadingIdx(headings);
11
12HeadingFlag = new Array(headings.length).fill(false);

创建观察器, 当标题进入/离开窗口时触发处理

1const intersectionOptions = {threshold : 1.0};
2const headingObserver = new IntersectionObserver(headings => { unfold_headings(headings); }, intersectionOptions);

观察正文标题

1headings.forEach((heading) => { headingObserver.observe(heading); });

完整代码

 1let HeadingFlag;
 2
 3function addHeadingIdx(list)
 4{
 5    let i = 0;
 6    list.forEach((item) => { item.setAttribute('headingIdx', i++); });
 7}
 8
 9document.addEventListener('DOMContentLoaded', () => {
10    const toc = document.querySelector('.toc-panel');
11    if (!toc)
12    {
13        console.log("toc is null", toc);
14        return;
15    }
16
17    const headings = Array.apply(null, document.querySelectorAll('h2[id], h3[id], h4[id]'))
18                         .filter(function(value, index, arr) { return arr[index].querySelector('.anchor'); });
19    const tocHeadings = toc.querySelectorAll('li');
20
21    if (tocHeadings.length !== headings.length)
22    {
23        console.log(headings);
24        console.log(tocHeadings);
25        return;
26    }
27
28    addHeadingIdx(tocHeadings);
29    addHeadingIdx(headings);
30
31    HeadingFlag = new Array(headings.length).fill(false);
32
33    const intersectionOptions = {threshold : 1.0};
34    const headingObserver = new IntersectionObserver(headings => { unfold_headings(headings); }, intersectionOptions);
35
36    headings.forEach((heading) => { headingObserver.observe(heading); });
37});

文章目录结构

 1<div>
 2  <ul>
 3    <li><a href="#"><span></span>heading 1</a></li>
 4    <li>
 5      <a href="#"><span></span>heading 2</a>
 6      <button></button>
 7      <div>
 8        <ul>
 9          <li><a href="#"><span></span>heading 2 - 1</a></li>
10          <li><a href="#"><span></span>heading 2 - 2</a>
11          </li>
12        </ul>
13      </div>
14    </li>
15    <li><a href="#><span></span>heading 3</a></li>
16  </ul>
17</div>

高亮和折叠标题逻辑


更新标题高亮状态, 记录最后一个移除高亮标题编号

 1let last;
 2// console.log(headings.length);
 3headings.forEach(heading => {
 4    // console.log('ratio', heading.target.getAttribute('id'), heading.intersectionRatio, heading.isIntersecting, HeadingCnt);
 5    const idx = heading.target.getAttribute('headingIdx');
 6    HeadingFlag[idx] = heading.isIntersecting;
 7    if (!heading.isIntersecting)
 8    {
 9        last = parseInt(idx);
10    }
11});

计算当前高亮标题个数: 如果为0, 保留最后一个移除高亮标题的高亮状态

 1function get_highlight_num()
 2{
 3    let cnt = 0;
 4    for (let i = 0; i < HeadingFlag.length; ++i)
 5    {
 6        if (HeadingFlag[i])
 7        {
 8            ++cnt;
 9        }
10    }
11    return cnt;
12}
13
14let cnt = get_highlight_num();
15if (cnt)
16{
17    last = -1;
18}

设置标题高亮

  • 如果最后一个移除高亮标题编号不为-1, 保留其高亮状态
  • 根据标题高亮状态设置标题
  • 之前的高亮状态存在暂时不移除高亮的情况: 这一次遍历的例外情况已改变
 1function refresh_highlight(last)
 2{
 3    for (let i = 0; i < HeadingFlag.length; ++i)
 4    {
 5        if (i === last)
 6        {
 7            continue;
 8        }
 9
10        if (HeadingFlag[i])
11        {
12            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.add('active');
13        }
14        else
15        {
16            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.remove('active');
17        }
18    }
19}

设置标题折叠/展开逻辑

  1. 遍历标题
     1function refresh_fold(last)
     2{
     3    // console.log(last);
     4    for (let i = 0; i < HeadingFlag.length; ++i)
     5    {
     6        const cur_toc_item = document.querySelector(`.toc-panel li[headingIdx="${i}"]`);
     7
     8        // 处理
     9    }
    10}
  2. 如果最后一个移除高亮标题编号不为-1, 保留其展开, 或双亲标题展开
  3. 若标题高亮, 展开; 否则折叠

    可以展开/折叠的标题其子元素个数不为0
     1// 展开/关闭子节点
     2if (cur_toc_item.childElementCount !== 1)
     3{
     4    const toc_button = cur_toc_item.childNodes[1];
     5    const toc_div = cur_toc_item.childNodes[2];
     6
     7    if (HeadingFlag[i] || i === last)
     8    {
     9        toc_button.setAttribute('aria-expanded', 'true');
    10        toc_div.classList.add('show');
    11    }
    12    else
    13    {
    14        toc_button.setAttribute('aria-expanded', 'false');
    15        toc_div.classList.remove('show');
    16    }
    17}
  4. 若标题高亮, 展开双亲标题

    拥有子标题的节点也可以有双亲节点
     1if (HeadingFlag[i] || i === last) // 展开双亲节点
     2{
     3    // if (i === last) console.log(1, i);
     4    // console.log(cur_toc_item);
     5    // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling.tagName);
     6    if (cur_toc_item && cur_toc_item.parentElement && cur_toc_item.parentElement.parentElement &&
     7        cur_toc_item.parentElement.parentElement.previousElementSibling &&
     8        cur_toc_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
     9    {
    10
    11        // console.log(cur_toc_item.parentElement.parentElement);
    12        // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling);
    13        const toc_div = cur_toc_item.parentElement.parentElement;
    14        const toc_button = toc_div.previousElementSibling;
    15
    16        toc_div.classList.add('show');
    17        toc_button.setAttribute('aria-expanded', 'true');
    18
    19        let sub_item = toc_div.parentElement;
    20
    21        while (sub_item && sub_item.parentElement && sub_item.parentElement.parentElement &&
    22               sub_item.parentElement.parentElement.previousElementSibling &&
    23               sub_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
    24        {
    25            // console.log(sub_item.parentElement.parentElement);
    26            // console.log(sub_item.parentElement.parentElement.previousElementSibling.childNodes[2]);
    27
    28            const toc_div_sub = sub_item.parentElement.parentElement;
    29            const toc_button_sub = toc_div_sub.previousElementSibling;
    30
    31            toc_div_sub.classList.add('show');
    32            toc_button_sub.setAttribute('aria-expanded', 'true');
    33
    34            sub_item = toc_div_sub.parentElement;
    35        }
    36    }
    37}

完整代码

  1function refresh_highlight(last)
  2{
  3    for (let i = 0; i < HeadingFlag.length; ++i)
  4    {
  5        if (i === last)
  6        {
  7            continue;
  8        }
  9
 10        if (HeadingFlag[i])
 11        {
 12            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.add('active');
 13        }
 14        else
 15        {
 16            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.remove('active');
 17        }
 18    }
 19}
 20
 21function refresh_fold(last)
 22{
 23    // console.log(last);
 24    for (let i = 0; i < HeadingFlag.length; ++i)
 25    {
 26        const cur_toc_item = document.querySelector(`.toc-panel li[headingIdx="${i}"]`);
 27
 28        // console.log(cur_toc_item);
 29        // console.log(cur_toc_item.childElementCount);
 30
 31        // 展开/关闭子节点
 32        if (cur_toc_item.childElementCount !== 1)
 33        {
 34            // console.log(cur_toc_item.childNodes[1]);
 35
 36            const toc_button = cur_toc_item.childNodes[1];
 37            const toc_div = cur_toc_item.childNodes[2];
 38
 39            if (HeadingFlag[i] || i === last)
 40            {
 41                // if (i === last) console.log(2, i);
 42                toc_button.setAttribute('aria-expanded', 'true');
 43                toc_div.classList.add('show');
 44            }
 45            else
 46            {
 47                toc_button.setAttribute('aria-expanded', 'false');
 48                toc_div.classList.remove('show');
 49            }
 50        }
 51
 52        if (HeadingFlag[i] || i === last) // 展开双亲节点
 53        {
 54            // if (i === last) console.log(1, i);
 55            // console.log(cur_toc_item);
 56            // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling.tagName);
 57            if (cur_toc_item && cur_toc_item.parentElement && cur_toc_item.parentElement.parentElement &&
 58                cur_toc_item.parentElement.parentElement.previousElementSibling &&
 59                cur_toc_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
 60            {
 61
 62                // console.log(cur_toc_item.parentElement.parentElement);
 63                // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling);
 64                const toc_div = cur_toc_item.parentElement.parentElement;
 65                const toc_button = toc_div.previousElementSibling;
 66
 67                toc_div.classList.add('show');
 68                toc_button.setAttribute('aria-expanded', 'true');
 69
 70                let sub_item = toc_div.parentElement;
 71
 72                while (sub_item && sub_item.parentElement && sub_item.parentElement.parentElement &&
 73                       sub_item.parentElement.parentElement.previousElementSibling &&
 74                       sub_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
 75                {
 76                    // console.log(sub_item.parentElement.parentElement);
 77                    // console.log(sub_item.parentElement.parentElement.previousElementSibling.childNodes[2]);
 78
 79                    const toc_div_sub = sub_item.parentElement.parentElement;
 80                    const toc_button_sub = toc_div_sub.previousElementSibling;
 81
 82                    toc_div_sub.classList.add('show');
 83                    toc_button_sub.setAttribute('aria-expanded', 'true');
 84
 85                    sub_item = toc_div_sub.parentElement;
 86                }
 87            }
 88        }
 89    }
 90}
 91
 92function get_highlight_num()
 93{
 94    let cnt = 0;
 95    for (let i = 0; i < HeadingFlag.length; ++i)
 96    {
 97        if (HeadingFlag[i])
 98        {
 99            ++cnt;
100        }
101    }
102    return cnt;
103}
104
105function unfold_headings(headings)
106{
107    let last;
108    // console.log(headings.length);
109    headings.forEach(heading => {
110        // console.log('ratio', heading.target.getAttribute('id'), heading.intersectionRatio, heading.isIntersecting, HeadingCnt);
111        const idx = heading.target.getAttribute('headingIdx');
112        HeadingFlag[idx] = heading.isIntersecting;
113        if (!heading.isIntersecting)
114        {
115            last = parseInt(idx);
116        }
117    });
118
119    let cnt = get_highlight_num();
120    if (cnt)
121    {
122        last = -1;
123    }
124    refresh_highlight(last);
125    refresh_fold(last);
126}

文章目录高亮 + 自动折叠展开



思路

  1. 目前标题id唯一. 由于需要数组存放标题高亮状态, 仍旧为标题进行编号, 使用编号读取数组值
  2. 文章目录标题项和正文标题项均使用li元素定位
  3. 出现在页面的所有标题高亮

框架


获取文章目录标题数和正文标题数, 判等

 1const toc = document.querySelector('.toc-panel');
 2if (!toc)
 3{
 4    console.log("toc is null", toc);
 5    return;
 6}
 7
 8const headings = Array.apply(null, document.querySelectorAll('h2[id], h3[id], h4[id]'))
 9                     .filter(function(value, index, arr) { return arr[index].querySelector('.anchor'); });
10const tocHeadings = toc.querySelectorAll('li');
11
12if (tocHeadings.length !== headings.length)
13{
14    console.log(headings);
15    console.log(tocHeadings);
16    return;
17}

为文章目录标题和正文标题添加关联编号, 创建标题高亮数组

 1function addHeadingIdx(list)
 2{
 3    let i = 0;
 4    list.forEach((item) => { item.setAttribute('headingIdx', i++); });
 5}
 6
 7let HeadingFlag;
 8
 9addHeadingIdx(tocHeadings);
10addHeadingIdx(headings);
11
12HeadingFlag = new Array(headings.length).fill(false);

创建观察器, 当标题进入/离开窗口时触发处理

1const intersectionOptions = {threshold : 1.0};
2const headingObserver = new IntersectionObserver(headings => { unfold_headings(headings); }, intersectionOptions);

观察正文标题

1headings.forEach((heading) => { headingObserver.observe(heading); });

完整代码

 1let HeadingFlag;
 2
 3function addHeadingIdx(list)
 4{
 5    let i = 0;
 6    list.forEach((item) => { item.setAttribute('headingIdx', i++); });
 7}
 8
 9document.addEventListener('DOMContentLoaded', () => {
10    const toc = document.querySelector('.toc-panel');
11    if (!toc)
12    {
13        console.log("toc is null", toc);
14        return;
15    }
16
17    const headings = Array.apply(null, document.querySelectorAll('h2[id], h3[id], h4[id]'))
18                         .filter(function(value, index, arr) { return arr[index].querySelector('.anchor'); });
19    const tocHeadings = toc.querySelectorAll('li');
20
21    if (tocHeadings.length !== headings.length)
22    {
23        console.log(headings);
24        console.log(tocHeadings);
25        return;
26    }
27
28    addHeadingIdx(tocHeadings);
29    addHeadingIdx(headings);
30
31    HeadingFlag = new Array(headings.length).fill(false);
32
33    const intersectionOptions = {threshold : 1.0};
34    const headingObserver = new IntersectionObserver(headings => { unfold_headings(headings); }, intersectionOptions);
35
36    headings.forEach((heading) => { headingObserver.observe(heading); });
37});

文章目录结构

 1<div>
 2  <ul>
 3    <li><a href="#"><span></span>heading 1</a></li>
 4    <li>
 5      <a href="#"><span></span>heading 2</a>
 6      <button></button>
 7      <div>
 8        <ul>
 9          <li><a href="#"><span></span>heading 2 - 1</a></li>
10          <li><a href="#"><span></span>heading 2 - 2</a>
11          </li>
12        </ul>
13      </div>
14    </li>
15    <li><a href="#><span></span>heading 3</a></li>
16  </ul>
17</div>

高亮和折叠标题逻辑


更新标题高亮状态, 记录最后一个移除高亮标题编号

 1let last;
 2// console.log(headings.length);
 3headings.forEach(heading => {
 4    // console.log('ratio', heading.target.getAttribute('id'), heading.intersectionRatio, heading.isIntersecting, HeadingCnt);
 5    const idx = heading.target.getAttribute('headingIdx');
 6    HeadingFlag[idx] = heading.isIntersecting;
 7    if (!heading.isIntersecting)
 8    {
 9        last = parseInt(idx);
10    }
11});

计算当前高亮标题个数: 如果为0, 保留最后一个移除高亮标题的高亮状态

 1function get_highlight_num()
 2{
 3    let cnt = 0;
 4    for (let i = 0; i < HeadingFlag.length; ++i)
 5    {
 6        if (HeadingFlag[i])
 7        {
 8            ++cnt;
 9        }
10    }
11    return cnt;
12}
13
14let cnt = get_highlight_num();
15if (cnt)
16{
17    last = -1;
18}

设置标题高亮

  • 如果最后一个移除高亮标题编号不为-1, 保留其高亮状态
  • 根据标题高亮状态设置标题
  • 之前的高亮状态存在暂时不移除高亮的情况: 这一次遍历的例外情况已改变
 1function refresh_highlight(last)
 2{
 3    for (let i = 0; i < HeadingFlag.length; ++i)
 4    {
 5        if (i === last)
 6        {
 7            continue;
 8        }
 9
10        if (HeadingFlag[i])
11        {
12            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.add('active');
13        }
14        else
15        {
16            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.remove('active');
17        }
18    }
19}

设置标题折叠/展开逻辑

  1. 遍历标题
     1function refresh_fold(last)
     2{
     3    // console.log(last);
     4    for (let i = 0; i < HeadingFlag.length; ++i)
     5    {
     6        const cur_toc_item = document.querySelector(`.toc-panel li[headingIdx="${i}"]`);
     7
     8        // 处理
     9    }
    10}
  2. 如果最后一个移除高亮标题编号不为-1, 保留其展开, 或双亲标题展开
  3. 若标题高亮, 展开; 否则折叠

    可以展开/折叠的标题其子元素个数不为0
     1// 展开/关闭子节点
     2if (cur_toc_item.childElementCount !== 1)
     3{
     4    const toc_button = cur_toc_item.childNodes[1];
     5    const toc_div = cur_toc_item.childNodes[2];
     6
     7    if (HeadingFlag[i] || i === last)
     8    {
     9        toc_button.setAttribute('aria-expanded', 'true');
    10        toc_div.classList.add('show');
    11    }
    12    else
    13    {
    14        toc_button.setAttribute('aria-expanded', 'false');
    15        toc_div.classList.remove('show');
    16    }
    17}
  4. 若标题高亮, 展开双亲标题

    拥有子标题的节点也可以有双亲节点
     1if (HeadingFlag[i] || i === last) // 展开双亲节点
     2{
     3    // if (i === last) console.log(1, i);
     4    // console.log(cur_toc_item);
     5    // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling.tagName);
     6    if (cur_toc_item && cur_toc_item.parentElement && cur_toc_item.parentElement.parentElement &&
     7        cur_toc_item.parentElement.parentElement.previousElementSibling &&
     8        cur_toc_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
     9    {
    10
    11        // console.log(cur_toc_item.parentElement.parentElement);
    12        // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling);
    13        const toc_div = cur_toc_item.parentElement.parentElement;
    14        const toc_button = toc_div.previousElementSibling;
    15
    16        toc_div.classList.add('show');
    17        toc_button.setAttribute('aria-expanded', 'true');
    18
    19        let sub_item = toc_div.parentElement;
    20
    21        while (sub_item && sub_item.parentElement && sub_item.parentElement.parentElement &&
    22               sub_item.parentElement.parentElement.previousElementSibling &&
    23               sub_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
    24        {
    25            // console.log(sub_item.parentElement.parentElement);
    26            // console.log(sub_item.parentElement.parentElement.previousElementSibling.childNodes[2]);
    27
    28            const toc_div_sub = sub_item.parentElement.parentElement;
    29            const toc_button_sub = toc_div_sub.previousElementSibling;
    30
    31            toc_div_sub.classList.add('show');
    32            toc_button_sub.setAttribute('aria-expanded', 'true');
    33
    34            sub_item = toc_div_sub.parentElement;
    35        }
    36    }
    37}

完整代码

  1function refresh_highlight(last)
  2{
  3    for (let i = 0; i < HeadingFlag.length; ++i)
  4    {
  5        if (i === last)
  6        {
  7            continue;
  8        }
  9
 10        if (HeadingFlag[i])
 11        {
 12            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.add('active');
 13        }
 14        else
 15        {
 16            document.querySelector(`.toc-panel li[headingIdx="${i}"]`).childNodes[0].classList.remove('active');
 17        }
 18    }
 19}
 20
 21function refresh_fold(last)
 22{
 23    // console.log(last);
 24    for (let i = 0; i < HeadingFlag.length; ++i)
 25    {
 26        const cur_toc_item = document.querySelector(`.toc-panel li[headingIdx="${i}"]`);
 27
 28        // console.log(cur_toc_item);
 29        // console.log(cur_toc_item.childElementCount);
 30
 31        // 展开/关闭子节点
 32        if (cur_toc_item.childElementCount !== 1)
 33        {
 34            // console.log(cur_toc_item.childNodes[1]);
 35
 36            const toc_button = cur_toc_item.childNodes[1];
 37            const toc_div = cur_toc_item.childNodes[2];
 38
 39            if (HeadingFlag[i] || i === last)
 40            {
 41                // if (i === last) console.log(2, i);
 42                toc_button.setAttribute('aria-expanded', 'true');
 43                toc_div.classList.add('show');
 44            }
 45            else
 46            {
 47                toc_button.setAttribute('aria-expanded', 'false');
 48                toc_div.classList.remove('show');
 49            }
 50        }
 51
 52        if (HeadingFlag[i] || i === last) // 展开双亲节点
 53        {
 54            // if (i === last) console.log(1, i);
 55            // console.log(cur_toc_item);
 56            // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling.tagName);
 57            if (cur_toc_item && cur_toc_item.parentElement && cur_toc_item.parentElement.parentElement &&
 58                cur_toc_item.parentElement.parentElement.previousElementSibling &&
 59                cur_toc_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
 60            {
 61
 62                // console.log(cur_toc_item.parentElement.parentElement);
 63                // console.log(cur_toc_item.parentElement.parentElement.previousElementSibling);
 64                const toc_div = cur_toc_item.parentElement.parentElement;
 65                const toc_button = toc_div.previousElementSibling;
 66
 67                toc_div.classList.add('show');
 68                toc_button.setAttribute('aria-expanded', 'true');
 69
 70                let sub_item = toc_div.parentElement;
 71
 72                while (sub_item && sub_item.parentElement && sub_item.parentElement.parentElement &&
 73                       sub_item.parentElement.parentElement.previousElementSibling &&
 74                       sub_item.parentElement.parentElement.previousElementSibling.tagName == "BUTTON")
 75                {
 76                    // console.log(sub_item.parentElement.parentElement);
 77                    // console.log(sub_item.parentElement.parentElement.previousElementSibling.childNodes[2]);
 78
 79                    const toc_div_sub = sub_item.parentElement.parentElement;
 80                    const toc_button_sub = toc_div_sub.previousElementSibling;
 81
 82                    toc_div_sub.classList.add('show');
 83                    toc_button_sub.setAttribute('aria-expanded', 'true');
 84
 85                    sub_item = toc_div_sub.parentElement;
 86                }
 87            }
 88        }
 89    }
 90}
 91
 92function get_highlight_num()
 93{
 94    let cnt = 0;
 95    for (let i = 0; i < HeadingFlag.length; ++i)
 96    {
 97        if (HeadingFlag[i])
 98        {
 99            ++cnt;
100        }
101    }
102    return cnt;
103}
104
105function unfold_headings(headings)
106{
107    let last;
108    // console.log(headings.length);
109    headings.forEach(heading => {
110        // console.log('ratio', heading.target.getAttribute('id'), heading.intersectionRatio, heading.isIntersecting, HeadingCnt);
111        const idx = heading.target.getAttribute('headingIdx');
112        HeadingFlag[idx] = heading.isIntersecting;
113        if (!heading.isIntersecting)
114        {
115            last = parseInt(idx);
116        }
117    });
118
119    let cnt = get_highlight_num();
120    if (cnt)
121    {
122        last = -1;
123    }
124    refresh_highlight(last);
125    refresh_fold(last);
126}