Javascript 로 MarkDown 문서를 HTML 로 변환하기
1. 원하는 것
- MarkDown 문서를 HTML 형식으로 변환한다.
- 소스코드는 highlight.js 를 이용해서 보기 좋게 만든다.
- 소스코드는 highlightjs-line-numbers.js 를 이용해서 line number 를 표시한다.
- onsubmit 에서 위의 작업을 수행하고, 결과를 Javascript 변수에 할당한다.
2. 라이브러리
2.1. marked.js (https://marked.js.org/)
- License : MIT license (https://marked.js.org/license)
- GitHUB : https://github.com/markedjs/marked
- CDN : https://cdn.jsdelivr.net/npm/marked/marked.min.js
- Language : Javascript
2.2. highlight.js (https://highlightjs.org/)
- License : BSD 3-Clause "New" or "Revised" License(https://github.com/highlightjs/highlight.js/blob/master/LICENSE)
- GitHUB : https://github.com/highlightjs/highlight.js
- CDN(js) : https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js
- CDN(css) : https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css
- Language : Javascript
지원하는 프로그래밍 언어는 SUPPORTED_LANGUAGES.md 문서를 참조한다.
2.3. highlightjs-line-numbers.js (https://wcoder.github.io/highlightjs-line-numbers.js/)
- License : MIT License (https://github.com/wcoder/highlightjs-line-numbers.js/blob/master/LICENSE)
- GitHUB : https://github.com/wcoder/highlightjs-line-numbers.js/
- CDN : https://cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.8.0/highlightjs-line-numbers.min.js
- Language : Javascript
3. 구현
memo.detail.js 의 mark 함수를 참조한다.
highlightjs-line-numbers.js 까지 적용된 html 을 Javascript 변수로 할당받는 것은 memo.detail.js 에는 포함되어 있지 않다.
3.1. marked.js + highlight.js 까지 적용
marked.js + highlight.js 까지 적용된 HTML 소스를 얻기 위해서 다음과 같이 한다.
var markedText = "# 제목"; marked.setOptions({ renderer: new marked.Renderer(), highlight: function(code, language) { let validLanguage = hljs.getLanguage(language) ? language : 'plaintext'; return hljs.highlight(validLanguage, code).value; }, pedantic: false, gfm: true, breaks: false, sanitize: false, smartLists: true, smartypants: false, xhtml: false }); var htmlText = marked.parse(markedText);
다음과 같이 (jquery 를 이용해서) htmlText 를 화면에 표시한다.
var selectedContents2 = $("table#memo td.contents2"); selectedContents2.html(htmlText);
위의 Javascript 는 다음과 같은 HTML 을 필요로 한다.
<table id="memo"> <tr> <td class="contents2"></td> </tr> </table>
주석으로 막힌 부분을 제거하려면 다음음 추가한다.
selectedContents2.contents().filter(function() { if(this.nodeType == 8) { return true; } return false; }).each(function(index, node) { $(node).remove(); });
3.2. highlightjs-line-numbers.js 적용
highlightjs-line-numbers.js 를 적용하기 위해서 (위의 소스들에 덧붙여) 다음을 추가한다.
selectedContents2.find("code").each(function(i, block) { hljs.lineNumbersBlock(block); });
highlightjs-line-numbers.js 는 htmlText 를 화면에 표시한 후에 적용할 수 있다.
3.3. 문제해결
3.3.1. highlightjs-line-numbers.js
위의 소스들에 덧붙여 다음을 추가하면, (화면은 정상적으로 표시되지만,) 경고창에는 highlightjs-line-numbers.js 적용 전의 html이 표시된다.
alert(selectedContents2.html());
위의 문제는 다음과 같이 해결할 수 있다.
window.setTimeout(function() { alert(selectedContents2.html()); }, 0);
최신 버전의 Firefox 와 Chrome 그리고 IE 11 에서 테스트했고, 끝이 보이지 않던 삽질 끝에 우연히 답을 얻었다.
(예를 들어 서버로 전송하기 위해서 HTML 로 변환된 결과를 textarea 에 채우는 등) submit 직전에 무엇인가 처리하려면, onsubmit 이벤트 함수는 다음과 같은 형태가 될 것이다.
function check_submit(form, msg) { window.setTimeout(function() { $("form#insert textarea.html_contents").val($("div#preview_area").html()); $("form#insert").removeAttr("onsubmit"); $("form#insert").submit(); }, 0); return false; }
3.3.2. IE 관련
IE 를 지원하는 마지막 버전은 각각 다음과 같다.
- marked.js : 5.0.5
- highlight.js : 9.18.5
폴리필(Polyfill)도 추가해야 한다.
폴리필(Polyfill)을 추가하지 않는다면, 객체가 무슨 함수를 지원하지 않는다는 runtime 에러가 발생할 것인데, 구체적으로 필요한 함수는 markdown 원문에 따라 다르다.
지원이 종료된 IE 를 지원할 것인지는 전적으로 서비스 운영자의 선택이다.