| | @@ -211,11 +211,12 @@ |
| 211 | 211 | if( tmFlags & TIMELINE_GRAPH ){ |
| 212 | 212 | pGraph = graph_init(); |
| 213 | 213 | /* style is not moved to css, because this is |
| 214 | 214 | ** a technical div for the timeline graph |
| 215 | 215 | */ |
| 216 | | - @ <div id="canvas" style="position:relative;width:1px;height:1px;"></div> |
| 216 | + @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 217 | + @ onclick="clickOnGraph(event)"></div> |
| 217 | 218 | } |
| 218 | 219 | db_static_prepare(&qbranch, |
| 219 | 220 | "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid", |
| 220 | 221 | TAG_BRANCH |
| 221 | 222 | ); |
| | @@ -311,11 +312,12 @@ |
| 311 | 312 | db_bind_int(&qparent, ":rid", rid); |
| 312 | 313 | while( db_step(&qparent)==SQLITE_ROW && nParent<32 ){ |
| 313 | 314 | aParent[nParent++] = db_column_int(&qparent, 0); |
| 314 | 315 | } |
| 315 | 316 | db_reset(&qparent); |
| 316 | | - gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr, isLeaf); |
| 317 | + gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr, |
| 318 | + zUuid, isLeaf); |
| 317 | 319 | db_reset(&qbranch); |
| 318 | 320 | @ <div id="m%d(gidx)"></div> |
| 319 | 321 | } |
| 320 | 322 | @</td> |
| 321 | 323 | if( zBgClr && zBgClr[0] ){ |
| | @@ -491,18 +493,22 @@ |
| 491 | 493 | @ </td><td></td></tr> |
| 492 | 494 | } |
| 493 | 495 | } |
| 494 | 496 | @ </table> |
| 495 | 497 | if( fchngQueryInit ) db_finalize(&fchngQuery); |
| 496 | | - timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0); |
| 498 | + timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0); |
| 497 | 499 | } |
| 498 | 500 | |
| 499 | 501 | /* |
| 500 | 502 | ** Generate all of the necessary javascript to generate a timeline |
| 501 | 503 | ** graph. |
| 502 | 504 | */ |
| 503 | | -void timeline_output_graph_javascript(GraphContext *pGraph, int omitDescenders){ |
| 505 | +void timeline_output_graph_javascript( |
| 506 | + GraphContext *pGraph, /* The graph to be displayed */ |
| 507 | + int omitDescenders, /* True to omit descenders */ |
| 508 | + int fileDiff /* True for file diff. False for check-in diff */ |
| 509 | +){ |
| 504 | 510 | if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){ |
| 505 | 511 | GraphRow *pRow; |
| 506 | 512 | int i; |
| 507 | 513 | char cSep; |
| 508 | 514 | @ <script type="text/JavaScript"> |
| | @@ -535,10 +541,11 @@ |
| 535 | 541 | ** mi: "merge-in". An array of integer x-coordinates from which |
| 536 | 542 | ** merge arrows should be drawn into this node. If the value is |
| 537 | 543 | ** negative, then the x-coordinate is the absolute value of mi[] |
| 538 | 544 | ** and a thin merge-arrow descender is drawn to the bottom of |
| 539 | 545 | ** the screen. |
| 546 | + ** h: The SHA1 hash of the object being graphed |
| 540 | 547 | */ |
| 541 | 548 | cgi_printf("var rowinfo = [\n"); |
| 542 | 549 | for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){ |
| 543 | 550 | int mo = pRow->mergeOut; |
| 544 | 551 | if( mo<0 ){ |
| | @@ -576,11 +583,11 @@ |
| 576 | 583 | cgi_printf("%c%d", cSep, mi); |
| 577 | 584 | cSep = ','; |
| 578 | 585 | } |
| 579 | 586 | } |
| 580 | 587 | if( cSep=='[' ) cgi_printf("["); |
| 581 | | - cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n"); |
| 588 | + cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n"); |
| 582 | 589 | } |
| 583 | 590 | cgi_printf("var nrail = %d\n", pGraph->mxRail+1); |
| 584 | 591 | graph_free(pGraph); |
| 585 | 592 | @ var canvasDiv = gebi("canvas"); |
| 586 | 593 | #if 0 |
| | @@ -598,10 +605,11 @@ |
| 598 | 605 | @ n.style.top = y0+"px"; |
| 599 | 606 | @ n.style.width = w+"px"; |
| 600 | 607 | @ n.style.height = h+"px"; |
| 601 | 608 | @ n.style.backgroundColor = color; |
| 602 | 609 | @ canvasDiv.appendChild(n); |
| 610 | + @ return n; |
| 603 | 611 | @ } |
| 604 | 612 | @ function absoluteY(id){ |
| 605 | 613 | @ var obj = gebi(id); |
| 606 | 614 | @ if( !obj ) return; |
| 607 | 615 | @ var top = 0; |
| | @@ -699,10 +707,12 @@ |
| 699 | 707 | @ }else{ |
| 700 | 708 | @ drawThinArrow(y0,mx,p.x-5); |
| 701 | 709 | @ } |
| 702 | 710 | @ } |
| 703 | 711 | @ } |
| 712 | + @ var selBox = null; |
| 713 | + @ var selRow = null; |
| 704 | 714 | @ function renderGraph(){ |
| 705 | 715 | @ var canvasDiv = gebi("canvas"); |
| 706 | 716 | @ while( canvasDiv.hasChildNodes() ){ |
| 707 | 717 | @ canvasDiv.removeChild(canvasDiv.firstChild); |
| 708 | 718 | @ } |
| | @@ -736,10 +746,41 @@ |
| 736 | 746 | @ }; |
| 737 | 747 | @ } |
| 738 | 748 | #endif |
| 739 | 749 | @ for(var i in rowinfo){ |
| 740 | 750 | @ drawNode(rowinfo[i], left, btm); |
| 751 | + @ } |
| 752 | + @ if( selRow!=null ) clickOnRow(selRow); |
| 753 | + @ } |
| 754 | + @ function clickOnGraph(event){ |
| 755 | + @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset; |
| 756 | + @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset; |
| 757 | + @ for(var i in rowinfo){ |
| 758 | + @ p = rowinfo[i]; |
| 759 | + @ if( p.y<y-10 ) continue; |
| 760 | + @ if( p.y>y+10 ) break; |
| 761 | + @ if( p.x>x-10 && p.x<x+10 ){ |
| 762 | + @ clickOnRow(p); |
| 763 | + @ break; |
| 764 | + @ } |
| 765 | + @ } |
| 766 | + @ } |
| 767 | + @ function clickOnRow(p){ |
| 768 | + @ if( selRow==null ){ |
| 769 | + @ selBox = drawBox("red",p.x-2,p.y-2,p.x+3,p.y+3); |
| 770 | + @ selRow = p; |
| 771 | + @ }else if( selRow==p ){ |
| 772 | + @ var canvasDiv = gebi("canvas"); |
| 773 | + @ canvasDiv.removeChild(selBox); |
| 774 | + @ selBox = null; |
| 775 | + @ selRow = null; |
| 776 | + @ }else{ |
| 777 | + if( fileDiff ){ |
| 778 | + @ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h; |
| 779 | + }else{ |
| 780 | + @ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h; |
| 781 | + } |
| 741 | 782 | @ } |
| 742 | 783 | @ } |
| 743 | 784 | @ var lastId = "m"+rowinfo[rowinfo.length-1].id; |
| 744 | 785 | @ var lastY = 0; |
| 745 | 786 | @ function checkHeight(){ |
| 746 | 787 | |