hgweb: parameterize the tag name of elements holding followlines selection
While plugging followlines.js into "annotate" view, we'll need to walk a
different DOM structure from that of "filerevision" view. In particular, the
selectable source line element is a <tr> in annotate view (in contrast with a
<span> in filerevision view). So make this tag name a parameter of
followlines.js script by passing its value as a "selectabletag" data attribute
of <pre class="sourcelines"> element.
As <pre class="sourcelines"> tags are getting quite long in templates, rewrite
them on several lines.
--- a/mercurial/templates/gitweb/filerevision.tmpl Wed Jun 21 17:02:21 2017 +0200
+++ b/mercurial/templates/gitweb/filerevision.tmpl Wed Jun 21 17:07:51 2017 +0200
@@ -66,7 +66,12 @@
</div>
<div class="page_body">
-<pre class="sourcelines stripes" data-logurl="{url|urlescape}log/{symrev}/{file|urlescape}" data-ishead="{ishead}">{text%fileline}</pre>
+<pre class="sourcelines stripes"
+ data-logurl="{url|urlescape}log/{symrev}/{file|urlescape}"
+ data-selectabletag="SPAN"
+ data-ishead="{ishead}">
+{text%fileline}
+</pre>
</div>
<script type="text/javascript" src="{staticurl|urlescape}followlines.js"></script>
--- a/mercurial/templates/paper/filerevision.tmpl Wed Jun 21 17:02:21 2017 +0200
+++ b/mercurial/templates/paper/filerevision.tmpl Wed Jun 21 17:07:51 2017 +0200
@@ -67,7 +67,12 @@
<div class="overflow">
<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
<div class="sourcefirst"> line source</div>
-<pre class="sourcelines stripes4 wrap bottomline" data-logurl="{url|urlescape}log/{symrev}/{file|urlescape}" data-ishead="{ishead}">{text%fileline}</pre>
+<pre class="sourcelines stripes4 wrap bottomline"
+ data-logurl="{url|urlescape}log/{symrev}/{file|urlescape}"
+ data-selectabletag="SPAN"
+ data-ishead="{ishead}">
+{text%fileline}
+</pre>
</div>
<script type="text/javascript" src="{staticurl|urlescape}followlines.js"></script>
--- a/mercurial/templates/static/followlines.js Wed Jun 21 17:02:21 2017 +0200
+++ b/mercurial/templates/static/followlines.js Wed Jun 21 17:07:51 2017 +0200
@@ -17,6 +17,13 @@
return;
}
+ // Tag of children of "sourcelines" element on which to add "line
+ // selection" style.
+ var selectableTag = sourcelines.dataset.selectabletag;
+ if (typeof selectableTag === 'undefined') {
+ return;
+ }
+
var isHead = parseInt(sourcelines.dataset.ishead || "0");
// tooltip to invite on lines selection
@@ -52,22 +59,23 @@
// on mousemove, show tooltip close to cursor position
sourcelines.addEventListener('mousemove', moveAndShowTooltip);
- // retrieve all direct <span> children of <pre class="sourcelines">
- var spans = Array.prototype.filter.call(
+ // retrieve all direct *selectable* children of class="sourcelines"
+ // element
+ var selectableElements = Array.prototype.filter.call(
sourcelines.children,
- function(x) { return x.tagName === 'SPAN' });
+ function(x) { return x.tagName === selectableTag });
// add a "followlines-select" class to change cursor type in CSS
- for (var i = 0; i < spans.length; i++) {
- spans[i].classList.add('followlines-select');
+ for (var i = 0; i < selectableElements.length; i++) {
+ selectableElements[i].classList.add('followlines-select');
}
var lineSelectedCSSClass = 'followlines-selected';
- //** add CSS class on <span> element in `from`-`to` line range */
+ //** add CSS class on selectable elements in `from`-`to` line range */
function addSelectedCSSClass(from, to) {
for (var i = from; i <= to; i++) {
- spans[i].classList.add(lineSelectedCSSClass);
+ selectableElements[i].classList.add(lineSelectedCSSClass);
}
}
@@ -80,24 +88,24 @@
}
}
- // ** return the <span> element parent of `element` */
- function findParentSpan(element) {
+ // ** return the element of type "selectableTag" parent of `element` */
+ function selectableParent(element) {
var parent = element.parentElement;
if (parent === null) {
return null;
}
- if (element.tagName == 'SPAN' && parent.isSameNode(sourcelines)) {
+ if (element.tagName == selectableTag && parent.isSameNode(sourcelines)) {
return element;
}
- return findParentSpan(parent);
+ return selectableParent(parent);
}
//** event handler for "click" on the first line of a block */
function lineSelectStart(e) {
- var startElement = findParentSpan(e.target);
+ var startElement = selectableParent(e.target);
if (startElement === null) {
- // not a <span> (maybe <a>): abort, keeping event listener
- // registered for other click with <span> target
+ // not a "selectable" element (maybe <a>): abort, keeping event
+ // listener registered for other click with a "selectable" target
return;
}
@@ -112,7 +120,7 @@
//** event handler for "click" on the last line of the block */
function lineSelectEnd(e) {
- var endElement = findParentSpan(e.target);
+ var endElement = selectableParent(e.target);
if (endElement === null) {
// not a <span> (maybe <a>): abort, keeping event listener
// registered for other click with <span> target
--- a/tests/test-hgweb-commands.t Wed Jun 21 17:02:21 2017 +0200
+++ b/tests/test-hgweb-commands.t Wed Jun 21 17:07:51 2017 +0200
@@ -1347,8 +1347,13 @@
<div class="overflow">
<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
<div class="sourcefirst"> line source</div>
- <pre class="sourcelines stripes4 wrap bottomline" data-logurl="/log/1/foo" data-ishead="0">
- <span id="l1">foo</span><a href="#l1"></a></pre>
+ <pre class="sourcelines stripes4 wrap bottomline"
+ data-logurl="/log/1/foo"
+ data-selectabletag="SPAN"
+ data-ishead="0">
+
+ <span id="l1">foo</span><a href="#l1"></a>
+ </pre>
</div>
<script type="text/javascript" src="/static/followlines.js"></script>
@@ -1476,8 +1481,13 @@
<div class="overflow">
<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
<div class="sourcefirst"> line source</div>
- <pre class="sourcelines stripes4 wrap bottomline" data-logurl="/log/2/foo" data-ishead="1">
- <span id="l1">another</span><a href="#l1"></a></pre>
+ <pre class="sourcelines stripes4 wrap bottomline"
+ data-logurl="/log/2/foo"
+ data-selectabletag="SPAN"
+ data-ishead="1">
+
+ <span id="l1">another</span><a href="#l1"></a>
+ </pre>
</div>
<script type="text/javascript" src="/static/followlines.js"></script>
--- a/tests/test-highlight.t Wed Jun 21 17:02:21 2017 +0200
+++ b/tests/test-highlight.t Wed Jun 21 17:07:51 2017 +0200
@@ -148,7 +148,11 @@
<div class="overflow">
<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
<div class="sourcefirst"> line source</div>
- <pre class="sourcelines stripes4 wrap bottomline" data-logurl="/log/tip/primes.py" data-ishead="1">
+ <pre class="sourcelines stripes4 wrap bottomline"
+ data-logurl="/log/tip/primes.py"
+ data-selectabletag="SPAN"
+ data-ishead="1">
+
<span id="l1"><span class="sd">"""Fun with generators. Corresponding Haskell implementation:</span></span><a href="#l1"></a>
<span id="l2"></span><a href="#l2"></a>
<span id="l3"><span class="sd">primes = 2 : sieve [3, 5..]</span></span><a href="#l3"></a>
@@ -179,7 +183,8 @@
<span id="l28"> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></span><a href="#l28"></a>
<span id="l29"> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l29"></a>
<span id="l30"> <span class="kn">print</span> <span class="s">"The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></span><a href="#l30"></a>
- <span id="l31"></span><a href="#l31"></a></pre>
+ <span id="l31"></span><a href="#l31"></a>
+ </pre>
</div>
<script type="text/javascript" src="/static/followlines.js"></script>