(function () { if (typeof self === 'undefined' || !self.Prism || !self.document) { return; } /** * Plugin name which is used as a class name for
which is activating the plugin * @type {String} */ var PLUGIN_NAME = 'line-numbers'; /** * Regular expression used for determining line breaks * @type {RegExp} */ var NEW_LINE_EXP = /\n(?!$)/g; /** * Resizes line numbers spans according to height of line of code * @param {Element} elementelement */ var _resizeElement = function (element) { var codeStyles = getStyles(element); var whiteSpace = codeStyles['white-space']; if (whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line') { var codeElement = element.querySelector('code'); var lineNumbersWrapper = element.querySelector('.line-numbers-rows'); var lineNumberSizer = element.querySelector('.line-numbers-sizer'); var codeLines = codeElement.textContent.split(NEW_LINE_EXP); if (!lineNumberSizer) { lineNumberSizer = document.createElement('span'); lineNumberSizer.className = 'line-numbers-sizer'; codeElement.appendChild(lineNumberSizer); } lineNumberSizer.style.display = 'block'; codeLines.forEach(function (line, lineNumber) { lineNumberSizer.textContent = line || '\n'; var lineSize = lineNumberSizer.getBoundingClientRect().height; lineNumbersWrapper.children[lineNumber].style.height = lineSize + 'px'; }); lineNumberSizer.textContent = ''; lineNumberSizer.style.display = 'none'; } }; /** * Returns style declarations for the element * @param {Element} element */ var getStyles = function (element) { if (!element) { return null; } return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null); }; window.addEventListener('resize', function () { Array.prototype.forEach.call(document.querySelectorAll('pre.' + PLUGIN_NAME), _resizeElement); }); Prism.hooks.add('complete', function (env) { if (!env.code) { return; } // works only forwrapped inside
(not inline) var pre = env.element.parentNode; var clsReg = /\s*\bline-numbers\b\s*/; if ( !pre || !/pre/i.test(pre.nodeName) || // Abort only if nor thenor thehave the class (!clsReg.test(pre.className) && !clsReg.test(env.element.className)) ) { return; } if (env.element.querySelector('.line-numbers-rows')) { // Abort if line numbers already exists return; } if (clsReg.test(env.element.className)) { // Remove the class 'line-numbers' from the
env.element.className = env.element.className.replace(clsReg, ' '); } if (!clsReg.test(pre.className)) { // Add the class 'line-numbers' to the
pre.className += ' line-numbers'; } var match = env.code.match(NEW_LINE_EXP); var linesNum = match ? match.length + 1 : 1; var lineNumbersWrapper; var lines = new Array(linesNum + 1); lines = lines.join(''); lineNumbersWrapper = document.createElement('span'); lineNumbersWrapper.setAttribute('aria-hidden', 'true'); lineNumbersWrapper.className = 'line-numbers-rows'; lineNumbersWrapper.innerHTML = lines; if (pre.hasAttribute('data-start')) { pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1); } env.element.appendChild(lineNumbersWrapper); _resizeElement(pre); Prism.hooks.run('line-numbers', env); }); Prism.hooks.add('line-numbers', function (env) { env.plugins = env.plugins || {}; env.plugins.lineNumbers = true; }); /** * Global exports */ Prism.plugins.lineNumbers = { /** * Get node for provided line number * @param {Element} element pre element * @param {Number} number line number * @return {Element|undefined} */ getLine: function (element, number) { if (element.tagName !== 'PRE' || !element.classList.contains(PLUGIN_NAME)) { return; } var lineNumberRows = element.querySelector('.line-numbers-rows'); var lineNumberStart = parseInt(element.getAttribute('data-start'), 10) || 1; var lineNumberEnd = lineNumberStart + (lineNumberRows.children.length - 1); if (number < lineNumberStart) { number = lineNumberStart; } if (number > lineNumberEnd) { number = lineNumberEnd; } var lineIndex = number - lineNumberStart; return lineNumberRows.children[lineIndex]; } }; }());