diff --git a/src/ui/js/diff2html-ui.js b/src/ui/js/diff2html-ui.js index fb18f2b..5b4daa4 100644 --- a/src/ui/js/diff2html-ui.js +++ b/src/ui/js/diff2html-ui.js @@ -12,6 +12,8 @@ (function() { + var highlightJS = require('./highlight.js-internals.js').HighlightJS; + var diffJson = null; var defaultTarget = "body"; var currentSelectionColumnId = -1; @@ -71,7 +73,7 @@ // collect all the diff files and execute the highlight on their lines var $files = $target.find(".d2h-file-wrapper"); - $files.map(function(i, file) { + $files.map(function(_i, file) { var oldLinesState; var newLinesState; var $file = $(file); @@ -79,7 +81,7 @@ // collect all the code lines and execute the highlight on them var $codeLines = $file.find(".d2h-code-line-ctn"); - $codeLines.map(function(i, line) { + $codeLines.map(function(_j, line) { var $line = $(line); var text = line.textContent; var lineParent = line.parentNode; @@ -102,11 +104,11 @@ newLinesState = result.top; } - var originalStream = nodeStream(line); + var originalStream = highlightJS.nodeStream(line); if (originalStream.length) { var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); resultNode.innerHTML = result.value; - result.value = mergeStreams(originalStream, nodeStream(resultNode), text); + result.value = highlightJS.mergeStreams(originalStream, highlightJS.nodeStream(resultNode), text); } $line.addClass("hljs"); @@ -198,129 +200,6 @@ return text; }; - /* - * Copied from Highlight.js Private API - * Will be removed when this part of the API is exposed - */ - - /* Utility functions */ - - function escape(value) { - return value.replace(/&/gm, '&').replace(//gm, '>'); - } - - function tag(node) { - return node.nodeName.toLowerCase(); - } - - /* Stream merging */ - - function nodeStream(node) { - var result = []; - (function _nodeStream(node, offset) { - for (var child = node.firstChild; child; child = child.nextSibling) { - if (child.nodeType == 3) - offset += child.nodeValue.length; - else if (child.nodeType == 1) { - result.push({ - event: 'start', - offset: offset, - node: child - }); - offset = _nodeStream(child, offset); - // Prevent void elements from having an end tag that would actually - // double them in the output. There are more void elements in HTML - // but we list only those realistically expected in code display. - if (!tag(child).match(/br|hr|img|input/)) { - result.push({ - event: 'stop', - offset: offset, - node: child - }); - } - } - } - return offset; - })(node, 0); - return result; - } - - function mergeStreams(original, highlighted, value) { - var processed = 0; - var result = ''; - var nodeStack = []; - - function selectStream() { - if (!original.length || !highlighted.length) { - return original.length ? original : highlighted; - } - if (original[0].offset != highlighted[0].offset) { - return (original[0].offset < highlighted[0].offset) ? original : highlighted; - } - - /* - To avoid starting the stream just before it should stop the order is - ensured that original always starts first and closes last: - if (event1 == 'start' && event2 == 'start') - return original; - if (event1 == 'start' && event2 == 'stop') - return highlighted; - if (event1 == 'stop' && event2 == 'start') - return original; - if (event1 == 'stop' && event2 == 'stop') - return highlighted; - ... which is collapsed to: - */ - return highlighted[0].event == 'start' ? original : highlighted; - } - - function open(node) { - function attrStr(a) { - return ' ' + a.nodeName + '="' + escape(a.value) + '"'; - } - - result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attrStr).join('') + '>'; - } - - function close(node) { - result += ''; - } - - function render(event) { - (event.event == 'start' ? open : close)(event.node); - } - - while (original.length || highlighted.length) { - var stream = selectStream(); - result += escape(value.substr(processed, stream[0].offset - processed)); - processed = stream[0].offset; - if (stream == original) { - /* - On any opening or closing tag of the original markup we first close - the entire highlighted node stack, then render the original tag along - with all the following original tags at the same offset and then - reopen all the tags on the highlighted stack. - */ - nodeStack.reverse().forEach(close); - do { - render(stream.splice(0, 1)[0]); - stream = selectStream(); - } while (stream == original && stream.length && stream[0].offset == processed); - nodeStack.reverse().forEach(open); - } else { - if (stream[0].event == 'start') { - nodeStack.push(stream[0].node); - } else { - nodeStack.pop(); - } - render(stream.splice(0, 1)[0]); - } - } - return result + escape(value.substr(processed)); - } - - /* **** Highlight.js Private API **** */ - module.exports.Diff2HtmlUI = Diff2HtmlUI; // Expose diff2html in the browser diff --git a/src/ui/js/highlight.js-internals.js b/src/ui/js/highlight.js-internals.js new file mode 100644 index 0000000..8bac6b4 --- /dev/null +++ b/src/ui/js/highlight.js-internals.js @@ -0,0 +1,139 @@ +/* + * + * highlight.js + * Author: isagalaev + * + */ + +(function() { + + function HighlightJS() { + } + + /* + * Copied from Highlight.js Private API + * Will be removed when this part of the API is exposed + */ + + /* Utility functions */ + + function escape(value) { + return value.replace(/&/gm, '&').replace(//gm, '>'); + } + + function tag(node) { + return node.nodeName.toLowerCase(); + } + + /* Stream merging */ + + HighlightJS.prototype.nodeStream = function(node) { + var result = []; + (function _nodeStream(node, offset) { + for (var child = node.firstChild; child; child = child.nextSibling) { + if (child.nodeType == 3) + offset += child.nodeValue.length; + else if (child.nodeType == 1) { + result.push({ + event: 'start', + offset: offset, + node: child + }); + offset = _nodeStream(child, offset); + // Prevent void elements from having an end tag that would actually + // double them in the output. There are more void elements in HTML + // but we list only those realistically expected in code display. + if (!tag(child).match(/br|hr|img|input/)) { + result.push({ + event: 'stop', + offset: offset, + node: child + }); + } + } + } + return offset; + })(node, 0); + return result; + }; + + HighlightJS.prototype.mergeStreams = function(original, highlighted, value) { + var processed = 0; + var result = ''; + var nodeStack = []; + + function selectStream() { + if (!original.length || !highlighted.length) { + return original.length ? original : highlighted; + } + if (original[0].offset != highlighted[0].offset) { + return (original[0].offset < highlighted[0].offset) ? original : highlighted; + } + + /* + To avoid starting the stream just before it should stop the order is + ensured that original always starts first and closes last: + if (event1 == 'start' && event2 == 'start') + return original; + if (event1 == 'start' && event2 == 'stop') + return highlighted; + if (event1 == 'stop' && event2 == 'start') + return original; + if (event1 == 'stop' && event2 == 'stop') + return highlighted; + ... which is collapsed to: + */ + return highlighted[0].event == 'start' ? original : highlighted; + } + + function open(node) { + function attrStr(a) { + return ' ' + a.nodeName + '="' + escape(a.value) + '"'; + } + + result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attrStr).join('') + '>'; + } + + function close(node) { + result += ''; + } + + function render(event) { + (event.event == 'start' ? open : close)(event.node); + } + + while (original.length || highlighted.length) { + var stream = selectStream(); + result += escape(value.substr(processed, stream[0].offset - processed)); + processed = stream[0].offset; + if (stream == original) { + + /* + On any opening or closing tag of the original markup we first close + the entire highlighted node stack, then render the original tag along + with all the following original tags at the same offset and then + reopen all the tags on the highlighted stack. + */ + nodeStack.reverse().forEach(close); + do { + render(stream.splice(0, 1)[0]); + stream = selectStream(); + } while (stream == original && stream.length && stream[0].offset == processed); + nodeStack.reverse().forEach(open); + } else { + if (stream[0].event == 'start') { + nodeStack.push(stream[0].node); + } else { + nodeStack.pop(); + } + render(stream.splice(0, 1)[0]); + } + } + return result + escape(value.substr(processed)); + }; + + /* **** Highlight.js Private API **** */ + + module.exports.HighlightJS = new HighlightJS(); + +})();