Реализация, представленная ниже, опирается на атрибут innerHTML
проверка и редактирование .
Выполняется следующие основные шаги:
- Анализ блоков кода сначала до защиты их от дальнейших подстановок;
- Внедрение результата в элемент HTML как
innerHTML
атрибут, позволяющий браузеру анализировать и превращать его в Node
набор (теперь кодовые блоки защищены); - Замените оставшийся текст (которые теперь являются текстовыми узлами) элементами
<P>
, чтобы проанализировать параграфов и выполнить синтаксический анализ встроенных элементов внутри, чтобы наконец получить ссылки и inline code
.
Ниже проверенного фрагмента.
// Some HTML elements used througout the parsing
var resultDiv = document.getElementById("rendered-result")
var resultSrcTA = document.getElementById("resultsrc");
// convert() - Our lite MD parser
function convert() {
var mdt = document.getElementById("md").value;
// First we parse the blocks to prevent them to be parsed later on
parseCodeBlocks(mdt);
// Then we deal with the remaning text, which are paragraphs
parseParagraphs();
resultSrcTA.value = resultDiv.innerHTML;
}
// This function simply performs a regexp substitution on a given text
// and inject it into the result HTML element (resultDiv)
// as an inner HTML string to let the browser parting it
function parseCodeBlocks(text) {
const codeblock = /```\s*([^]+?.*?[^]+?[^]+?)```/g;
resultDiv.innerHTML =
text.replace(codeblock, '<pre><code>$1
');} // Эта функция заменяет оставшиеся текстовые узлы абзацами // (Сложная часть) function parseParagraphs () {var node = resultDiv.childNodes;// Цикл по узлам для (var i = 0; i элементов ps = createPElementFromMDParagraphs (node [i] .nodeValue);// Обратный цикл по элементам
// Поскольку мы вставляем их сразу после анализируемого текстового узла для (var j = ps.length -1; j> -1; j--) {resultDiv.insertBefore (ps [j], node [i] .nextSibling)} // Мы закончили со вставкой абзаца, пора удалять // анализируемый текстовый узел resultDiv.removeChild (node [i]);// Обновление i: мы добавили n абзаца и удалили один текстовый узел i + = ps.length - 1;}} // Эта функция возвращает для заданного текста массив
, представляющий // функцию содержимого createPElementFromMDParagraphs (text) {const абзац = /(.+)((\r?\n.+)*)/g;const code = /`(.*?)`/g;const link = /\[(.*?)\]\((.*?)\)/g;var ps = [];вар совпадений;// Мы перебираем совпадения с регулярным выражением абзаца // Для каждого соответствия мы создаем элемент
и помещаем его // в массив результатов while ((match = para.exec (text))! == null) {varp = document.createElement ("p");p.appendChild (document.createTextNode (матчи [1]));// И у нас есть здесь возможность отформатировать встроенные элементы // Обратите внимание, что ссылки будут анализироваться внутри элемента кода и будут работать p.innerHTML = p.innerHTML.replace (code, '$1
');p.innerHTML = p.innerHTML.replace (ссылка, ' $ 1 ');ps.push (р);} вернуть пс;}
/* Just to get it fancy */
textarea {
width: 100%;
height: 15ex;
}
div#rendered-result {
min-height:10ex;
height:10ex;
border: 1px solid black;
padding:1em;
font-family:sans-serif;
overflow-y:auto;
}
div#rendered-result > pre {
background: #f0f0f0;
margin: 1em;
padding:0.5em;
border: 1px solid #808080;
}
div#rendered-result > pre > code {
margin: 0;
}
/* To check if this is a well parsed paragraph. */
div#rendered-result > p::first-letter {
font-weight:bold;
color:darkred;
}
<p>Type your markdown text below:</p>
<textarea id="md">
The first paragraph.
```
A code block very well catched
Haha this `inline code` wont be parsed.
```
And a sentence with [two](http://stackoverflow.com) [links](http://askbuntu.com).
And another with an `inline code` and a [link](http://superuser.com).
```
And another code block
```
And another with an link as `[inline code](http://superuser.com)`.
Last sentence.
</textarea>
<p>
<!-- yes it's bad -->
<button onclick="convert()">Convert it</button>
</p>
<p>Result</p>
<div id="rendered-result">
</div>
<p>Source:</p>
<textarea id="resultsrc">
</textarea>