| Index: lib/src/prism/plugins/keep-markup/prism-keep-markup.js
 | 
| diff --git a/lib/src/prism/plugins/keep-markup/prism-keep-markup.js b/lib/src/prism/plugins/keep-markup/prism-keep-markup.js
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..9038ed01dd5379a3198b014bc87d2527afd16296
 | 
| --- /dev/null
 | 
| +++ b/lib/src/prism/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
 | 
| +				});
 | 
| +			});
 | 
| +		}
 | 
| +	});
 | 
| +}());
 | 
| 
 |