Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line Highlight: Added linkable line numbers #2328

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions plugins/line-highlight/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
<link rel="stylesheet" href="plugins/line-highlight/prism-line-highlight.css" data-noprefix />
<link rel="stylesheet" href="plugins/line-numbers/prism-line-numbers.css" data-noprefix />
<script src="scripts/prefixfree.min.js"></script>

<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
Expand Down Expand Up @@ -51,6 +52,8 @@ <h1>How to use</h1>
<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
<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
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>

<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>
</section>

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

<p><a href="plugins/line-highlight/#play.50-55,60">Linking example</a></p>

<h2>With line numbers</h2>
<pre class="line-numbers" data-line="43" data-start="41" data-src="plugins/line-highlight/prism-line-highlight.js"></pre>

<h2>With linkable line numbers</h2>
<pre id="foo" class="line-numbers linkable-line-numbers" data-start="20" data-src="plugins/line-highlight/prism-line-highlight.js"></pre>

</section>

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

<script src="prism.js"></script>
<script src="plugins/line-highlight/prism-line-highlight.js"></script>
<script src="plugins/line-numbers/prism-line-numbers.js"></script>
<script src="scripts/utopia.js"></script>
<script src="components.js"></script>
<script src="scripts/code.js"></script>
Expand Down
10 changes: 10 additions & 0 deletions plugins/line-highlight/prism-line-highlight.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@ pre[data-line] {
.line-numbers .line-highlight:after {
content: none;
}

pre[id].linkable-line-numbers span.line-numbers-rows {
pointer-events: all;
}
pre[id].linkable-line-numbers span.line-numbers-rows > span:before {
cursor: pointer;
}
pre[id].linkable-line-numbers span.line-numbers-rows > span:hover:before {
background-color: rgba(128, 128, 128, .2);
}
85 changes: 76 additions & 9 deletions plugins/line-highlight/prism-line-highlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@
return;
}

function $$(expr, con) {
return Array.prototype.slice.call((con || document).querySelectorAll(expr));
/**
* @param {string} selector
* @param {ParentNode} [container]
* @returns {HTMLElement[]}
*/
function $$(selector, container) {
return Array.prototype.slice.call((container || document).querySelectorAll(selector));
}

/**
* Returns whether the given element has the given class.
*
* @param {Element} element
* @param {string} className
* @returns {boolean}
*/
function hasClass(element, className) {
className = " " + className + " ";
return (" " + element.className + " ").replace(/[\n\t]/g, " ").indexOf(className) > -1
}

/**
* Calls the given function.
*
* @param {() => any} func
* @returns {void}
*/
function callFunction(func) {
func();
}
Expand All @@ -26,8 +44,8 @@
var d = document.createElement('div');
d.style.fontSize = '13px';
d.style.lineHeight = '1.5';
d.style.padding = 0;
d.style.border = 0;
d.style.padding = '0';
d.style.border = '0';
d.innerHTML = '&nbsp;<br />&nbsp;';
document.body.appendChild(d);
// Browsers that round the line-height should have offsetHeight === 38
Expand All @@ -53,7 +71,7 @@
function highlightLines(pre, lines, classes) {
lines = typeof lines === 'string' ? lines : pre.getAttribute('data-line');

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

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

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

mutateActions.push(function () {
Expand Down Expand Up @@ -115,11 +134,58 @@
});
});

var id = pre.id;
if (hasLineNumbers && id) {
// This implements linkable line numbers. Linkable line numbers use Line Highlight to create a link to a
// specific line. For this to work, the pre element has to:
// 1) have line numbers,
// 2) have the `linkable-line-numbers` class or an ascendant that has that class, and
// 3) have an id.

var linkableLineNumbersClass = 'linkable-line-numbers';
var linkableLineNumbers = false;
var node = pre;
while (node) {
if (hasClass(node, linkableLineNumbersClass)) {
linkableLineNumbers = true;
break;
}
node = node.parentElement;
}

if (linkableLineNumbers) {
if (!hasClass(pre, linkableLineNumbersClass)) {
// add class to pre
mutateActions.push(function () {
pre.className = (pre.className + ' ' + linkableLineNumbersClass).trim();
});
}

var start = parseInt(pre.getAttribute('data-start') || '1');

// iterate all line number spans
$$('.line-numbers-rows > span', pre).forEach(function (lineSpan, i) {
var lineNumber = i + start;
lineSpan.onclick = function () {
var hash = id + '.' + lineNumber;

// this will prevent scrolling since the span is obviously in view
scrollIntoView = false;
location.hash = hash;
setTimeout(function () {
scrollIntoView = true;
}, 1);
};
});
}
}

return function () {
mutateActions.forEach(callFunction);
};
}

var scrollIntoView = true;
function applyHash() {
var hash = location.hash.slice(1);

Expand Down Expand Up @@ -148,7 +214,9 @@
var mutateDom = highlightLines(pre, range, 'temporary ');
mutateDom();

document.querySelector('.temporary.line-highlight').scrollIntoView();
if (scrollIntoView) {
document.querySelector('.temporary.line-highlight').scrollIntoView();
}
}

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

window.addEventListener('hashchange', applyHash);
window.addEventListener('resize', function () {
var actions = [];
$$('pre[data-line]').forEach(function (pre) {
actions.push(highlightLines(pre));
var actions = $$('pre[data-line]').map(function (pre) {
return highlightLines(pre);
});
actions.forEach(callFunction);
});
Expand Down
2 changes: 1 addition & 1 deletion plugins/line-highlight/prism-line-highlight.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion plugins/line-numbers/prism-line-numbers.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ pre[class*="language-"].line-numbers > code {
}

.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
Expand Down