openscad/scripts/examples-html/assets/js/rainbow.linenumbers.js

118 lines
No EOL
3.9 KiB
JavaScript

// Only install the plugin if Rainbow is present and has been loaded
if (window.Rainbow) window.Rainbow.linenumbers = (function(Rainbow) {
/**
* Splits up a single element into individual lines
*
* @param {HTMLElement} elem
* @returns {Array}
*/
function splitElement(elem) {
if (elem.nodeType === 3) {
// Just split up the text node
return elem.nodeValue.split('\n');
}
// Otherwise, we need to split up the HTML
var sourceLines = elem.innerHTML.split('\n');
var lines = [];
// Wraps each chunk in the parent element. For example:
// <b>foo\nbar</b> -> [<b>foo</b>, <b>bar</b>]
for (var i = 0; i < sourceLines.length; i++) {
// Handles <b>\nbar</b> -> [, <b>bar</b>]
if (sourceLines[i] === '') {
lines.push('');
} else {
var wrapper = elem.cloneNode(true);
wrapper.innerHTML = sourceLines[i];
var div = document.createElement('div');
div.appendChild(wrapper.cloneNode(true));
lines.push(div.innerHTML);
}
}
return lines;
};
/**
* Splits up the element containing highlighted source code
* into an array of lines
*
* @param {HTMLElement} block
* @returns {Array}
*/
function splitLines(block) {
var lines = [''];
for (var i = 0; i < block.childNodes.length; i++) {
var elemLines = splitElement(block.childNodes[i]);
// The first element in elemLines is
// a continuation of the previous line
lines[lines.length - 1] += elemLines[0];
// The remaining elements get their own lines
for (var j = 1; j < elemLines.length; j++) {
lines.push(elemLines[j]);
}
}
// Returns the array of lines
return lines;
};
// Callback is called when Rainbow has highlighted a block
Rainbow.onHighlight(function(block) {
// This addresses an issue when Rainbow.color() is called multiple times.
// Since code element is replaced with table element below,
// second pass of Rainbow.color() will result in block.parentNode being null.
if (!block || !block.parentNode) {
return;
}
// Create a table wrapper
var table = document.createElement('table');
table.className = 'rainbow';
table.setAttribute('data-language', block.getAttribute('data-language'));
// Split up the lines of the block
var lines = splitLines(block);
// For each line
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var index = i + 1;
// Create a row
var row = table.insertRow(-1);
row.className = 'line line-' + index;
// Create a cell which displays the line number with CSS
var lineNumber = row.insertCell(-1);
lineNumber.className = 'line-number';
lineNumber.setAttribute('data-line-number', index);
// Add in the actual line of source code
var code = row.insertCell(-1);
code.className = 'line-code';
// If the line is blank, add a newline to make it copyable.
if (line === '') {
line = '\n';
}
code.innerHTML = line;
}
// If the block is a <pre> element, its parent is not an element
// generated by Rainbow (i.e. it could be <body>). We don't want
// to clear this.
var parent = (block.nodeName.toLowerCase() === 'pre') ? block : block.parentNode;
// Clear the parent element and use the table in place of the <code> block
parent.innerHTML = '';
parent.appendChild(table);
});
})(window.Rainbow);