Hello !

I have attached a patch that solves this bug.

>From the commit message:

It supports two formats: #L50 and #L50-L150 (The latter will highlight
from line 50 to line 150).

It also changes the hash if we click on a line, and if we click on a
second line holding the SHIFT key, it will highlight the whole range,
and update the hash as well, allowing one to share the URL.


I have tested in Chromium 38, Iceweasel 31.2, and IE8 (I assume it
should work for later versions of IE)

Cheers

-- 
Jason Pleau
>From 8bde6c68437ae6634297cdff321b495ed6e9a052 Mon Sep 17 00:00:00 2001
From: Jason Pleau <ja...@jpleau.ca>
Date: Sat, 1 Nov 2014 10:44:24 -0400
Subject: [PATCH] add automatic line numbers from #Lxx location.hash

It supports #L50 and #L50-L150 (The latter will highlight from line 50
to line 150).

It also changes the hash if we click on a line, and if we click on a
second line holding the SHIFT key, it will highlight the whole range,
and update the hash as well.
---
 debsources/app/templates/source_file_code.inc.html | 117 ++++++++++++++++++++-
 1 file changed, 112 insertions(+), 5 deletions(-)

diff --git a/debsources/app/templates/source_file_code.inc.html b/debsources/app/templates/source_file_code.inc.html
index 9ea5a88..17bd3d0 100644
--- a/debsources/app/templates/source_file_code.inc.html
+++ b/debsources/app/templates/source_file_code.inc.html
@@ -19,17 +19,14 @@
   <tr>
     <td>
       <pre id="sourceslinenumbers">{% for i in range(1, nlines+1) -%}
-        <a id="L{{ i }}" href="#L{{ i }}">{{ i }}</a><br />
+        <a id="L{{ i }}" href="#L{{ i }}" class="linenumber" data-line="{{ i }}">{{ i }}</a><br />
         {%- endfor %}</pre>
     </td>
     <td>
       <pre><code id="sourcecode" class="{% if file_language -%}
 					{{ file_language }}{% else %}no-highlight
 					{%- endif %}">{% for (line, highlight) in code -%}
-          {% if highlight -%}
-          <span class="highlight">{{ line }}</span>{% else -%}
-          {{ line }}
-          {%- endif %}
+            <span id="line{{ loop.index }}" class="codeline {% if highlight -%} highlight   {%- endif %}">{{ line }}</span>
           {%- endfor %}</code></pre>
     </td>
     {% if msg -%}
@@ -46,3 +43,113 @@
     {%- endif %}
   </tr>
 </table>
+
+<script type="text/javascript">
+function highlight_lines(start, end) {
+    // First, remove the highlight class from elements that already have it
+    var elements = document.querySelectorAll("span.highlight");
+    for (i = 0; i < elements.length; ++i) {
+        var element = elements[i];
+        element.className = element.className.replace(/\bhighlight\b/, '');
+    }
+
+    // Then, add the highlight class to elements that contain the lines we want to highlight
+    for (i = start; i <= end; ++i) {
+        var element = document.getElementById("line" + i);
+        element.className = element.className + " highlight ";
+    }
+}
+
+var hash_changed = function(event, scroll) {
+
+    event = typeof event !== 'undefined' ? event: null;
+    scroll = typeof scroll !== 'undefined' ? scroll: false;
+
+    // Will match strings like #L15 and #L15-20
+    var regex = /#L(\d+)(-L(\d+))*$/;
+
+    var match = regex.exec(window.location.hash);
+    if (match != null) {
+        var first_line = second_line = null;
+        first_line = parseInt(match[1]);
+
+        if (typeof match[3] !== 'undefined' && match[3].length > 0) {
+            second_line = parseInt(match[3]);
+        } else {
+            second_line = first_line;
+        }
+
+        // If we get something like #L20-L15, just swap the two line numbers so the loop will work
+        if (second_line < first_line) {
+            var tmp = first_line;
+            first_line = second_line;
+            second_line = tmp;
+        }
+
+        highlight_lines(first_line, second_line);
+
+        if (scroll) {
+            window.scroll(0, document.getElementById("L"+first_line).offsetTop);
+        }
+    }
+}
+
+
+function change_hash_without_scroll(element, hash) {
+    // This is necessary because when changing window.location.hash, the window will
+    // scroll to the element's id if it matches the hash
+    var id = element.id;
+    element.id = id+'-tmpNoScroll';
+    window.location.hash = hash;
+    element.id = id;
+}
+
+var last_clicked;
+var line_click_handler = function(event) {
+    if (event.preventDefault) {
+        event.preventDefault();
+    } else {
+        event.returnValue = false;
+    }
+
+    var callerElement = event.target || event.srcElement;
+
+    if (!event.shiftKey || !last_clicked) {
+        last_clicked = callerElement;
+        change_hash_without_scroll(callerElement, "L" + callerElement.getAttribute('data-line'));
+    } else {
+        var first_line = parseInt(last_clicked.getAttribute('data-line'));
+        var second_line = parseInt(callerElement.getAttribute('data-line'));
+
+        if (second_line < first_line) {
+            var tmp = first_line;
+            first_line = second_line;
+            second_line = tmp;
+        }
+
+        change_hash_without_scroll(callerElement, "L" + first_line + "-L" + second_line);
+    }
+};
+
+var window_load_sourcecode = function(event) {
+    var line_numbers = document.querySelectorAll("a.linenumber");
+    for (i = 0; i < line_numbers.length; ++i) {
+        var line_number_element = line_numbers[i];
+        if (line_number_element.addEventListener) {
+            line_number_element.addEventListener('click', line_click_handler, false);
+        } else {
+            line_number_element.attachEvent('onclick',  line_click_handler);
+        }
+    }
+};
+
+if (window.addEventListener) {
+	window.addEventListener('load', window_load_sourcecode, false);
+} else {
+	window.attachEvent('onload', window_load_sourcecode);
+}
+
+window.onhashchange = hash_changed;
+hash_changed(null, true);
+
+</script>
-- 
2.1.1

Reply via email to