Mercurial > hg
comparison mercurial/templates/static/followlines.js @ 31848:7160bdd56b84
hgweb: add a floating tooltip to invite on followlines action
In followlines.js, we create a <div id="followlines-tooltip"> element to draw
attention of users on "followlines" feature. The element shows up on hover of
source lines after one second and follows the cursor. After first click (start
line selection), the text changes and indicates that next click will terminate
selection.
author | Denis Laxalde <denis.laxalde@logilab.fr> |
---|---|
date | Thu, 06 Apr 2017 19:15:09 +0200 |
parents | d15c9feb4399 |
children | 5c1abb4bd3ee |
comparison
equal
deleted
inserted
replaced
31847:39d36c2db68e | 31848:7160bdd56b84 |
---|---|
14 // URL to complement with "linerange" query parameter | 14 // URL to complement with "linerange" query parameter |
15 var targetUri = sourcelines.dataset.logurl; | 15 var targetUri = sourcelines.dataset.logurl; |
16 if (typeof targetUri === 'undefined') { | 16 if (typeof targetUri === 'undefined') { |
17 return; | 17 return; |
18 } | 18 } |
19 | |
20 // tooltip to invite on lines selection | |
21 var tooltip = document.createElement('div'); | |
22 tooltip.id = 'followlines-tooltip'; | |
23 tooltip.classList.add('hidden'); | |
24 var initTooltipText = 'click to start following lines history from here'; | |
25 tooltip.textContent = initTooltipText; | |
26 sourcelines.appendChild(tooltip); | |
27 | |
28 var tooltipTimeoutID; | |
29 //* move the "tooltip" with cursor (top-right) and show it after 1s */ | |
30 function moveAndShowTooltip(e) { | |
31 if (typeof tooltipTimeoutID !== 'undefined') { | |
32 // avoid accumulation of timeout callbacks (blinking) | |
33 window.clearTimeout(tooltipTimeoutID); | |
34 } | |
35 tooltip.classList.add('hidden'); | |
36 var x = (e.clientX + 10) + 'px', | |
37 y = (e.clientY - 20) + 'px'; | |
38 tooltip.style.top = y; | |
39 tooltip.style.left = x; | |
40 tooltipTimeoutID = window.setTimeout(function() { | |
41 tooltip.classList.remove('hidden'); | |
42 }, 1000); | |
43 } | |
44 | |
45 // on mousemove, show tooltip close to cursor position | |
46 sourcelines.addEventListener('mousemove', moveAndShowTooltip); | |
19 | 47 |
20 // retrieve all direct <span> children of <pre class="sourcelines"> | 48 // retrieve all direct <span> children of <pre class="sourcelines"> |
21 var spans = Array.prototype.filter.call( | 49 var spans = Array.prototype.filter.call( |
22 sourcelines.children, | 50 sourcelines.children, |
23 function(x) { return x.tagName === 'SPAN' }); | 51 function(x) { return x.tagName === 'SPAN' }); |
63 if (startElement === null) { | 91 if (startElement === null) { |
64 // not a <span> (maybe <a>): abort, keeping event listener | 92 // not a <span> (maybe <a>): abort, keeping event listener |
65 // registered for other click with <span> target | 93 // registered for other click with <span> target |
66 return; | 94 return; |
67 } | 95 } |
96 | |
97 // update tooltip text | |
98 tooltip.textContent = 'click again to terminate line block selection here'; | |
99 | |
68 var startId = parseInt(startElement.id.slice(1)); | 100 var startId = parseInt(startElement.id.slice(1)); |
69 startElement.classList.add(lineSelectedCSSClass); // CSS | 101 startElement.classList.add(lineSelectedCSSClass); // CSS |
70 | 102 |
71 // remove this event listener | 103 // remove this event listener |
72 sourcelines.removeEventListener('click', lineSelectStart); | 104 sourcelines.removeEventListener('click', lineSelectStart); |
81 } | 113 } |
82 | 114 |
83 // remove this event listener | 115 // remove this event listener |
84 sourcelines.removeEventListener('click', lineSelectEnd); | 116 sourcelines.removeEventListener('click', lineSelectEnd); |
85 | 117 |
118 // hide tooltip and disable motion tracking | |
119 tooltip.classList.add('hidden'); | |
120 sourcelines.removeEventListener('mousemove', moveAndShowTooltip); | |
121 window.clearTimeout(tooltipTimeoutID); | |
122 | |
123 //* restore initial "tooltip" state */ | |
124 function restoreTooltip() { | |
125 tooltip.textContent = initTooltipText; | |
126 sourcelines.addEventListener('mousemove', moveAndShowTooltip); | |
127 } | |
128 | |
86 // compute line range (startId, endId) | 129 // compute line range (startId, endId) |
87 var endId = parseInt(endElement.id.slice(1)); | 130 var endId = parseInt(endElement.id.slice(1)); |
88 if (endId == startId) { | 131 if (endId == startId) { |
89 // clicked twice the same line, cancel and reset initial state | 132 // clicked twice the same line, cancel and reset initial state |
90 // (CSS and event listener for selection start) | 133 // (CSS, event listener for selection start, tooltip) |
91 removeSelectedCSSClass(); | 134 removeSelectedCSSClass(); |
92 sourcelines.addEventListener('click', lineSelectStart); | 135 sourcelines.addEventListener('click', lineSelectStart); |
136 restoreTooltip(); | |
93 return; | 137 return; |
94 } | 138 } |
95 var inviteElement = endElement; | 139 var inviteElement = endElement; |
96 if (endId < startId) { | 140 if (endId < startId) { |
97 var tmp = endId; | 141 var tmp = endId; |
116 // restore initial event listeners | 160 // restore initial event listeners |
117 sourcelines.addEventListener('click', lineSelectStart); | 161 sourcelines.addEventListener('click', lineSelectStart); |
118 sourcelines.removeEventListener('click', cancel); | 162 sourcelines.removeEventListener('click', cancel); |
119 // remove styles on selected lines | 163 // remove styles on selected lines |
120 removeSelectedCSSClass(); | 164 removeSelectedCSSClass(); |
165 // restore tooltip element | |
166 restoreTooltip(); | |
121 } | 167 } |
122 | 168 |
123 // bind cancel event to click on <button> | 169 // bind cancel event to click on <button> |
124 button.addEventListener('click', cancel); | 170 button.addEventListener('click', cancel); |
125 // as well as on an click on any source line | 171 // as well as on an click on any source line |