[ 목차 ]
구현목표
내가 만들고자 하는 것은 마크업언어로 #in(textarea) 에 작성을 하면 #out에 html로 자동 변환되고 여기서 변환된 #out의 html 문법을 보고 목차를 자동으로 만드는게 목표이다. 작업을 하면서 구글에 많은 티스토리 블로그 자동 목차만들기를 활용해서 사용하면 되겠다고 생각하였다. 여기서는 자동목차 만들기만 확인할것이다.
html 기본 구조
<div id="in" style= "disply:none;">
<form>
<textarea id="code" contenteditable= "true">
# 뉴스 제목 1
## 부제목 1
### 소제목 1.1
# 또 다른 주제
</textarea>
</form>
</div>
<div id="out" class="markdown-body"></div>
<div id="tree"></div>
<div id="menu">
<span>다운로드</span>
<div id="saveas-pdf">
<span>Markdown</span>
</div>
<div id="saveas-markdown">
<span>Markdown</span>
</div>
<div id="saveas-html">
<span>HTML</span>
</div>
<a id="close-menu">×</a>>
</div>
위는 기본적인 html의 뼈대이다. 생략된 css난 html 부분이 많이있다. (참고용)
결과페이지 미리보기
자바스크립트 전체
$(document).ready(function () {
// 여기에 Markdown 콘텐츠를 HTML로 변환하고 #out 요소를 업데이트하는 코드 추가
// 목차 플러그인 초기화
$("#tree").toc({
content: "#out", // HTML 콘텐츠는 표시할 요소의 ID와 일치해야 합니다.
headings: "h1,h2,h3", // Markdown 제목 구조에 맞게 사용자 정의
indent: true,
indentBy: " ",
level: function (element) {
var tagName = element.tagName.toLowerCase();
if (tagName == "h1") return 0;
if (tagName == "h2") return 1;
if (tagName == "h3") return 2;
return 0;
}
});
});
(function ($) {
"use strict";
// 현재 선택한 요소의 목차를 포함한 목록을 작성합니다.
// 옵션:
// content: 목차를 찾을 콘텐츠
// headings: 상대적인 계층 구조 순서대로 나열된 쉼표로 구분된 선택기 문자열
var toc = function (options) {
return this.each(function () {
var root = $(this),
data = root.data(),
thisOptions,
stack = [root], // 상위로 올라간 역순 스택은 목록 요소를 추적합니다.
listTag = this.tagName;
currentLevel = 0;
headingSelectors;
// 기본값: 플러그인 매개변수는 데이터 속성을 재정의하고 기본값을 재정의합니다.
thisOptions = $.extend(
{ content: "body", headings: "h1,h2,h3" },
{ content: data.toc || undefined, headings: data.tocHeadings || undefined },
options
);
headingSelectors = thisOptions.headings.split(",");
// 이미 ID가 없는 경우 몇 가지 자동 ID를 설정합니다.
$(thisOptions.content)
.find(thisOptions.headings)
.attr("id", function (index, attr) {
// HTML5에서는 ID 속성은 하나 이상의 문자를 가져야 하며 공백 문자를 포함해서는 안됩니다.
//
// 모든 브라우저가 이것을 처리하므로 이제 HTML5 사양을 사용합니다.
// https://mathiasbynens.be/notes/html5-id-class
var generateUniqueId = function (text) {
// 유효한 ID를 생성합니다. 공백은 밑줄로 대체됩니다. 또한 문서에서 이미 ID가 있는지 확인합니다.
// 그렇다면 "_1", "_2" 등을 추가합니다.
//사용되지 않은 ID를 찾을 때까지.
if (text.length === 0) {
text = "?";
}
var baseId = text.replace(/\s+/g, "_"),
suffix = "",
count = 1;
while (document.getElementById(baseId + suffix) !== null) {
suffix = "_" + count++;
}
return baseId + suffix;
};
return attr || generateUniqueId($(this).text());
})
.each(function () {
//현재 제목의 수준은 무엇인가요?
var elem = $(this),
level = $.map(headingSelectors, function (selector, index) {
return elem.is(selector) ? index : undefined;
})[0];
if (level > currentLevel) {
// 제목이 현재 수준보다 더 깊은 수준에 있다면 새로운 중첩 목록을 시작합니다.
// 단, 상위에 이미 몇 개의 목록 항목이 있는 경우에만 수행합니다.
// 그렇지 않으면 수준을 건너뛰고 현재 수준에 새 목록 항목을 추가할 수 있습니다.
// 상위 목록에 이미 몇 개의 목록 항목이 있는지 확인하는 것입니다.
// 역방향 스택에서 unshift = push이며 stack[0] = 상단입니다.
var parentItem = stack[0].children("li:last")[0];
if (parentItem) {
stack.unshift($("<" + listTag + "/>").appendTo(parentItem));
}
} else {
// 스택을 현재 수준에 맞게 자르기 위해 스택의 맨 위에서부터 일부를 잘라내기 위해 splice를 사용합니다.
// 또한 스택에 적어도 하나의 요소를 유지해야 합니다. 즉, 포함 요소입니다.
stack.splice(0, Math.min(currentLevel - level, Math.max(stack.length - 1, 0)));
}
//목록 항목 추가
$("<li/>")
.appendTo(stack[0])
.append($("<a/>").text(elem.text()).attr("href", "#" + elem.attr("id")));
currentLevel = level;
});
});
},
old = $.fn.toc;
$.fn.toc = toc;
$.fn.toc.noConflict = function () {
$.fn.toc = old;
return this;
};
// Data API
$(function () {
toc.call($("[data-toc]"));
});
})(window.jQuery));
먼저 마크업으로 작성한 #in 에서 #out에 html로 변환한 후 목차를 h1, h2, h3 태그로 변환된 내용을 목차로 자동으로 만든 부분이다. 더 자세하게 설명하면 내가 #in부분에 "# 안녕" 이라고 작성을하면 <h1>안녕<h1/>으로 # out에 자동으로 변환되고 이를 통해 목차를 자동으로 만들어 준다.
자바스크립트 세부설명
문서준비 함수
$(document).ready(function () {
// Markdown 내용을 HTML로 변환하고 #out 요소를 업데이트하는 코드를 여기에 작성합니다.
// 목차 플러그인 초기화
$("#tree").toc({
content: "#out", // HTML 컨텐츠는 보여질 요소의 ID와 일치해야 합니다.
headings: "h1,h2,h3", // Markdown 제목 구조에 맞게 수정하세요.
indent: true; // 들여쓰기 활성화
indentBy : " "; // 들여쓰기에 사용할 문자(여기서는 공백)
level: function (element){
var tagName = element.tagName.toLowerCase();
if(tagName =="h1") return 0;
if(tagName =="h2") return 1;
if(tagName =="h3") return 2;
return 0;
}
});
});
html 페이지가 로드된 시점에서 실행된다. tagName이 h1, h2, h3 에 따라 들여쓰기를 활성화하고 구분을 공백으로 작업할려고 하였다.
목차 플러그인(플러그인 이름은 사용자 정의 가능) 초기화:
$("#tree").toc({
// 목차 플러그인의 구성 옵션들을 정의합니다.
});
목차 플러그인 초기화의 주요 이유는 웹 페이지나 문서의 긴 내용을 보다 쉽게 탐색하고 이해하기 위함으로 이 부분은 ID가 "tree"인 HTML 요소에 목차 플러그인을 초기화하였다.
중첩된 목록을 생성하거나 스택에서 항목을 제거
if (level > currentLevel) {
// 제목이 현재 수준보다 더 깊은 수준에 있다면 새로운 중첩 목록을 시작합니다.
// 단, 상위에 이미 몇 개의 목록 항목이 있는 경우에만 수행합니다.
// 그렇지 않으면 수준을 건너뛰고 현재 수준에 새 목록 항목을 추가할 수 있습니다.
// 상위 목록에 이미 몇 개의 목록 항목이 있는지 확인하는 것입니다.
// 역방향 스택에서 unshift = push이며 stack[0] = 상단입니다.
var parentItem = stack[0].children("li:last")[0];
if (parentItem) {
stack.unshift($("<" + listTag + "/>").appendTo(parentItem));
}
} else {
// 스택을 현재 수준에 맞게 자르기 위해 스택의 맨 위에서부터 일부를 잘라내기 위해 splice를 사용합니다.
// 또한 스택에 적어도 하나의 요소를 유지해야 합니다. 즉, 포함 요소입니다.
stack.splice(0, Math.min(currentLevel - level, Math.max(stack.length - 1, 0)));
}
제목 요소의 수준을 기반으로 중첩된 목록을 생성하거나 스택을 조정합니다. 현재 수준과 비교하여 중첩된 목록을 생성하거나 스택에서 항목을 제거
목록 이동
$("<li/>")
.appendTo(stack[0])
.append($("<a/>").text(elem.text()).attr("href", "#" + elem.attr("id")));
생성된 목차에 각 항목을 추가합니다. li 요소를 생성하고, 해당 항목의 텍스트와 링크를 설정하여 목차에 포함
또하나의 목적은 h1, h2, h3 목차 구분을 위해서 들여쓰기를 통해 시각화를 할려했지만 테스트에서는 잘 적용되었는데 실제 내가 만들고 있는 사이트에서 js, css등이 많아 겹치는 느낌이 있어 적용이 안되었다. 근데 막상보니 정렬되면 공간이 부족할거 같아 그냥 변경을 포기했다.
수정
if (parentItem) {
stack.unshift($("<" + listTag + "/>").appendTo(parentItem)
.css("margin-left", "10px");
}
.css("margin-left", "10px") 적용을 안했던 문제였다. 이전에는 왜 작동을 했는지 모르겠지만 내가 값을 빼먹은거같다. 이 후 정상작동을 한다.
'업무 기록 > WEB' 카테고리의 다른 글
Markdown Viewer for Multiple Documents and Loader(배열이용) 랜더링 (0) | 2023.09.11 |
---|---|
자바스크립트 마크다운 검색창 만들기 (0) | 2023.09.08 |
JSP 모달창 버튼 출력 조건 (0) | 2023.08.30 |
Node js, Express js - res.render 렌더링 (0) | 2023.08.01 |
Spring Security 인증처리 SecurityContextHolder.getContext(), getAuthentication(), getPrincipal() (0) | 2023.07.31 |