summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/line_highlighter.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/line_highlighter.js')
-rw-r--r--app/assets/javascripts/line_highlighter.js70
1 files changed, 69 insertions, 1 deletions
diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js
index f145bd3ad74..ea5a60bb78e 100644
--- a/app/assets/javascripts/line_highlighter.js
+++ b/app/assets/javascripts/line_highlighter.js
@@ -1,17 +1,50 @@
-
+/* eslint-disable */
+// LineHighlighter
+//
+// Handles single- and multi-line selection and highlight for blob views.
+//
/*= require jquery.scrollTo */
+//
+// ### Example Markup
+//
+// <div id="blob-content-holder">
+// <div class="file-content">
+// <div class="line-numbers">
+// <a href="#L1" id="L1" data-line-number="1">1</a>
+// <a href="#L2" id="L2" data-line-number="2">2</a>
+// <a href="#L3" id="L3" data-line-number="3">3</a>
+// <a href="#L4" id="L4" data-line-number="4">4</a>
+// <a href="#L5" id="L5" data-line-number="5">5</a>
+// </div>
+// <pre class="code highlight">
+// <code>
+// <span id="LC1" class="line">...</span>
+// <span id="LC2" class="line">...</span>
+// <span id="LC3" class="line">...</span>
+// <span id="LC4" class="line">...</span>
+// <span id="LC5" class="line">...</span>
+// </code>
+// </pre>
+// </div>
+// </div>
+//
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
this.LineHighlighter = (function() {
+ // CSS class applied to highlighted lines
LineHighlighter.prototype.highlightClass = 'hll';
+ // Internal copy of location.hash so we're not dependent on `location` in tests
LineHighlighter.prototype._hash = '';
function LineHighlighter(hash) {
var range;
if (hash == null) {
+ // Initialize a LineHighlighter object
+ //
+ // hash - String URL hash for dependency injection in tests
hash = location.hash;
}
this.setHash = bind(this.setHash, this);
@@ -24,6 +57,8 @@
if (range[0]) {
this.highlightRange(range);
$.scrollTo("#L" + range[0], {
+ // Scroll to the first highlighted line on initial load
+ // Offset -50 for the sticky top bar, and another -100 for some context
offset: -150
});
}
@@ -32,6 +67,12 @@
LineHighlighter.prototype.bindEvents = function() {
$('#blob-content-holder').on('mousedown', 'a[data-line-number]', this.clickHandler);
+ // While it may seem odd to bind to the mousedown event and then throw away
+ // the click event, there is a method to our madness.
+ //
+ // If not done this way, the line number anchor will sometimes keep its
+ // active state even when the event is cancelled, resulting in an ugly border
+ // around the link and/or a persisted underline text decoration.
return $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
return event.preventDefault();
});
@@ -44,6 +85,8 @@
lineNumber = $(event.target).closest('a').data('line-number');
current = this.hashToRange(this._hash);
if (!(current[0] && event.shiftKey)) {
+ // If there's no current selection, or there is but Shift wasn't held,
+ // treat this like a single-line selection.
this.setHash(lineNumber);
return this.highlightLine(lineNumber);
} else if (event.shiftKey) {
@@ -59,10 +102,23 @@
LineHighlighter.prototype.clearHighlight = function() {
return $("." + this.highlightClass).removeClass(this.highlightClass);
+ // Unhighlight previously highlighted lines
};
+ // Convert a URL hash String into line numbers
+ //
+ // hash - Hash String
+ //
+ // Examples:
+ //
+ // hashToRange('#L5') # => [5, null]
+ // hashToRange('#L5-15') # => [5, 15]
+ // hashToRange('#foo') # => [null, null]
+ //
+ // Returns an Array
LineHighlighter.prototype.hashToRange = function(hash) {
var first, last, matches;
+ //?L(\d+)(?:-(\d+))?$/)
matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/);
if (matches && matches.length) {
first = parseInt(matches[1]);
@@ -73,10 +129,16 @@
}
};
+ // Highlight a single line
+ //
+ // lineNumber - Line number to highlight
LineHighlighter.prototype.highlightLine = function(lineNumber) {
return $("#LC" + lineNumber).addClass(this.highlightClass);
};
+ // Highlight all lines within a range
+ //
+ // range - Array containing the starting and ending line numbers
LineHighlighter.prototype.highlightRange = function(range) {
var i, lineNumber, ref, ref1, results;
if (range[1]) {
@@ -90,6 +152,7 @@
}
};
+ // Set the URL hash string
LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
var hash;
if (lastLineNumber) {
@@ -101,10 +164,15 @@
return this.__setLocationHash__(hash);
};
+ // Make the actual hash change in the browser
+ //
+ // This method is stubbed in tests.
LineHighlighter.prototype.__setLocationHash__ = function(value) {
return history.pushState({
turbolinks: false,
url: value
+ // We're using pushState instead of assigning location.hash directly to
+ // prevent the page from scrolling on the hashchange event
}, document.title, value);
};