##// END OF EJS Templates
hgweb: add a link to followlines in descending direction...
Denis Laxalde -
r31940:6ce09d2c default
parent child Browse files
Show More
@@ -1,219 +1,229 b''
1 1 // followlines.js - JavaScript utilities for followlines UI
2 2 //
3 3 // Copyright 2017 Logilab SA <contact@logilab.fr>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 //** Install event listeners for line block selection and followlines action */
9 9 document.addEventListener('DOMContentLoaded', function() {
10 10 var sourcelines = document.getElementsByClassName('sourcelines')[0];
11 11 if (typeof sourcelines === 'undefined') {
12 12 return;
13 13 }
14 14 // URL to complement with "linerange" query parameter
15 15 var targetUri = sourcelines.dataset.logurl;
16 16 if (typeof targetUri === 'undefined')Β {
17 17 return;
18 18 }
19 19
20 20 // tooltip to invite on lines selection
21 21 var tooltip = document.createElement('div');
22 22 tooltip.id = 'followlines-tooltip';
23 23 tooltip.classList.add('hidden');
24 24 var initTooltipText = 'click to start following lines history from here';
25 25 tooltip.textContent = initTooltipText;
26 26 sourcelines.appendChild(tooltip);
27 27
28 28 //* position "element" on top-right of cursor */
29 29 function positionTopRight(element, event) {
30 30 var x = (event.clientX + 10) + 'px',
31 31 y = (event.clientY - 20) + 'px';
32 32 element.style.top = y;
33 33 element.style.left = x;
34 34 }
35 35
36 36 var tooltipTimeoutID;
37 37 //* move the "tooltip" with cursor (top-right) and show it after 1s */
38 38 function moveAndShowTooltip(e) {
39 39 if (typeof tooltipTimeoutID !== 'undefined') {
40 40 // avoid accumulation of timeout callbacks (blinking)
41 41 window.clearTimeout(tooltipTimeoutID);
42 42 }
43 43 tooltip.classList.add('hidden');
44 44 positionTopRight(tooltip, e);
45 45 tooltipTimeoutID = window.setTimeout(function() {
46 46 tooltip.classList.remove('hidden');
47 47 }, 1000);
48 48 }
49 49
50 50 // on mousemove, show tooltip close to cursor position
51 51 sourcelines.addEventListener('mousemove', moveAndShowTooltip);
52 52
53 53 // retrieve all direct <span> children of <pre class="sourcelines">
54 54 var spans = Array.prototype.filter.call(
55 55 sourcelines.children,
56 56 function(x) { return x.tagName === 'SPAN' });
57 57
58 58 // add a "followlines-select" class to change cursor type in CSS
59 59 for (var i = 0; i < spans.length; i++) {
60 60 spans[i].classList.add('followlines-select');
61 61 }
62 62
63 63 var lineSelectedCSSClass = 'followlines-selected';
64 64
65 65 //** add CSS class on <span> element in `from`-`to` line range */
66 66 function addSelectedCSSClass(from, to) {
67 67 for (var i = from; i <= to; i++) {
68 68 spans[i].classList.add(lineSelectedCSSClass);
69 69 }
70 70 }
71 71
72 72 //** remove CSS class from previously selected lines */
73 73 function removeSelectedCSSClass() {
74 74 var elements = sourcelines.getElementsByClassName(
75 75 lineSelectedCSSClass);
76 76 while (elements.length) {
77 77 elements[0].classList.remove(lineSelectedCSSClass);
78 78 }
79 79 }
80 80
81 81 // ** return the <span> element parent of `element` */
82 82 function findParentSpan(element) {
83 83 var parent = element.parentElement;
84 84 if (parent === null) {
85 85 return null;
86 86 }
87 87 if (element.tagName == 'SPAN' && parent.isSameNode(sourcelines)) {
88 88 return element;
89 89 }
90 90 return findParentSpan(parent);
91 91 }
92 92
93 93 //** event handler for "click" on the first line of a block */
94 94 function lineSelectStart(e) {
95 95 var startElement = findParentSpan(e.target);
96 96 if (startElement === null) {
97 97 // not a <span> (maybe <a>): abort, keeping event listener
98 98 // registered for other click with <span> target
99 99 return;
100 100 }
101 101
102 102 // update tooltip text
103 103 tooltip.textContent = 'click again to terminate line block selection here';
104 104
105 105 var startId = parseInt(startElement.id.slice(1));
106 106 startElement.classList.add(lineSelectedCSSClass); // CSS
107 107
108 108 // remove this event listener
109 109 sourcelines.removeEventListener('click', lineSelectStart);
110 110
111 111 //** event handler for "click" on the last line of the block */
112 112 function lineSelectEnd(e) {
113 113 var endElement = findParentSpan(e.target);
114 114 if (endElement === null) {
115 115 // not a <span> (maybe <a>): abort, keeping event listener
116 116 // registered for other click with <span> target
117 117 return;
118 118 }
119 119
120 120 // remove this event listener
121 121 sourcelines.removeEventListener('click', lineSelectEnd);
122 122
123 123 // hide tooltip and disable motion tracking
124 124 tooltip.classList.add('hidden');
125 125 sourcelines.removeEventListener('mousemove', moveAndShowTooltip);
126 126 window.clearTimeout(tooltipTimeoutID);
127 127
128 128 //* restore initial "tooltip" state */
129 129 function restoreTooltip() {
130 130 tooltip.textContent = initTooltipText;
131 131 sourcelines.addEventListener('mousemove', moveAndShowTooltip);
132 132 }
133 133
134 134 // compute line range (startId, endId)
135 135 var endId = parseInt(endElement.id.slice(1));
136 136 if (endId == startId) {
137 137 // clicked twice the same line, cancel and reset initial state
138 138 // (CSS, event listener for selection start, tooltip)
139 139 removeSelectedCSSClass();
140 140 sourcelines.addEventListener('click', lineSelectStart);
141 141 restoreTooltip();
142 142 return;
143 143 }
144 144 var inviteElement = endElement;
145 145 if (endId < startId) {
146 146 var tmp = endId;
147 147 endId = startId;
148 148 startId = tmp;
149 149 inviteElement = startElement;
150 150 }
151 151
152 152 addSelectedCSSClass(startId - 1, endId -1); // CSS
153 153
154 154 // append the <div id="followlines"> element to last line of the
155 155 // selection block
156 156 var divAndButton = followlinesBox(targetUri, startId, endId);
157 157 var div = divAndButton[0],
158 158 button = divAndButton[1];
159 159 inviteElement.appendChild(div);
160 160 // set position close to cursor (top-right)
161 161 positionTopRight(div, e);
162 162
163 163 //** event handler for cancelling selection */
164 164 function cancel() {
165 165 // remove invite box
166 166 div.parentNode.removeChild(div);
167 167 // restore initial event listeners
168 168 sourcelines.addEventListener('click', lineSelectStart);
169 169 sourcelines.removeEventListener('click', cancel);
170 170 // remove styles on selected lines
171 171 removeSelectedCSSClass();
172 172 // restore tooltip element
173 173 restoreTooltip();
174 174 }
175 175
176 176 // bind cancel event to click on <button>
177 177 button.addEventListener('click', cancel);
178 178 // as well as on an click on any source line
179 179 sourcelines.addEventListener('click', cancel);
180 180 }
181 181
182 182 sourcelines.addEventListener('click', lineSelectEnd);
183 183
184 184 }
185 185
186 186 sourcelines.addEventListener('click', lineSelectStart);
187 187
188 188 //** return a <div id="followlines"> and inner cancel <button> elements */
189 189 function followlinesBox(targetUri, fromline, toline) {
190 190 // <div id="followlines">
191 191 var div = document.createElement('div');
192 192 div.id = 'followlines';
193 193
194 194 // <div class="followlines-cancel">
195 195 var buttonDiv = document.createElement('div');
196 196 buttonDiv.classList.add('followlines-cancel');
197 197
198 198 // <button>x</button>
199 199 var button = document.createElement('button');
200 200 button.textContent = 'x';
201 201 buttonDiv.appendChild(button);
202 202 div.appendChild(buttonDiv);
203 203
204 204 // <div class="followlines-link">
205 205 var aDiv = document.createElement('div');
206 206 aDiv.classList.add('followlines-link');
207
208 // <a href="/log/<rev>/<file>?patch=&linerange=...">
209 var a = document.createElement('a');
207 aDiv.textContent = 'follow history of lines ' + fromline + ':' + toline + ':';
208 var linesep = document.createElement('br');
209 aDiv.appendChild(linesep);
210 // link to "ascending" followlines
211 var aAsc = document.createElement('a');
210 212 var url = targetUri + '?patch=&linerange=' + fromline + ':' + toline;
211 a.setAttribute('href', url);
212 a.textContent = 'follow lines ' + fromline + ':' + toline;
213 aDiv.appendChild(a);
213 aAsc.setAttribute('href', url);
214 aAsc.textContent = 'ascending';
215 aDiv.appendChild(aAsc);
216 var sep = document.createTextNode(' / ');
217 aDiv.appendChild(sep);
218 // link to "descending" followlines
219 var aDesc = document.createElement('a');
220 aDesc.setAttribute('href', url + '&descend=');
221 aDesc.textContent = 'descending';
222 aDiv.appendChild(aDesc);
223
214 224 div.appendChild(aDiv);
215 225
216 226 return [div, button];
217 227 }
218 228
219 229 }, false);
General Comments 0
You need to be logged in to leave comments. Login now