Как предотвратить Markdown от упаковки сгенерированного HTML в элементе <p>?

Обновление: Баунти предназначена для решения с использованием "отмеченной" библиотеки.


Этот код Markdown:

*foo*

создаст этот HTML-код:

<p><em>foo</em></p>

Live demo: https://jsbin.com/luganot/edit?js,console

Однако я уже вставляю сгенерированный HTML-код в встроенный контекст, например:

<p> text [inject generated HTML here] text </p>

поэтому я не хочу, чтобы элемент <p> обменивался сгенерированным кодом HTML. Я просто хочу, чтобы разделители * были преобразованы в элемент <em> и т.д.

Есть ли способ сообщить конвертеру Markdown не создавать обертку <p>? В настоящее время я делаю .slice(3,-4) в сгенерированной строке HTML, которая удаляет теги <p> и </p>, но это, очевидно, не является решением, которое я хотел бы сохранить в течение длительного времени.

Ответы

Ответ 1

Вы можете пропустить блок-лексику и использовать inlineLexer.

html = marked.inlineLexer(markdown, [], options);

//example
marked.inlineLexer('*foo*', []) // will output '<em>foo</em>'

Ответ 2

Можно ли использовать jQuery? Это будет работать в случае:

var $text = $(new Showdown.converter().makeHtml( '*foo*' ) );
console.log( $text.html() );

Ответ 3

Я искал решение для этого, когда нашел этот поток SO. Я пока не нашел хорошего решения, поэтому написал свои собственные.

var markdown = new Showdown.converter().makeHtml( '*foo*' );
console.log(markdown.replace(/^<p>|<\/p>$/g, ''));

Ответ 4

Если вы следуете стандарту обычного знака, нет официального способа удаления нежелательных элементов из разметки, которые в противном случае генерирует уценка. В 2014 году я спросил о возможности встроенного режима, но это на самом деле не вызвало большой активности, и я никогда не выполнял его, чтобы сделать это реальность.

С учетом сказанного, самое простое решение, которое я знаю для дезинфекции уценки, заключается в том, чтобы запустить его через белый список в качестве этапа последующей обработки.

Просто удалить дескрипторы <p>, вероятно, недостаточно, потому что было бы относительно легко случайно добавить символы # и в итоге получить бродячие теги h1-6 или иметь встроенные <div> элементы, которые не разрешены в <p>.

Белый список довольно прост в JS, если вы находитесь в контексте браузера или используете аналогичный API DOM.

Этот пример выводит результат из marked и генерирует фрагмент документа. Затем узлы в фрагменте фильтруются на основе того, являются ли они фразирование контента (которые являются единственными узлами, которые могут содержать элементы <p>)), После фильтрации результирующие узлы затем возвращаются так, что они могут использоваться в DOM.

const phrasingContent = [
  '#text', 'a', 'abbr', 'area', 'audio', 'b', 'bdi', 'bdo', 'br', 'button',
  'canvas', 'cite', 'code', 'data', 'datalist', 'del', 'dfn', 'em', 'embed',
  'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark',
  'math', 'meter', 'noscript', 'object', 'output', 'picture', 'progress', 'q',
  'ruby', 's', 'samp', 'script', 'select', 'small', 'span', 'strong', 'sub',
  'sup', 'svg', 'template', 'textarea', 'time', 'u', 'var', 'video', 'wbr'
]

function sanitize(text) {
  const t = document.createElement('template')
  t.innerHTML = text
  whitelist(t.content, phrasingContent)
  return t.content
}

function whitelist(parent, names) {
  for (const node of parent.childNodes) {
    whitelist(node, names)
  
    if (!names.includes(node.nodeName.toLowerCase())) {
      unwrap(node)
    }
  }
}

function unwrap(node) {
  const parent = node.parentNode
  while (node.firstChild) {
    parent.insertBefore(node.firstChild, node)
  }
  parent.removeChild(node)
}

function empty(node) {
  while (node.firstChild) {
    node.removeChild(node.firstChild)
  }
}

const form = document.querySelector('form')
const input = document.querySelector('textarea')
const output = document.querySelector('output')

form.addEventListener('submit', e => {
  e.preventDefault()
  
  empty(output)
  
  output.appendChild(sanitize(marked(input.value)))
}, false)
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
<form>
  <p>
    <textarea name="input" cols="30" rows="10">*foo*</textarea>
  </p>
  <button type="submit">Test</button>
</form>

<p> text <output></output> text </p>