ShunS
(Shun Sakurai)
7월 8, 2023, 2:33오전
1
목차:
위와 같이 접을 수 있는 목차(ToC)를 생성하는 북마크릿(bookmarklet)을 만들었습니다.
긴 글을 많이 작성하시는 커뮤니티 회원분들에게 도움이 되기를 바랍니다!
요약
가끔 긴 주제/게시글을 작성할 때, 읽기 편하도록 목차가 필요했습니다.
DiscoTOC - automatic table of contents 같은 기존 작업물을 찾았지만, 커뮤니티 전체에 무언가를 설치해야 하는 것이 아니라 나만을 위한 도구가 필요했습니다.
구조화된 게시글을 게시한 후 북마크릿을 클릭하면 목차가 클립보드에 복사됩니다. 게시글을 편집하여 맨 위에 목차를 붙여넣으세요!
사용 방법
설치
페이지를 북마크로 저장합니다.
이름을 “ 포럼 목차를 클립보드에 복사” 등으로 수정합니다.
URL을 편집하고 다음 코드를 붙여넣습니다. 필요에 따라 코드를 사용자 지정할 수 있습니다 – 아래 “선택 사항” 2가지를 참조하세요.
javascript:(function() {
const copyForumTocToClipboard = function() {
const urlMatch = window.location.href.match(/\/t\/[^\/]*\/\d+\/?(\d*)/);
if (!urlMatch) return;
const postIndex = urlMatch ? urlMatch[1] : 1;
const anchors = document.querySelectorAll('#post_' + postIndex + ' div.cooked h6>a.anchor,h5>a.anchor,h4>a.anchor,h3>a.anchor,h2>a.anchor,h1>a.anchor');
if (!anchors) return;
let toc = '';
anchors.forEach(anchor => {
toc +=
' '.repeat((anchor.parentNode.nodeName[1] - 1) * 4) +
`<a href="${anchor.href}">${anchor.parentNode.textContent}</a><br>\n`;
});
if (!toc) return;
navigator.clipboard.writeText('<details open><summary>Table of contents: </summary><ul>\n' + toc + '</ul></details>');
};
copyForumTocToClipboard();
})();
코드의 동작 방식
URL이 커뮤니티 게시글인지 확인합니다: https://{domain}/t/{title}/{topicID}(/{postIndex}).
게시글에 앵커(<h1> 및 # 와 같은 제목)가 포함되어 있는지 확인합니다.
목차를 위한 HTML 코드를 생성합니다.
코드를 클립보드에 복사합니다.
목차 생성
구조화된 게시글(HTML <h1>, <h2>, … 및 마크다운 # , ## , …)을 게시합니다. Discourse가 각 제목에 앵커를 할당합니다.
진행 상태 표시줄(예: 1/22)이나 URL(예: /1)을 확인하여 게시글이 선택되었는지 확인합니다.
북마크 바의 북마크릿을 클릭합니다.
목차가 클립보드에 복사됩니다.
목차 사용
연필 아이콘을 클릭하여 게시글을 편집합니다.
맨 위에 코드를 붙여넣습니다.
목차 항목이 올바르게 표시되는지 확인합니다. (알려진 문제: 북마크릿이 일부 이모지를 놓칠 수 있습니다.)
(선택 사항) "Table of contents"를 변경하거나 번역합니다.
(선택 사항) 기본적으로 접힌 상태의 목차를 원하면 open을 삭제합니다.
"저장"을 클릭합니다. 게시글 게시 후 몇 분 이내에 이 작업을 수행하면 게시글에 “편집됨” 연필 아이콘이 추가되지 않습니다.
기술적 참고 사항
개발자 콘솔에 JavaScript 코드를 복사하여 붙여넣을 수도 있습니다.
함수 외부에서 return;이 작동하지 않기 때문에 코드를 함수로 감쌌습니다.
' '.repeat() 방식은 주제 미리보기에서 지저분해 보일 수 있지만, 제 생각에는 실제 게시글에서(이를 <li></li> 사용과 비교했을 때) 가장 잘 보입니다.
querySelectorAll을 테스트했을 때, h6>a.anchor,h5>a.anchor, ...의 첫 번째 항목이 왜인지 찾지지 않았습니다. h6을 맨 앞에 둔 이유는 아마도 가장 덜 자주 사용될 것이기 때문입니다.
Discourse가 UI/DOM을 변경하면 북마크릿이 작동하지 않을 수 있습니다. 오류를 발견하시면 제게 답글을 남겨 주세요.
스크린샷
meta.discourse.org의 신규 사용자로서 여러 이미지를 추가할 수 없으므로, 모든 스크린샷을 하나의 이미지로 묶어 올립니다:
오, 좋다 - 모든 답변을 포함하여 전체 게시물의 목차를 만들 수 있도록 확장할 수 있을까?
Lhc_fl
(Linca)
7월 8, 2023, 8:13오전
3
게시물은 보통 한 번에 20개 정도 로드되므로, 모든 게시물의 목차를 한 번에 생성하는 것은 어려울 것 같습니다.
mcwumbly
(Dave McClure)
7월 8, 2023, 7:24오후
4
정말 멋지네요! 공유해 주셔서 감사합니다, @ShunS !
이 도구로 해결하려는 문제를 어떻게 정의했는지, 그리고 현재 사이트에서 변경 권한이 없는 중요한 사용자들의 요구를 충족하도록 설계된 점이 정말 마음에 듭니다.
ShunS
(Shun Sakurai)
7월 9, 2023, 1:47오전
5
답변해 주셔서 감사합니다
@Lhc_fl 님이 말씀하신 대로, DOM 방식(HTML/JavaScript)은 관리할 수 있는 항목 수에 한계가 있습니다. 이러한 작업에는 Discourse API가 도움이 될 수 있습니다.
또한, 답글에 대해 목차(TOC)를 생성하는 또 다른 문제는 각 답글의 제목을 정의하기가 쉽지 않다는 점입니다. 작성자와 날짜 같은 정보를 사용할 수는 있지만, 기존에 있는 스크롤 진행률 바보다 더 유용한지 확신이 서지 않습니다.
@mcwumbly 님도 감사합니다!
Lilly
(Lillian )
7월 9, 2023, 3:08오전
6
@ShunS 정말 멋지네요, 공유해 주셔서 감사합니다. 그리고 메타에 오신 것을 환영합니다
RBoy
(RBoy)
7월 9, 2023, 3:39오후
7
정말 훌륭하고, 제가 찾던 바로 그거네요. 이 문제를 해결하는 것 같습니다.
here is an alternative solution that’s very cool and outside the box
왜 이걸 Discourse에 제출해서 공식 플러그인이나 기능으로 포함시키지 않나요? 작성기/에디터 툴바에 포함시켜서 게시물에 목차(TOC)를 자동으로 삽입할 수 있도록 할 수 있습니다.
RBoy
(RBoy)
7월 9, 2023, 5:56오후
8
한 가지 제안을 드리고 싶습니다. 목차(TOC)의 각 줄 앞에 불릿(•)을 추가할 수 있을까요? 제 경우 각 헤딩이 긴 줄로 구성되어 있어, 불릿이 항목을 구분하는 데 도움이 됩니다.
ShunS
(Shun Sakurai)
7월 9, 2023, 11:12오후
9
Hi @RBoy , 피드백과 제안 감사합니다!
에디터 플러그인이 있으면 좋겠지만, discourse 소스 코드 를 읽어서 이모지 처리 로직과 헤딩/앵커 텍스트 정의 방식을 이해하고 플러그인 저장소를 만드는 것은 상당한 노력이 필요합니다.
Spoiler Alert 처럼 (겉보기에) 단순한 플러그인도 큰 저장소인데, 개발에 전적으로 매진할 여유가 없습니다. 따라서 Discourse가 Automatic Table of Contents generation 같은 기능 요청을 우선순위로 다루고, 그 사이 네이티브 기능을 개발해 주기를 바랍니다
아래는 불릿 포인트가 포함된 버전입니다. <ul> 태그 사이의 간격이 다소 넓어 원래의 불릿 없는 버전을 선호했습니다.
스크린샷:
코드:
javascript:(function() {
const copyForumTocToClipboard = function() {
const urlMatch = window.location.href.match(/\/t\/[^\/]*\/\d+\/?(\d*)/);
if (!urlMatch) return;
const postIndex = 1;
const anchors = document.querySelectorAll('#post_' + postIndex + ' div.cooked h6>a.anchor,h5>a.anchor,h4>a.anchor,h3>a.anchor,h2>a.anchor,h1>a.anchor');
let toc = '';
let currentLevel = 1;
anchors.forEach(anchor => {
newLevel = anchor.parentNode.nodeName[1];
levelChange = newLevel - currentLevel;
toc +=
((levelChange >= 0) ? '<ul>'.repeat(levelChange) : '</ul>'.repeat(levelChange * -1)) +
`<li><a href="${anchor.href}">${anchor.parentNode.textContent}</a></li>`;
currentLevel = newLevel;
});
if (newLevel > 1) toc += '</ul>'.repeat(newLevel - 1);
toc = '<details open><summary>목차: </summary><ul>\n' + toc + '</ul></details>';
navigator.clipboard.writeText(toc);
};
copyForumTocToClipboard();
})();
RBoy:
공식 플러그인 또는 기능
우리는 이미 ToC 플러그인 을 가지고 있으며, 이는 게시물 본문에서 목차(ToC)를 유지할 필요가 없습니다.
설치되어 있다면 확실히 해당 플러그인을 추천합니다. 동기화가 어긋날 일이 없기 때문입니다.
다만 DiscoToC가 사용 불가능한 경우 이 도구는 훌륭한 대안이 될 것 같습니다. 좋은 작업입니다!
Lhc_fl
(Linca)
7월 10, 2023, 12:45오전
11
이 작업은 테마 컴포넌트를 사용하여 수행할 수 있습니다. api의 decorateCookedElement 메서드를 확인해 보시기 바랍니다. 유용할 것입니다.
ShunS
(Shun Sakurai)
7월 10, 2023, 1:06오전
12
HI @supermathie , 답변 감사합니다.
when DiscoToC is not available
네, 그게 구별점입니다. 제가 주로 활동하는 포럼에 어떤 "테마-컴포넌트"를 설치할지 결정할 권한이 없기 때문에 북마크릿을 만들었습니다. 그리고 긴 텍스트를 작성해서 목차가 필요한 사람은 몇 명에 불과하거든요.
@Lhc_fl , 정말 큰 도움이 됩니다!
GitHub 저장소를 검색해 해당 메서드를 찾았습니다. 여유가 생기고 이 기능에 대한 수요가 충분히 있을 때만 (그 경우에만) 개발을 고려해 보겠습니다.
다만, @supermathie가 말한 대로 커뮤니티에 테마-컴포넌트를 추가할 수 있다면 이미 DiscoTOC가 있죠
RBoy
(RBoy)
7월 10, 2023, 2:07오전
13
불행히도 제목이 몇 단어를 넘어가면 이 플러그인은 완전히 쓸모없어지며, 페이지를 엉망으로 만들어 버립니다. 헤더가 한두 줄 길이인 경우(예: FAQ 페이지) Disco TOC 플러그인은 페이지 전체를 엉망으로 만들어 버리는데, 바로 이 때문에 인라인 TOC(이 플러그인이 제공하는 기능)에 대한 요청을 제기한 것입니다. 이 기능은 그러한 페이지에 완벽합니다.
게시글 자체의 맨 위에 목차(TOC)를 포함할 수 있을까요? (Word에서 자동 목차를 생성하는 방식과 비슷하게요.) 문제는 제목이 실제로는 긴 문장인 경우가 많아, 사이드바가 매우 지저분해지고 전체 페이지가 가독성이 떨어지는 것입니다.
목차를 주제(topic) 자체의 맨 위에 내장하면 이 문제를 해결할 수 있고, 위키를 쉽게 업데이트하면서 플러그인이 자동으로 목차를 갱신해 주므로 사이드바가 지저분해지는 일도 방지할 수 있습니다.
discourse를 개발하는 팀들 안에 뛰어난 천재성과 재능이 풍부하므로, DiscoTOC의 대안으로 이 놀라운 기능을 포함시켜 사용 범위를 훨씬 넓히는 것이 그렇게 어렵지 않아야 합니다.