[d24f17c] | 1 | (function () {
|
---|
| 2 |
|
---|
| 3 | if (typeof Prism === 'undefined' || typeof document === 'undefined') {
|
---|
| 4 | return;
|
---|
| 5 | }
|
---|
| 6 |
|
---|
| 7 | /**
|
---|
| 8 | * Plugin name which is used as a class name for <pre> which is activating the plugin
|
---|
| 9 | *
|
---|
| 10 | * @type {string}
|
---|
| 11 | */
|
---|
| 12 | var PLUGIN_NAME = 'line-numbers';
|
---|
| 13 |
|
---|
| 14 | /**
|
---|
| 15 | * Regular expression used for determining line breaks
|
---|
| 16 | *
|
---|
| 17 | * @type {RegExp}
|
---|
| 18 | */
|
---|
| 19 | var NEW_LINE_EXP = /\n(?!$)/g;
|
---|
| 20 |
|
---|
| 21 |
|
---|
| 22 | /**
|
---|
| 23 | * Global exports
|
---|
| 24 | */
|
---|
| 25 | var config = Prism.plugins.lineNumbers = {
|
---|
| 26 | /**
|
---|
| 27 | * Get node for provided line number
|
---|
| 28 | *
|
---|
| 29 | * @param {Element} element pre element
|
---|
| 30 | * @param {number} number line number
|
---|
| 31 | * @returns {Element|undefined}
|
---|
| 32 | */
|
---|
| 33 | getLine: function (element, number) {
|
---|
| 34 | if (element.tagName !== 'PRE' || !element.classList.contains(PLUGIN_NAME)) {
|
---|
| 35 | return;
|
---|
| 36 | }
|
---|
| 37 |
|
---|
| 38 | var lineNumberRows = element.querySelector('.line-numbers-rows');
|
---|
| 39 | if (!lineNumberRows) {
|
---|
| 40 | return;
|
---|
| 41 | }
|
---|
| 42 | var lineNumberStart = parseInt(element.getAttribute('data-start'), 10) || 1;
|
---|
| 43 | var lineNumberEnd = lineNumberStart + (lineNumberRows.children.length - 1);
|
---|
| 44 |
|
---|
| 45 | if (number < lineNumberStart) {
|
---|
| 46 | number = lineNumberStart;
|
---|
| 47 | }
|
---|
| 48 | if (number > lineNumberEnd) {
|
---|
| 49 | number = lineNumberEnd;
|
---|
| 50 | }
|
---|
| 51 |
|
---|
| 52 | var lineIndex = number - lineNumberStart;
|
---|
| 53 |
|
---|
| 54 | return lineNumberRows.children[lineIndex];
|
---|
| 55 | },
|
---|
| 56 |
|
---|
| 57 | /**
|
---|
| 58 | * Resizes the line numbers of the given element.
|
---|
| 59 | *
|
---|
| 60 | * This function will not add line numbers. It will only resize existing ones.
|
---|
| 61 | *
|
---|
| 62 | * @param {HTMLElement} element A `<pre>` element with line numbers.
|
---|
| 63 | * @returns {void}
|
---|
| 64 | */
|
---|
| 65 | resize: function (element) {
|
---|
| 66 | resizeElements([element]);
|
---|
| 67 | },
|
---|
| 68 |
|
---|
| 69 | /**
|
---|
| 70 | * Whether the plugin can assume that the units font sizes and margins are not depended on the size of
|
---|
| 71 | * the current viewport.
|
---|
| 72 | *
|
---|
| 73 | * Setting this to `true` will allow the plugin to do certain optimizations for better performance.
|
---|
| 74 | *
|
---|
| 75 | * Set this to `false` if you use any of the following CSS units: `vh`, `vw`, `vmin`, `vmax`.
|
---|
| 76 | *
|
---|
| 77 | * @type {boolean}
|
---|
| 78 | */
|
---|
| 79 | assumeViewportIndependence: true
|
---|
| 80 | };
|
---|
| 81 |
|
---|
| 82 | /**
|
---|
| 83 | * Resizes the given elements.
|
---|
| 84 | *
|
---|
| 85 | * @param {HTMLElement[]} elements
|
---|
| 86 | */
|
---|
| 87 | function resizeElements(elements) {
|
---|
| 88 | elements = elements.filter(function (e) {
|
---|
| 89 | var codeStyles = getStyles(e);
|
---|
| 90 | var whiteSpace = codeStyles['white-space'];
|
---|
| 91 | return whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line';
|
---|
| 92 | });
|
---|
| 93 |
|
---|
| 94 | if (elements.length == 0) {
|
---|
| 95 | return;
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | var infos = elements.map(function (element) {
|
---|
| 99 | var codeElement = element.querySelector('code');
|
---|
| 100 | var lineNumbersWrapper = element.querySelector('.line-numbers-rows');
|
---|
| 101 | if (!codeElement || !lineNumbersWrapper) {
|
---|
| 102 | return undefined;
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | /** @type {HTMLElement} */
|
---|
| 106 | var lineNumberSizer = element.querySelector('.line-numbers-sizer');
|
---|
| 107 | var codeLines = codeElement.textContent.split(NEW_LINE_EXP);
|
---|
| 108 |
|
---|
| 109 | if (!lineNumberSizer) {
|
---|
| 110 | lineNumberSizer = document.createElement('span');
|
---|
| 111 | lineNumberSizer.className = 'line-numbers-sizer';
|
---|
| 112 |
|
---|
| 113 | codeElement.appendChild(lineNumberSizer);
|
---|
| 114 | }
|
---|
| 115 |
|
---|
| 116 | lineNumberSizer.innerHTML = '0';
|
---|
| 117 | lineNumberSizer.style.display = 'block';
|
---|
| 118 |
|
---|
| 119 | var oneLinerHeight = lineNumberSizer.getBoundingClientRect().height;
|
---|
| 120 | lineNumberSizer.innerHTML = '';
|
---|
| 121 |
|
---|
| 122 | return {
|
---|
| 123 | element: element,
|
---|
| 124 | lines: codeLines,
|
---|
| 125 | lineHeights: [],
|
---|
| 126 | oneLinerHeight: oneLinerHeight,
|
---|
| 127 | sizer: lineNumberSizer,
|
---|
| 128 | };
|
---|
| 129 | }).filter(Boolean);
|
---|
| 130 |
|
---|
| 131 | infos.forEach(function (info) {
|
---|
| 132 | var lineNumberSizer = info.sizer;
|
---|
| 133 | var lines = info.lines;
|
---|
| 134 | var lineHeights = info.lineHeights;
|
---|
| 135 | var oneLinerHeight = info.oneLinerHeight;
|
---|
| 136 |
|
---|
| 137 | lineHeights[lines.length - 1] = undefined;
|
---|
| 138 | lines.forEach(function (line, index) {
|
---|
| 139 | if (line && line.length > 1) {
|
---|
| 140 | var e = lineNumberSizer.appendChild(document.createElement('span'));
|
---|
| 141 | e.style.display = 'block';
|
---|
| 142 | e.textContent = line;
|
---|
| 143 | } else {
|
---|
| 144 | lineHeights[index] = oneLinerHeight;
|
---|
| 145 | }
|
---|
| 146 | });
|
---|
| 147 | });
|
---|
| 148 |
|
---|
| 149 | infos.forEach(function (info) {
|
---|
| 150 | var lineNumberSizer = info.sizer;
|
---|
| 151 | var lineHeights = info.lineHeights;
|
---|
| 152 |
|
---|
| 153 | var childIndex = 0;
|
---|
| 154 | for (var i = 0; i < lineHeights.length; i++) {
|
---|
| 155 | if (lineHeights[i] === undefined) {
|
---|
| 156 | lineHeights[i] = lineNumberSizer.children[childIndex++].getBoundingClientRect().height;
|
---|
| 157 | }
|
---|
| 158 | }
|
---|
| 159 | });
|
---|
| 160 |
|
---|
| 161 | infos.forEach(function (info) {
|
---|
| 162 | var lineNumberSizer = info.sizer;
|
---|
| 163 | var wrapper = info.element.querySelector('.line-numbers-rows');
|
---|
| 164 |
|
---|
| 165 | lineNumberSizer.style.display = 'none';
|
---|
| 166 | lineNumberSizer.innerHTML = '';
|
---|
| 167 |
|
---|
| 168 | info.lineHeights.forEach(function (height, lineNumber) {
|
---|
| 169 | wrapper.children[lineNumber].style.height = height + 'px';
|
---|
| 170 | });
|
---|
| 171 | });
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | /**
|
---|
| 175 | * Returns style declarations for the element
|
---|
| 176 | *
|
---|
| 177 | * @param {Element} element
|
---|
| 178 | */
|
---|
| 179 | function getStyles(element) {
|
---|
| 180 | if (!element) {
|
---|
| 181 | return null;
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 | return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null);
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | var lastWidth = undefined;
|
---|
| 188 | window.addEventListener('resize', function () {
|
---|
| 189 | if (config.assumeViewportIndependence && lastWidth === window.innerWidth) {
|
---|
| 190 | return;
|
---|
| 191 | }
|
---|
| 192 | lastWidth = window.innerWidth;
|
---|
| 193 |
|
---|
| 194 | resizeElements(Array.prototype.slice.call(document.querySelectorAll('pre.' + PLUGIN_NAME)));
|
---|
| 195 | });
|
---|
| 196 |
|
---|
| 197 | Prism.hooks.add('complete', function (env) {
|
---|
| 198 | if (!env.code) {
|
---|
| 199 | return;
|
---|
| 200 | }
|
---|
| 201 |
|
---|
| 202 | var code = /** @type {Element} */ (env.element);
|
---|
| 203 | var pre = /** @type {HTMLElement} */ (code.parentNode);
|
---|
| 204 |
|
---|
| 205 | // works only for <code> wrapped inside <pre> (not inline)
|
---|
| 206 | if (!pre || !/pre/i.test(pre.nodeName)) {
|
---|
| 207 | return;
|
---|
| 208 | }
|
---|
| 209 |
|
---|
| 210 | // Abort if line numbers already exists
|
---|
| 211 | if (code.querySelector('.line-numbers-rows')) {
|
---|
| 212 | return;
|
---|
| 213 | }
|
---|
| 214 |
|
---|
| 215 | // only add line numbers if <code> or one of its ancestors has the `line-numbers` class
|
---|
| 216 | if (!Prism.util.isActive(code, PLUGIN_NAME)) {
|
---|
| 217 | return;
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | // Remove the class 'line-numbers' from the <code>
|
---|
| 221 | code.classList.remove(PLUGIN_NAME);
|
---|
| 222 | // Add the class 'line-numbers' to the <pre>
|
---|
| 223 | pre.classList.add(PLUGIN_NAME);
|
---|
| 224 |
|
---|
| 225 | var match = env.code.match(NEW_LINE_EXP);
|
---|
| 226 | var linesNum = match ? match.length + 1 : 1;
|
---|
| 227 | var lineNumbersWrapper;
|
---|
| 228 |
|
---|
| 229 | var lines = new Array(linesNum + 1).join('<span></span>');
|
---|
| 230 |
|
---|
| 231 | lineNumbersWrapper = document.createElement('span');
|
---|
| 232 | lineNumbersWrapper.setAttribute('aria-hidden', 'true');
|
---|
| 233 | lineNumbersWrapper.className = 'line-numbers-rows';
|
---|
| 234 | lineNumbersWrapper.innerHTML = lines;
|
---|
| 235 |
|
---|
| 236 | if (pre.hasAttribute('data-start')) {
|
---|
| 237 | pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | env.element.appendChild(lineNumbersWrapper);
|
---|
| 241 |
|
---|
| 242 | resizeElements([pre]);
|
---|
| 243 |
|
---|
| 244 | Prism.hooks.run('line-numbers', env);
|
---|
| 245 | });
|
---|
| 246 |
|
---|
| 247 | Prism.hooks.add('line-numbers', function (env) {
|
---|
| 248 | env.plugins = env.plugins || {};
|
---|
| 249 | env.plugins.lineNumbers = true;
|
---|
| 250 | });
|
---|
| 251 |
|
---|
| 252 | }());
|
---|