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.

drh 2017-11-28 19:41 UTC sticky-timeline-style
Commit fdf071e1819d01caf7c631970eedc994009e82a22cc864e809bc497db09248fa
1 file changed +130 -113
+130 -113
--- src/timeline.c
+++ src/timeline.c
@@ -103,10 +103,13 @@
103103
#define TIMELINE_UCOLOR 0x0080 /* Background color by user */
104104
#define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
105105
#define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */
106106
#define TIMELINE_SHOWRID 0x0400 /* Show RID values in addition to UUIDs */
107107
#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 */
108111
#endif
109112
110113
/*
111114
** Hash a string and use the hash to determine a background color.
112115
*/
@@ -248,10 +251,11 @@
248251
static Stmt qbranch;
249252
int pendingEndTr = 0; /* True if a </td></tr> is needed */
250253
int vid = 0; /* Current checkout version */
251254
int dateFormat = 0; /* 0: HH:MM (default) */
252255
int bCommentGitStyle = 0; /* Only show comments through first blank line */
256
+ const char *zTdClass;
253257
int bHashBeforeComment = 0; /* Show hash before the comment */
254258
int bHashAfterComment = 0; /* Show hash after the comment */
255259
int bHashInDetail = 0; /* Show the hash inside the detail section */
256260
int bShowDetail; /* Show the detail section */
257261
int bSeparateDetail; /* Detail in a separate column */
@@ -264,22 +268,16 @@
264268
}
265269
zPrevDate[0] = 0;
266270
mxWikiLen = db_get_int("timeline-max-comment", 0);
267271
dateFormat = db_get_int("timeline-date-format", 0);
268272
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";
281279
}
282280
zDateFmt = P("datefmt");
283281
if( zDateFmt ) dateFormat = atoi(zDateFmt);
284282
if( tmFlags & TIMELINE_GRAPH ){
285283
pGraph = graph_init();
@@ -304,11 +302,11 @@
304302
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
305303
const char *zBr = 0; /* Branch */
306304
int commentColumn = 3; /* Column containing comment text */
307305
int modPending; /* Pending moderation */
308306
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 */
310308
char zTime[20];
311309
312310
if( zDate==0 ){
313311
zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */
314312
}
@@ -441,13 +439,13 @@
441439
db_reset(&qbranch);
442440
@ <div id="m%d(gidx)" class="tl-nodemark"></div>
443441
}
444442
@</td>
445443
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);">
447445
}else{
448
- @ <td class="timelineTableCell">
446
+ @ <td class="timelineTableCell %s(zTdClass)">
449447
}
450448
if( pGraph && zType[0]!='c' ){
451449
@ &bull;
452450
}
453451
if( modPending ){
@@ -461,10 +459,11 @@
461459
@ <b>%s(db_column_text(&bisectQuery,1))</b>
462460
@ (%d(db_column_int(&bisectQuery,0)))
463461
}
464462
db_reset(&bisectQuery);
465463
}
464
+#if 0
466465
if( bHashBeforeComment ){
467466
if( zType[0]=='c' ){
468467
hyperlink_to_uuid(zUuid);
469468
if( isLeaf ){
470469
if( db_exists("SELECT 1 FROM tagxref"
@@ -487,10 +486,12 @@
487486
}else{
488487
@ (%d(rid))
489488
}
490489
}
491490
}
491
+#endif
492
+ drawDetailEllipsis = (tmFlags & TIMELINE_COMPACT)!=0;
492493
db_column_blob(pQuery, commentColumn, &comment);
493494
if( zType[0]!='c' ){
494495
/* Comments for anything other than a check-in are generated by
495496
** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
496497
@ <span class='timelineComment' onclick='toggleDetail(%d(rid))'>
@@ -525,10 +526,11 @@
525526
}
526527
@ </span>
527528
}
528529
blob_reset(&comment);
529530
531
+#if 0
530532
if( bHashAfterComment ){
531533
if( zType[0]=='c' ){
532534
hyperlink_to_uuid(zUuid);
533535
if( isLeaf ){
534536
if( db_exists("SELECT 1 FROM tagxref"
@@ -552,111 +554,110 @@
552554
@ (%d(rid))
553555
}
554556
}
555557
drawDetailEllipsis = 1;
556558
}
557
-
559
+#endif
558560
559561
/* Generate extra information and hyperlinks to follow the comment.
560562
** Example: "(check-in: [abcdefg], user: drh, tags: trunk)"
561563
*/
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&larr;%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&larr;%d", rid, srcId);
650
+ }else{
651
+ cgi_printf(" id: %d", rid);
652
+ }
653
+ }
654
+ tag_private_status(rid);
655655
if( xExtra ){
656656
xExtra(rid);
657657
}
658
+ cgi_printf("</span></span>\n"); /* End timelineDetail and timelineDetailWrapper */
658659
659660
/* Generate the file-change list if requested */
660661
if( (tmFlags & (TIMELINE_FCHANGES|TIMELINE_FRENAMES))!=0
661662
&& zType[0]=='c' && g.perm.Hyperlink
662663
){
@@ -1356,11 +1357,11 @@
13561357
az[i++] = "Wiki";
13571358
}
13581359
assert( i<=count(az) );
13591360
}
13601361
if( i>2 ){
1361
- style_submenu_multichoice("y", i/2, az, isDisabled|STYLE_CLUTTER);
1362
+ style_submenu_multichoice("y", i/2, az, isDisabled);
13621363
}
13631364
}
13641365
13651366
/*
13661367
** If the zChng string is not NULL, then it should be a comma-separated
@@ -1618,13 +1619,14 @@
16181619
** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN
16191620
** t=TAG Show only check-ins with the given TAG
16201621
** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel
16211622
** rel Show related check-ins as well as those matching t=TAG
16221623
** 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
16241625
** 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"
16261628
** ng No Graph.
16271629
** nd Do not highlight the focus check-in
16281630
** v Show details of files changed
16291631
** f=CHECKIN Show family (immediate parents and children) of CHECKIN
16301632
** from=CHECKIN Path from...
@@ -1699,10 +1701,16 @@
16991701
const char *z;
17001702
char *zOlderButton = 0; /* URL for Older button at the bottom */
17011703
char *zNewerButton = 0; /* URL for Newer button at the top */
17021704
int selectedRid = -9999999; /* Show a highlight on this RID */
17031705
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
+ };
17041712
17051713
/* Set number of rows to display */
17061714
cookie_parse("fossil_display_settings");
17071715
cookie_link_parameter("n","tln");
17081716
z = P("n");
@@ -1719,10 +1727,14 @@
17191727
}
17201728
}else{
17211729
cgi_replace_query_parameter("n","50");
17221730
nEntry = 50;
17231731
}
1732
+ cookie_link_parameter("vs","tlvs");
1733
+ cViewStyle = PD("vs","n")[0];
1734
+ style_submenu_multichoice("vs", 3, azViewStyles, 0);
1735
+
17241736
17251737
/* To view the timeline, must have permission to read project data.
17261738
*/
17271739
pd_rid = name_to_typed_rid(P("dp"),"ci");
17281740
if( pd_rid ){
@@ -1792,10 +1804,15 @@
17921804
"FROM tagxref NATURAL JOIN tag WHERE %s",zTagSql/*safe-for-%s*/)<=nEntry)
17931805
){
17941806
nEntry = -1;
17951807
zCirca = 0;
17961808
}
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
+ }
17971814
if( zType[0]=='a' ){
17981815
tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH;
17991816
}else{
18001817
tmFlags |= TIMELINE_GRAPH;
18011818
}
@@ -2265,11 +2282,11 @@
22652282
}
22662283
if( zType[0]=='a' || zType[0]=='c' ){
22672284
style_submenu_checkbox("unhide", "Unhide", STYLE_CLUTTER, 0);
22682285
}
22692286
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);
22712288
timeline_y_submenu(disableY);
22722289
style_submenu_entry("t", "Tag Filter:", -8, STYLE_CLUTTER);
22732290
style_submenu_multichoice("ms", count(azMatchStyles)/2, azMatchStyles, STYLE_CLUTTER);
22742291
}
22752292
blob_zero(&cond);
22762293
--- 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 @ &bull;
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&larr;%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 @ &bull;
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&larr;%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

Keyboard Shortcuts

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