From 6f69da62d68a95cd0c03e4ac004ef24242efbd9a Mon Sep 17 00:00:00 2001 From: Golmote Date: Wed, 16 Sep 2015 22:08:29 +0200 Subject: [PATCH] Keep Markup Plugin. Fix #495, fix #579 --- components.js | 5 + plugins/keep-markup/index.html | 80 ++++++++++++++++ plugins/keep-markup/prism-keep-markup.js | 97 ++++++++++++++++++++ plugins/keep-markup/prism-keep-markup.min.js | 1 + 4 files changed, 183 insertions(+) create mode 100644 plugins/keep-markup/index.html create mode 100644 plugins/keep-markup/prism-keep-markup.js create mode 100644 plugins/keep-markup/prism-keep-markup.min.js diff --git a/components.js b/components.js index 919b3c13ae..aec60cb59d 100644 --- a/components.js +++ b/components.js @@ -377,6 +377,11 @@ var components = { "title": "Highlight Keywords", "owner": "vkbansal", "noCSS": true + }, + "keep-markup": { + "title": "Keep Markup", + "owner": "Golmote", + "noCSS": true } } }; diff --git a/plugins/keep-markup/index.html b/plugins/keep-markup/index.html new file mode 100644 index 0000000000..1eba471d86 --- /dev/null +++ b/plugins/keep-markup/index.html @@ -0,0 +1,80 @@ + + + + + + + Keep markup ▲ Prism plugins + + + + + + + + + + + + + +
+
+ +

Keep markup

+

Prevents custom markup from being dropped out during highlighting.

+
+ +
+ +

How to use

+

You have nothing to do. With this plugin loaded, all markup inside code will be kept.

+ +

Examples

+ +

The following source code

+
<pre><code class="language-css">
+@media <mark>screen</mark> {
+	div {
+		<mark>text</mark>-decoration: <mark><mark>under</mark>line</mark>;
+		back<mark>ground: url</mark>('foo.png');
+	}
+}</code></pre>
+ +

would render like this:

+

+@media screen {
+	div {
+		text-decoration: underline;
+		background: url('foo.png');
+	}
+}
+ +

+ It also works for inline code: + var bar = function () { /* foo */ }; +

+ +
+ + + + + + + + + + + \ No newline at end of file diff --git a/plugins/keep-markup/prism-keep-markup.js b/plugins/keep-markup/prism-keep-markup.js new file mode 100644 index 0000000000..9038ed01dd --- /dev/null +++ b/plugins/keep-markup/prism-keep-markup.js @@ -0,0 +1,97 @@ +(function () { + + if (typeof self === 'undefined' || !self.Prism || !self.document || !document.createRange) { + return; + } + + Prism.hooks.add('before-highlight', function (env) { + var firstWhiteSpaces = false; + var pos = 0; + var data = []; + var f = function (elt, baseNode) { + var o = {}; + if (!baseNode) { + // Clone the original tag to keep all attributes + o.clone = elt.cloneNode(false); + o.posOpen = pos; + data.push(o); + } + for (var i = 0, l = elt.childNodes.length; i < l; i++) { + var child = elt.childNodes[i]; + if (child.nodeType === 1) { // element + f(child); + } else if(child.nodeType === 3) { // text + if(!firstWhiteSpaces) { + // We need to ignore the first white spaces in the code block + child.data = child.data.replace(/^(?:\r?\n|\r)/, ''); + firstWhiteSpaces = true; + } + pos += child.data.length; + } + } + if (!baseNode) { + o.posClose = pos; + } + }; + f(env.element, true); + + if (data && data.length) { + // data is an array of all existing tags + env.keepMarkup = data; + } + }); + + Prism.hooks.add('after-highlight', function (env) { + if(env.keepMarkup && env.keepMarkup.length) { + + var walk = function (elt, nodeState) { + for (var i = 0, l = elt.childNodes.length; i < l; i++) { + + var child = elt.childNodes[i]; + + if (child.nodeType === 1) { // element + if (!walk(child, nodeState)) { + return false; + } + + } else if (child.nodeType === 3) { // text + if(!nodeState.nodeStart && nodeState.pos + child.data.length > nodeState.node.posOpen) { + // We found the start position + nodeState.nodeStart = child; + nodeState.nodeStartPos = nodeState.node.posOpen - nodeState.pos; + } + if(nodeState.nodeStart && nodeState.pos + child.data.length >= nodeState.node.posClose) { + // We found the end position + nodeState.nodeEnd = child; + nodeState.nodeEndPos = nodeState.node.posClose - nodeState.pos; + } + + nodeState.pos += child.data.length; + } + + if (nodeState.nodeStart && nodeState.nodeEnd) { + // Select the range and wrap it with the clone + var range = document.createRange(); + range.setStart(nodeState.nodeStart, nodeState.nodeStartPos); + range.setEnd(nodeState.nodeEnd, nodeState.nodeEndPos); + nodeState.node.clone.appendChild(range.extractContents()); + range.insertNode(nodeState.node.clone); + range.detach(); + + // Process is over + return false; + } + } + return true; + }; + + // For each tag, we walk the DOM to reinsert it + env.keepMarkup.forEach(function (node) { + walk(env.element, { + node: node, + pos: 0 + }); + }); + } + }); +}()); \ No newline at end of file diff --git a/plugins/keep-markup/prism-keep-markup.min.js b/plugins/keep-markup/prism-keep-markup.min.js new file mode 100644 index 0000000000..86a39c93b7 --- /dev/null +++ b/plugins/keep-markup/prism-keep-markup.min.js @@ -0,0 +1 @@ +!function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.createRange&&(Prism.hooks.add("before-highlight",function(e){var n=!1,o=0,t=[],d=function(e,a){var r={};a||(r.clone=e.cloneNode(!1),r.posOpen=o,t.push(r));for(var s=0,p=e.childNodes.length;p>s;s++){var l=e.childNodes[s];1===l.nodeType?d(l):3===l.nodeType&&(n||(l.data=l.data.replace(/^(?:\r?\n|\r)/,""),n=!0),o+=l.data.length)}a||(r.posClose=o)};d(e.element,!0),t&&t.length&&(e.keepMarkup=t)}),Prism.hooks.add("after-highlight",function(e){if(e.keepMarkup&&e.keepMarkup.length){var n=function(e,o){for(var t=0,d=e.childNodes.length;d>t;t++){var a=e.childNodes[t];if(1===a.nodeType){if(!n(a,o))return!1}else 3===a.nodeType&&(!o.nodeStart&&o.pos+a.data.length>o.node.posOpen&&(o.nodeStart=a,o.nodeStartPos=o.node.posOpen-o.pos),o.nodeStart&&o.pos+a.data.length>=o.node.posClose&&(o.nodeEnd=a,o.nodeEndPos=o.node.posClose-o.pos),o.pos+=a.data.length);if(o.nodeStart&&o.nodeEnd){var r=document.createRange();return r.setStart(o.nodeStart,o.nodeStartPos),r.setEnd(o.nodeEnd,o.nodeEndPos),o.node.clone.appendChild(r.extractContents()),r.insertNode(o.node.clone),r.detach(),!1}}return!0};e.keepMarkup.forEach(function(o){n(e.element,{node:o,pos:0})})}}))}(); \ No newline at end of file