diff --git a/src/rules.js b/src/rules.js index 5414fcd..3c6b28b 100644 --- a/src/rules.js +++ b/src/rules.js @@ -6,12 +6,14 @@ export default function Rules (options) { this.options = options this._keep = [] this._remove = [] + this._preserve = [] this.blankRule = { replacement: options.blankReplacement } this.keepReplacement = options.keepReplacement + this.preserveReplacement = options.preserveReplacement this.defaultRule = { replacement: options.defaultReplacement @@ -42,12 +44,20 @@ Rules.prototype = { }) }, + preserve: function (filter) { + this._preserve.unshift({ + filter: filter, + replacement: this.preserveReplacement + }) + }, + forNode: function (node) { if (node.isBlank) return this.blankRule var rule if ((rule = findRule(this.array, node, this.options))) return rule if ((rule = findRule(this._keep, node, this.options))) return rule + if ((rule = findRule(this._preserve, node, this.options))) return rule if ((rule = findRule(this._remove, node, this.options))) return rule return this.defaultRule diff --git a/src/turndown.js b/src/turndown.js index ff4a2cb..b8773b1 100644 --- a/src/turndown.js +++ b/src/turndown.js @@ -1,6 +1,6 @@ import COMMONMARK_RULES from './commonmark-rules' import Rules from './rules' -import { extend, trimLeadingNewlines, trimTrailingNewlines } from './utilities' +import { extend, trimLeadingNewlines, trimTrailingNewlines, getOpenTag, getCloseTag } from './utilities' import RootNode from './root-node' import Node from './node' var reduce = Array.prototype.reduce @@ -44,6 +44,15 @@ export default function TurndownService (options) { }, defaultReplacement: function (content, node) { return node.isBlock ? '\n\n' + content + '\n\n' : content + }, + preserveReplacement: function (innerContent, node) { + const html = node.cloneNode() + html.setAttribute('markdown', '1') + const openTag = getOpenTag(html) + const closeTag = getCloseTag(html) + + const outerContent = openTag + innerContent + closeTag + return node.isBlock ? '\n\n' + outerContent + '\n\n' : outerContent } } this.options = extend({}, defaults, options) @@ -131,6 +140,19 @@ TurndownService.prototype = { return this }, + /** + * Preserves (using markdown="1") a node that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + preserve: function (filter) { + this.rules.preserve(filter) + return this + }, + /** * Escapes Markdown syntax * @public diff --git a/src/utilities.js b/src/utilities.js index 36f0acc..61afe42 100644 --- a/src/utilities.js +++ b/src/utilities.js @@ -74,3 +74,20 @@ function has (node, tagNames) { }) ) } + +export function getOpenTag (element) { + // Credit: https://stackoverflow.com/questions/9604235 + const outerHtml = element.outerHTML + const len = outerHtml.length + + if (outerHtml[len - 2] === '/') { // Is self-closing tag? + return outerHtml.slice(0, len - 2) + '>' + } else { + const openTagLength = len - element.innerHTML.length - (element.tagName.length + 3) + return outerHtml.slice(0, openTagLength) + } +} + +export function getCloseTag (element) { + return `` +}