Skip to content

Commit eb82e80

Browse files
authoredMay 7, 2020
Line Highlight: Added linkable line numbers (#2328)
This makes individual line numbers clickable creating a link to that specific line for that specific code block.
1 parent 2c10ef8 commit eb82e80

File tree

5 files changed

+98
-11
lines changed

5 files changed

+98
-11
lines changed
 

‎plugins/line-highlight/index.html

+11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<link rel="stylesheet" href="style.css" />
1010
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
1111
<link rel="stylesheet" href="plugins/line-highlight/prism-line-highlight.css" data-noprefix />
12+
<link rel="stylesheet" href="plugins/line-numbers/prism-line-numbers.css" data-noprefix />
1213
<script src="scripts/prefixfree.min.js"></script>
1314

1415
<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
@@ -51,6 +52,8 @@ <h1>How to use</h1>
5152
<p>You can also link to specific lines on any code snippet, by using the following as a url hash: <code>#{element-id}.{lines}</code> where
5253
<code>{element-id}</code> is the id of the <code>&lt;pre></code> element and <code>{lines}</code> is one or more lines or line ranges that follow the format
5354
outlined above. For example, if there is an element with <code>id="play"</code> on the page, you can link to lines 5-6 by linking to <a href="plugins/line-highlight/#play.5-6">#play.5-6</a></p>
55+
56+
<p>If line numbers are also enabled for a code block and the <code>&lt;pre></code> element has an id, you can add the <code>linkable-line-numbers</code> class to the <code>&lt;pre></code> element. This will make all line numbers clickable and when clicking any line number, it will change the hash of the current page to link to that specific line.</p>
5457
</section>
5558

5659
<section>
@@ -69,12 +72,20 @@ <h2>Line 43, starting from line 41</h2>
6972
<pre data-line="43" data-line-offset="40" data-src="plugins/line-highlight/prism-line-highlight.js"></pre>
7073

7174
<p><a href="plugins/line-highlight/#play.50-55,60">Linking example</a></p>
75+
76+
<h2>With line numbers</h2>
77+
<pre class="line-numbers" data-line="43" data-start="41" data-src="plugins/line-highlight/prism-line-highlight.js"></pre>
78+
79+
<h2>With linkable line numbers</h2>
80+
<pre id="foo" class="line-numbers linkable-line-numbers" data-start="20" data-src="plugins/line-highlight/prism-line-highlight.js"></pre>
81+
7282
</section>
7383

7484
<footer data-src="templates/footer.html" data-type="text/html"></footer>
7585

7686
<script src="prism.js"></script>
7787
<script src="plugins/line-highlight/prism-line-highlight.js"></script>
88+
<script src="plugins/line-numbers/prism-line-numbers.js"></script>
7889
<script src="scripts/utopia.js"></script>
7990
<script src="components.js"></script>
8091
<script src="scripts/code.js"></script>

‎plugins/line-highlight/prism-line-highlight.css

+10
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,13 @@ pre[data-line] {
4747
.line-numbers .line-highlight:after {
4848
content: none;
4949
}
50+
51+
pre[id].linkable-line-numbers span.line-numbers-rows {
52+
pointer-events: all;
53+
}
54+
pre[id].linkable-line-numbers span.line-numbers-rows > span:before {
55+
cursor: pointer;
56+
}
57+
pre[id].linkable-line-numbers span.line-numbers-rows > span:hover:before {
58+
background-color: rgba(128, 128, 128, .2);
59+
}

‎plugins/line-highlight/prism-line-highlight.js

+76-9
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,33 @@
44
return;
55
}
66

7-
function $$(expr, con) {
8-
return Array.prototype.slice.call((con || document).querySelectorAll(expr));
7+
/**
8+
* @param {string} selector
9+
* @param {ParentNode} [container]
10+
* @returns {HTMLElement[]}
11+
*/
12+
function $$(selector, container) {
13+
return Array.prototype.slice.call((container || document).querySelectorAll(selector));
914
}
1015

16+
/**
17+
* Returns whether the given element has the given class.
18+
*
19+
* @param {Element} element
20+
* @param {string} className
21+
* @returns {boolean}
22+
*/
1123
function hasClass(element, className) {
1224
className = " " + className + " ";
1325
return (" " + element.className + " ").replace(/[\n\t]/g, " ").indexOf(className) > -1
1426
}
1527

28+
/**
29+
* Calls the given function.
30+
*
31+
* @param {() => any} func
32+
* @returns {void}
33+
*/
1634
function callFunction(func) {
1735
func();
1836
}
@@ -26,8 +44,8 @@
2644
var d = document.createElement('div');
2745
d.style.fontSize = '13px';
2846
d.style.lineHeight = '1.5';
29-
d.style.padding = 0;
30-
d.style.border = 0;
47+
d.style.padding = '0';
48+
d.style.border = '0';
3149
d.innerHTML = '&nbsp;<br />&nbsp;';
3250
document.body.appendChild(d);
3351
// Browsers that round the line-height should have offsetHeight === 38
@@ -53,7 +71,7 @@
5371
function highlightLines(pre, lines, classes) {
5472
lines = typeof lines === 'string' ? lines : pre.getAttribute('data-line');
5573

56-
var ranges = lines.replace(/\s+/g, '').split(',');
74+
var ranges = lines.replace(/\s+/g, '').split(',').filter(Boolean);
5775
var offset = +pre.getAttribute('data-line-offset') || 0;
5876

5977
var parseMethod = isLineHeightRounded() ? parseInt : parseFloat;
@@ -68,6 +86,7 @@
6886
var start = +range[0];
6987
var end = +range[1] || start;
7088

89+
/** @type {HTMLElement} */
7190
var line = pre.querySelector('.line-highlight[data-range="' + currentRange + '"]') || document.createElement('div');
7291

7392
mutateActions.push(function () {
@@ -115,11 +134,58 @@
115134
});
116135
});
117136

137+
var id = pre.id;
138+
if (hasLineNumbers && id) {
139+
// This implements linkable line numbers. Linkable line numbers use Line Highlight to create a link to a
140+
// specific line. For this to work, the pre element has to:
141+
// 1) have line numbers,
142+
// 2) have the `linkable-line-numbers` class or an ascendant that has that class, and
143+
// 3) have an id.
144+
145+
var linkableLineNumbersClass = 'linkable-line-numbers';
146+
var linkableLineNumbers = false;
147+
var node = pre;
148+
while (node) {
149+
if (hasClass(node, linkableLineNumbersClass)) {
150+
linkableLineNumbers = true;
151+
break;
152+
}
153+
node = node.parentElement;
154+
}
155+
156+
if (linkableLineNumbers) {
157+
if (!hasClass(pre, linkableLineNumbersClass)) {
158+
// add class to pre
159+
mutateActions.push(function () {
160+
pre.className = (pre.className + ' ' + linkableLineNumbersClass).trim();
161+
});
162+
}
163+
164+
var start = parseInt(pre.getAttribute('data-start') || '1');
165+
166+
// iterate all line number spans
167+
$$('.line-numbers-rows > span', pre).forEach(function (lineSpan, i) {
168+
var lineNumber = i + start;
169+
lineSpan.onclick = function () {
170+
var hash = id + '.' + lineNumber;
171+
172+
// this will prevent scrolling since the span is obviously in view
173+
scrollIntoView = false;
174+
location.hash = hash;
175+
setTimeout(function () {
176+
scrollIntoView = true;
177+
}, 1);
178+
};
179+
});
180+
}
181+
}
182+
118183
return function () {
119184
mutateActions.forEach(callFunction);
120185
};
121186
}
122187

188+
var scrollIntoView = true;
123189
function applyHash() {
124190
var hash = location.hash.slice(1);
125191

@@ -148,7 +214,9 @@
148214
var mutateDom = highlightLines(pre, range, 'temporary ');
149215
mutateDom();
150216

151-
document.querySelector('.temporary.line-highlight').scrollIntoView();
217+
if (scrollIntoView) {
218+
document.querySelector('.temporary.line-highlight').scrollIntoView();
219+
}
152220
}
153221

154222
var fakeTimer = 0; // Hack to limit the number of times applyHash() runs
@@ -203,9 +271,8 @@
203271

204272
window.addEventListener('hashchange', applyHash);
205273
window.addEventListener('resize', function () {
206-
var actions = [];
207-
$$('pre[data-line]').forEach(function (pre) {
208-
actions.push(highlightLines(pre));
274+
var actions = $$('pre[data-line]').map(function (pre) {
275+
return highlightLines(pre);
209276
});
210277
actions.forEach(callFunction);
211278
});

‎plugins/line-highlight/prism-line-highlight.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎plugins/line-numbers/prism-line-numbers.css

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ pre[class*="language-"].line-numbers > code {
2727
}
2828

2929
.line-numbers-rows > span {
30-
pointer-events: none;
3130
display: block;
3231
counter-increment: linenumber;
3332
}

0 commit comments

Comments
 (0)