Fossil SCM

Single-click to get the tooltip. Double-click to hyperlink to the branch graph. Click is approximate and does not require a direct hit on the graph line.

drh 2019-05-18 02:07 tooltips
Commit 9dc74546513b070a641d4c0ab26a745d7eaca7a7db32a55b81212d8f55526787
2 files changed +65 -31 +5 -1
+65 -31
--- src/graph.js
+++ src/graph.js
@@ -77,17 +77,21 @@
7777
var tooltipObj = document.createElement("span");
7878
tooltipObj.className = "tl-tooltip";
7979
tooltipObj.style.visibility = "hidden";
8080
document.getElementsByClassName("content")[0].appendChild(tooltipObj);
8181
82
+/* Construct that graph corresponding to the timeline-data-N object */
8283
function TimelineGraph(tx){
8384
var topObj = document.getElementById("timelineTable"+tx.iTableId);
8485
amendCss(tx.circleNodes, tx.showArrowheads);
86
+ topObj.onclick = clickOnGraph
87
+ topObj.ondblclick = dblclickOnGraph
8588
var canvasDiv;
8689
var railPitch;
8790
var mergeOffset;
8891
var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
92
+
8993
function initGraph(){
9094
var parent = topObj.rows[0].cells[1];
9195
parent.style.verticalAlign = "top";
9296
canvasDiv = document.createElement("div");
9397
canvasDiv.className = "tl-canvas";
@@ -167,17 +171,22 @@
167171
n.className = "tl-"+cls;
168172
canvasDiv.appendChild(n);
169173
return n;
170174
}
171175
function absoluteY(obj){
172
- var top = 0;
173
- if( obj.offsetParent ){
174
- do{
175
- top += obj.offsetTop;
176
- }while( obj = obj.offsetParent );
177
- }
178
- return top;
176
+ var y = 0;
177
+ do{
178
+ y += obj.offsetTop;
179
+ }while( obj = obj.offsetParent );
180
+ return y;
181
+ }
182
+ function absoluteX(obj){
183
+ var x = 0;
184
+ do{
185
+ x += obj.offsetLeft;
186
+ }while( obj = obj.offsetParent );
187
+ return x;
179188
}
180189
function miLineY(p){
181190
return p.y + node.h - mLine.w - 1;
182191
}
183192
function drawLine(elem,color,x0,y0,x1,y1){
@@ -212,16 +221,11 @@
212221
var n = drawLine(dotLine,null,x,y0,null,y1)
213222
if( color ) n.style.borderColor = color
214223
addToolTip(n,id)
215224
}
216225
function addToolTip(n,id){
217
- if( id ){
218
- n.onmouseenter = tooltipEnter
219
- n.onmouseleave = tooltipLeave
220
- n.onclick = tooltipClick
221
- n.setAttribute("data-ix",id-tx.iTopRow)
222
- }
226
+ if( id ) n.setAttribute("data-ix",id-tx.iTopRow)
223227
}
224228
/* Draw thin horizontal or vertical lines representing merges */
225229
function drawMergeLine(x0,y0,x1,y1){
226230
drawLine(mLine,null,x0,y0,x1,y1);
227231
}
@@ -267,10 +271,11 @@
267271
if( p.f&1 ) cls += " leaf";
268272
var n = drawBox(cls,p.bg,p.x,p.y);
269273
n.id = "tln"+p.id;
270274
addToolTip(n,p.id)
271275
n.onclick = clickOnNode;
276
+ n.ondblclick = dblclickOnNode;
272277
n.style.zIndex = 10;
273278
if( !tx.omitDescenders ){
274279
if( p.u==0 ){
275280
if( p.hasOwnProperty('mo') && p.r==p.mo ){
276281
var ix = p.hasOwnProperty('cu') ? p.cu : p.mu;
@@ -406,11 +411,11 @@
406411
for( var i=tx.rowinfo.length-1; i>=0; i-- ){
407412
drawNode(tx.rowinfo[i], btm);
408413
}
409414
}
410415
var selRow;
411
- function clickOnNode(){
416
+ function clickOnNode(e){
412417
var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
413418
if( !selRow ){
414419
selRow = p;
415420
this.className += " sel";
416421
canvasDiv.className += " sel";
@@ -423,32 +428,61 @@
423428
location.href=tx.baseUrl + "/fdiff?v1="+selRow.h+"&v2="+p.h
424429
}else{
425430
location.href=tx.baseUrl + "/vdiff?from="+selRow.h+"&to="+p.h
426431
}
427432
}
428
- }
429
- function tooltipEnter(e){
430
- var ix = this.getAttribute("data-ix")
431
- tooltipObj.textContent = tx.rowinfo[ix].br
432
- tooltipObj.style.display = "inline"
433
- tooltipObj.style.position = "absolute"
434
- var x = e.x + 4 + window.pageXOffset
435
- tooltipObj.style.left = x+"px"
436
- var y = e.y + window.pageYOffset - tooltipObj.clientHeight - 4
437
- tooltipObj.style.top = y+"px"
438
- tooltipObj.style.visibility = "visible"
439
- }
440
- function tooltipClick(e){
441
- var ix = this.getAttribute("data-ix")
433
+ e.stopPropagation()
434
+ }
435
+ function dblclickOnNode(e){
436
+ var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
437
+ window.location.href = tx.baseUrl+"/info/"+p.h
438
+ e.stopPropagation()
439
+ }
440
+ function findTxIndex(e){
441
+ /* Look at all the graph elements. If any graph elements that is near
442
+ ** the click-point "e" and has a "data-ix" attribute, then return
443
+ ** the value of that attribute. Otherwise return -1 */
444
+ var x = e.x + window.pageXOffset - absoluteX(canvasDiv);
445
+ var y = e.y + window.pageYOffset - absoluteY(canvasDiv);
446
+ var aNode = canvasDiv.childNodes
447
+ var nNode = aNode.length;
448
+ var i;
449
+ for(i=0;i<nNode;i++){
450
+ var n = aNode[i]
451
+ if( !n.hasAttribute("data-ix") ) continue;
452
+ if( x<n.offsetLeft-5 ) continue;
453
+ if( x>n.offsetLeft+n.offsetWidth+5 ) continue;
454
+ if( y<n.offsetTop-5 ) continue;
455
+ if( y>n.offsetTop+n.offsetHeight ) continue;
456
+ return n.getAttribute("data-ix")
457
+ }
458
+ return -1
459
+ }
460
+ function clickOnGraph(e){
461
+ var ix = findTxIndex(e);
462
+ if( ix<0 ){
463
+ tooltipObj.style.display = "none"
464
+ }else{
465
+ tooltipObj.textContent = tx.rowinfo[ix].br
466
+ tooltipObj.style.display = "inline"
467
+ tooltipObj.style.position = "absolute"
468
+ var x = e.x + 4 + window.pageXOffset
469
+ tooltipObj.style.left = x+"px"
470
+ var y = e.y + window.pageYOffset - tooltipObj.clientHeight - 4
471
+ tooltipObj.style.top = y+"px"
472
+ tooltipObj.style.visibility = "visible"
473
+ }
474
+ }
475
+ function dblclickOnGraph(e){
476
+ if( tx.fileDiff ) return
477
+ var ix = findTxIndex(e);
442478
var br = tx.rowinfo[ix].br
443479
var dest = "/timeline?r=" + encodeURIComponent(br)
480
+ dest += "&c=" + encodeURIComponent(tx.rowinfo[ix].h)
444481
tooltipObj.style.display = "none"
445482
window.location.href = tx.baseUrl + dest
446483
}
447
- function tooltipLeave(e){
448
- tooltipObj.style.display = "none"
449
- }
450484
function changeDisplay(selector,value){
451485
var x = document.getElementsByClassName(selector);
452486
var n = x.length;
453487
for(var i=0; i<n; i++) {x[i].style.display = value;}
454488
}
455489
--- src/graph.js
+++ src/graph.js
@@ -77,17 +77,21 @@
77 var tooltipObj = document.createElement("span");
78 tooltipObj.className = "tl-tooltip";
79 tooltipObj.style.visibility = "hidden";
80 document.getElementsByClassName("content")[0].appendChild(tooltipObj);
81
 
82 function TimelineGraph(tx){
83 var topObj = document.getElementById("timelineTable"+tx.iTableId);
84 amendCss(tx.circleNodes, tx.showArrowheads);
 
 
85 var canvasDiv;
86 var railPitch;
87 var mergeOffset;
88 var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
 
89 function initGraph(){
90 var parent = topObj.rows[0].cells[1];
91 parent.style.verticalAlign = "top";
92 canvasDiv = document.createElement("div");
93 canvasDiv.className = "tl-canvas";
@@ -167,17 +171,22 @@
167 n.className = "tl-"+cls;
168 canvasDiv.appendChild(n);
169 return n;
170 }
171 function absoluteY(obj){
172 var top = 0;
173 if( obj.offsetParent ){
174 do{
175 top += obj.offsetTop;
176 }while( obj = obj.offsetParent );
177 }
178 return top;
 
 
 
 
 
179 }
180 function miLineY(p){
181 return p.y + node.h - mLine.w - 1;
182 }
183 function drawLine(elem,color,x0,y0,x1,y1){
@@ -212,16 +221,11 @@
212 var n = drawLine(dotLine,null,x,y0,null,y1)
213 if( color ) n.style.borderColor = color
214 addToolTip(n,id)
215 }
216 function addToolTip(n,id){
217 if( id ){
218 n.onmouseenter = tooltipEnter
219 n.onmouseleave = tooltipLeave
220 n.onclick = tooltipClick
221 n.setAttribute("data-ix",id-tx.iTopRow)
222 }
223 }
224 /* Draw thin horizontal or vertical lines representing merges */
225 function drawMergeLine(x0,y0,x1,y1){
226 drawLine(mLine,null,x0,y0,x1,y1);
227 }
@@ -267,10 +271,11 @@
267 if( p.f&1 ) cls += " leaf";
268 var n = drawBox(cls,p.bg,p.x,p.y);
269 n.id = "tln"+p.id;
270 addToolTip(n,p.id)
271 n.onclick = clickOnNode;
 
272 n.style.zIndex = 10;
273 if( !tx.omitDescenders ){
274 if( p.u==0 ){
275 if( p.hasOwnProperty('mo') && p.r==p.mo ){
276 var ix = p.hasOwnProperty('cu') ? p.cu : p.mu;
@@ -406,11 +411,11 @@
406 for( var i=tx.rowinfo.length-1; i>=0; i-- ){
407 drawNode(tx.rowinfo[i], btm);
408 }
409 }
410 var selRow;
411 function clickOnNode(){
412 var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
413 if( !selRow ){
414 selRow = p;
415 this.className += " sel";
416 canvasDiv.className += " sel";
@@ -423,32 +428,61 @@
423 location.href=tx.baseUrl + "/fdiff?v1="+selRow.h+"&v2="+p.h
424 }else{
425 location.href=tx.baseUrl + "/vdiff?from="+selRow.h+"&to="+p.h
426 }
427 }
428 }
429 function tooltipEnter(e){
430 var ix = this.getAttribute("data-ix")
431 tooltipObj.textContent = tx.rowinfo[ix].br
432 tooltipObj.style.display = "inline"
433 tooltipObj.style.position = "absolute"
434 var x = e.x + 4 + window.pageXOffset
435 tooltipObj.style.left = x+"px"
436 var y = e.y + window.pageYOffset - tooltipObj.clientHeight - 4
437 tooltipObj.style.top = y+"px"
438 tooltipObj.style.visibility = "visible"
439 }
440 function tooltipClick(e){
441 var ix = this.getAttribute("data-ix")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442 var br = tx.rowinfo[ix].br
443 var dest = "/timeline?r=" + encodeURIComponent(br)
 
444 tooltipObj.style.display = "none"
445 window.location.href = tx.baseUrl + dest
446 }
447 function tooltipLeave(e){
448 tooltipObj.style.display = "none"
449 }
450 function changeDisplay(selector,value){
451 var x = document.getElementsByClassName(selector);
452 var n = x.length;
453 for(var i=0; i<n; i++) {x[i].style.display = value;}
454 }
455
--- src/graph.js
+++ src/graph.js
@@ -77,17 +77,21 @@
77 var tooltipObj = document.createElement("span");
78 tooltipObj.className = "tl-tooltip";
79 tooltipObj.style.visibility = "hidden";
80 document.getElementsByClassName("content")[0].appendChild(tooltipObj);
81
82 /* Construct that graph corresponding to the timeline-data-N object */
83 function TimelineGraph(tx){
84 var topObj = document.getElementById("timelineTable"+tx.iTableId);
85 amendCss(tx.circleNodes, tx.showArrowheads);
86 topObj.onclick = clickOnGraph
87 topObj.ondblclick = dblclickOnGraph
88 var canvasDiv;
89 var railPitch;
90 var mergeOffset;
91 var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
92
93 function initGraph(){
94 var parent = topObj.rows[0].cells[1];
95 parent.style.verticalAlign = "top";
96 canvasDiv = document.createElement("div");
97 canvasDiv.className = "tl-canvas";
@@ -167,17 +171,22 @@
171 n.className = "tl-"+cls;
172 canvasDiv.appendChild(n);
173 return n;
174 }
175 function absoluteY(obj){
176 var y = 0;
177 do{
178 y += obj.offsetTop;
179 }while( obj = obj.offsetParent );
180 return y;
181 }
182 function absoluteX(obj){
183 var x = 0;
184 do{
185 x += obj.offsetLeft;
186 }while( obj = obj.offsetParent );
187 return x;
188 }
189 function miLineY(p){
190 return p.y + node.h - mLine.w - 1;
191 }
192 function drawLine(elem,color,x0,y0,x1,y1){
@@ -212,16 +221,11 @@
221 var n = drawLine(dotLine,null,x,y0,null,y1)
222 if( color ) n.style.borderColor = color
223 addToolTip(n,id)
224 }
225 function addToolTip(n,id){
226 if( id ) n.setAttribute("data-ix",id-tx.iTopRow)
 
 
 
 
 
227 }
228 /* Draw thin horizontal or vertical lines representing merges */
229 function drawMergeLine(x0,y0,x1,y1){
230 drawLine(mLine,null,x0,y0,x1,y1);
231 }
@@ -267,10 +271,11 @@
271 if( p.f&1 ) cls += " leaf";
272 var n = drawBox(cls,p.bg,p.x,p.y);
273 n.id = "tln"+p.id;
274 addToolTip(n,p.id)
275 n.onclick = clickOnNode;
276 n.ondblclick = dblclickOnNode;
277 n.style.zIndex = 10;
278 if( !tx.omitDescenders ){
279 if( p.u==0 ){
280 if( p.hasOwnProperty('mo') && p.r==p.mo ){
281 var ix = p.hasOwnProperty('cu') ? p.cu : p.mu;
@@ -406,11 +411,11 @@
411 for( var i=tx.rowinfo.length-1; i>=0; i-- ){
412 drawNode(tx.rowinfo[i], btm);
413 }
414 }
415 var selRow;
416 function clickOnNode(e){
417 var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
418 if( !selRow ){
419 selRow = p;
420 this.className += " sel";
421 canvasDiv.className += " sel";
@@ -423,32 +428,61 @@
428 location.href=tx.baseUrl + "/fdiff?v1="+selRow.h+"&v2="+p.h
429 }else{
430 location.href=tx.baseUrl + "/vdiff?from="+selRow.h+"&to="+p.h
431 }
432 }
433 e.stopPropagation()
434 }
435 function dblclickOnNode(e){
436 var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
437 window.location.href = tx.baseUrl+"/info/"+p.h
438 e.stopPropagation()
439 }
440 function findTxIndex(e){
441 /* Look at all the graph elements. If any graph elements that is near
442 ** the click-point "e" and has a "data-ix" attribute, then return
443 ** the value of that attribute. Otherwise return -1 */
444 var x = e.x + window.pageXOffset - absoluteX(canvasDiv);
445 var y = e.y + window.pageYOffset - absoluteY(canvasDiv);
446 var aNode = canvasDiv.childNodes
447 var nNode = aNode.length;
448 var i;
449 for(i=0;i<nNode;i++){
450 var n = aNode[i]
451 if( !n.hasAttribute("data-ix") ) continue;
452 if( x<n.offsetLeft-5 ) continue;
453 if( x>n.offsetLeft+n.offsetWidth+5 ) continue;
454 if( y<n.offsetTop-5 ) continue;
455 if( y>n.offsetTop+n.offsetHeight ) continue;
456 return n.getAttribute("data-ix")
457 }
458 return -1
459 }
460 function clickOnGraph(e){
461 var ix = findTxIndex(e);
462 if( ix<0 ){
463 tooltipObj.style.display = "none"
464 }else{
465 tooltipObj.textContent = tx.rowinfo[ix].br
466 tooltipObj.style.display = "inline"
467 tooltipObj.style.position = "absolute"
468 var x = e.x + 4 + window.pageXOffset
469 tooltipObj.style.left = x+"px"
470 var y = e.y + window.pageYOffset - tooltipObj.clientHeight - 4
471 tooltipObj.style.top = y+"px"
472 tooltipObj.style.visibility = "visible"
473 }
474 }
475 function dblclickOnGraph(e){
476 if( tx.fileDiff ) return
477 var ix = findTxIndex(e);
478 var br = tx.rowinfo[ix].br
479 var dest = "/timeline?r=" + encodeURIComponent(br)
480 dest += "&c=" + encodeURIComponent(tx.rowinfo[ix].h)
481 tooltipObj.style.display = "none"
482 window.location.href = tx.baseUrl + dest
483 }
 
 
 
484 function changeDisplay(selector,value){
485 var x = document.getElementsByClassName(selector);
486 var n = x.length;
487 for(var i=0; i<n; i++) {x[i].style.display = value;}
488 }
489
+5 -1
--- src/style.c
+++ src/style.c
@@ -578,10 +578,14 @@
578578
int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0);
579579
@ <script id='href-data' type='application/json'>\
580580
@ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script>
581581
}
582582
@ <script nonce="%h(style_nonce())">
583
+ @ function debugMsg(msg){
584
+ @ var n = document.getElementById("debugMsg");
585
+ @ if(n){n.textContent=msg;}
586
+ @ }
583587
if( needHrefJs ){
584588
cgi_append_content(builtin_text("href.js"),-1);
585589
}
586590
if( needSortJs ){
587591
cgi_append_content(builtin_text("sorttable.js"),-1);
@@ -743,11 +747,11 @@
743747
if( zAd ){
744748
@ <div class="adunit_banner">
745749
cgi_append_content(zAd, -1);
746750
@ </div>
747751
}
748
- @ <div class="content">
752
+ @ <div class="content"><span id="debugMsg"></span>
749753
}
750754
cgi_destination(CGI_BODY);
751755
752756
if( sideboxUsed ){
753757
/* Put the footer at the bottom of the page.
754758
--- src/style.c
+++ src/style.c
@@ -578,10 +578,14 @@
578 int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0);
579 @ <script id='href-data' type='application/json'>\
580 @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script>
581 }
582 @ <script nonce="%h(style_nonce())">
 
 
 
 
583 if( needHrefJs ){
584 cgi_append_content(builtin_text("href.js"),-1);
585 }
586 if( needSortJs ){
587 cgi_append_content(builtin_text("sorttable.js"),-1);
@@ -743,11 +747,11 @@
743 if( zAd ){
744 @ <div class="adunit_banner">
745 cgi_append_content(zAd, -1);
746 @ </div>
747 }
748 @ <div class="content">
749 }
750 cgi_destination(CGI_BODY);
751
752 if( sideboxUsed ){
753 /* Put the footer at the bottom of the page.
754
--- src/style.c
+++ src/style.c
@@ -578,10 +578,14 @@
578 int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0);
579 @ <script id='href-data' type='application/json'>\
580 @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script>
581 }
582 @ <script nonce="%h(style_nonce())">
583 @ function debugMsg(msg){
584 @ var n = document.getElementById("debugMsg");
585 @ if(n){n.textContent=msg;}
586 @ }
587 if( needHrefJs ){
588 cgi_append_content(builtin_text("href.js"),-1);
589 }
590 if( needSortJs ){
591 cgi_append_content(builtin_text("sorttable.js"),-1);
@@ -743,11 +747,11 @@
747 if( zAd ){
748 @ <div class="adunit_banner">
749 cgi_append_content(zAd, -1);
750 @ </div>
751 }
752 @ <div class="content"><span id="debugMsg"></span>
753 }
754 cgi_destination(CGI_BODY);
755
756 if( sideboxUsed ){
757 /* Put the footer at the bottom of the page.
758

Keyboard Shortcuts

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