in myfaces-html5-demo/src/main/webapp/resources/script/google-code-prettify/prettify.js [1053:1191]
function recombineTagsAndDecorations(job) {
var sourceText = job.source;
var extractedTags = job.extractedTags;
var decorations = job.decorations;
var html = [];
// index past the last char in sourceText written to html
var outputIdx = 0;
var openDecoration = null;
var currentDecoration = null;
var tagPos = 0; // index into extractedTags
var decPos = 0; // index into decorations
var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
var adjacentSpaceRe = /([\r\n ]) /g;
var startOrSpaceRe = /(^| ) /gm;
var newlineRe = /\r\n?|\n/g;
var trailingSpaceRe = /[ \r\n]$/;
var lastWasSpace = true; // the last text chunk emitted ended with a space.
// See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
var isIE678 = window['_pr_isIE6']();
var lineBreakHtml = (
isIE678
? (job.sourceNode.tagName === 'PRE'
// Use line feeds instead of <br>s so that copying and pasting works
// on IE.
// Doing this on other browsers breaks lots of stuff since \r\n is
// treated as two newlines on Firefox.
? (isIE678 === 6 ? ' \r\n' :
isIE678 === 7 ? ' <br>\r' : ' \r')
// IE collapses multiple adjacent <br>s into 1 line break.
// Prefix every newline with ' ' to prevent such behavior.
// is the same as   but works in XML as well as HTML.
: ' <br />')
: '<br />');
// Look for a class like linenums or linenums:<n> where <n> is the 1-indexed
// number of the first line.
var numberLines = job.sourceNode.className.match(/\blinenums\b(?::(\d+))?/);
var lineBreaker;
if (numberLines) {
var lineBreaks = [];
for (var i = 0; i < 10; ++i) {
lineBreaks[i] = lineBreakHtml + '</li><li class="L' + i + '">';
}
var lineNum = numberLines[1] && numberLines[1].length
? numberLines[1] - 1 : 0; // Lines are 1-indexed
html.push('<ol class="linenums"><li class="L', (lineNum) % 10, '"');
if (lineNum) {
html.push(' value="', lineNum + 1, '"');
}
html.push('>');
lineBreaker = function () {
var lb = lineBreaks[++lineNum % 10];
// If a decoration is open, we need to close it before closing a list-item
// and reopen it on the other side of the list item.
return openDecoration
? ('</span>' + lb + '<span class="' + openDecoration + '">') : lb;
};
} else {
lineBreaker = lineBreakHtml;
}
// A helper function that is responsible for opening sections of decoration
// and outputing properly escaped chunks of source
function emitTextUpTo(sourceIdx) {
if (sourceIdx > outputIdx) {
if (openDecoration && openDecoration !== currentDecoration) {
// Close the current decoration
html.push('</span>');
openDecoration = null;
}
if (!openDecoration && currentDecoration) {
openDecoration = currentDecoration;
html.push('<span class="', openDecoration, '">');
}
// This interacts badly with some wikis which introduces paragraph tags
// into pre blocks for some strange reason.
// It's necessary for IE though which seems to lose the preformattedness
// of <pre> tags when their innerHTML is assigned.
// http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
// and it serves to undo the conversion of <br>s to newlines done in
// chunkify.
var htmlChunk = textToHtml(
tabExpander(sourceText.substring(outputIdx, sourceIdx)))
.replace(lastWasSpace
? startOrSpaceRe
: adjacentSpaceRe, '$1 ');
// Keep track of whether we need to escape space at the beginning of the
// next chunk.
lastWasSpace = trailingSpaceRe.test(htmlChunk);
html.push(htmlChunk.replace(newlineRe, lineBreaker));
outputIdx = sourceIdx;
}
}
while (true) {
// Determine if we're going to consume a tag this time around. Otherwise
// we consume a decoration or exit.
var outputTag;
if (tagPos < extractedTags.length) {
if (decPos < decorations.length) {
// Pick one giving preference to extractedTags since we shouldn't open
// a new style that we're going to have to immediately close in order
// to output a tag.
outputTag = extractedTags[tagPos] <= decorations[decPos];
} else {
outputTag = true;
}
} else {
outputTag = false;
}
// Consume either a decoration or a tag or exit.
if (outputTag) {
emitTextUpTo(extractedTags[tagPos]);
if (openDecoration) {
// Close the current decoration
html.push('</span>');
openDecoration = null;
}
html.push(extractedTags[tagPos + 1]);
tagPos += 2;
} else if (decPos < decorations.length) {
emitTextUpTo(decorations[decPos]);
currentDecoration = decorations[decPos + 1];
decPos += 2;
} else {
break;
}
}
emitTextUpTo(sourceText.length);
if (openDecoration) {
html.push('</span>');
}
if (numberLines) { html.push('</li></ol>'); }
job.prettyPrintedHtml = html.join('');
}