You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
3.3 KiB
126 lines
3.3 KiB
(function () { |
|
|
|
if (typeof Prism === 'undefined' || typeof document === 'undefined' || !document.createRange) { |
|
return; |
|
} |
|
|
|
Prism.plugins.KeepMarkup = true; |
|
|
|
Prism.hooks.add('before-highlight', function (env) { |
|
if (!env.element.children.length) { |
|
return; |
|
} |
|
|
|
if (!Prism.util.isActive(env.element, 'keep-markup', true)) { |
|
return; |
|
} |
|
|
|
var dropTokens = Prism.util.isActive(env.element, 'drop-tokens', false); |
|
/** |
|
* Returns whether the given element should be kept. |
|
* |
|
* @param {HTMLElement} element |
|
* @returns {boolean} |
|
*/ |
|
function shouldKeep(element) { |
|
if (dropTokens && element.nodeName.toLowerCase() === 'span' && element.classList.contains('token')) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
var pos = 0; |
|
var data = []; |
|
function processElement(element) { |
|
if (!shouldKeep(element)) { |
|
// don't keep this element and just process its children |
|
processChildren(element); |
|
return; |
|
} |
|
|
|
var o = { |
|
// Store original element so we can restore it after highlighting |
|
element: element, |
|
posOpen: pos |
|
}; |
|
data.push(o); |
|
|
|
processChildren(element); |
|
|
|
o.posClose = pos; |
|
} |
|
function processChildren(element) { |
|
for (var i = 0, l = element.childNodes.length; i < l; i++) { |
|
var child = element.childNodes[i]; |
|
if (child.nodeType === 1) { // element |
|
processElement(child); |
|
} else if (child.nodeType === 3) { // text |
|
pos += child.data.length; |
|
} |
|
} |
|
} |
|
processChildren(env.element); |
|
|
|
if (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 element |
|
var range = document.createRange(); |
|
range.setStart(nodeState.nodeStart, nodeState.nodeStartPos); |
|
range.setEnd(nodeState.nodeEnd, nodeState.nodeEndPos); |
|
nodeState.node.element.innerHTML = ''; |
|
nodeState.node.element.appendChild(range.extractContents()); |
|
range.insertNode(nodeState.node.element); |
|
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 |
|
}); |
|
}); |
|
// Store new highlightedCode for later hooks calls |
|
env.highlightedCode = env.element.innerHTML; |
|
} |
|
}); |
|
}());
|
|
|