Prism Line-Number Plugin

by Wei Lin Chen

HTML

<link rel="stylesheet" href="http://bililite.com/blog/blogfiles/prism/prism-line-highlight.css">
<script src="http://bililite.com/blog/wp-content/plugins/syntaxhighlightchooser/prism/prism.js"></script>
<script src="http://bililite.com/blog/wp-content/plugins/syntaxhighlightchooser/prism/prism.linenumber.js"></script>
<script src="http://bililite.com/blog/blogfiles/prism/prism-line-highlight.js"></script>
<pre id=1><code class="language-javascript">function hello(name){
	alert('Hello, '+name);
}</code></pre>
	<pre id=2><code class="language-javascript" data-linenumber>function hello(name){
	alert('Hello, '+name);
}</code></pre>
	<pre id=3><code class="language-javascript" data-linenumber=1>function hello(name){
	alert('Hello, '+name);
	// This is a longer code example
	return {
		'success' : true,
		'message' : 'Hello, '+name
	};
}</code></pre>
	<pre id=4><code class="language-javascript"data-linenumber=40>function hello(name){
	alert('Hello, '+name);
}</code></pre>
<p><a href="#1.1">Line 1, first div</a></p>
<p><a href="#2.1">Line 1, second div</a></p>
<p><a href="#3.4">Line 4, third div</a></p>

CSS

pre {
		margin: 2em;
		border: 1px solid #eee;
		background: #f5f2f0;
		position: relative;
		line-height: 150%;
	}
	.token.string {
		color: #690;
	}
	.token.punctuation {
		color: #999;
	}
	.token.keyword {
		color: #07a;
	}
	.token.comment {
		color: green;
		font-style: italic;
	}
	/* for line numbers */
	code[class*="language-"] {
		counter-reset: linenumber;
	}
	span.line{
		display: inline-block;
		width: 100%;
		counter-increment: linenumber;
	}
	span.line:nth-child(odd){
		background: #f0f0f0;
	}
	span.line:before{
		content: counter(linenumber);
		font-size: 100%;
		width: 2em;
		display: inline-block;
		font-weight: normal;
		color: black;
		border-right: 1px solid black;
		margin-right: 5px;
		padding-right: 5px;
		text-align: right;
	}

JavaScript

/*
	This plugins was created based on the Prism line-numbering plugin.
	This plugin aims to number all lines and is independent of highlighting.
*/
(function() {

  if (!window.Prism || !document.querySelectorAll) {
    return;
  }

  function $$(expr, con) {
    return Array.prototype.slice.call((con || document).querySelectorAll(expr));
  }

  function numberLines(pre) {
    var offset = +pre.getAttribute('data-line-offset') || 0;
    var lineHeight = parseFloat(getComputedStyle(pre).lineHeight);
    var code = pre.querySelector('code');
    var numLines = code.innerHTML.split('\n').length;
    pre.setAttribute('data-number', '');

    for (var i = 1; i <= numLines; i++) {
      var line = document.createElement('div');
      line.className = 'line-number';
      line.setAttribute('data-start', i);
      line.style.top = (i - offset - 1) * lineHeight + 'px';

      (code || pre).appendChild(line);
    }
  }

  Prism.hooks.add('after-highlight', function(env) {
    var pre = env.element.parentNode;

    if (!pre || !/pre/i.test(pre.nodeName)) {
      return;
    }

    $$('.line-number', pre).forEach(function(line) {
      line.parentNode.removeChild(line);
    });

    numberLines(pre);
  });

})();