Fossil SCM

Add the "Comment Format" selector for to the /setup_timeline page. This allows the admin to configure the timeline comment display in various ways, so that nearly all preferences are satisfied.

drh 2017-11-24 20:04 UTC timeline-improvements
Commit 4cb350ecc094eae521f1100bc817fcbc3f1ab205cea619f3481899dea3a4690c
3 files changed +69 -47 +22 -1 +170 -91
+69 -47
--- src/finfo.c
+++ src/finfo.c
@@ -313,10 +313,15 @@
313313
int uBg = P("ubg")!=0;
314314
int fDebug = atoi(PD("debug","0"));
315315
int fShowId = P("showid")!=0;
316316
Stmt qparent;
317317
int iTableId = timeline_tableid();
318
+ int bHashBeforeComment = 0; /* Show hash before the comment */
319
+ int bHashAfterComment = 0; /* Show hash after the comment */
320
+ int bHashInDetail = 0; /* Show the hash inside the detail section */
321
+ int bShowDetail; /* Show the detail section */
322
+ int eCommentFormat; /* value for timeline-comment-format */
318323
319324
login_check_credentials();
320325
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
321326
style_header("File History");
322327
login_anonymous_available();
@@ -324,10 +329,17 @@
324329
if( brBg ) url_add_parameter(&url, "brbg", 0);
325330
if( uBg ) url_add_parameter(&url, "ubg", 0);
326331
baseCheckin = name_to_rid_www("ci");
327332
zPrevDate[0] = 0;
328333
zFilename = PD("name","");
334
+ eCommentFormat = db_get_int("timeline-comment-format", 0);
335
+ bShowDetail = (eCommentFormat & 1)==0; /* Bit 0 suppresses the comment */
336
+ switch( (eCommentFormat>>1)&3 ){
337
+ case 1: bHashAfterComment = 1; break;
338
+ case 2: bHashInDetail = 1; break;
339
+ default: bHashBeforeComment = 1; break;
340
+ }
329341
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
330342
if( fnid==0 ){
331343
@ No such file: %h(zFilename)
332344
style_footer();
333345
return;
@@ -502,56 +514,64 @@
502514
if( zBgClr && zBgClr[0] ){
503515
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
504516
}else{
505517
@ <td class="timelineTableCell">
506518
}
507
- @ <span class="timelineComment">%W(zCom)</span>
508
- cgi_printf("<span class='timelineDetail'>(");
509
- if( zUuid ){
510
- @ file: %z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
511
- if( fShowId ){
512
- int srcId = delta_source_rid(frid);
513
- if( srcId>0 ){
514
- @ id: %d(frid)&larr;%d(srcId)
515
- }else{
516
- @ id: %d(frid)
517
- }
518
- }
519
- }
520
- @ check-in:
521
- hyperlink_to_uuid(zCkin);
522
- if( fShowId ){
523
- @ (%d(fmid))
524
- }
525
- @ user:
526
- hyperlink_to_user(zUser, zDate, ",");
527
- @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>,
528
- @ size: %d(szFile))
529
- if( zUuid && origCheckin==0 ){
530
- if( nParent==0 ){
531
- @ <b>Added</b>
532
- }else if( pfnid ){
533
- char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
534
- pfnid);
535
- @ <b>Renamed</b> from
536
- @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
537
- }
538
- }
539
- if( zUuid==0 ){
540
- char *zNewName;
541
- zNewName = db_text(0,
542
- "SELECT name FROM filename WHERE fnid = "
543
- " (SELECT fnid FROM mlink"
544
- " WHERE mid=%d"
545
- " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))",
546
- fmid, zFilename);
547
- if( zNewName ){
548
- @ <b>Renamed</b> to
549
- @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a>
550
- fossil_free(zNewName);
551
- }else{
552
- @ <b>Deleted</b>
519
+ if( bHashBeforeComment && zUuid ){
520
+ hyperlink_to_uuid(zUuid);
521
+ }
522
+ @ <span class="timelineComment timelineCheckinComment">%W(zCom)</span>
523
+ if( bHashAfterComment && zUuid ){
524
+ hyperlink_to_uuid(zUuid);
525
+ }
526
+ if( bShowDetail ){
527
+ cgi_printf("<span class='timelineDetail timelineCheckinDetail'>(");
528
+ if( zUuid && bHashInDetail ){
529
+ @ file: %z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
530
+ if( fShowId ){
531
+ int srcId = delta_source_rid(frid);
532
+ if( srcId>0 ){
533
+ @ id: %d(frid)&larr;%d(srcId)
534
+ }else{
535
+ @ id: %d(frid)
536
+ }
537
+ }
538
+ }
539
+ @ check-in:
540
+ hyperlink_to_uuid(zCkin);
541
+ if( fShowId ){
542
+ @ (%d(fmid))
543
+ }
544
+ @ user:
545
+ hyperlink_to_user(zUser, zDate, ",");
546
+ @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>,
547
+ @ size: %d(szFile))
548
+ if( zUuid && origCheckin==0 ){
549
+ if( nParent==0 ){
550
+ @ <b>Added</b>
551
+ }else if( pfnid ){
552
+ char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
553
+ pfnid);
554
+ @ <b>Renamed</b> from
555
+ @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
556
+ }
557
+ }
558
+ if( zUuid==0 ){
559
+ char *zNewName;
560
+ zNewName = db_text(0,
561
+ "SELECT name FROM filename WHERE fnid = "
562
+ " (SELECT fnid FROM mlink"
563
+ " WHERE mid=%d"
564
+ " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))",
565
+ fmid, zFilename);
566
+ if( zNewName ){
567
+ @ <b>Renamed</b> to
568
+ @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a>
569
+ fossil_free(zNewName);
570
+ }else{
571
+ @ <b>Deleted</b>
572
+ }
553573
}
554574
}
555575
if( g.perm.Hyperlink && zUuid ){
556576
const char *z = zFilename;
557577
@ <span class='timelineExtraLinks'>
@@ -577,11 +597,13 @@
577597
}
578598
zAncLink = href("%R/finfo?name=%T&ci=%!S&debug=1",zFilename,zCkin);
579599
@ %z(zAncLink)[ancestry]</a>
580600
}
581601
tag_private_status(frid);
582
- @ </span>
602
+ if( bShowDetail ){
603
+ @ </span>
604
+ }
583605
@ </td></tr>
584606
}
585607
db_finalize(&q);
586608
db_finalize(&qparent);
587609
if( pGraph ){
588610
--- src/finfo.c
+++ src/finfo.c
@@ -313,10 +313,15 @@
313 int uBg = P("ubg")!=0;
314 int fDebug = atoi(PD("debug","0"));
315 int fShowId = P("showid")!=0;
316 Stmt qparent;
317 int iTableId = timeline_tableid();
 
 
 
 
 
318
319 login_check_credentials();
320 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
321 style_header("File History");
322 login_anonymous_available();
@@ -324,10 +329,17 @@
324 if( brBg ) url_add_parameter(&url, "brbg", 0);
325 if( uBg ) url_add_parameter(&url, "ubg", 0);
326 baseCheckin = name_to_rid_www("ci");
327 zPrevDate[0] = 0;
328 zFilename = PD("name","");
 
 
 
 
 
 
 
329 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
330 if( fnid==0 ){
331 @ No such file: %h(zFilename)
332 style_footer();
333 return;
@@ -502,56 +514,64 @@
502 if( zBgClr && zBgClr[0] ){
503 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
504 }else{
505 @ <td class="timelineTableCell">
506 }
507 @ <span class="timelineComment">%W(zCom)</span>
508 cgi_printf("<span class='timelineDetail'>(");
509 if( zUuid ){
510 @ file: %z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
511 if( fShowId ){
512 int srcId = delta_source_rid(frid);
513 if( srcId>0 ){
514 @ id: %d(frid)&larr;%d(srcId)
515 }else{
516 @ id: %d(frid)
517 }
518 }
519 }
520 @ check-in:
521 hyperlink_to_uuid(zCkin);
522 if( fShowId ){
523 @ (%d(fmid))
524 }
525 @ user:
526 hyperlink_to_user(zUser, zDate, ",");
527 @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>,
528 @ size: %d(szFile))
529 if( zUuid && origCheckin==0 ){
530 if( nParent==0 ){
531 @ <b>Added</b>
532 }else if( pfnid ){
533 char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
534 pfnid);
535 @ <b>Renamed</b> from
536 @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
537 }
538 }
539 if( zUuid==0 ){
540 char *zNewName;
541 zNewName = db_text(0,
542 "SELECT name FROM filename WHERE fnid = "
543 " (SELECT fnid FROM mlink"
544 " WHERE mid=%d"
545 " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))",
546 fmid, zFilename);
547 if( zNewName ){
548 @ <b>Renamed</b> to
549 @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a>
550 fossil_free(zNewName);
551 }else{
552 @ <b>Deleted</b>
 
 
 
 
 
 
 
 
553 }
554 }
555 if( g.perm.Hyperlink && zUuid ){
556 const char *z = zFilename;
557 @ <span class='timelineExtraLinks'>
@@ -577,11 +597,13 @@
577 }
578 zAncLink = href("%R/finfo?name=%T&ci=%!S&debug=1",zFilename,zCkin);
579 @ %z(zAncLink)[ancestry]</a>
580 }
581 tag_private_status(frid);
582 @ </span>
 
 
583 @ </td></tr>
584 }
585 db_finalize(&q);
586 db_finalize(&qparent);
587 if( pGraph ){
588
--- src/finfo.c
+++ src/finfo.c
@@ -313,10 +313,15 @@
313 int uBg = P("ubg")!=0;
314 int fDebug = atoi(PD("debug","0"));
315 int fShowId = P("showid")!=0;
316 Stmt qparent;
317 int iTableId = timeline_tableid();
318 int bHashBeforeComment = 0; /* Show hash before the comment */
319 int bHashAfterComment = 0; /* Show hash after the comment */
320 int bHashInDetail = 0; /* Show the hash inside the detail section */
321 int bShowDetail; /* Show the detail section */
322 int eCommentFormat; /* value for timeline-comment-format */
323
324 login_check_credentials();
325 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
326 style_header("File History");
327 login_anonymous_available();
@@ -324,10 +329,17 @@
329 if( brBg ) url_add_parameter(&url, "brbg", 0);
330 if( uBg ) url_add_parameter(&url, "ubg", 0);
331 baseCheckin = name_to_rid_www("ci");
332 zPrevDate[0] = 0;
333 zFilename = PD("name","");
334 eCommentFormat = db_get_int("timeline-comment-format", 0);
335 bShowDetail = (eCommentFormat & 1)==0; /* Bit 0 suppresses the comment */
336 switch( (eCommentFormat>>1)&3 ){
337 case 1: bHashAfterComment = 1; break;
338 case 2: bHashInDetail = 1; break;
339 default: bHashBeforeComment = 1; break;
340 }
341 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
342 if( fnid==0 ){
343 @ No such file: %h(zFilename)
344 style_footer();
345 return;
@@ -502,56 +514,64 @@
514 if( zBgClr && zBgClr[0] ){
515 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
516 }else{
517 @ <td class="timelineTableCell">
518 }
519 if( bHashBeforeComment && zUuid ){
520 hyperlink_to_uuid(zUuid);
521 }
522 @ <span class="timelineComment timelineCheckinComment">%W(zCom)</span>
523 if( bHashAfterComment && zUuid ){
524 hyperlink_to_uuid(zUuid);
525 }
526 if( bShowDetail ){
527 cgi_printf("<span class='timelineDetail timelineCheckinDetail'>(");
528 if( zUuid && bHashInDetail ){
529 @ file: %z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
530 if( fShowId ){
531 int srcId = delta_source_rid(frid);
532 if( srcId>0 ){
533 @ id: %d(frid)&larr;%d(srcId)
534 }else{
535 @ id: %d(frid)
536 }
537 }
538 }
539 @ check-in:
540 hyperlink_to_uuid(zCkin);
541 if( fShowId ){
542 @ (%d(fmid))
543 }
544 @ user:
545 hyperlink_to_user(zUser, zDate, ",");
546 @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>,
547 @ size: %d(szFile))
548 if( zUuid && origCheckin==0 ){
549 if( nParent==0 ){
550 @ <b>Added</b>
551 }else if( pfnid ){
552 char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d",
553 pfnid);
554 @ <b>Renamed</b> from
555 @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
556 }
557 }
558 if( zUuid==0 ){
559 char *zNewName;
560 zNewName = db_text(0,
561 "SELECT name FROM filename WHERE fnid = "
562 " (SELECT fnid FROM mlink"
563 " WHERE mid=%d"
564 " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))",
565 fmid, zFilename);
566 if( zNewName ){
567 @ <b>Renamed</b> to
568 @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a>
569 fossil_free(zNewName);
570 }else{
571 @ <b>Deleted</b>
572 }
573 }
574 }
575 if( g.perm.Hyperlink && zUuid ){
576 const char *z = zFilename;
577 @ <span class='timelineExtraLinks'>
@@ -577,11 +597,13 @@
597 }
598 zAncLink = href("%R/finfo?name=%T&ci=%!S&debug=1",zFilename,zCkin);
599 @ %z(zAncLink)[ancestry]</a>
600 }
601 tag_private_status(frid);
602 if( bShowDetail ){
603 @ </span>
604 }
605 @ </td></tr>
606 }
607 db_finalize(&q);
608 db_finalize(&qparent);
609 if( pGraph ){
610
+22 -1
--- src/setup.c
+++ src/setup.c
@@ -1446,10 +1446,18 @@
14461446
"0", "HH:MM",
14471447
"1", "HH:MM:SS",
14481448
"2", "YYYY-MM-DD HH:MM",
14491449
"3", "YYMMDD HH:MM",
14501450
"4", "(off)"
1451
+ };
1452
+ static const char *const azCommentFormats[] = {
1453
+ "0", "[hash] comment (details)",
1454
+ "1", "[hash] comment",
1455
+ "2", "comment [hash] (details)",
1456
+ "3", "comment [hash]",
1457
+ "4", "comment (details)",
1458
+ "5", "comment-only",
14511459
};
14521460
login_check_credentials();
14531461
if( !g.perm.Setup ){
14541462
login_needed(0);
14551463
return;
@@ -1457,12 +1465,25 @@
14571465
14581466
style_header("Timeline Display Preferences");
14591467
db_begin_transaction();
14601468
@ <form action="%s(g.zTop)/setup_timeline" method="post"><div>
14611469
login_insert_csrf_secret();
1462
-
14631470
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1471
+
1472
+ @ <hr />
1473
+ multiple_choice_attribute("Comment Format", "timeline-comment-format",
1474
+ "tcf", "0", count(azCommentFormats)/2, azCommentFormats);
1475
+ @ <p>Each timeline entry may contain the following subsections:
1476
+ @ <ol>
1477
+ @ <li> an artifact hash with a hyperlink to a detail page
1478
+ @ <li> the check-in comment or other text describing the item
1479
+ @ <li> details, such as the user, branch, tags, etc.
1480
+ @ </ol>
1481
+ @ This control selects which of the three items above are included on each
1482
+ @ timeline entry and the order in which they are displayed.
1483
+ @ (Preperty: "timeline-commit-format")</p>
1484
+
14641485
@ <hr />
14651486
onoff_attribute("Allow block-markup in timeline",
14661487
"timeline-block-markup", "tbm", 0, 0);
14671488
@ <p>In timeline displays, check-in comments can be displayed with or
14681489
@ without block markup such as paragraphs, tables, etc.
14691490
--- src/setup.c
+++ src/setup.c
@@ -1446,10 +1446,18 @@
1446 "0", "HH:MM",
1447 "1", "HH:MM:SS",
1448 "2", "YYYY-MM-DD HH:MM",
1449 "3", "YYMMDD HH:MM",
1450 "4", "(off)"
 
 
 
 
 
 
 
 
1451 };
1452 login_check_credentials();
1453 if( !g.perm.Setup ){
1454 login_needed(0);
1455 return;
@@ -1457,12 +1465,25 @@
1457
1458 style_header("Timeline Display Preferences");
1459 db_begin_transaction();
1460 @ <form action="%s(g.zTop)/setup_timeline" method="post"><div>
1461 login_insert_csrf_secret();
1462
1463 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1464 @ <hr />
1465 onoff_attribute("Allow block-markup in timeline",
1466 "timeline-block-markup", "tbm", 0, 0);
1467 @ <p>In timeline displays, check-in comments can be displayed with or
1468 @ without block markup such as paragraphs, tables, etc.
1469
--- src/setup.c
+++ src/setup.c
@@ -1446,10 +1446,18 @@
1446 "0", "HH:MM",
1447 "1", "HH:MM:SS",
1448 "2", "YYYY-MM-DD HH:MM",
1449 "3", "YYMMDD HH:MM",
1450 "4", "(off)"
1451 };
1452 static const char *const azCommentFormats[] = {
1453 "0", "[hash] comment (details)",
1454 "1", "[hash] comment",
1455 "2", "comment [hash] (details)",
1456 "3", "comment [hash]",
1457 "4", "comment (details)",
1458 "5", "comment-only",
1459 };
1460 login_check_credentials();
1461 if( !g.perm.Setup ){
1462 login_needed(0);
1463 return;
@@ -1457,12 +1465,25 @@
1465
1466 style_header("Timeline Display Preferences");
1467 db_begin_transaction();
1468 @ <form action="%s(g.zTop)/setup_timeline" method="post"><div>
1469 login_insert_csrf_secret();
 
1470 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1471
1472 @ <hr />
1473 multiple_choice_attribute("Comment Format", "timeline-comment-format",
1474 "tcf", "0", count(azCommentFormats)/2, azCommentFormats);
1475 @ <p>Each timeline entry may contain the following subsections:
1476 @ <ol>
1477 @ <li> an artifact hash with a hyperlink to a detail page
1478 @ <li> the check-in comment or other text describing the item
1479 @ <li> details, such as the user, branch, tags, etc.
1480 @ </ol>
1481 @ This control selects which of the three items above are included on each
1482 @ timeline entry and the order in which they are displayed.
1483 @ (Preperty: "timeline-commit-format")</p>
1484
1485 @ <hr />
1486 onoff_attribute("Allow block-markup in timeline",
1487 "timeline-block-markup", "tbm", 0, 0);
1488 @ <p>In timeline displays, check-in comments can be displayed with or
1489 @ without block markup such as paragraphs, tables, etc.
1490
+170 -91
--- src/timeline.c
+++ src/timeline.c
@@ -248,10 +248,15 @@
248248
static Stmt qbranch;
249249
int pendingEndTr = 0; /* True if a </td></tr> is needed */
250250
int vid = 0; /* Current checkout version */
251251
int dateFormat = 0; /* 0: HH:MM (default) */
252252
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 eCommentFormat; /* value for timeline-comment-format */
253258
const char *zDateFmt;
254259
int iTableId = timeline_tableid();
255260
256261
if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){
257262
vid = db_lget_int("checkout", 0);
@@ -258,10 +263,17 @@
258263
}
259264
zPrevDate[0] = 0;
260265
mxWikiLen = db_get_int("timeline-max-comment", 0);
261266
dateFormat = db_get_int("timeline-date-format", 0);
262267
bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0);
268
+ eCommentFormat = db_get_int("timeline-comment-format", 0);
269
+ bShowDetail = (eCommentFormat & 1)==0; /* Bit 0 suppresses the comment */
270
+ switch( (eCommentFormat>>1)&3 ){
271
+ case 1: bHashAfterComment = 1; break;
272
+ case 2: bHashInDetail = 1; break;
273
+ default: bHashBeforeComment = 1; break;
274
+ }
263275
zDateFmt = P("datefmt");
264276
if( zDateFmt ) dateFormat = atoi(zDateFmt);
265277
if( tmFlags & TIMELINE_GRAPH ){
266278
pGraph = graph_init();
267279
}
@@ -429,114 +441,181 @@
429441
if( db_step(&bisectQuery)==SQLITE_ROW ){
430442
@ <b>%s(db_column_text(&bisectQuery,1))</b>
431443
@ (%d(db_column_int(&bisectQuery,0)))
432444
}
433445
db_reset(&bisectQuery);
446
+ }
447
+ if( bHashBeforeComment ){
448
+ if( zType[0]=='c' ){
449
+ hyperlink_to_uuid(zUuid);
450
+ if( isLeaf ){
451
+ if( db_exists("SELECT 1 FROM tagxref"
452
+ " WHERE rid=%d AND tagid=%d AND tagtype>0",
453
+ rid, TAG_CLOSED) ){
454
+ @ <span class="timelineLeaf">Closed-Leaf:</span>
455
+ }else{
456
+ @ <span class="timelineLeaf">Leaf:</span>
457
+ }
458
+ }
459
+ }else if( zType[0]=='e' && tagid ){
460
+ hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
461
+ }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
462
+ hyperlink_to_uuid(zUuid);
463
+ }
464
+ if( tmFlags & TIMELINE_SHOWRID ){
465
+ int srcId = delta_source_rid(rid);
466
+ if( srcId ){
467
+ @ (%d(rid)&larr;%d(srcId))
468
+ }else{
469
+ @ (%d(rid))
470
+ }
471
+ }
434472
}
435473
db_column_blob(pQuery, commentColumn, &comment);
436474
if( zType[0]!='c' ){
437475
/* Comments for anything other than a check-in are generated by
438476
** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
477
+ @ <span class='timelineComment'>
439478
wiki_convert(&comment, 0, WIKI_INLINE);
440
- }else if( bCommentGitStyle ){
441
- /* Truncate comment at first blank line */
442
- int ii, jj;
443
- int n = blob_size(&comment);
444
- char *z = blob_str(&comment);
445
- for(ii=0; ii<n; ii++){
446
- if( z[ii]=='\n' ){
447
- for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){}
448
- if( z[jj]=='\n' ) break;
449
- }
450
- }
451
- z[ii] = 0;
452
- @ <span class="timelineComment">%W(z)</span>
453
- }else if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
454
- Blob truncated;
455
- blob_zero(&truncated);
456
- blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
457
- blob_append(&truncated, "...", 3);
458
- @ <span class="timelineComment">%W(blob_str(&truncated))</span>
459
- blob_reset(&truncated);
479
+ @ </span>
460480
}else{
461
- @ <span class="timelineComment">%W(blob_str(&comment))</span>
481
+ @ <span class='timelineComment timelineCheckinComment'>
482
+ if( bCommentGitStyle ){
483
+ /* Truncate comment at first blank line */
484
+ int ii, jj;
485
+ int n = blob_size(&comment);
486
+ char *z = blob_str(&comment);
487
+ for(ii=0; ii<n; ii++){
488
+ if( z[ii]=='\n' ){
489
+ for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){}
490
+ if( z[jj]=='\n' ) break;
491
+ }
492
+ }
493
+ z[ii] = 0;
494
+ @ %W(z)
495
+ }else if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
496
+ Blob truncated;
497
+ blob_zero(&truncated);
498
+ blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
499
+ blob_append(&truncated, "...", 3);
500
+ @ %W(blob_str(&truncated))
501
+ blob_reset(&truncated);
502
+ }else{
503
+ @ %W(blob_str(&comment))
504
+ }
505
+ @ </span>
462506
}
463507
blob_reset(&comment);
508
+
509
+ if( bHashAfterComment ){
510
+ if( zType[0]=='c' ){
511
+ hyperlink_to_uuid(zUuid);
512
+ if( isLeaf ){
513
+ if( db_exists("SELECT 1 FROM tagxref"
514
+ " WHERE rid=%d AND tagid=%d AND tagtype>0",
515
+ rid, TAG_CLOSED) ){
516
+ @ <span class="timelineLeaf">Closed-Leaf</span>
517
+ }else{
518
+ @ <span class="timelineLeaf">Leaf</span>
519
+ }
520
+ }
521
+ }else if( zType[0]=='e' && tagid ){
522
+ hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
523
+ }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
524
+ hyperlink_to_uuid(zUuid);
525
+ }
526
+ if( tmFlags & TIMELINE_SHOWRID ){
527
+ int srcId = delta_source_rid(rid);
528
+ if( srcId ){
529
+ @ (%d(rid)&larr;%d(srcId))
530
+ }else{
531
+ @ (%d(rid))
532
+ }
533
+ }
534
+ }
535
+
464536
465537
/* Generate extra information and hyperlinks to follow the comment.
466538
** Example: "(check-in: [abcdefg], user: drh, tags: trunk)"
467539
*/
468
- cgi_printf("<span class='timelineDetail'>(");
469
- if( isLeaf ){
470
- if( db_exists("SELECT 1 FROM tagxref"
471
- " WHERE rid=%d AND tagid=%d AND tagtype>0",
472
- rid, TAG_CLOSED) ){
473
- @ <span class='timelineLeaf'>Closed-Leaf</span>
474
- }else{
475
- @ <span class='timelineLeaf'>Leaf</span>
476
- }
477
- }
478
-
479
- if( zType[0]=='c' ){
480
- cgi_printf("check-in: ");
481
- hyperlink_to_uuid(zUuid);
482
- }else if( zType[0]=='e' && tagid ){
483
- cgi_printf("technote: ");
484
- hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
485
- }else{
486
- cgi_printf("artifact: ");
487
- hyperlink_to_uuid(zUuid);
488
- }
489
-
490
- if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
491
- char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate);
492
- cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser);
493
- }else{
494
- cgi_printf("user: %h", zDispUser);
495
- }
496
-
497
- /* Generate the "tags: TAGLIST" at the end of the comment, together
498
- ** with hyperlinks to the tag list.
499
- */
500
- if( zTagList && zTagList[0]==0 ) zTagList = 0;
501
- if( zTagList ){
502
- if( g.perm.Hyperlink ){
503
- int i;
504
- const char *z = zTagList;
505
- Blob links;
506
- blob_zero(&links);
507
- while( z && z[0] ){
508
- for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
509
- if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
510
- blob_appendf(&links,
511
- "%z%#h</a>%.2s",
512
- href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i]
513
- );
514
- }else{
515
- blob_appendf(&links, "%#h", i+2, z);
516
- }
517
- if( z[i]==0 ) break;
518
- z += i+2;
519
- }
520
- cgi_printf(" tags: %s", blob_str(&links));
521
- blob_reset(&links);
522
- }else{
523
- cgi_printf(" tags: %h", zTagList);
524
- }
525
- }
526
-
527
- if( tmFlags & TIMELINE_SHOWRID ){
528
- int srcId = delta_source_rid(rid);
529
- if( srcId ){
530
- cgi_printf(" id: %d&larr;%d", rid, srcId);
531
- }else{
532
- cgi_printf(" id: %d", rid);
533
- }
534
- }
535
-
536
- cgi_printf(")</span>\n"); /* End of the details section */
537
-
540
+ if( bShowDetail ){
541
+ if( zType[0]=='c' ){
542
+ cgi_printf("<span class='timelineDetail timelineCheckinDetail'>(");
543
+ }else{
544
+ cgi_printf("<span class='timelineDetail'>(");
545
+ }
546
+
547
+ if( bHashInDetail ){
548
+ if( zType[0]=='c' ){
549
+ if( isLeaf ){
550
+ if( db_exists("SELECT 1 FROM tagxref"
551
+ " WHERE rid=%d AND tagid=%d AND tagtype>0",
552
+ rid, TAG_CLOSED) ){
553
+ @ <span class='timelineLeaf'>Closed-Leaf</span>
554
+ }else{
555
+ @ <span class='timelineLeaf'>Leaf</span>
556
+ }
557
+ }
558
+ cgi_printf("check-in: ");
559
+ hyperlink_to_uuid(zUuid);
560
+ }else if( zType[0]=='e' && tagid ){
561
+ cgi_printf("technote: ");
562
+ hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
563
+ }else{
564
+ cgi_printf("artifact: ");
565
+ hyperlink_to_uuid(zUuid);
566
+ }
567
+ }
568
+
569
+ if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
570
+ char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate);
571
+ cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser);
572
+ }else{
573
+ cgi_printf("user: %h", zDispUser);
574
+ }
575
+
576
+ /* Generate the "tags: TAGLIST" at the end of the comment, together
577
+ ** with hyperlinks to the tag list.
578
+ */
579
+ if( zTagList && zTagList[0]==0 ) zTagList = 0;
580
+ if( zTagList ){
581
+ if( g.perm.Hyperlink ){
582
+ int i;
583
+ const char *z = zTagList;
584
+ Blob links;
585
+ blob_zero(&links);
586
+ while( z && z[0] ){
587
+ for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
588
+ if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
589
+ blob_appendf(&links,
590
+ "%z%#h</a>%.2s",
591
+ href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i]
592
+ );
593
+ }else{
594
+ blob_appendf(&links, "%#h", i+2, z);
595
+ }
596
+ if( z[i]==0 ) break;
597
+ z += i+2;
598
+ }
599
+ cgi_printf(" tags: %s", blob_str(&links));
600
+ blob_reset(&links);
601
+ }else{
602
+ cgi_printf(" tags: %h", zTagList);
603
+ }
604
+ }
605
+
606
+ if( tmFlags & TIMELINE_SHOWRID ){
607
+ int srcId = delta_source_rid(rid);
608
+ if( srcId ){
609
+ cgi_printf(" id: %d&larr;%d", rid, srcId);
610
+ }else{
611
+ cgi_printf(" id: %d", rid);
612
+ }
613
+ }
614
+ cgi_printf(")</span>\n"); /* End of the details section */
615
+ }
616
+
538617
tag_private_status(rid);
539618
540619
/* Generate extra hyperlinks at the end of the comment */
541620
if( xExtra ){
542621
xExtra(rid);
543622
--- src/timeline.c
+++ src/timeline.c
@@ -248,10 +248,15 @@
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 const char *zDateFmt;
254 int iTableId = timeline_tableid();
255
256 if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){
257 vid = db_lget_int("checkout", 0);
@@ -258,10 +263,17 @@
258 }
259 zPrevDate[0] = 0;
260 mxWikiLen = db_get_int("timeline-max-comment", 0);
261 dateFormat = db_get_int("timeline-date-format", 0);
262 bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0);
 
 
 
 
 
 
 
263 zDateFmt = P("datefmt");
264 if( zDateFmt ) dateFormat = atoi(zDateFmt);
265 if( tmFlags & TIMELINE_GRAPH ){
266 pGraph = graph_init();
267 }
@@ -429,114 +441,181 @@
429 if( db_step(&bisectQuery)==SQLITE_ROW ){
430 @ <b>%s(db_column_text(&bisectQuery,1))</b>
431 @ (%d(db_column_int(&bisectQuery,0)))
432 }
433 db_reset(&bisectQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
434 }
435 db_column_blob(pQuery, commentColumn, &comment);
436 if( zType[0]!='c' ){
437 /* Comments for anything other than a check-in are generated by
438 ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
 
439 wiki_convert(&comment, 0, WIKI_INLINE);
440 }else if( bCommentGitStyle ){
441 /* Truncate comment at first blank line */
442 int ii, jj;
443 int n = blob_size(&comment);
444 char *z = blob_str(&comment);
445 for(ii=0; ii<n; ii++){
446 if( z[ii]=='\n' ){
447 for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){}
448 if( z[jj]=='\n' ) break;
449 }
450 }
451 z[ii] = 0;
452 @ <span class="timelineComment">%W(z)</span>
453 }else if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
454 Blob truncated;
455 blob_zero(&truncated);
456 blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
457 blob_append(&truncated, "...", 3);
458 @ <span class="timelineComment">%W(blob_str(&truncated))</span>
459 blob_reset(&truncated);
460 }else{
461 @ <span class="timelineComment">%W(blob_str(&comment))</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462 }
463 blob_reset(&comment);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
465 /* Generate extra information and hyperlinks to follow the comment.
466 ** Example: "(check-in: [abcdefg], user: drh, tags: trunk)"
467 */
468 cgi_printf("<span class='timelineDetail'>(");
469 if( isLeaf ){
470 if( db_exists("SELECT 1 FROM tagxref"
471 " WHERE rid=%d AND tagid=%d AND tagtype>0",
472 rid, TAG_CLOSED) ){
473 @ <span class='timelineLeaf'>Closed-Leaf</span>
474 }else{
475 @ <span class='timelineLeaf'>Leaf</span>
476 }
477 }
478
479 if( zType[0]=='c' ){
480 cgi_printf("check-in: ");
481 hyperlink_to_uuid(zUuid);
482 }else if( zType[0]=='e' && tagid ){
483 cgi_printf("technote: ");
484 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
485 }else{
486 cgi_printf("artifact: ");
487 hyperlink_to_uuid(zUuid);
488 }
489
490 if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
491 char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate);
492 cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser);
493 }else{
494 cgi_printf("user: %h", zDispUser);
495 }
496
497 /* Generate the "tags: TAGLIST" at the end of the comment, together
498 ** with hyperlinks to the tag list.
499 */
500 if( zTagList && zTagList[0]==0 ) zTagList = 0;
501 if( zTagList ){
502 if( g.perm.Hyperlink ){
503 int i;
504 const char *z = zTagList;
505 Blob links;
506 blob_zero(&links);
507 while( z && z[0] ){
508 for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
509 if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
510 blob_appendf(&links,
511 "%z%#h</a>%.2s",
512 href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i]
513 );
514 }else{
515 blob_appendf(&links, "%#h", i+2, z);
516 }
517 if( z[i]==0 ) break;
518 z += i+2;
519 }
520 cgi_printf(" tags: %s", blob_str(&links));
521 blob_reset(&links);
522 }else{
523 cgi_printf(" tags: %h", zTagList);
524 }
525 }
526
527 if( tmFlags & TIMELINE_SHOWRID ){
528 int srcId = delta_source_rid(rid);
529 if( srcId ){
530 cgi_printf(" id: %d&larr;%d", rid, srcId);
531 }else{
532 cgi_printf(" id: %d", rid);
533 }
534 }
535
536 cgi_printf(")</span>\n"); /* End of the details section */
537
 
 
 
 
 
 
 
538 tag_private_status(rid);
539
540 /* Generate extra hyperlinks at the end of the comment */
541 if( xExtra ){
542 xExtra(rid);
543
--- src/timeline.c
+++ src/timeline.c
@@ -248,10 +248,15 @@
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 eCommentFormat; /* value for timeline-comment-format */
258 const char *zDateFmt;
259 int iTableId = timeline_tableid();
260
261 if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){
262 vid = db_lget_int("checkout", 0);
@@ -258,10 +263,17 @@
263 }
264 zPrevDate[0] = 0;
265 mxWikiLen = db_get_int("timeline-max-comment", 0);
266 dateFormat = db_get_int("timeline-date-format", 0);
267 bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0);
268 eCommentFormat = db_get_int("timeline-comment-format", 0);
269 bShowDetail = (eCommentFormat & 1)==0; /* Bit 0 suppresses the comment */
270 switch( (eCommentFormat>>1)&3 ){
271 case 1: bHashAfterComment = 1; break;
272 case 2: bHashInDetail = 1; break;
273 default: bHashBeforeComment = 1; break;
274 }
275 zDateFmt = P("datefmt");
276 if( zDateFmt ) dateFormat = atoi(zDateFmt);
277 if( tmFlags & TIMELINE_GRAPH ){
278 pGraph = graph_init();
279 }
@@ -429,114 +441,181 @@
441 if( db_step(&bisectQuery)==SQLITE_ROW ){
442 @ <b>%s(db_column_text(&bisectQuery,1))</b>
443 @ (%d(db_column_int(&bisectQuery,0)))
444 }
445 db_reset(&bisectQuery);
446 }
447 if( bHashBeforeComment ){
448 if( zType[0]=='c' ){
449 hyperlink_to_uuid(zUuid);
450 if( isLeaf ){
451 if( db_exists("SELECT 1 FROM tagxref"
452 " WHERE rid=%d AND tagid=%d AND tagtype>0",
453 rid, TAG_CLOSED) ){
454 @ <span class="timelineLeaf">Closed-Leaf:</span>
455 }else{
456 @ <span class="timelineLeaf">Leaf:</span>
457 }
458 }
459 }else if( zType[0]=='e' && tagid ){
460 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
461 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
462 hyperlink_to_uuid(zUuid);
463 }
464 if( tmFlags & TIMELINE_SHOWRID ){
465 int srcId = delta_source_rid(rid);
466 if( srcId ){
467 @ (%d(rid)&larr;%d(srcId))
468 }else{
469 @ (%d(rid))
470 }
471 }
472 }
473 db_column_blob(pQuery, commentColumn, &comment);
474 if( zType[0]!='c' ){
475 /* Comments for anything other than a check-in are generated by
476 ** "fossil rebuild" and expect to be rendered as text/x-fossil-wiki */
477 @ <span class='timelineComment'>
478 wiki_convert(&comment, 0, WIKI_INLINE);
479 @ </span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480 }else{
481 @ <span class='timelineComment timelineCheckinComment'>
482 if( bCommentGitStyle ){
483 /* Truncate comment at first blank line */
484 int ii, jj;
485 int n = blob_size(&comment);
486 char *z = blob_str(&comment);
487 for(ii=0; ii<n; ii++){
488 if( z[ii]=='\n' ){
489 for(jj=ii+1; jj<n && z[jj]!='\n' && fossil_isspace(z[jj]); jj++){}
490 if( z[jj]=='\n' ) break;
491 }
492 }
493 z[ii] = 0;
494 @ %W(z)
495 }else if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
496 Blob truncated;
497 blob_zero(&truncated);
498 blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
499 blob_append(&truncated, "...", 3);
500 @ %W(blob_str(&truncated))
501 blob_reset(&truncated);
502 }else{
503 @ %W(blob_str(&comment))
504 }
505 @ </span>
506 }
507 blob_reset(&comment);
508
509 if( bHashAfterComment ){
510 if( zType[0]=='c' ){
511 hyperlink_to_uuid(zUuid);
512 if( isLeaf ){
513 if( db_exists("SELECT 1 FROM tagxref"
514 " WHERE rid=%d AND tagid=%d AND tagtype>0",
515 rid, TAG_CLOSED) ){
516 @ <span class="timelineLeaf">Closed-Leaf</span>
517 }else{
518 @ <span class="timelineLeaf">Leaf</span>
519 }
520 }
521 }else if( zType[0]=='e' && tagid ){
522 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
523 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
524 hyperlink_to_uuid(zUuid);
525 }
526 if( tmFlags & TIMELINE_SHOWRID ){
527 int srcId = delta_source_rid(rid);
528 if( srcId ){
529 @ (%d(rid)&larr;%d(srcId))
530 }else{
531 @ (%d(rid))
532 }
533 }
534 }
535
536
537 /* Generate extra information and hyperlinks to follow the comment.
538 ** Example: "(check-in: [abcdefg], user: drh, tags: trunk)"
539 */
540 if( bShowDetail ){
541 if( zType[0]=='c' ){
542 cgi_printf("<span class='timelineDetail timelineCheckinDetail'>(");
543 }else{
544 cgi_printf("<span class='timelineDetail'>(");
545 }
546
547 if( bHashInDetail ){
548 if( zType[0]=='c' ){
549 if( isLeaf ){
550 if( db_exists("SELECT 1 FROM tagxref"
551 " WHERE rid=%d AND tagid=%d AND tagtype>0",
552 rid, TAG_CLOSED) ){
553 @ <span class='timelineLeaf'>Closed-Leaf</span>
554 }else{
555 @ <span class='timelineLeaf'>Leaf</span>
556 }
557 }
558 cgi_printf("check-in: ");
559 hyperlink_to_uuid(zUuid);
560 }else if( zType[0]=='e' && tagid ){
561 cgi_printf("technote: ");
562 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
563 }else{
564 cgi_printf("artifact: ");
565 hyperlink_to_uuid(zUuid);
566 }
567 }
568
569 if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
570 char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd&n=200", zDispUser, zDate);
571 cgi_printf("user: %z%h</a>", href("%z",zLink), zDispUser);
572 }else{
573 cgi_printf("user: %h", zDispUser);
574 }
575
576 /* Generate the "tags: TAGLIST" at the end of the comment, together
577 ** with hyperlinks to the tag list.
578 */
579 if( zTagList && zTagList[0]==0 ) zTagList = 0;
580 if( zTagList ){
581 if( g.perm.Hyperlink ){
582 int i;
583 const char *z = zTagList;
584 Blob links;
585 blob_zero(&links);
586 while( z && z[0] ){
587 for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
588 if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
589 blob_appendf(&links,
590 "%z%#h</a>%.2s",
591 href("%R/timeline?r=%#t&nd&c=%t&n=200",i,z,zDate), i,z, &z[i]
592 );
593 }else{
594 blob_appendf(&links, "%#h", i+2, z);
595 }
596 if( z[i]==0 ) break;
597 z += i+2;
598 }
599 cgi_printf(" tags: %s", blob_str(&links));
600 blob_reset(&links);
601 }else{
602 cgi_printf(" tags: %h", zTagList);
603 }
604 }
605
606 if( tmFlags & TIMELINE_SHOWRID ){
607 int srcId = delta_source_rid(rid);
608 if( srcId ){
609 cgi_printf(" id: %d&larr;%d", rid, srcId);
610 }else{
611 cgi_printf(" id: %d", rid);
612 }
613 }
614 cgi_printf(")</span>\n"); /* End of the details section */
615 }
616
617 tag_private_status(rid);
618
619 /* Generate extra hyperlinks at the end of the comment */
620 if( xExtra ){
621 xExtra(rid);
622

Keyboard Shortcuts

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