Fossil SCM

This check-in started as a follow-up to [55f56e91ba] to make the tooltip less hasty, and prevent it from being instantly reshown (and slightly moved) when the mouse pointer goes back from the tooltip to the owning node. The final result is a combined and simplified "mousemove" handler for both nodes and rails, with consistent tooltip lifetime: the tooltip is only closed if the mouse pointer is at a fixed point over another element for the (full) duration of the dwell timeout, or away from the owning element (and the tooltip) for the (full) duration of the close timeout. This check-in also improves positioning of the tooltip for longer dwell timeouts.

florian 2019-06-10 16:02 trunk
Commit 1fc616382820b859e680cfcc5f56b51686ddfa52a4109d323963cd041e177446
1 file changed +23 -34
+23 -34
--- src/graph.js
+++ src/graph.js
@@ -116,10 +116,11 @@
116116
** over a graph node. Or -1 when the mouse is not
117117
** over anything. */
118118
ixActive: -1, /* The item shown in the tooltip is tx.rowinfo[ixActive].
119119
** ixActive is -1 if the tooltip is not visible */
120120
nodeHover: null, /* Graph node under mouse when ixHover==-2 */
121
+ idNodeActive: 0, /* Element ID of the graph node with the tooltip. */
121122
posX: 0, posY: 0 /* The last mouse position. */
122123
};
123124
124125
/* Functions used to control the tooltip popup and its timer */
125126
function onKeyDown(event){ /* Hide the tooltip when ESC key pressed */
@@ -132,10 +133,11 @@
132133
function hideGraphTooltip(){ /* Hide the tooltip */
133134
document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
134135
stopCloseTimer();
135136
tooltipObj.style.display = "none";
136137
tooltipInfo.ixActive = -1;
138
+ tooltipInfo.idNodeActive = 0;
137139
}
138140
document.body.onunload = hideGraphTooltip
139141
function stopDwellTimer(){
140142
if(tooltipInfo.idTimer!=0){
141143
clearTimeout(tooltipInfo.idTimer);
@@ -169,36 +171,11 @@
169171
topObj.onclick = clickOnGraph
170172
topObj.ondblclick = dblclickOnGraph
171173
topObj.onmousemove = function(e) {
172174
var ix = findTxIndex(e);
173175
topObj.style.cursor = (ix<0) ? "" : "pointer"
174
- /* Keep the already visible tooltip at a constant position, as long as the
175
- ** mouse is over the same element. */
176
- if(tooltipObj.style.display != "none"){
177
- if(ix == tooltipInfo.ixHover) return;
178
- }
179
- /* The tooltip is either not visible, or the mouse is over a different
180
- ** element, so clear the dwell timer, and record the new element id and
181
- ** mouse position. */
182
- stopDwellTimer();
183
- if(ix >= 0){
184
- tooltipInfo.ixHover = ix;
185
- tooltipInfo.posX = e.clientX;
186
- tooltipInfo.posY = e.clientY;
187
- stopCloseTimer();
188
- if(tooltipInfo.dwellTimeout>0){
189
- tooltipInfo.idTimer = setTimeout(function() {
190
- tooltipInfo.idTimer = 0;
191
- stopCloseTimer();
192
- showGraphTooltip();
193
- },tooltipInfo.dwellTimeout);
194
- }
195
- }else{
196
- /* The mouse is not over an element with a tooltip */
197
- tooltipInfo.ixHover = -1;
198
- resumeCloseTimer();
199
- }
176
+ mouseOverGraph(e,ix,null);
200177
};
201178
topObj.onmouseleave = function(e) {
202179
/* Hide the tooltip if the mouse is outside the "timelineTableN" element,
203180
** and outside the tooltip. */
204181
if(e.relatedTarget && e.relatedTarget != tooltipObj){
@@ -208,18 +185,26 @@
208185
stopCloseTimer();
209186
}
210187
};
211188
function mouseOverNode(e){ /* Invoked by mousemove events over a graph node */
212189
e.stopPropagation()
213
- if(tooltipInfo.ixHover==-2) return
214
- tooltipInfo.ixHover = -2
215
- tooltipInfo.posX = e.clientX
216
- tooltipInfo.posY = e.clientY
217
- tooltipInfo.nodeHover = this
218
- stopCloseTimer();
219
- if(tooltipInfo.dwellTimeout>0){
220
- tooltipInfo.idTimer = setTimeout(function() {
190
+ mouseOverGraph(e,-2,this)
191
+ }
192
+ /* Combined mousemove handler for graph nodes and rails. */
193
+ function mouseOverGraph(e,ix,node){
194
+ stopDwellTimer(); // Mouse movement: reset the dwell timer.
195
+ var ownTooltip = // Check if the hovered element already has the tooltip.
196
+ (ix!=-2 && ix==tooltipInfo.ixHover && ix==tooltipInfo.ixActive) ||
197
+ (ix==-2 && tooltipInfo.ixHover==-2 && tooltipInfo.idNodeActive==node.id);
198
+ if(ownTooltip) stopCloseTimer(); // ownTooltip: clear the close timer.
199
+ else resumeCloseTimer(); // !ownTooltip: resume the close timer.
200
+ tooltipInfo.ixHover = ix;
201
+ tooltipInfo.nodeHover = node;
202
+ tooltipInfo.posX = e.clientX;
203
+ tooltipInfo.posY = e.clientY;
204
+ if(ix!=-1 && !ownTooltip && tooltipInfo.dwellTimeout>0){ // Go dwell timer.
205
+ tooltipInfo.idTimer = setTimeout(function(){
221206
tooltipInfo.idTimer = 0;
222207
stopCloseTimer();
223208
showGraphTooltip();
224209
},tooltipInfo.dwellTimeout);
225210
}
@@ -605,10 +590,12 @@
605590
dest += tx.fileDiff ? "&m&cf=" : "&m&c="
606591
dest += encodeURIComponent(tx.rowinfo[ix].h)
607592
return dest
608593
}
609594
function clickOnGraph(e){
595
+ stopCloseTimer();
596
+ stopDwellTimer();
610597
tooltipInfo.ixHover = findTxIndex(e);
611598
tooltipInfo.posX = e.clientX;
612599
tooltipInfo.posY = e.clientY;
613600
showGraphTooltip();
614601
}
@@ -624,10 +611,11 @@
624611
html = "artifact <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
625612
}else{
626613
html = "check-in <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
627614
}
628615
tooltipInfo.ixActive = -2;
616
+ tooltipInfo.idNodeActive = tooltipInfo.nodeHover.id;
629617
}else if( tooltipInfo.ixHover>=0 ){
630618
ix = tooltipInfo.ixHover
631619
var br = tx.rowinfo[ix].br
632620
var dest = branchHyperlink(ix)
633621
var hbr = br.replace(/&/g, "&amp;")
@@ -635,10 +623,11 @@
635623
.replace(/>/g, "&gt;")
636624
.replace(/"/g, "&quot;")
637625
.replace(/'/g, "&#039;");
638626
html = "branch <a id=\"tooltip-link\" href=\""+dest+"\">"+hbr+"</a>"
639627
tooltipInfo.ixActive = ix;
628
+ tooltipInfo.idNodeActive = 0;
640629
}
641630
if( html ){
642631
/* Setup while hidden, to ensure proper dimensions. */
643632
var s = getComputedStyle(document.body)
644633
if( tx.rowinfo[ix].bg.length ){
645634
--- src/graph.js
+++ src/graph.js
@@ -116,10 +116,11 @@
116 ** over a graph node. Or -1 when the mouse is not
117 ** over anything. */
118 ixActive: -1, /* The item shown in the tooltip is tx.rowinfo[ixActive].
119 ** ixActive is -1 if the tooltip is not visible */
120 nodeHover: null, /* Graph node under mouse when ixHover==-2 */
 
121 posX: 0, posY: 0 /* The last mouse position. */
122 };
123
124 /* Functions used to control the tooltip popup and its timer */
125 function onKeyDown(event){ /* Hide the tooltip when ESC key pressed */
@@ -132,10 +133,11 @@
132 function hideGraphTooltip(){ /* Hide the tooltip */
133 document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
134 stopCloseTimer();
135 tooltipObj.style.display = "none";
136 tooltipInfo.ixActive = -1;
 
137 }
138 document.body.onunload = hideGraphTooltip
139 function stopDwellTimer(){
140 if(tooltipInfo.idTimer!=0){
141 clearTimeout(tooltipInfo.idTimer);
@@ -169,36 +171,11 @@
169 topObj.onclick = clickOnGraph
170 topObj.ondblclick = dblclickOnGraph
171 topObj.onmousemove = function(e) {
172 var ix = findTxIndex(e);
173 topObj.style.cursor = (ix<0) ? "" : "pointer"
174 /* Keep the already visible tooltip at a constant position, as long as the
175 ** mouse is over the same element. */
176 if(tooltipObj.style.display != "none"){
177 if(ix == tooltipInfo.ixHover) return;
178 }
179 /* The tooltip is either not visible, or the mouse is over a different
180 ** element, so clear the dwell timer, and record the new element id and
181 ** mouse position. */
182 stopDwellTimer();
183 if(ix >= 0){
184 tooltipInfo.ixHover = ix;
185 tooltipInfo.posX = e.clientX;
186 tooltipInfo.posY = e.clientY;
187 stopCloseTimer();
188 if(tooltipInfo.dwellTimeout>0){
189 tooltipInfo.idTimer = setTimeout(function() {
190 tooltipInfo.idTimer = 0;
191 stopCloseTimer();
192 showGraphTooltip();
193 },tooltipInfo.dwellTimeout);
194 }
195 }else{
196 /* The mouse is not over an element with a tooltip */
197 tooltipInfo.ixHover = -1;
198 resumeCloseTimer();
199 }
200 };
201 topObj.onmouseleave = function(e) {
202 /* Hide the tooltip if the mouse is outside the "timelineTableN" element,
203 ** and outside the tooltip. */
204 if(e.relatedTarget && e.relatedTarget != tooltipObj){
@@ -208,18 +185,26 @@
208 stopCloseTimer();
209 }
210 };
211 function mouseOverNode(e){ /* Invoked by mousemove events over a graph node */
212 e.stopPropagation()
213 if(tooltipInfo.ixHover==-2) return
214 tooltipInfo.ixHover = -2
215 tooltipInfo.posX = e.clientX
216 tooltipInfo.posY = e.clientY
217 tooltipInfo.nodeHover = this
218 stopCloseTimer();
219 if(tooltipInfo.dwellTimeout>0){
220 tooltipInfo.idTimer = setTimeout(function() {
 
 
 
 
 
 
 
 
221 tooltipInfo.idTimer = 0;
222 stopCloseTimer();
223 showGraphTooltip();
224 },tooltipInfo.dwellTimeout);
225 }
@@ -605,10 +590,12 @@
605 dest += tx.fileDiff ? "&m&cf=" : "&m&c="
606 dest += encodeURIComponent(tx.rowinfo[ix].h)
607 return dest
608 }
609 function clickOnGraph(e){
 
 
610 tooltipInfo.ixHover = findTxIndex(e);
611 tooltipInfo.posX = e.clientX;
612 tooltipInfo.posY = e.clientY;
613 showGraphTooltip();
614 }
@@ -624,10 +611,11 @@
624 html = "artifact <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
625 }else{
626 html = "check-in <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
627 }
628 tooltipInfo.ixActive = -2;
 
629 }else if( tooltipInfo.ixHover>=0 ){
630 ix = tooltipInfo.ixHover
631 var br = tx.rowinfo[ix].br
632 var dest = branchHyperlink(ix)
633 var hbr = br.replace(/&/g, "&amp;")
@@ -635,10 +623,11 @@
635 .replace(/>/g, "&gt;")
636 .replace(/"/g, "&quot;")
637 .replace(/'/g, "&#039;");
638 html = "branch <a id=\"tooltip-link\" href=\""+dest+"\">"+hbr+"</a>"
639 tooltipInfo.ixActive = ix;
 
640 }
641 if( html ){
642 /* Setup while hidden, to ensure proper dimensions. */
643 var s = getComputedStyle(document.body)
644 if( tx.rowinfo[ix].bg.length ){
645
--- src/graph.js
+++ src/graph.js
@@ -116,10 +116,11 @@
116 ** over a graph node. Or -1 when the mouse is not
117 ** over anything. */
118 ixActive: -1, /* The item shown in the tooltip is tx.rowinfo[ixActive].
119 ** ixActive is -1 if the tooltip is not visible */
120 nodeHover: null, /* Graph node under mouse when ixHover==-2 */
121 idNodeActive: 0, /* Element ID of the graph node with the tooltip. */
122 posX: 0, posY: 0 /* The last mouse position. */
123 };
124
125 /* Functions used to control the tooltip popup and its timer */
126 function onKeyDown(event){ /* Hide the tooltip when ESC key pressed */
@@ -132,10 +133,11 @@
133 function hideGraphTooltip(){ /* Hide the tooltip */
134 document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
135 stopCloseTimer();
136 tooltipObj.style.display = "none";
137 tooltipInfo.ixActive = -1;
138 tooltipInfo.idNodeActive = 0;
139 }
140 document.body.onunload = hideGraphTooltip
141 function stopDwellTimer(){
142 if(tooltipInfo.idTimer!=0){
143 clearTimeout(tooltipInfo.idTimer);
@@ -169,36 +171,11 @@
171 topObj.onclick = clickOnGraph
172 topObj.ondblclick = dblclickOnGraph
173 topObj.onmousemove = function(e) {
174 var ix = findTxIndex(e);
175 topObj.style.cursor = (ix<0) ? "" : "pointer"
176 mouseOverGraph(e,ix,null);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177 };
178 topObj.onmouseleave = function(e) {
179 /* Hide the tooltip if the mouse is outside the "timelineTableN" element,
180 ** and outside the tooltip. */
181 if(e.relatedTarget && e.relatedTarget != tooltipObj){
@@ -208,18 +185,26 @@
185 stopCloseTimer();
186 }
187 };
188 function mouseOverNode(e){ /* Invoked by mousemove events over a graph node */
189 e.stopPropagation()
190 mouseOverGraph(e,-2,this)
191 }
192 /* Combined mousemove handler for graph nodes and rails. */
193 function mouseOverGraph(e,ix,node){
194 stopDwellTimer(); // Mouse movement: reset the dwell timer.
195 var ownTooltip = // Check if the hovered element already has the tooltip.
196 (ix!=-2 && ix==tooltipInfo.ixHover && ix==tooltipInfo.ixActive) ||
197 (ix==-2 && tooltipInfo.ixHover==-2 && tooltipInfo.idNodeActive==node.id);
198 if(ownTooltip) stopCloseTimer(); // ownTooltip: clear the close timer.
199 else resumeCloseTimer(); // !ownTooltip: resume the close timer.
200 tooltipInfo.ixHover = ix;
201 tooltipInfo.nodeHover = node;
202 tooltipInfo.posX = e.clientX;
203 tooltipInfo.posY = e.clientY;
204 if(ix!=-1 && !ownTooltip && tooltipInfo.dwellTimeout>0){ // Go dwell timer.
205 tooltipInfo.idTimer = setTimeout(function(){
206 tooltipInfo.idTimer = 0;
207 stopCloseTimer();
208 showGraphTooltip();
209 },tooltipInfo.dwellTimeout);
210 }
@@ -605,10 +590,12 @@
590 dest += tx.fileDiff ? "&m&cf=" : "&m&c="
591 dest += encodeURIComponent(tx.rowinfo[ix].h)
592 return dest
593 }
594 function clickOnGraph(e){
595 stopCloseTimer();
596 stopDwellTimer();
597 tooltipInfo.ixHover = findTxIndex(e);
598 tooltipInfo.posX = e.clientX;
599 tooltipInfo.posY = e.clientY;
600 showGraphTooltip();
601 }
@@ -624,10 +611,11 @@
611 html = "artifact <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
612 }else{
613 html = "check-in <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
614 }
615 tooltipInfo.ixActive = -2;
616 tooltipInfo.idNodeActive = tooltipInfo.nodeHover.id;
617 }else if( tooltipInfo.ixHover>=0 ){
618 ix = tooltipInfo.ixHover
619 var br = tx.rowinfo[ix].br
620 var dest = branchHyperlink(ix)
621 var hbr = br.replace(/&/g, "&amp;")
@@ -635,10 +623,11 @@
623 .replace(/>/g, "&gt;")
624 .replace(/"/g, "&quot;")
625 .replace(/'/g, "&#039;");
626 html = "branch <a id=\"tooltip-link\" href=\""+dest+"\">"+hbr+"</a>"
627 tooltipInfo.ixActive = ix;
628 tooltipInfo.idNodeActive = 0;
629 }
630 if( html ){
631 /* Setup while hidden, to ensure proper dimensions. */
632 var s = getComputedStyle(document.body)
633 if( tx.rowinfo[ix].bg.length ){
634

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button