Blogger에 목차 자동으로 추가하기(Table of Contents on blogger)

제 블로그 글에 아직까진 목차 개념이 없었는데, 아무래도 있는게 좋을 것 같아 새벽에 부랴부랴 만들어봤습니다.

관련 내용 공유드립니당

Subtitle on blogger

음.. 구글 블로거 말고도 마크다운, 다른 위지윅 에디터등에서 본문을 구별해주는 부제목들을 설정해서 쓰는데 보통 h2, h3 으로 많이 지정합니다. (h1 부터 쓰는곳도 있긴하죠. 마크다운의 경우에도 h1 사용하기도 합니다) Blogger 기준으론 대략 이런식입니다.

제목: h2 부제목 h3

이제 이런 subtitle 들만 수집해서 하나의 리스트로 만들어주고, 바로 볼 수 있게 링크만 걸어주면 끝납니다.

다만 h2만 뽑아내면 문제가되는게 하나 있느데, 본문 이외에 적용된 h2도 모두 잡힌다는 점입니다.

테스트한다고 막 쓰던터라… 비주얼이 영 ㅜㅜ

이 부분도 고려해서 코드를 구성해야겠네요.

본문(post-body)의 h2만 추출하기

우선 h2만 추출해봅시다

Jquery

var h2 = $('h2')

no Jquery

var h2 = document.getElementsByTagName('h2')

이러면 h2 변수에는 페이지에서 찾은 h2들이 쭉 모이게됩니다. 아까 보여드린 이미지처럼 본문 이외 영역의 h2도 모두 수집되는데, 실제로 목차를 만들떄 제외해주고 만들어주면 될 것 같네요.

blogger에서 본문 영역은 보통 post-body class를 사용합니다. 그 class 하위에 존재하는 h2가 본문에 정의된 h2들이기 때문에 h2 리스트에서 각각 객체의 부모가 post-body인지만 걸러주면 됩니다.

$('h2')[0].parentElement.className // => post-body

이렇게하면, 부모의 className 을 가져올 수 있고 이를 분기 태워서 post-body만 처리하면 본문의 데이터만 수집할 수 있습니다. 그럼… 이제 코드로 적용해보죠.

Code on my blogger

HTML(table of contents가 삽입될 위치를 만들어줍시다)

<article> <div class="table-contents"> </div> </article>

JS(그리고.. 자바스크립트로 본문 내 h2를 수집해서 만들어줍니다)

var ToC =
  "<nav class='table-of-contents' role='navigation'>" +
    "<ul>";

var newLine, el, title, link;

$("h2").each(function() {
if($(this)[0].parentElement.className == 'post-body'){
  el = $(this);
  title = el.text();
  link = "#" + el.attr("id");

  newLine =
    "<li>" +
      "<a href='" + link + "'>" +
        title +
      "</a>" +
    "</li>";

  ToC += newLine;
}
});

ToC +=
   "</ul>" +
  "</nav>";

$(".table-contents").prepend(ToC);

h2 태그가 없거나 너무 적을 떄

적용하다 보니 하나의 문제가 있습니다. 바로 h2가 없거나 1개인 경우에 좀 보기가 안좋다는 거죠.. (그냥 떡하니 table of contents 만 적혀있의 원..) 예외처리 로직을 추가해줍시다.

var ToC =
  "<nav class='table-of-contents' role='navigation'>" +
    "<h2 class='post-body'>Table of Contents</h2>" +
    "<ul>";

var newLine, el, title, link;
var count = 0;

$("h2").each(function() {
if($(this)[0].parentElement.className == 'post-body'){
  el = $(this);
  title = el.text();
  link = "#" + el.attr("id");

  newLine =
    "<li>" +
      "<a href='" + link + "'>" +
        title +
      "</a>" +
    "</li>";

  ToC += newLine;
  count += 1; // 그냥 갯수 세고
}
});

ToC +=
   "</ul>" +
  "</nav>";

if(count > 1){ // 2개 안되면 노출 안되도록...
  $(".table-contents").prepend(ToC);
}

이러면 h2 없거나 1개인 애들은 노출이 되지 않습니다 :)