Fossil SCM
Work toward getting the mode selector to work on /timeline. This check-in is incomplete and is intended only to transfer code between machines.
Commit
fdf071e1819d01caf7c631970eedc994009e82a22cc864e809bc497db09248fa
Parent
0f446ca69dfa93f…
1 file changed
+130
-113
+130
-113
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -103,10 +103,13 @@ | ||
| 103 | 103 | #define TIMELINE_UCOLOR 0x0080 /* Background color by user */ |
| 104 | 104 | #define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */ |
| 105 | 105 | #define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */ |
| 106 | 106 | #define TIMELINE_SHOWRID 0x0400 /* Show RID values in addition to UUIDs */ |
| 107 | 107 | #define TIMELINE_BISECT 0x0800 /* Show supplimental bisect information */ |
| 108 | +#define TIMELINE_COMPACT 0x1000 /* Use the "compact" view style */ | |
| 109 | +#define TIMELINE_DETAILED 0x2000 /* Use the "detailed" view style */ | |
| 110 | +#define TIMELINE_NORMAL 0x4000 /* Use the "normal" view style */ | |
| 108 | 111 | #endif |
| 109 | 112 | |
| 110 | 113 | /* |
| 111 | 114 | ** Hash a string and use the hash to determine a background color. |
| 112 | 115 | */ |
| @@ -248,10 +251,11 @@ | ||
| 248 | 251 | static Stmt qbranch; |
| 249 | 252 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | 253 | int vid = 0; /* Current checkout version */ |
| 251 | 254 | int dateFormat = 0; /* 0: HH:MM (default) */ |
| 252 | 255 | int bCommentGitStyle = 0; /* Only show comments through first blank line */ |
| 256 | + const char *zTdClass; | |
| 253 | 257 | int bHashBeforeComment = 0; /* Show hash before the comment */ |
| 254 | 258 | int bHashAfterComment = 0; /* Show hash after the comment */ |
| 255 | 259 | int bHashInDetail = 0; /* Show the hash inside the detail section */ |
| 256 | 260 | int bShowDetail; /* Show the detail section */ |
| 257 | 261 | int bSeparateDetail; /* Detail in a separate column */ |
| @@ -264,22 +268,16 @@ | ||
| 264 | 268 | } |
| 265 | 269 | zPrevDate[0] = 0; |
| 266 | 270 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 267 | 271 | dateFormat = db_get_int("timeline-date-format", 0); |
| 268 | 272 | bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0); |
| 269 | - { | |
| 270 | - /* Undocumented query parameter commentformat=N takes a numeric parameter to | |
| 271 | - ** adjust the comment-format for testing purposes. */ | |
| 272 | - const char *z = P("commentformat"); | |
| 273 | - eCommentFormat = z ? atoi(z) : db_get_int("timeline-comment-format", 4); | |
| 274 | - } | |
| 275 | - bShowDetail = (eCommentFormat & 1)==0; /* Bit 0 suppresses the comment */ | |
| 276 | - bSeparateDetail = (eCommentFormat & 8)!=0; /* Bit 3 turns on the detail column */ | |
| 277 | - switch( (eCommentFormat>>1)&3 ){ | |
| 278 | - case 1: bHashAfterComment = 1; break; | |
| 279 | - case 2: bHashInDetail = 1; break; | |
| 280 | - default: bHashBeforeComment = 1; break; | |
| 273 | + if( tmFlags & TIMELINE_NORMAL ){ | |
| 274 | + zTdClass = "timelineStyleNormal"; | |
| 275 | + }else if( tmFlags & TIMELINE_COMPACT ){ | |
| 276 | + zTdClass = "timelineStyleCompact"; | |
| 277 | + }else if( tmFlags & TIMELINE_DETAILED ){ | |
| 278 | + zTdClass = "timelineStyleDetailed"; | |
| 281 | 279 | } |
| 282 | 280 | zDateFmt = P("datefmt"); |
| 283 | 281 | if( zDateFmt ) dateFormat = atoi(zDateFmt); |
| 284 | 282 | if( tmFlags & TIMELINE_GRAPH ){ |
| 285 | 283 | pGraph = graph_init(); |
| @@ -304,11 +302,11 @@ | ||
| 304 | 302 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 305 | 303 | const char *zBr = 0; /* Branch */ |
| 306 | 304 | int commentColumn = 3; /* Column containing comment text */ |
| 307 | 305 | int modPending; /* Pending moderation */ |
| 308 | 306 | char *zDateLink; /* URL for the link on the timestamp */ |
| 309 | - int drawDetailEllipsis = 1; /* True to show ellipsis in place of detail */ | |
| 307 | + int drawDetailEllipsis; /* True to show ellipsis in place of detail */ | |
| 310 | 308 | char zTime[20]; |
| 311 | 309 | |
| 312 | 310 | if( zDate==0 ){ |
| 313 | 311 | zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */ |
| 314 | 312 | } |
| @@ -441,13 +439,13 @@ | ||
| 441 | 439 | db_reset(&qbranch); |
| 442 | 440 | @ <div id="m%d(gidx)" class="tl-nodemark"></div> |
| 443 | 441 | } |
| 444 | 442 | @</td> |
| 445 | 443 | if( zBgClr && zBgClr[0] && rid!=selectedRid ){ |
| 446 | - @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> | |
| 444 | + @ <td class="timelineTableCell %s(zTdClass)" style="background-color: %h(zBgClr);"> | |
| 447 | 445 | }else{ |
| 448 | - @ <td class="timelineTableCell"> | |
| 446 | + @ <td class="timelineTableCell %s(zTdClass)"> | |
| 449 | 447 | } |
| 450 | 448 | if( pGraph && zType[0]!='c' ){ |
| 451 | 449 | @ • |
| 452 | 450 | } |
| 453 | 451 | if( modPending ){ |
| @@ -461,10 +459,11 @@ | ||
| 461 | 459 | @ <b>%s(db_column_text(&bisectQuery,1))</b> |
| 462 | 460 | @ (%d(db_column_int(&bisectQuery,0))) |
| 463 | 461 | } |
| 464 | 462 | db_reset(&bisectQuery); |
| 465 | 463 | } |
| 464 | +#if 0 | |
| 466 | 465 | if( bHashBeforeComment ){ |
| 467 | 466 | if( zType[0]=='c' ){ |
| 468 | 467 | hyperlink_to_uuid(zUuid); |
| 469 | 468 | if( isLeaf ){ |
| 470 | 469 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -487,10 +486,12 @@ | ||
| 487 | 486 | }else{ |
| 488 | 487 | @ (%d(rid)) |
| 489 | 488 | } |
| 490 | 489 | } |
| 491 | 490 | } |
| 491 | +#endif | |
| 492 | + drawDetailEllipsis = (tmFlags & TIMELINE_COMPACT)!=0; | |
| 492 | 493 | db_column_blob(pQuery, commentColumn, &comment); |
| 493 | 494 | if( zType[0]!='c' ){ |
| 494 | 495 | /* Comments for anything other than a check-in are generated by |
| 495 | 496 | ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */ |
| 496 | 497 | @ <span class='timelineComment' onclick='toggleDetail(%d(rid))'> |
| @@ -525,10 +526,11 @@ | ||
| 525 | 526 | } |
| 526 | 527 | @ </span> |
| 527 | 528 | } |
| 528 | 529 | blob_reset(&comment); |
| 529 | 530 | |
| 531 | +#if 0 | |
| 530 | 532 | if( bHashAfterComment ){ |
| 531 | 533 | if( zType[0]=='c' ){ |
| 532 | 534 | hyperlink_to_uuid(zUuid); |
| 533 | 535 | if( isLeaf ){ |
| 534 | 536 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -552,111 +554,110 @@ | ||
| 552 | 554 | @ (%d(rid)) |
| 553 | 555 | } |
| 554 | 556 | } |
| 555 | 557 | drawDetailEllipsis = 1; |
| 556 | 558 | } |
| 557 | - | |
| 559 | +#endif | |
| 558 | 560 | |
| 559 | 561 | /* Generate extra information and hyperlinks to follow the comment. |
| 560 | 562 | ** Example: "(check-in: [abcdefg], user: drh, tags: trunk)" |
| 561 | 563 | */ |
| 562 | - if( bShowDetail ){ | |
| 563 | - if( drawDetailEllipsis ){ | |
| 564 | - @ <span class='timelineEllipsis anticlutter' id='ellipsis-%d(rid)' \ | |
| 565 | - @ onclick='toggleDetail(%d(rid))'>...</span> | |
| 566 | - } | |
| 567 | - if( bSeparateDetail ){ | |
| 568 | - if( zBgClr && zBgClr[0] && rid!=selectedRid ){ | |
| 569 | - @ <td class="timelineTableCell timelineDetailCell" | |
| 570 | - @ style="background-color: %h(zBgClr);"> | |
| 571 | - }else{ | |
| 572 | - @ <td class="timelineTableCell timelineDetailCell"> | |
| 573 | - } | |
| 574 | - } | |
| 575 | - cgi_printf("<span class='clutter' id='detail-%d'>", rid); | |
| 576 | - if( zType[0]=='c' ){ | |
| 577 | - cgi_printf("<span class='timelineDetail timelineCheckinDetail'>("); | |
| 578 | - }else{ | |
| 579 | - cgi_printf("<span class='timelineDetail'>("); | |
| 580 | - } | |
| 581 | - | |
| 582 | - if( bHashInDetail ){ | |
| 583 | - if( zType[0]=='c' ){ | |
| 584 | - if( isLeaf ){ | |
| 585 | - if( db_exists("SELECT 1 FROM tagxref" | |
| 586 | - " WHERE rid=%d AND tagid=%d AND tagtype>0", | |
| 587 | - rid, TAG_CLOSED) ){ | |
| 588 | - @ <span class='timelineLeaf'>Closed-Leaf</span> | |
| 589 | - }else{ | |
| 590 | - @ <span class='timelineLeaf'>Leaf</span> | |
| 591 | - } | |
| 592 | - } | |
| 593 | - cgi_printf("check-in: "); | |
| 594 | - hyperlink_to_uuid(zUuid); | |
| 595 | - }else if( zType[0]=='e' && tagid ){ | |
| 596 | - cgi_printf("technote: "); | |
| 597 | - hyperlink_to_event_tagid(tagid<0?-tagid:tagid); | |
| 598 | - }else{ | |
| 599 | - cgi_printf("artifact: "); | |
| 600 | - hyperlink_to_uuid(zUuid); | |
| 601 | - } | |
| 602 | - } | |
| 603 | - | |
| 604 | - if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){ | |
| 605 | - char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate); | |
| 606 | - cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser); | |
| 607 | - }else{ | |
| 608 | - cgi_printf("user: %h", zDispUser); | |
| 609 | - } | |
| 610 | - | |
| 611 | - /* Generate the "tags: TAGLIST" at the end of the comment, together | |
| 612 | - ** with hyperlinks to the tag list. | |
| 613 | - */ | |
| 614 | - if( zTagList && zTagList[0]==0 ) zTagList = 0; | |
| 615 | - if( zTagList ){ | |
| 616 | - if( g.perm.Hyperlink ){ | |
| 617 | - int i; | |
| 618 | - const char *z = zTagList; | |
| 619 | - Blob links; | |
| 620 | - blob_zero(&links); | |
| 621 | - while( z && z[0] ){ | |
| 622 | - for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){} | |
| 623 | - if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){ | |
| 624 | - blob_appendf(&links, | |
| 625 | - "%z%#h</a>%.2s", | |
| 626 | - href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i] | |
| 627 | - ); | |
| 628 | - }else{ | |
| 629 | - blob_appendf(&links, "%#h", i+2, z); | |
| 630 | - } | |
| 631 | - if( z[i]==0 ) break; | |
| 632 | - z += i+2; | |
| 633 | - } | |
| 634 | - cgi_printf(" tags: %s", blob_str(&links)); | |
| 635 | - blob_reset(&links); | |
| 636 | - }else{ | |
| 637 | - cgi_printf(" tags: %h", zTagList); | |
| 638 | - } | |
| 639 | - } | |
| 640 | - | |
| 641 | - if( tmFlags & TIMELINE_SHOWRID ){ | |
| 642 | - int srcId = delta_source_rid(rid); | |
| 643 | - if( srcId ){ | |
| 644 | - cgi_printf(" id: %d←%d", rid, srcId); | |
| 645 | - }else{ | |
| 646 | - cgi_printf(" id: %d", rid); | |
| 647 | - } | |
| 648 | - } | |
| 649 | - cgi_printf(")</span></span>\n"); /* End of the details section */ | |
| 650 | - } | |
| 651 | - | |
| 652 | - tag_private_status(rid); | |
| 653 | - | |
| 654 | - /* Generate extra hyperlinks at the end of the comment */ | |
| 564 | + if( drawDetailEllipsis ){ | |
| 565 | + @ <span class='timelineEllipsis anticlutter' id='ellipsis-%d(rid)' \ | |
| 566 | + @ onclick='toggleDetail(%d(rid))'>...</span> | |
| 567 | + } | |
| 568 | + if( bSeparateDetail ){ | |
| 569 | + if( zBgClr && zBgClr[0] && rid!=selectedRid ){ | |
| 570 | + @ <td class="timelineTableCell timelineDetailCell" | |
| 571 | + @ style="background-color: %h(zBgClr);"> | |
| 572 | + }else{ | |
| 573 | + @ <td class="timelineTableCell timelineDetailCell"> | |
| 574 | + } | |
| 575 | + } | |
| 576 | + if( tmFlags & TIMELINE_COMPACT ){ | |
| 577 | + cgi_printf("<span class='timelineDetailWrapper clutter' id='detail-%d'>", rid); | |
| 578 | + }else{ | |
| 579 | + cgi_printf("<span class='timelineDetailWrapper'>"); | |
| 580 | + } | |
| 581 | + if( zType[0]=='c' ){ | |
| 582 | + cgi_printf("<span class='timelineDetail timelineCheckinDetail'>"); | |
| 583 | + }else{ | |
| 584 | + cgi_printf("<span class='timelineDetail'>"); | |
| 585 | + } | |
| 586 | + | |
| 587 | + if( bHashInDetail ){ | |
| 588 | + if( zType[0]=='c' ){ | |
| 589 | + if( isLeaf ){ | |
| 590 | + if( db_exists("SELECT 1 FROM tagxref" | |
| 591 | + " WHERE rid=%d AND tagid=%d AND tagtype>0", | |
| 592 | + rid, TAG_CLOSED) ){ | |
| 593 | + @ <span class='timelineLeaf'>Closed-Leaf</span> | |
| 594 | + }else{ | |
| 595 | + @ <span class='timelineLeaf'>Leaf</span> | |
| 596 | + } | |
| 597 | + } | |
| 598 | + cgi_printf("check-in: "); | |
| 599 | + hyperlink_to_uuid(zUuid); | |
| 600 | + }else if( zType[0]=='e' && tagid ){ | |
| 601 | + cgi_printf("technote: "); | |
| 602 | + hyperlink_to_event_tagid(tagid<0?-tagid:tagid); | |
| 603 | + }else{ | |
| 604 | + cgi_printf("artifact: "); | |
| 605 | + hyperlink_to_uuid(zUuid); | |
| 606 | + } | |
| 607 | + } | |
| 608 | + | |
| 609 | + if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){ | |
| 610 | + char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate); | |
| 611 | + cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser); | |
| 612 | + }else{ | |
| 613 | + cgi_printf("user: %h", zDispUser); | |
| 614 | + } | |
| 615 | + | |
| 616 | + /* Generate the "tags: TAGLIST" at the end of the comment, together | |
| 617 | + ** with hyperlinks to the tag list. | |
| 618 | + */ | |
| 619 | + if( zTagList && zTagList[0]==0 ) zTagList = 0; | |
| 620 | + if( zTagList ){ | |
| 621 | + if( g.perm.Hyperlink ){ | |
| 622 | + int i; | |
| 623 | + const char *z = zTagList; | |
| 624 | + Blob links; | |
| 625 | + blob_zero(&links); | |
| 626 | + while( z && z[0] ){ | |
| 627 | + for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){} | |
| 628 | + if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){ | |
| 629 | + blob_appendf(&links, | |
| 630 | + "%z%#h</a>%.2s", | |
| 631 | + href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i] | |
| 632 | + ); | |
| 633 | + }else{ | |
| 634 | + blob_appendf(&links, "%#h", i+2, z); | |
| 635 | + } | |
| 636 | + if( z[i]==0 ) break; | |
| 637 | + z += i+2; | |
| 638 | + } | |
| 639 | + cgi_printf(" tags: %s", blob_str(&links)); | |
| 640 | + blob_reset(&links); | |
| 641 | + }else{ | |
| 642 | + cgi_printf(" tags: %h", zTagList); | |
| 643 | + } | |
| 644 | + } | |
| 645 | + | |
| 646 | + if( tmFlags & TIMELINE_SHOWRID ){ | |
| 647 | + int srcId = delta_source_rid(rid); | |
| 648 | + if( srcId ){ | |
| 649 | + cgi_printf(" id: %d←%d", rid, srcId); | |
| 650 | + }else{ | |
| 651 | + cgi_printf(" id: %d", rid); | |
| 652 | + } | |
| 653 | + } | |
| 654 | + tag_private_status(rid); | |
| 655 | 655 | if( xExtra ){ |
| 656 | 656 | xExtra(rid); |
| 657 | 657 | } |
| 658 | + cgi_printf("</span></span>\n"); /* End timelineDetail and timelineDetailWrapper */ | |
| 658 | 659 | |
| 659 | 660 | /* Generate the file-change list if requested */ |
| 660 | 661 | if( (tmFlags & (TIMELINE_FCHANGES|TIMELINE_FRENAMES))!=0 |
| 661 | 662 | && zType[0]=='c' && g.perm.Hyperlink |
| 662 | 663 | ){ |
| @@ -1356,11 +1357,11 @@ | ||
| 1356 | 1357 | az[i++] = "Wiki"; |
| 1357 | 1358 | } |
| 1358 | 1359 | assert( i<=count(az) ); |
| 1359 | 1360 | } |
| 1360 | 1361 | if( i>2 ){ |
| 1361 | - style_submenu_multichoice("y", i/2, az, isDisabled|STYLE_CLUTTER); | |
| 1362 | + style_submenu_multichoice("y", i/2, az, isDisabled); | |
| 1362 | 1363 | } |
| 1363 | 1364 | } |
| 1364 | 1365 | |
| 1365 | 1366 | /* |
| 1366 | 1367 | ** If the zChng string is not NULL, then it should be a comma-separated |
| @@ -1618,13 +1619,14 @@ | ||
| 1618 | 1619 | ** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN |
| 1619 | 1620 | ** t=TAG Show only check-ins with the given TAG |
| 1620 | 1621 | ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel |
| 1621 | 1622 | ** rel Show related check-ins as well as those matching t=TAG |
| 1622 | 1623 | ** mionly Limit rel to show ancestors but not descendants |
| 1623 | -** ms=STYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP | |
| 1624 | +** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP | |
| 1624 | 1625 | ** u=USER Only show items associated with USER |
| 1625 | -** y=TYPE 'ci', 'w', 't', 'e', or 'all'. 'ci' is the default. | |
| 1626 | +** y=TYPE 'ci', 'w', 't', 'e', or 'all'. | |
| 1627 | +** vs=VIEWSTYLE c: "compact" d: "detail" n: "normal" | |
| 1626 | 1628 | ** ng No Graph. |
| 1627 | 1629 | ** nd Do not highlight the focus check-in |
| 1628 | 1630 | ** v Show details of files changed |
| 1629 | 1631 | ** f=CHECKIN Show family (immediate parents and children) of CHECKIN |
| 1630 | 1632 | ** from=CHECKIN Path from... |
| @@ -1699,10 +1701,16 @@ | ||
| 1699 | 1701 | const char *z; |
| 1700 | 1702 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1701 | 1703 | char *zNewerButton = 0; /* URL for Newer button at the top */ |
| 1702 | 1704 | int selectedRid = -9999999; /* Show a highlight on this RID */ |
| 1703 | 1705 | int disableY = 0; /* Disable type selector on submenu */ |
| 1706 | + char cViewStyle; /* Overall style of the page */ | |
| 1707 | + static const char *azViewStyles[] = { | |
| 1708 | + "n", "Normal", | |
| 1709 | + "c", "Compact", | |
| 1710 | + "d", "Detailed", | |
| 1711 | + }; | |
| 1704 | 1712 | |
| 1705 | 1713 | /* Set number of rows to display */ |
| 1706 | 1714 | cookie_parse("fossil_display_settings"); |
| 1707 | 1715 | cookie_link_parameter("n","tln"); |
| 1708 | 1716 | z = P("n"); |
| @@ -1719,10 +1727,14 @@ | ||
| 1719 | 1727 | } |
| 1720 | 1728 | }else{ |
| 1721 | 1729 | cgi_replace_query_parameter("n","50"); |
| 1722 | 1730 | nEntry = 50; |
| 1723 | 1731 | } |
| 1732 | + cookie_link_parameter("vs","tlvs"); | |
| 1733 | + cViewStyle = PD("vs","n")[0]; | |
| 1734 | + style_submenu_multichoice("vs", 3, azViewStyles, 0); | |
| 1735 | + | |
| 1724 | 1736 | |
| 1725 | 1737 | /* To view the timeline, must have permission to read project data. |
| 1726 | 1738 | */ |
| 1727 | 1739 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 1728 | 1740 | if( pd_rid ){ |
| @@ -1792,10 +1804,15 @@ | ||
| 1792 | 1804 | "FROM tagxref NATURAL JOIN tag WHERE %s",zTagSql/*safe-for-%s*/)<=nEntry) |
| 1793 | 1805 | ){ |
| 1794 | 1806 | nEntry = -1; |
| 1795 | 1807 | zCirca = 0; |
| 1796 | 1808 | } |
| 1809 | + switch( cViewStyle ){ | |
| 1810 | + case 'n': tmFlags |= TIMELINE_NORMAL; break; | |
| 1811 | + case 'c': tmFlags |= TIMELINE_COMPACT; break; | |
| 1812 | + case 'd': tmFlags |= TIMELINE_DETAILED; break; | |
| 1813 | + } | |
| 1797 | 1814 | if( zType[0]=='a' ){ |
| 1798 | 1815 | tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; |
| 1799 | 1816 | }else{ |
| 1800 | 1817 | tmFlags |= TIMELINE_GRAPH; |
| 1801 | 1818 | } |
| @@ -2265,11 +2282,11 @@ | ||
| 2265 | 2282 | } |
| 2266 | 2283 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 2267 | 2284 | style_submenu_checkbox("unhide", "Unhide", STYLE_CLUTTER, 0); |
| 2268 | 2285 | } |
| 2269 | 2286 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c')|STYLE_CLUTTER,0); |
| 2270 | - style_submenu_entry("n","Max:",4,STYLE_CLUTTER); | |
| 2287 | + style_submenu_entry("n","Max:",4,0); | |
| 2271 | 2288 | timeline_y_submenu(disableY); |
| 2272 | 2289 | style_submenu_entry("t", "Tag Filter:", -8, STYLE_CLUTTER); |
| 2273 | 2290 | style_submenu_multichoice("ms", count(azMatchStyles)/2, azMatchStyles, STYLE_CLUTTER); |
| 2274 | 2291 | } |
| 2275 | 2292 | blob_zero(&cond); |
| 2276 | 2293 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -103,10 +103,13 @@ | |
| 103 | #define TIMELINE_UCOLOR 0x0080 /* Background color by user */ |
| 104 | #define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */ |
| 105 | #define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */ |
| 106 | #define TIMELINE_SHOWRID 0x0400 /* Show RID values in addition to UUIDs */ |
| 107 | #define TIMELINE_BISECT 0x0800 /* Show supplimental bisect information */ |
| 108 | #endif |
| 109 | |
| 110 | /* |
| 111 | ** Hash a string and use the hash to determine a background color. |
| 112 | */ |
| @@ -248,10 +251,11 @@ | |
| 248 | static Stmt qbranch; |
| 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | int vid = 0; /* Current checkout version */ |
| 251 | int dateFormat = 0; /* 0: HH:MM (default) */ |
| 252 | int bCommentGitStyle = 0; /* Only show comments through first blank line */ |
| 253 | int bHashBeforeComment = 0; /* Show hash before the comment */ |
| 254 | int bHashAfterComment = 0; /* Show hash after the comment */ |
| 255 | int bHashInDetail = 0; /* Show the hash inside the detail section */ |
| 256 | int bShowDetail; /* Show the detail section */ |
| 257 | int bSeparateDetail; /* Detail in a separate column */ |
| @@ -264,22 +268,16 @@ | |
| 264 | } |
| 265 | zPrevDate[0] = 0; |
| 266 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 267 | dateFormat = db_get_int("timeline-date-format", 0); |
| 268 | bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0); |
| 269 | { |
| 270 | /* Undocumented query parameter commentformat=N takes a numeric parameter to |
| 271 | ** adjust the comment-format for testing purposes. */ |
| 272 | const char *z = P("commentformat"); |
| 273 | eCommentFormat = z ? atoi(z) : db_get_int("timeline-comment-format", 4); |
| 274 | } |
| 275 | bShowDetail = (eCommentFormat & 1)==0; /* Bit 0 suppresses the comment */ |
| 276 | bSeparateDetail = (eCommentFormat & 8)!=0; /* Bit 3 turns on the detail column */ |
| 277 | switch( (eCommentFormat>>1)&3 ){ |
| 278 | case 1: bHashAfterComment = 1; break; |
| 279 | case 2: bHashInDetail = 1; break; |
| 280 | default: bHashBeforeComment = 1; break; |
| 281 | } |
| 282 | zDateFmt = P("datefmt"); |
| 283 | if( zDateFmt ) dateFormat = atoi(zDateFmt); |
| 284 | if( tmFlags & TIMELINE_GRAPH ){ |
| 285 | pGraph = graph_init(); |
| @@ -304,11 +302,11 @@ | |
| 304 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 305 | const char *zBr = 0; /* Branch */ |
| 306 | int commentColumn = 3; /* Column containing comment text */ |
| 307 | int modPending; /* Pending moderation */ |
| 308 | char *zDateLink; /* URL for the link on the timestamp */ |
| 309 | int drawDetailEllipsis = 1; /* True to show ellipsis in place of detail */ |
| 310 | char zTime[20]; |
| 311 | |
| 312 | if( zDate==0 ){ |
| 313 | zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */ |
| 314 | } |
| @@ -441,13 +439,13 @@ | |
| 441 | db_reset(&qbranch); |
| 442 | @ <div id="m%d(gidx)" class="tl-nodemark"></div> |
| 443 | } |
| 444 | @</td> |
| 445 | if( zBgClr && zBgClr[0] && rid!=selectedRid ){ |
| 446 | @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> |
| 447 | }else{ |
| 448 | @ <td class="timelineTableCell"> |
| 449 | } |
| 450 | if( pGraph && zType[0]!='c' ){ |
| 451 | @ • |
| 452 | } |
| 453 | if( modPending ){ |
| @@ -461,10 +459,11 @@ | |
| 461 | @ <b>%s(db_column_text(&bisectQuery,1))</b> |
| 462 | @ (%d(db_column_int(&bisectQuery,0))) |
| 463 | } |
| 464 | db_reset(&bisectQuery); |
| 465 | } |
| 466 | if( bHashBeforeComment ){ |
| 467 | if( zType[0]=='c' ){ |
| 468 | hyperlink_to_uuid(zUuid); |
| 469 | if( isLeaf ){ |
| 470 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -487,10 +486,12 @@ | |
| 487 | }else{ |
| 488 | @ (%d(rid)) |
| 489 | } |
| 490 | } |
| 491 | } |
| 492 | db_column_blob(pQuery, commentColumn, &comment); |
| 493 | if( zType[0]!='c' ){ |
| 494 | /* Comments for anything other than a check-in are generated by |
| 495 | ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */ |
| 496 | @ <span class='timelineComment' onclick='toggleDetail(%d(rid))'> |
| @@ -525,10 +526,11 @@ | |
| 525 | } |
| 526 | @ </span> |
| 527 | } |
| 528 | blob_reset(&comment); |
| 529 | |
| 530 | if( bHashAfterComment ){ |
| 531 | if( zType[0]=='c' ){ |
| 532 | hyperlink_to_uuid(zUuid); |
| 533 | if( isLeaf ){ |
| 534 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -552,111 +554,110 @@ | |
| 552 | @ (%d(rid)) |
| 553 | } |
| 554 | } |
| 555 | drawDetailEllipsis = 1; |
| 556 | } |
| 557 | |
| 558 | |
| 559 | /* Generate extra information and hyperlinks to follow the comment. |
| 560 | ** Example: "(check-in: [abcdefg], user: drh, tags: trunk)" |
| 561 | */ |
| 562 | if( bShowDetail ){ |
| 563 | if( drawDetailEllipsis ){ |
| 564 | @ <span class='timelineEllipsis anticlutter' id='ellipsis-%d(rid)' \ |
| 565 | @ onclick='toggleDetail(%d(rid))'>...</span> |
| 566 | } |
| 567 | if( bSeparateDetail ){ |
| 568 | if( zBgClr && zBgClr[0] && rid!=selectedRid ){ |
| 569 | @ <td class="timelineTableCell timelineDetailCell" |
| 570 | @ style="background-color: %h(zBgClr);"> |
| 571 | }else{ |
| 572 | @ <td class="timelineTableCell timelineDetailCell"> |
| 573 | } |
| 574 | } |
| 575 | cgi_printf("<span class='clutter' id='detail-%d'>", rid); |
| 576 | if( zType[0]=='c' ){ |
| 577 | cgi_printf("<span class='timelineDetail timelineCheckinDetail'>("); |
| 578 | }else{ |
| 579 | cgi_printf("<span class='timelineDetail'>("); |
| 580 | } |
| 581 | |
| 582 | if( bHashInDetail ){ |
| 583 | if( zType[0]=='c' ){ |
| 584 | if( isLeaf ){ |
| 585 | if( db_exists("SELECT 1 FROM tagxref" |
| 586 | " WHERE rid=%d AND tagid=%d AND tagtype>0", |
| 587 | rid, TAG_CLOSED) ){ |
| 588 | @ <span class='timelineLeaf'>Closed-Leaf</span> |
| 589 | }else{ |
| 590 | @ <span class='timelineLeaf'>Leaf</span> |
| 591 | } |
| 592 | } |
| 593 | cgi_printf("check-in: "); |
| 594 | hyperlink_to_uuid(zUuid); |
| 595 | }else if( zType[0]=='e' && tagid ){ |
| 596 | cgi_printf("technote: "); |
| 597 | hyperlink_to_event_tagid(tagid<0?-tagid:tagid); |
| 598 | }else{ |
| 599 | cgi_printf("artifact: "); |
| 600 | hyperlink_to_uuid(zUuid); |
| 601 | } |
| 602 | } |
| 603 | |
| 604 | if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){ |
| 605 | char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate); |
| 606 | cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser); |
| 607 | }else{ |
| 608 | cgi_printf("user: %h", zDispUser); |
| 609 | } |
| 610 | |
| 611 | /* Generate the "tags: TAGLIST" at the end of the comment, together |
| 612 | ** with hyperlinks to the tag list. |
| 613 | */ |
| 614 | if( zTagList && zTagList[0]==0 ) zTagList = 0; |
| 615 | if( zTagList ){ |
| 616 | if( g.perm.Hyperlink ){ |
| 617 | int i; |
| 618 | const char *z = zTagList; |
| 619 | Blob links; |
| 620 | blob_zero(&links); |
| 621 | while( z && z[0] ){ |
| 622 | for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){} |
| 623 | if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){ |
| 624 | blob_appendf(&links, |
| 625 | "%z%#h</a>%.2s", |
| 626 | href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i] |
| 627 | ); |
| 628 | }else{ |
| 629 | blob_appendf(&links, "%#h", i+2, z); |
| 630 | } |
| 631 | if( z[i]==0 ) break; |
| 632 | z += i+2; |
| 633 | } |
| 634 | cgi_printf(" tags: %s", blob_str(&links)); |
| 635 | blob_reset(&links); |
| 636 | }else{ |
| 637 | cgi_printf(" tags: %h", zTagList); |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | if( tmFlags & TIMELINE_SHOWRID ){ |
| 642 | int srcId = delta_source_rid(rid); |
| 643 | if( srcId ){ |
| 644 | cgi_printf(" id: %d←%d", rid, srcId); |
| 645 | }else{ |
| 646 | cgi_printf(" id: %d", rid); |
| 647 | } |
| 648 | } |
| 649 | cgi_printf(")</span></span>\n"); /* End of the details section */ |
| 650 | } |
| 651 | |
| 652 | tag_private_status(rid); |
| 653 | |
| 654 | /* Generate extra hyperlinks at the end of the comment */ |
| 655 | if( xExtra ){ |
| 656 | xExtra(rid); |
| 657 | } |
| 658 | |
| 659 | /* Generate the file-change list if requested */ |
| 660 | if( (tmFlags & (TIMELINE_FCHANGES|TIMELINE_FRENAMES))!=0 |
| 661 | && zType[0]=='c' && g.perm.Hyperlink |
| 662 | ){ |
| @@ -1356,11 +1357,11 @@ | |
| 1356 | az[i++] = "Wiki"; |
| 1357 | } |
| 1358 | assert( i<=count(az) ); |
| 1359 | } |
| 1360 | if( i>2 ){ |
| 1361 | style_submenu_multichoice("y", i/2, az, isDisabled|STYLE_CLUTTER); |
| 1362 | } |
| 1363 | } |
| 1364 | |
| 1365 | /* |
| 1366 | ** If the zChng string is not NULL, then it should be a comma-separated |
| @@ -1618,13 +1619,14 @@ | |
| 1618 | ** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN |
| 1619 | ** t=TAG Show only check-ins with the given TAG |
| 1620 | ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel |
| 1621 | ** rel Show related check-ins as well as those matching t=TAG |
| 1622 | ** mionly Limit rel to show ancestors but not descendants |
| 1623 | ** ms=STYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP |
| 1624 | ** u=USER Only show items associated with USER |
| 1625 | ** y=TYPE 'ci', 'w', 't', 'e', or 'all'. 'ci' is the default. |
| 1626 | ** ng No Graph. |
| 1627 | ** nd Do not highlight the focus check-in |
| 1628 | ** v Show details of files changed |
| 1629 | ** f=CHECKIN Show family (immediate parents and children) of CHECKIN |
| 1630 | ** from=CHECKIN Path from... |
| @@ -1699,10 +1701,16 @@ | |
| 1699 | const char *z; |
| 1700 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1701 | char *zNewerButton = 0; /* URL for Newer button at the top */ |
| 1702 | int selectedRid = -9999999; /* Show a highlight on this RID */ |
| 1703 | int disableY = 0; /* Disable type selector on submenu */ |
| 1704 | |
| 1705 | /* Set number of rows to display */ |
| 1706 | cookie_parse("fossil_display_settings"); |
| 1707 | cookie_link_parameter("n","tln"); |
| 1708 | z = P("n"); |
| @@ -1719,10 +1727,14 @@ | |
| 1719 | } |
| 1720 | }else{ |
| 1721 | cgi_replace_query_parameter("n","50"); |
| 1722 | nEntry = 50; |
| 1723 | } |
| 1724 | |
| 1725 | /* To view the timeline, must have permission to read project data. |
| 1726 | */ |
| 1727 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 1728 | if( pd_rid ){ |
| @@ -1792,10 +1804,15 @@ | |
| 1792 | "FROM tagxref NATURAL JOIN tag WHERE %s",zTagSql/*safe-for-%s*/)<=nEntry) |
| 1793 | ){ |
| 1794 | nEntry = -1; |
| 1795 | zCirca = 0; |
| 1796 | } |
| 1797 | if( zType[0]=='a' ){ |
| 1798 | tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; |
| 1799 | }else{ |
| 1800 | tmFlags |= TIMELINE_GRAPH; |
| 1801 | } |
| @@ -2265,11 +2282,11 @@ | |
| 2265 | } |
| 2266 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 2267 | style_submenu_checkbox("unhide", "Unhide", STYLE_CLUTTER, 0); |
| 2268 | } |
| 2269 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c')|STYLE_CLUTTER,0); |
| 2270 | style_submenu_entry("n","Max:",4,STYLE_CLUTTER); |
| 2271 | timeline_y_submenu(disableY); |
| 2272 | style_submenu_entry("t", "Tag Filter:", -8, STYLE_CLUTTER); |
| 2273 | style_submenu_multichoice("ms", count(azMatchStyles)/2, azMatchStyles, STYLE_CLUTTER); |
| 2274 | } |
| 2275 | blob_zero(&cond); |
| 2276 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -103,10 +103,13 @@ | |
| 103 | #define TIMELINE_UCOLOR 0x0080 /* Background color by user */ |
| 104 | #define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */ |
| 105 | #define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */ |
| 106 | #define TIMELINE_SHOWRID 0x0400 /* Show RID values in addition to UUIDs */ |
| 107 | #define TIMELINE_BISECT 0x0800 /* Show supplimental bisect information */ |
| 108 | #define TIMELINE_COMPACT 0x1000 /* Use the "compact" view style */ |
| 109 | #define TIMELINE_DETAILED 0x2000 /* Use the "detailed" view style */ |
| 110 | #define TIMELINE_NORMAL 0x4000 /* Use the "normal" view style */ |
| 111 | #endif |
| 112 | |
| 113 | /* |
| 114 | ** Hash a string and use the hash to determine a background color. |
| 115 | */ |
| @@ -248,10 +251,11 @@ | |
| 251 | static Stmt qbranch; |
| 252 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 253 | int vid = 0; /* Current checkout version */ |
| 254 | int dateFormat = 0; /* 0: HH:MM (default) */ |
| 255 | int bCommentGitStyle = 0; /* Only show comments through first blank line */ |
| 256 | const char *zTdClass; |
| 257 | int bHashBeforeComment = 0; /* Show hash before the comment */ |
| 258 | int bHashAfterComment = 0; /* Show hash after the comment */ |
| 259 | int bHashInDetail = 0; /* Show the hash inside the detail section */ |
| 260 | int bShowDetail; /* Show the detail section */ |
| 261 | int bSeparateDetail; /* Detail in a separate column */ |
| @@ -264,22 +268,16 @@ | |
| 268 | } |
| 269 | zPrevDate[0] = 0; |
| 270 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 271 | dateFormat = db_get_int("timeline-date-format", 0); |
| 272 | bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0); |
| 273 | if( tmFlags & TIMELINE_NORMAL ){ |
| 274 | zTdClass = "timelineStyleNormal"; |
| 275 | }else if( tmFlags & TIMELINE_COMPACT ){ |
| 276 | zTdClass = "timelineStyleCompact"; |
| 277 | }else if( tmFlags & TIMELINE_DETAILED ){ |
| 278 | zTdClass = "timelineStyleDetailed"; |
| 279 | } |
| 280 | zDateFmt = P("datefmt"); |
| 281 | if( zDateFmt ) dateFormat = atoi(zDateFmt); |
| 282 | if( tmFlags & TIMELINE_GRAPH ){ |
| 283 | pGraph = graph_init(); |
| @@ -304,11 +302,11 @@ | |
| 302 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 303 | const char *zBr = 0; /* Branch */ |
| 304 | int commentColumn = 3; /* Column containing comment text */ |
| 305 | int modPending; /* Pending moderation */ |
| 306 | char *zDateLink; /* URL for the link on the timestamp */ |
| 307 | int drawDetailEllipsis; /* True to show ellipsis in place of detail */ |
| 308 | char zTime[20]; |
| 309 | |
| 310 | if( zDate==0 ){ |
| 311 | zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */ |
| 312 | } |
| @@ -441,13 +439,13 @@ | |
| 439 | db_reset(&qbranch); |
| 440 | @ <div id="m%d(gidx)" class="tl-nodemark"></div> |
| 441 | } |
| 442 | @</td> |
| 443 | if( zBgClr && zBgClr[0] && rid!=selectedRid ){ |
| 444 | @ <td class="timelineTableCell %s(zTdClass)" style="background-color: %h(zBgClr);"> |
| 445 | }else{ |
| 446 | @ <td class="timelineTableCell %s(zTdClass)"> |
| 447 | } |
| 448 | if( pGraph && zType[0]!='c' ){ |
| 449 | @ • |
| 450 | } |
| 451 | if( modPending ){ |
| @@ -461,10 +459,11 @@ | |
| 459 | @ <b>%s(db_column_text(&bisectQuery,1))</b> |
| 460 | @ (%d(db_column_int(&bisectQuery,0))) |
| 461 | } |
| 462 | db_reset(&bisectQuery); |
| 463 | } |
| 464 | #if 0 |
| 465 | if( bHashBeforeComment ){ |
| 466 | if( zType[0]=='c' ){ |
| 467 | hyperlink_to_uuid(zUuid); |
| 468 | if( isLeaf ){ |
| 469 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -487,10 +486,12 @@ | |
| 486 | }else{ |
| 487 | @ (%d(rid)) |
| 488 | } |
| 489 | } |
| 490 | } |
| 491 | #endif |
| 492 | drawDetailEllipsis = (tmFlags & TIMELINE_COMPACT)!=0; |
| 493 | db_column_blob(pQuery, commentColumn, &comment); |
| 494 | if( zType[0]!='c' ){ |
| 495 | /* Comments for anything other than a check-in are generated by |
| 496 | ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */ |
| 497 | @ <span class='timelineComment' onclick='toggleDetail(%d(rid))'> |
| @@ -525,10 +526,11 @@ | |
| 526 | } |
| 527 | @ </span> |
| 528 | } |
| 529 | blob_reset(&comment); |
| 530 | |
| 531 | #if 0 |
| 532 | if( bHashAfterComment ){ |
| 533 | if( zType[0]=='c' ){ |
| 534 | hyperlink_to_uuid(zUuid); |
| 535 | if( isLeaf ){ |
| 536 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -552,111 +554,110 @@ | |
| 554 | @ (%d(rid)) |
| 555 | } |
| 556 | } |
| 557 | drawDetailEllipsis = 1; |
| 558 | } |
| 559 | #endif |
| 560 | |
| 561 | /* Generate extra information and hyperlinks to follow the comment. |
| 562 | ** Example: "(check-in: [abcdefg], user: drh, tags: trunk)" |
| 563 | */ |
| 564 | if( drawDetailEllipsis ){ |
| 565 | @ <span class='timelineEllipsis anticlutter' id='ellipsis-%d(rid)' \ |
| 566 | @ onclick='toggleDetail(%d(rid))'>...</span> |
| 567 | } |
| 568 | if( bSeparateDetail ){ |
| 569 | if( zBgClr && zBgClr[0] && rid!=selectedRid ){ |
| 570 | @ <td class="timelineTableCell timelineDetailCell" |
| 571 | @ style="background-color: %h(zBgClr);"> |
| 572 | }else{ |
| 573 | @ <td class="timelineTableCell timelineDetailCell"> |
| 574 | } |
| 575 | } |
| 576 | if( tmFlags & TIMELINE_COMPACT ){ |
| 577 | cgi_printf("<span class='timelineDetailWrapper clutter' id='detail-%d'>", rid); |
| 578 | }else{ |
| 579 | cgi_printf("<span class='timelineDetailWrapper'>"); |
| 580 | } |
| 581 | if( zType[0]=='c' ){ |
| 582 | cgi_printf("<span class='timelineDetail timelineCheckinDetail'>"); |
| 583 | }else{ |
| 584 | cgi_printf("<span class='timelineDetail'>"); |
| 585 | } |
| 586 | |
| 587 | if( bHashInDetail ){ |
| 588 | if( zType[0]=='c' ){ |
| 589 | if( isLeaf ){ |
| 590 | if( db_exists("SELECT 1 FROM tagxref" |
| 591 | " WHERE rid=%d AND tagid=%d AND tagtype>0", |
| 592 | rid, TAG_CLOSED) ){ |
| 593 | @ <span class='timelineLeaf'>Closed-Leaf</span> |
| 594 | }else{ |
| 595 | @ <span class='timelineLeaf'>Leaf</span> |
| 596 | } |
| 597 | } |
| 598 | cgi_printf("check-in: "); |
| 599 | hyperlink_to_uuid(zUuid); |
| 600 | }else if( zType[0]=='e' && tagid ){ |
| 601 | cgi_printf("technote: "); |
| 602 | hyperlink_to_event_tagid(tagid<0?-tagid:tagid); |
| 603 | }else{ |
| 604 | cgi_printf("artifact: "); |
| 605 | hyperlink_to_uuid(zUuid); |
| 606 | } |
| 607 | } |
| 608 | |
| 609 | if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){ |
| 610 | char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate); |
| 611 | cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser); |
| 612 | }else{ |
| 613 | cgi_printf("user: %h", zDispUser); |
| 614 | } |
| 615 | |
| 616 | /* Generate the "tags: TAGLIST" at the end of the comment, together |
| 617 | ** with hyperlinks to the tag list. |
| 618 | */ |
| 619 | if( zTagList && zTagList[0]==0 ) zTagList = 0; |
| 620 | if( zTagList ){ |
| 621 | if( g.perm.Hyperlink ){ |
| 622 | int i; |
| 623 | const char *z = zTagList; |
| 624 | Blob links; |
| 625 | blob_zero(&links); |
| 626 | while( z && z[0] ){ |
| 627 | for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){} |
| 628 | if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){ |
| 629 | blob_appendf(&links, |
| 630 | "%z%#h</a>%.2s", |
| 631 | href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i] |
| 632 | ); |
| 633 | }else{ |
| 634 | blob_appendf(&links, "%#h", i+2, z); |
| 635 | } |
| 636 | if( z[i]==0 ) break; |
| 637 | z += i+2; |
| 638 | } |
| 639 | cgi_printf(" tags: %s", blob_str(&links)); |
| 640 | blob_reset(&links); |
| 641 | }else{ |
| 642 | cgi_printf(" tags: %h", zTagList); |
| 643 | } |
| 644 | } |
| 645 | |
| 646 | if( tmFlags & TIMELINE_SHOWRID ){ |
| 647 | int srcId = delta_source_rid(rid); |
| 648 | if( srcId ){ |
| 649 | cgi_printf(" id: %d←%d", rid, srcId); |
| 650 | }else{ |
| 651 | cgi_printf(" id: %d", rid); |
| 652 | } |
| 653 | } |
| 654 | tag_private_status(rid); |
| 655 | if( xExtra ){ |
| 656 | xExtra(rid); |
| 657 | } |
| 658 | cgi_printf("</span></span>\n"); /* End timelineDetail and timelineDetailWrapper */ |
| 659 | |
| 660 | /* Generate the file-change list if requested */ |
| 661 | if( (tmFlags & (TIMELINE_FCHANGES|TIMELINE_FRENAMES))!=0 |
| 662 | && zType[0]=='c' && g.perm.Hyperlink |
| 663 | ){ |
| @@ -1356,11 +1357,11 @@ | |
| 1357 | az[i++] = "Wiki"; |
| 1358 | } |
| 1359 | assert( i<=count(az) ); |
| 1360 | } |
| 1361 | if( i>2 ){ |
| 1362 | style_submenu_multichoice("y", i/2, az, isDisabled); |
| 1363 | } |
| 1364 | } |
| 1365 | |
| 1366 | /* |
| 1367 | ** If the zChng string is not NULL, then it should be a comma-separated |
| @@ -1618,13 +1619,14 @@ | |
| 1619 | ** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN |
| 1620 | ** t=TAG Show only check-ins with the given TAG |
| 1621 | ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel |
| 1622 | ** rel Show related check-ins as well as those matching t=TAG |
| 1623 | ** mionly Limit rel to show ancestors but not descendants |
| 1624 | ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP |
| 1625 | ** u=USER Only show items associated with USER |
| 1626 | ** y=TYPE 'ci', 'w', 't', 'e', or 'all'. |
| 1627 | ** vs=VIEWSTYLE c: "compact" d: "detail" n: "normal" |
| 1628 | ** ng No Graph. |
| 1629 | ** nd Do not highlight the focus check-in |
| 1630 | ** v Show details of files changed |
| 1631 | ** f=CHECKIN Show family (immediate parents and children) of CHECKIN |
| 1632 | ** from=CHECKIN Path from... |
| @@ -1699,10 +1701,16 @@ | |
| 1701 | const char *z; |
| 1702 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1703 | char *zNewerButton = 0; /* URL for Newer button at the top */ |
| 1704 | int selectedRid = -9999999; /* Show a highlight on this RID */ |
| 1705 | int disableY = 0; /* Disable type selector on submenu */ |
| 1706 | char cViewStyle; /* Overall style of the page */ |
| 1707 | static const char *azViewStyles[] = { |
| 1708 | "n", "Normal", |
| 1709 | "c", "Compact", |
| 1710 | "d", "Detailed", |
| 1711 | }; |
| 1712 | |
| 1713 | /* Set number of rows to display */ |
| 1714 | cookie_parse("fossil_display_settings"); |
| 1715 | cookie_link_parameter("n","tln"); |
| 1716 | z = P("n"); |
| @@ -1719,10 +1727,14 @@ | |
| 1727 | } |
| 1728 | }else{ |
| 1729 | cgi_replace_query_parameter("n","50"); |
| 1730 | nEntry = 50; |
| 1731 | } |
| 1732 | cookie_link_parameter("vs","tlvs"); |
| 1733 | cViewStyle = PD("vs","n")[0]; |
| 1734 | style_submenu_multichoice("vs", 3, azViewStyles, 0); |
| 1735 | |
| 1736 | |
| 1737 | /* To view the timeline, must have permission to read project data. |
| 1738 | */ |
| 1739 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 1740 | if( pd_rid ){ |
| @@ -1792,10 +1804,15 @@ | |
| 1804 | "FROM tagxref NATURAL JOIN tag WHERE %s",zTagSql/*safe-for-%s*/)<=nEntry) |
| 1805 | ){ |
| 1806 | nEntry = -1; |
| 1807 | zCirca = 0; |
| 1808 | } |
| 1809 | switch( cViewStyle ){ |
| 1810 | case 'n': tmFlags |= TIMELINE_NORMAL; break; |
| 1811 | case 'c': tmFlags |= TIMELINE_COMPACT; break; |
| 1812 | case 'd': tmFlags |= TIMELINE_DETAILED; break; |
| 1813 | } |
| 1814 | if( zType[0]=='a' ){ |
| 1815 | tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; |
| 1816 | }else{ |
| 1817 | tmFlags |= TIMELINE_GRAPH; |
| 1818 | } |
| @@ -2265,11 +2282,11 @@ | |
| 2282 | } |
| 2283 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 2284 | style_submenu_checkbox("unhide", "Unhide", STYLE_CLUTTER, 0); |
| 2285 | } |
| 2286 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c')|STYLE_CLUTTER,0); |
| 2287 | style_submenu_entry("n","Max:",4,0); |
| 2288 | timeline_y_submenu(disableY); |
| 2289 | style_submenu_entry("t", "Tag Filter:", -8, STYLE_CLUTTER); |
| 2290 | style_submenu_multichoice("ms", count(azMatchStyles)/2, azMatchStyles, STYLE_CLUTTER); |
| 2291 | } |
| 2292 | blob_zero(&cond); |
| 2293 |