UNPKG

nodebb-plugin-markdown

Version:

A Markdown parser for NodeBB

190 lines (160 loc) 5.55 kB
/** * STOP! This file was edited from the version found in the repo * https://github.com/wcoder/highlightjs-line-numbers.js * * Changes: * - Made into a requirejs module * - Instead of passing window, document in as w and d, they * are defined at top of module */ define('highlightjs-line-numbers', ['highlight'], function () { var w = window; var d = document; var TABLE_NAME = 'hljs-ln', LINE_NAME = 'hljs-ln-line', CODE_BLOCK_NAME = 'hljs-ln-code', NUMBERS_BLOCK_NAME = 'hljs-ln-numbers', NUMBER_LINE_NAME = 'hljs-ln-n', DATA_ATTR_NAME = 'data-line-number', BREAK_LINE_REGEXP = /\r\n|\r|\n/g; if (w.hljs) { w.hljs.initLineNumbersOnLoad = initLineNumbersOnLoad; w.hljs.lineNumbersBlock = lineNumbersBlock; addStyles(); } else { w.console.error('highlight.js not detected!'); } function addStyles () { var css = d.createElement('style'); css.type = 'text/css'; css.innerHTML = format( '.{0}{border-collapse:collapse}\ .{0} td{padding:0}\ .{1}:before{content:attr({2})}', [ TABLE_NAME, NUMBER_LINE_NAME, DATA_ATTR_NAME ]); d.getElementsByTagName('head')[0].appendChild(css); } function initLineNumbersOnLoad (options) { if (d.readyState === 'complete') { documentReady(options); } else { w.addEventListener('DOMContentLoaded', function () { documentReady(options); }); } } function documentReady (options) { try { var blocks = d.querySelectorAll('code.hljs'); for (var i in blocks) { if (blocks.hasOwnProperty(i)) { lineNumbersBlock(blocks[i], options); } } } catch (e) { w.console.error('LineNumbers error: ', e); } } function lineNumbersBlock (element, options) { if (typeof element !== 'object') return; // define options or set default options = options || { singleLine: false }; // convert options var firstLineIndex = !!options.singleLine ? 0 : 1; async(function () { duplicateMultilineNodes(element); element.innerHTML = addLineNumbersBlockFor(element.innerHTML, firstLineIndex); }); } function addLineNumbersBlockFor (inputHtml, firstLineIndex) { var lines = getLines(inputHtml); // if last line contains only carriage return remove it if (lines[lines.length-1].trim() === '') { lines.pop(); } if (lines.length > firstLineIndex) { var html = ''; for (var i = 0, l = lines.length; i < l; i++) { html += format( '<tr>\ <td class="{0}">\ <div class="{1} {2}" {3}="{5}"></div>\ </td>\ <td class="{4}">\ <div class="{1}">{6}</div>\ </td>\ </tr>', [ NUMBERS_BLOCK_NAME, LINE_NAME, NUMBER_LINE_NAME, DATA_ATTR_NAME, CODE_BLOCK_NAME, i + 1, lines[i].length > 0 ? lines[i] : ' ' ]); } return format('<table class="{0}">{1}</table>', [ TABLE_NAME, html ]); } return inputHtml; } /** * Recursive method for fix multi-line elements implementation in highlight.js * Doing deep passage on child nodes. * @param {HTMLElement} element */ function duplicateMultilineNodes (element) { var nodes = element.childNodes; for (var node in nodes) { if (nodes.hasOwnProperty(node)) { var child = nodes[node]; if (getLinesCount(child.textContent) > 0) { if (child.childNodes.length > 0) { duplicateMultilineNodes(child); } else { duplicateMultilineNode(child.parentNode); } } } } } /** * Method for fix multi-line elements implementation in highlight.js * @param {HTMLElement} element */ function duplicateMultilineNode (element) { var className = element.className; if ( ! /hljs-/.test(className)) return; var lines = getLines(element.innerHTML); for (var i = 0, result = ''; i < lines.length; i++) { result += format('<span class="{0}">{1}</span>\n', [ className, lines[i] ]); } element.innerHTML = result.trim(); } function getLines (text) { if (text.length === 0) return []; return text.split(BREAK_LINE_REGEXP); } function getLinesCount (text) { return (text.trim().match(BREAK_LINE_REGEXP) || []).length; } function async (func) { w.setTimeout(func, 0); } /** * {@link https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript} * @param {string} format * @param {array} args */ function format (format, args) { return format.replace(/\{(\d+)\}/g, function(m, n){ return args[n] ? args[n] : m; }); } });