Fossil SCM
The tooltip over a graph node shows a link to the check-in or artifact that the node represents, not a link to the branch.
Commit
fa811f95c46f6d8180b758fd83fac4a567d564c27be6c85e157884f5fcf4530e
Parent
c0f8f57835fe368…
1 file changed
+41
-16
+41
-16
| --- src/graph.js | ||
| +++ src/graph.js | ||
| @@ -101,10 +101,11 @@ | ||
| 101 | 101 | closeTimeout: 3000, /* The tooltip close timeout. */ |
| 102 | 102 | idTimer: 0, /* The tooltip dwell timer id. */ |
| 103 | 103 | idTimerClose: 0, /* The tooltip close timer id. */ |
| 104 | 104 | ixHover: -1, /* The id of the element with the mouse. */ |
| 105 | 105 | ixActive: -1, /* The id of the element with the tooltip. */ |
| 106 | + nodeHover: null, /* Graph node under mouse when ixHover==-2 */ | |
| 106 | 107 | posX: 0, posY: 0 /* The last mouse position. */ |
| 107 | 108 | }; |
| 108 | 109 | |
| 109 | 110 | /* Functions used to control the tooltip popup and its timer */ |
| 110 | 111 | function hideGraphTooltip(){ |
| @@ -146,37 +147,30 @@ | ||
| 146 | 147 | topObj.onmousemove = function(e) { |
| 147 | 148 | var ix = findTxIndex(e); |
| 148 | 149 | topObj.style.cursor = (ix<0) ? "" : "pointer" |
| 149 | 150 | /* Keep the already visible tooltip at a constant position, as long as the |
| 150 | 151 | ** mouse is over the same element. */ |
| 151 | - var isReentry = false; // Detect mouse move back to same element. | |
| 152 | 152 | if(tooltipObj.style.display != "none"){ |
| 153 | 153 | if(ix == tooltipInfo.ixHover) return; |
| 154 | - if(-1==tooltipInfo.ixHover && ix==tooltipInfo.ixActive) isReentry = true; | |
| 155 | 154 | } |
| 156 | 155 | /* The tooltip is either not visible, or the mouse is over a different |
| 157 | 156 | ** element, so clear the dwell timer, and record the new element id and |
| 158 | 157 | ** mouse position. */ |
| 159 | 158 | stopDwellTimer(); |
| 160 | 159 | if(ix >= 0){ |
| 161 | - if(!isReentry){ | |
| 162 | - /* Close existing tooltip only if the mouse is over a different element */ | |
| 163 | - hideGraphTooltip(); | |
| 164 | - } | |
| 165 | 160 | tooltipInfo.ixHover = ix; |
| 166 | 161 | tooltipInfo.posX = e.x; |
| 167 | 162 | tooltipInfo.posY = e.y; |
| 168 | 163 | stopCloseTimer(); |
| 169 | - if (!isReentry && tooltipInfo.dwellTimeout>0) { | |
| 164 | + if(tooltipInfo.dwellTimeout>0){ | |
| 170 | 165 | tooltipInfo.idTimer = setTimeout(function() { |
| 171 | 166 | tooltipInfo.idTimer = 0; |
| 172 | 167 | stopCloseTimer(); |
| 173 | 168 | showGraphTooltip(); |
| 174 | 169 | },tooltipInfo.dwellTimeout); |
| 175 | 170 | } |
| 176 | - } | |
| 177 | - else { | |
| 171 | + }else{ | |
| 178 | 172 | /* The mouse is not over an element with a tooltip */ |
| 179 | 173 | tooltipInfo.ixHover = -1; |
| 180 | 174 | resumeCloseTimer(); |
| 181 | 175 | } |
| 182 | 176 | }; |
| @@ -188,10 +182,27 @@ | ||
| 188 | 182 | hideGraphTooltip(); |
| 189 | 183 | stopDwellTimer(); |
| 190 | 184 | stopCloseTimer(); |
| 191 | 185 | } |
| 192 | 186 | }; |
| 187 | + function nodeHover(e){ | |
| 188 | + /* Invoked by mousemove events over a graph node */ | |
| 189 | + e.stopPropagation() | |
| 190 | + if(tooltipInfo.ixHover==-2) return | |
| 191 | + tooltipInfo.ixHover = -2 | |
| 192 | + tooltipInfo.posX = e.x | |
| 193 | + tooltipInfo.posY = e.y | |
| 194 | + tooltipInfo.nodeHover = this | |
| 195 | + stopCloseTimer(); | |
| 196 | + if(tooltipInfo.dwellTimeout>0){ | |
| 197 | + tooltipInfo.idTimer = setTimeout(function() { | |
| 198 | + tooltipInfo.idTimer = 0; | |
| 199 | + stopCloseTimer(); | |
| 200 | + showGraphTooltip(); | |
| 201 | + },tooltipInfo.dwellTimeout); | |
| 202 | + } | |
| 203 | + } | |
| 193 | 204 | var canvasDiv; |
| 194 | 205 | var railPitch; |
| 195 | 206 | var mergeOffset; |
| 196 | 207 | var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine; |
| 197 | 208 | |
| @@ -374,13 +385,13 @@ | ||
| 374 | 385 | var cls = node.cls; |
| 375 | 386 | if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge"; |
| 376 | 387 | if( p.f&1 ) cls += " leaf"; |
| 377 | 388 | var n = drawBox(cls,p.bg,p.x,p.y); |
| 378 | 389 | n.id = "tln"+p.id; |
| 379 | - addToolTip(n,p.id) | |
| 380 | 390 | n.onclick = clickOnNode; |
| 381 | 391 | n.ondblclick = dblclickOnNode; |
| 392 | + n.onmousemove = nodeHover; | |
| 382 | 393 | n.style.zIndex = 10; |
| 383 | 394 | if( !tx.omitDescenders ){ |
| 384 | 395 | if( p.u==0 ){ |
| 385 | 396 | if( p.hasOwnProperty('mo') && p.r==p.mo ){ |
| 386 | 397 | var ix = p.hasOwnProperty('cu') ? p.cu : p.mu; |
| @@ -576,32 +587,46 @@ | ||
| 576 | 587 | tooltipInfo.posX = e.x; |
| 577 | 588 | tooltipInfo.posY = e.y; |
| 578 | 589 | showGraphTooltip(); |
| 579 | 590 | } |
| 580 | 591 | function showGraphTooltip(){ |
| 581 | - if( tooltipInfo.ixHoever<0 ){ | |
| 582 | - hideGraphTooltip() | |
| 583 | - }else{ | |
| 592 | + var html = null | |
| 593 | + if( tooltipInfo.ixHover==-2 ){ | |
| 594 | + var ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow | |
| 595 | + var h = tx.rowinfo[ix].h | |
| 596 | + var dest = tx.baseUrl + "/info/" + h | |
| 597 | + if( tx.fileDiff ){ | |
| 598 | + html = "<a href=\""+dest+"\">artifact "+h+"</a>" | |
| 599 | + }else{ | |
| 600 | + html = "<a href=\""+dest+"\">check-in "+h+"</a>" | |
| 601 | + } | |
| 602 | + }else if( tooltipInfo.ixHover>=0 ){ | |
| 584 | 603 | var ix = tooltipInfo.ixHover |
| 585 | 604 | var br = tx.rowinfo[ix].br |
| 586 | 605 | var dest = branchHyperlink(ix) |
| 587 | 606 | var hbr = br.replace(/&/g, "&") |
| 588 | 607 | .replace(/</g, "<") |
| 589 | 608 | .replace(/>/g, ">") |
| 590 | 609 | .replace(/"/g, """) |
| 591 | 610 | .replace(/'/g, "'"); |
| 611 | + html = "<a href=\""+dest+"\">"+hbr+"</a>" | |
| 612 | + tooltipInfo.ixActive = ix; | |
| 613 | + } | |
| 614 | + if( html ){ | |
| 592 | 615 | /* Setup while hidden, to ensure proper dimensions. */ |
| 593 | 616 | tooltipObj.style.visibility = "hidden" |
| 594 | - tooltipObj.innerHTML = "<a href=\""+dest+"\">"+hbr+"</a>" | |
| 617 | + tooltipObj.innerHTML = html | |
| 595 | 618 | tooltipObj.style.display = "inline" |
| 596 | 619 | tooltipObj.style.position = "absolute" |
| 597 | 620 | var x = tooltipInfo.posX + 4 + window.pageXOffset |
| 598 | 621 | tooltipObj.style.left = x+"px" |
| 599 | - var y = tooltipInfo.posY + window.pageYOffset - tooltipObj.clientHeight - 4 | |
| 622 | + var y = tooltipInfo.posY + window.pageYOffset | |
| 623 | + - tooltipObj.clientHeight - 4 | |
| 600 | 624 | tooltipObj.style.top = y+"px" |
| 601 | 625 | tooltipObj.style.visibility = "visible" |
| 602 | - tooltipInfo.ixActive = ix; | |
| 626 | + }else{ | |
| 627 | + hideGraphTooltip() | |
| 603 | 628 | } |
| 604 | 629 | } |
| 605 | 630 | function dblclickOnGraph(e){ |
| 606 | 631 | var ix = findTxIndex(e); |
| 607 | 632 | var dest = branchHyperlink(ix) |
| 608 | 633 |
| --- src/graph.js | |
| +++ src/graph.js | |
| @@ -101,10 +101,11 @@ | |
| 101 | closeTimeout: 3000, /* The tooltip close timeout. */ |
| 102 | idTimer: 0, /* The tooltip dwell timer id. */ |
| 103 | idTimerClose: 0, /* The tooltip close timer id. */ |
| 104 | ixHover: -1, /* The id of the element with the mouse. */ |
| 105 | ixActive: -1, /* The id of the element with the tooltip. */ |
| 106 | posX: 0, posY: 0 /* The last mouse position. */ |
| 107 | }; |
| 108 | |
| 109 | /* Functions used to control the tooltip popup and its timer */ |
| 110 | function hideGraphTooltip(){ |
| @@ -146,37 +147,30 @@ | |
| 146 | topObj.onmousemove = function(e) { |
| 147 | var ix = findTxIndex(e); |
| 148 | topObj.style.cursor = (ix<0) ? "" : "pointer" |
| 149 | /* Keep the already visible tooltip at a constant position, as long as the |
| 150 | ** mouse is over the same element. */ |
| 151 | var isReentry = false; // Detect mouse move back to same element. |
| 152 | if(tooltipObj.style.display != "none"){ |
| 153 | if(ix == tooltipInfo.ixHover) return; |
| 154 | if(-1==tooltipInfo.ixHover && ix==tooltipInfo.ixActive) isReentry = true; |
| 155 | } |
| 156 | /* The tooltip is either not visible, or the mouse is over a different |
| 157 | ** element, so clear the dwell timer, and record the new element id and |
| 158 | ** mouse position. */ |
| 159 | stopDwellTimer(); |
| 160 | if(ix >= 0){ |
| 161 | if(!isReentry){ |
| 162 | /* Close existing tooltip only if the mouse is over a different element */ |
| 163 | hideGraphTooltip(); |
| 164 | } |
| 165 | tooltipInfo.ixHover = ix; |
| 166 | tooltipInfo.posX = e.x; |
| 167 | tooltipInfo.posY = e.y; |
| 168 | stopCloseTimer(); |
| 169 | if (!isReentry && tooltipInfo.dwellTimeout>0) { |
| 170 | tooltipInfo.idTimer = setTimeout(function() { |
| 171 | tooltipInfo.idTimer = 0; |
| 172 | stopCloseTimer(); |
| 173 | showGraphTooltip(); |
| 174 | },tooltipInfo.dwellTimeout); |
| 175 | } |
| 176 | } |
| 177 | else { |
| 178 | /* The mouse is not over an element with a tooltip */ |
| 179 | tooltipInfo.ixHover = -1; |
| 180 | resumeCloseTimer(); |
| 181 | } |
| 182 | }; |
| @@ -188,10 +182,27 @@ | |
| 188 | hideGraphTooltip(); |
| 189 | stopDwellTimer(); |
| 190 | stopCloseTimer(); |
| 191 | } |
| 192 | }; |
| 193 | var canvasDiv; |
| 194 | var railPitch; |
| 195 | var mergeOffset; |
| 196 | var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine; |
| 197 | |
| @@ -374,13 +385,13 @@ | |
| 374 | var cls = node.cls; |
| 375 | if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge"; |
| 376 | if( p.f&1 ) cls += " leaf"; |
| 377 | var n = drawBox(cls,p.bg,p.x,p.y); |
| 378 | n.id = "tln"+p.id; |
| 379 | addToolTip(n,p.id) |
| 380 | n.onclick = clickOnNode; |
| 381 | n.ondblclick = dblclickOnNode; |
| 382 | n.style.zIndex = 10; |
| 383 | if( !tx.omitDescenders ){ |
| 384 | if( p.u==0 ){ |
| 385 | if( p.hasOwnProperty('mo') && p.r==p.mo ){ |
| 386 | var ix = p.hasOwnProperty('cu') ? p.cu : p.mu; |
| @@ -576,32 +587,46 @@ | |
| 576 | tooltipInfo.posX = e.x; |
| 577 | tooltipInfo.posY = e.y; |
| 578 | showGraphTooltip(); |
| 579 | } |
| 580 | function showGraphTooltip(){ |
| 581 | if( tooltipInfo.ixHoever<0 ){ |
| 582 | hideGraphTooltip() |
| 583 | }else{ |
| 584 | var ix = tooltipInfo.ixHover |
| 585 | var br = tx.rowinfo[ix].br |
| 586 | var dest = branchHyperlink(ix) |
| 587 | var hbr = br.replace(/&/g, "&") |
| 588 | .replace(/</g, "<") |
| 589 | .replace(/>/g, ">") |
| 590 | .replace(/"/g, """) |
| 591 | .replace(/'/g, "'"); |
| 592 | /* Setup while hidden, to ensure proper dimensions. */ |
| 593 | tooltipObj.style.visibility = "hidden" |
| 594 | tooltipObj.innerHTML = "<a href=\""+dest+"\">"+hbr+"</a>" |
| 595 | tooltipObj.style.display = "inline" |
| 596 | tooltipObj.style.position = "absolute" |
| 597 | var x = tooltipInfo.posX + 4 + window.pageXOffset |
| 598 | tooltipObj.style.left = x+"px" |
| 599 | var y = tooltipInfo.posY + window.pageYOffset - tooltipObj.clientHeight - 4 |
| 600 | tooltipObj.style.top = y+"px" |
| 601 | tooltipObj.style.visibility = "visible" |
| 602 | tooltipInfo.ixActive = ix; |
| 603 | } |
| 604 | } |
| 605 | function dblclickOnGraph(e){ |
| 606 | var ix = findTxIndex(e); |
| 607 | var dest = branchHyperlink(ix) |
| 608 |
| --- src/graph.js | |
| +++ src/graph.js | |
| @@ -101,10 +101,11 @@ | |
| 101 | closeTimeout: 3000, /* The tooltip close timeout. */ |
| 102 | idTimer: 0, /* The tooltip dwell timer id. */ |
| 103 | idTimerClose: 0, /* The tooltip close timer id. */ |
| 104 | ixHover: -1, /* The id of the element with the mouse. */ |
| 105 | ixActive: -1, /* The id of the element with the tooltip. */ |
| 106 | nodeHover: null, /* Graph node under mouse when ixHover==-2 */ |
| 107 | posX: 0, posY: 0 /* The last mouse position. */ |
| 108 | }; |
| 109 | |
| 110 | /* Functions used to control the tooltip popup and its timer */ |
| 111 | function hideGraphTooltip(){ |
| @@ -146,37 +147,30 @@ | |
| 147 | topObj.onmousemove = function(e) { |
| 148 | var ix = findTxIndex(e); |
| 149 | topObj.style.cursor = (ix<0) ? "" : "pointer" |
| 150 | /* Keep the already visible tooltip at a constant position, as long as the |
| 151 | ** mouse is over the same element. */ |
| 152 | if(tooltipObj.style.display != "none"){ |
| 153 | if(ix == tooltipInfo.ixHover) return; |
| 154 | } |
| 155 | /* The tooltip is either not visible, or the mouse is over a different |
| 156 | ** element, so clear the dwell timer, and record the new element id and |
| 157 | ** mouse position. */ |
| 158 | stopDwellTimer(); |
| 159 | if(ix >= 0){ |
| 160 | tooltipInfo.ixHover = ix; |
| 161 | tooltipInfo.posX = e.x; |
| 162 | tooltipInfo.posY = e.y; |
| 163 | stopCloseTimer(); |
| 164 | if(tooltipInfo.dwellTimeout>0){ |
| 165 | tooltipInfo.idTimer = setTimeout(function() { |
| 166 | tooltipInfo.idTimer = 0; |
| 167 | stopCloseTimer(); |
| 168 | showGraphTooltip(); |
| 169 | },tooltipInfo.dwellTimeout); |
| 170 | } |
| 171 | }else{ |
| 172 | /* The mouse is not over an element with a tooltip */ |
| 173 | tooltipInfo.ixHover = -1; |
| 174 | resumeCloseTimer(); |
| 175 | } |
| 176 | }; |
| @@ -188,10 +182,27 @@ | |
| 182 | hideGraphTooltip(); |
| 183 | stopDwellTimer(); |
| 184 | stopCloseTimer(); |
| 185 | } |
| 186 | }; |
| 187 | function nodeHover(e){ |
| 188 | /* Invoked by mousemove events over a graph node */ |
| 189 | e.stopPropagation() |
| 190 | if(tooltipInfo.ixHover==-2) return |
| 191 | tooltipInfo.ixHover = -2 |
| 192 | tooltipInfo.posX = e.x |
| 193 | tooltipInfo.posY = e.y |
| 194 | tooltipInfo.nodeHover = this |
| 195 | stopCloseTimer(); |
| 196 | if(tooltipInfo.dwellTimeout>0){ |
| 197 | tooltipInfo.idTimer = setTimeout(function() { |
| 198 | tooltipInfo.idTimer = 0; |
| 199 | stopCloseTimer(); |
| 200 | showGraphTooltip(); |
| 201 | },tooltipInfo.dwellTimeout); |
| 202 | } |
| 203 | } |
| 204 | var canvasDiv; |
| 205 | var railPitch; |
| 206 | var mergeOffset; |
| 207 | var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine; |
| 208 | |
| @@ -374,13 +385,13 @@ | |
| 385 | var cls = node.cls; |
| 386 | if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge"; |
| 387 | if( p.f&1 ) cls += " leaf"; |
| 388 | var n = drawBox(cls,p.bg,p.x,p.y); |
| 389 | n.id = "tln"+p.id; |
| 390 | n.onclick = clickOnNode; |
| 391 | n.ondblclick = dblclickOnNode; |
| 392 | n.onmousemove = nodeHover; |
| 393 | n.style.zIndex = 10; |
| 394 | if( !tx.omitDescenders ){ |
| 395 | if( p.u==0 ){ |
| 396 | if( p.hasOwnProperty('mo') && p.r==p.mo ){ |
| 397 | var ix = p.hasOwnProperty('cu') ? p.cu : p.mu; |
| @@ -576,32 +587,46 @@ | |
| 587 | tooltipInfo.posX = e.x; |
| 588 | tooltipInfo.posY = e.y; |
| 589 | showGraphTooltip(); |
| 590 | } |
| 591 | function showGraphTooltip(){ |
| 592 | var html = null |
| 593 | if( tooltipInfo.ixHover==-2 ){ |
| 594 | var ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow |
| 595 | var h = tx.rowinfo[ix].h |
| 596 | var dest = tx.baseUrl + "/info/" + h |
| 597 | if( tx.fileDiff ){ |
| 598 | html = "<a href=\""+dest+"\">artifact "+h+"</a>" |
| 599 | }else{ |
| 600 | html = "<a href=\""+dest+"\">check-in "+h+"</a>" |
| 601 | } |
| 602 | }else if( tooltipInfo.ixHover>=0 ){ |
| 603 | var ix = tooltipInfo.ixHover |
| 604 | var br = tx.rowinfo[ix].br |
| 605 | var dest = branchHyperlink(ix) |
| 606 | var hbr = br.replace(/&/g, "&") |
| 607 | .replace(/</g, "<") |
| 608 | .replace(/>/g, ">") |
| 609 | .replace(/"/g, """) |
| 610 | .replace(/'/g, "'"); |
| 611 | html = "<a href=\""+dest+"\">"+hbr+"</a>" |
| 612 | tooltipInfo.ixActive = ix; |
| 613 | } |
| 614 | if( html ){ |
| 615 | /* Setup while hidden, to ensure proper dimensions. */ |
| 616 | tooltipObj.style.visibility = "hidden" |
| 617 | tooltipObj.innerHTML = html |
| 618 | tooltipObj.style.display = "inline" |
| 619 | tooltipObj.style.position = "absolute" |
| 620 | var x = tooltipInfo.posX + 4 + window.pageXOffset |
| 621 | tooltipObj.style.left = x+"px" |
| 622 | var y = tooltipInfo.posY + window.pageYOffset |
| 623 | - tooltipObj.clientHeight - 4 |
| 624 | tooltipObj.style.top = y+"px" |
| 625 | tooltipObj.style.visibility = "visible" |
| 626 | }else{ |
| 627 | hideGraphTooltip() |
| 628 | } |
| 629 | } |
| 630 | function dblclickOnGraph(e){ |
| 631 | var ix = findTxIndex(e); |
| 632 | var dest = branchHyperlink(ix) |
| 633 |