1 | (function () {
|
2 |
|
3 | if (typeof Prism === 'undefined' || typeof document === 'undefined' || !document.querySelector) {
|
4 | return;
|
5 | }
|
6 |
|
7 | var LINE_NUMBERS_CLASS = 'line-numbers';
|
8 | var LINKABLE_LINE_NUMBERS_CLASS = 'linkable-line-numbers';
|
9 | var NEW_LINE_EXP = /\n(?!$)/g;
|
10 |
|
11 | |
12 |
|
13 |
|
14 |
|
15 |
|
16 | function $$(selector, container) {
|
17 | return Array.prototype.slice.call((container || document).querySelectorAll(selector));
|
18 | }
|
19 |
|
20 | |
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | function hasClass(element, className) {
|
28 | return element.classList.contains(className);
|
29 | }
|
30 |
|
31 | |
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | function callFunction(func) {
|
38 | func();
|
39 | }
|
40 |
|
41 |
|
42 |
|
43 | var isLineHeightRounded = (function () {
|
44 | var res;
|
45 | return function () {
|
46 | if (typeof res === 'undefined') {
|
47 | var d = document.createElement('div');
|
48 | d.style.fontSize = '13px';
|
49 | d.style.lineHeight = '1.5';
|
50 | d.style.padding = '0';
|
51 | d.style.border = '0';
|
52 | d.innerHTML = ' <br /> ';
|
53 | document.body.appendChild(d);
|
54 |
|
55 |
|
56 | res = d.offsetHeight === 38;
|
57 | document.body.removeChild(d);
|
58 | }
|
59 | return res;
|
60 | };
|
61 | }());
|
62 |
|
63 | |
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | function getContentBoxTopOffset(parent, child) {
|
70 | var parentStyle = getComputedStyle(parent);
|
71 | var childStyle = getComputedStyle(child);
|
72 |
|
73 | |
74 |
|
75 |
|
76 |
|
77 |
|
78 | function pxToNumber(px) {
|
79 | return +px.substr(0, px.length - 2);
|
80 | }
|
81 |
|
82 | return child.offsetTop
|
83 | + pxToNumber(childStyle.borderTopWidth)
|
84 | + pxToNumber(childStyle.paddingTop)
|
85 | - pxToNumber(parentStyle.paddingTop);
|
86 | }
|
87 |
|
88 | |
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | function isActiveFor(pre) {
|
97 | if (!pre || !/pre/i.test(pre.nodeName)) {
|
98 | return false;
|
99 | }
|
100 |
|
101 | if (pre.hasAttribute('data-line')) {
|
102 | return true;
|
103 | }
|
104 |
|
105 | if (pre.id && Prism.util.isActive(pre, LINKABLE_LINE_NUMBERS_CLASS)) {
|
106 |
|
107 |
|
108 | return true;
|
109 | }
|
110 |
|
111 | return false;
|
112 | }
|
113 |
|
114 | var scrollIntoView = true;
|
115 |
|
116 | Prism.plugins.lineHighlight = {
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 | highlightLines: function highlightLines(pre, lines, classes) {
|
129 | lines = typeof lines === 'string' ? lines : (pre.getAttribute('data-line') || '');
|
130 |
|
131 | var ranges = lines.replace(/\s+/g, '').split(',').filter(Boolean);
|
132 | var offset = +pre.getAttribute('data-line-offset') || 0;
|
133 |
|
134 | var parseMethod = isLineHeightRounded() ? parseInt : parseFloat;
|
135 | var lineHeight = parseMethod(getComputedStyle(pre).lineHeight);
|
136 | var hasLineNumbers = Prism.util.isActive(pre, LINE_NUMBERS_CLASS);
|
137 | var codeElement = pre.querySelector('code');
|
138 | var parentElement = hasLineNumbers ? pre : codeElement || pre;
|
139 | var mutateActions = ([]);
|
140 | var lineBreakMatch = codeElement.textContent.match(NEW_LINE_EXP);
|
141 | var numberOfLines = lineBreakMatch ? lineBreakMatch.length + 1 : 1;
|
142 | |
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 | var codePreOffset = !codeElement || parentElement == codeElement ? 0 : getContentBoxTopOffset(pre, codeElement);
|
153 |
|
154 | ranges.forEach(function (currentRange) {
|
155 | var range = currentRange.split('-');
|
156 |
|
157 | var start = +range[0];
|
158 | var end = +range[1] || start;
|
159 | end = Math.min(numberOfLines + offset, end);
|
160 |
|
161 | if (end < start) {
|
162 | return;
|
163 | }
|
164 |
|
165 |
|
166 | var line = pre.querySelector('.line-highlight[data-range="' + currentRange + '"]') || document.createElement('div');
|
167 |
|
168 | mutateActions.push(function () {
|
169 | line.setAttribute('aria-hidden', 'true');
|
170 | line.setAttribute('data-range', currentRange);
|
171 | line.className = (classes || '') + ' line-highlight';
|
172 | });
|
173 |
|
174 |
|
175 | if (hasLineNumbers && Prism.plugins.lineNumbers) {
|
176 | var startNode = Prism.plugins.lineNumbers.getLine(pre, start);
|
177 | var endNode = Prism.plugins.lineNumbers.getLine(pre, end);
|
178 |
|
179 | if (startNode) {
|
180 | var top = startNode.offsetTop + codePreOffset + 'px';
|
181 | mutateActions.push(function () {
|
182 | line.style.top = top;
|
183 | });
|
184 | }
|
185 |
|
186 | if (endNode) {
|
187 | var height = (endNode.offsetTop - startNode.offsetTop) + endNode.offsetHeight + 'px';
|
188 | mutateActions.push(function () {
|
189 | line.style.height = height;
|
190 | });
|
191 | }
|
192 | } else {
|
193 | mutateActions.push(function () {
|
194 | line.setAttribute('data-start', String(start));
|
195 |
|
196 | if (end > start) {
|
197 | line.setAttribute('data-end', String(end));
|
198 | }
|
199 |
|
200 | line.style.top = (start - offset - 1) * lineHeight + codePreOffset + 'px';
|
201 |
|
202 | line.textContent = new Array(end - start + 2).join(' \n');
|
203 | });
|
204 | }
|
205 |
|
206 | mutateActions.push(function () {
|
207 | line.style.width = pre.scrollWidth + 'px';
|
208 | });
|
209 |
|
210 | mutateActions.push(function () {
|
211 |
|
212 |
|
213 | parentElement.appendChild(line);
|
214 | });
|
215 | });
|
216 |
|
217 | var id = pre.id;
|
218 | if (hasLineNumbers && Prism.util.isActive(pre, LINKABLE_LINE_NUMBERS_CLASS) && id) {
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | if (!hasClass(pre, LINKABLE_LINE_NUMBERS_CLASS)) {
|
226 |
|
227 | mutateActions.push(function () {
|
228 | pre.classList.add(LINKABLE_LINE_NUMBERS_CLASS);
|
229 | });
|
230 | }
|
231 |
|
232 | var start = parseInt(pre.getAttribute('data-start') || '1');
|
233 |
|
234 |
|
235 | $$('.line-numbers-rows > span', pre).forEach(function (lineSpan, i) {
|
236 | var lineNumber = i + start;
|
237 | lineSpan.onclick = function () {
|
238 | var hash = id + '.' + lineNumber;
|
239 |
|
240 |
|
241 | scrollIntoView = false;
|
242 | location.hash = hash;
|
243 | setTimeout(function () {
|
244 | scrollIntoView = true;
|
245 | }, 1);
|
246 | };
|
247 | });
|
248 | }
|
249 |
|
250 | return function () {
|
251 | mutateActions.forEach(callFunction);
|
252 | };
|
253 | }
|
254 | };
|
255 |
|
256 |
|
257 | function applyHash() {
|
258 | var hash = location.hash.slice(1);
|
259 |
|
260 |
|
261 | $$('.temporary.line-highlight').forEach(function (line) {
|
262 | line.parentNode.removeChild(line);
|
263 | });
|
264 |
|
265 | var range = (hash.match(/\.([\d,-]+)$/) || [, ''])[1];
|
266 |
|
267 | if (!range || document.getElementById(hash)) {
|
268 | return;
|
269 | }
|
270 |
|
271 | var id = hash.slice(0, hash.lastIndexOf('.'));
|
272 | var pre = document.getElementById(id);
|
273 |
|
274 | if (!pre) {
|
275 | return;
|
276 | }
|
277 |
|
278 | if (!pre.hasAttribute('data-line')) {
|
279 | pre.setAttribute('data-line', '');
|
280 | }
|
281 |
|
282 | var mutateDom = Prism.plugins.lineHighlight.highlightLines(pre, range, 'temporary ');
|
283 | mutateDom();
|
284 |
|
285 | if (scrollIntoView) {
|
286 | document.querySelector('.temporary.line-highlight').scrollIntoView();
|
287 | }
|
288 | }
|
289 |
|
290 | var fakeTimer = 0;
|
291 |
|
292 | Prism.hooks.add('before-sanity-check', function (env) {
|
293 | var pre = env.element.parentElement;
|
294 | if (!isActiveFor(pre)) {
|
295 | return;
|
296 | }
|
297 |
|
298 | |
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 | var num = 0;
|
306 | $$('.line-highlight', pre).forEach(function (line) {
|
307 | num += line.textContent.length;
|
308 | line.parentNode.removeChild(line);
|
309 | });
|
310 |
|
311 | if (num && /^(?: \n)+$/.test(env.code.slice(-num))) {
|
312 | env.code = env.code.slice(0, -num);
|
313 | }
|
314 | });
|
315 |
|
316 | Prism.hooks.add('complete', function completeHook(env) {
|
317 | var pre = env.element.parentElement;
|
318 | if (!isActiveFor(pre)) {
|
319 | return;
|
320 | }
|
321 |
|
322 | clearTimeout(fakeTimer);
|
323 |
|
324 | var hasLineNumbers = Prism.plugins.lineNumbers;
|
325 | var isLineNumbersLoaded = env.plugins && env.plugins.lineNumbers;
|
326 |
|
327 | if (hasClass(pre, LINE_NUMBERS_CLASS) && hasLineNumbers && !isLineNumbersLoaded) {
|
328 | Prism.hooks.add('line-numbers', completeHook);
|
329 | } else {
|
330 | var mutateDom = Prism.plugins.lineHighlight.highlightLines(pre);
|
331 | mutateDom();
|
332 | fakeTimer = setTimeout(applyHash, 1);
|
333 | }
|
334 | });
|
335 |
|
336 | window.addEventListener('hashchange', applyHash);
|
337 | window.addEventListener('resize', function () {
|
338 | var actions = $$('pre')
|
339 | .filter(isActiveFor)
|
340 | .map(function (pre) {
|
341 | return Prism.plugins.lineHighlight.highlightLines(pre);
|
342 | });
|
343 | actions.forEach(callFunction);
|
344 | });
|
345 |
|
346 | }());
|