Fossil SCM

Add the ability to display the history of edits to a single timeline post. Improvements to the CSS for timeline display in the default skin.

drh 2020-04-18 21:05 trunk
Commit 34d8d7e714a8e9f0ec785906a2cd9da01faac680d623612e6ab60a37f38b850a
2 files changed +1 -1 +102 -1
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -145,11 +145,11 @@
145145
border-radius: 5px;
146146
}
147147
.content blockquote {
148148
padding: 0 15px;
149149
}
150
-div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote {
150
+div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote, div.forumTime blockquote, div.forumTimeline blockquote {
151151
background-color: rgba(65, 131, 196, 0.1);
152152
border-left: 3px solid #254769;
153153
padding: .1em 1em;
154154
}
155155
156156
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -145,11 +145,11 @@
145 border-radius: 5px;
146 }
147 .content blockquote {
148 padding: 0 15px;
149 }
150 div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote {
151 background-color: rgba(65, 131, 196, 0.1);
152 border-left: 3px solid #254769;
153 padding: .1em 1em;
154 }
155
156
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -145,11 +145,11 @@
145 border-radius: 5px;
146 }
147 .content blockquote {
148 padding: 0 15px;
149 }
150 div.forumHierRoot blockquote, div.forumHier blockquote, div.forumEdit blockquote, div.forumTime blockquote, div.forumTimeline blockquote {
151 background-color: rgba(65, 131, 196, 0.1);
152 border-left: 3px solid #254769;
153 padding: .1em 1em;
154 }
155
156
+102 -1
--- src/forum.c
+++ src/forum.c
@@ -501,10 +501,101 @@
501501
manifest_destroy(pPost);
502502
@ </div>
503503
}
504504
forumthread_delete(pThread);
505505
}
506
+/*
507
+** Display all the edit history of post "target".
508
+*/
509
+static void forum_display_history(int froot, int target, int bRawMode){
510
+ ForumThread *pThread = forumthread_create(froot, 0);
511
+ ForumEntry *p;
512
+ int notAnon = login_is_individual();
513
+ char cMode = bRawMode ? 'r' : 'c';
514
+ ForumEntry *pLeaf = 0;
515
+ int cnt = 0;
516
+ for(p=pThread->pFirst; p; p=p->pNext){
517
+ if( p->fpid==target ){
518
+ pLeaf = p->pLeaf ? p->pLeaf : p;
519
+ break;
520
+ }
521
+ }
522
+ for(p=pThread->pFirst; p; p=p->pNext){
523
+ char *zDate;
524
+ Manifest *pPost;
525
+ int isPrivate; /* True for posts awaiting moderation */
526
+ int sameUser; /* True if author is also the reader */
527
+ const char *zUuid;
528
+ char *zDisplayName; /* The display name */
529
+
530
+ if( p->fpid!=pLeaf->fpid && p->pLeaf!=pLeaf ) continue;
531
+ cnt++;
532
+ pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
533
+ if( pPost==0 ) continue;
534
+ @ <div id="forum%d(p->fpid)" class="forumTime">
535
+ zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
536
+ zDisplayName = display_name_from_login(pPost->zUser);
537
+ @ <h3 class='forumPostHdr'>(%d(p->sid)) By %h(zDisplayName) on %h(zDate)
538
+ fossil_free(zDisplayName);
539
+ fossil_free(zDate);
540
+ if( g.perm.Debug ){
541
+ @ <span class="debug">\
542
+ @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span>
543
+ }
544
+ if( p->firt && cnt==1 ){
545
+ ForumEntry *pIrt = p->pPrev;
546
+ while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev;
547
+ if( pIrt ){
548
+ @ in reply to %z(href("%R/forumpost/%S?t=%c",pIrt->zUuid,cMode))\
549
+ @ %d(pIrt->sid)</a>
550
+ }
551
+ }
552
+ zUuid = p->zUuid;
553
+ @ %z(href("%R/forumpost/%S?t=c",zUuid))[link]</a>
554
+ if( !bRawMode ){
555
+ @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a>
556
+ }
557
+ isPrivate = content_is_private(p->fpid);
558
+ sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
559
+ @ </h3>
560
+ if( isPrivate && !g.perm.ModForum && !sameUser ){
561
+ @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
562
+ }else{
563
+ forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki,
564
+ 0, 1);
565
+ }
566
+ if( g.perm.WrForum && p->pLeaf==0 ){
567
+ int sameUser = login_is_individual()
568
+ && fossil_strcmp(pPost->zUser, g.zLogin)==0;
569
+ @ <p><form action="%R/forumedit" method="POST">
570
+ @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
571
+ if( !isPrivate ){
572
+ /* Reply and Edit are only available if the post has already
573
+ ** been approved */
574
+ @ <input type="submit" name="reply" value="Reply">
575
+ if( g.perm.Admin || sameUser ){
576
+ @ <input type="submit" name="edit" value="Edit">
577
+ @ <input type="submit" name="nullout" value="Delete">
578
+ }
579
+ }else if( g.perm.ModForum ){
580
+ /* Provide moderators with moderation buttons for posts that
581
+ ** are pending moderation */
582
+ @ <input type="submit" name="approve" value="Approve">
583
+ @ <input type="submit" name="reject" value="Reject">
584
+ generateTrustControls(pPost);
585
+ }else if( sameUser ){
586
+ /* A post that is pending moderation can be deleted by the
587
+ ** person who originally submitted the post */
588
+ @ <input type="submit" name="reject" value="Delete">
589
+ }
590
+ @ </form></p>
591
+ }
592
+ manifest_destroy(pPost);
593
+ @ </div>
594
+ }
595
+ forumthread_delete(pThread);
596
+}
506597
507598
/*
508599
** Display all messages in a forumthread with indentation.
509600
*/
510601
static int forum_display_hierarchical(int froot, int target){
@@ -576,10 +667,11 @@
576667
if( g.perm.Debug ){
577668
@ <span class="debug">\
578669
@ <a href="%R/artifact/%h(p->pLeaf->zUuid)">\
579670
@ (artifact-%d(p->pLeaf->fpid))</a></span>
580671
}
672
+ @ %z(href("%R/forumpost/%S?t=y",p->zUuid))[history]</a>
581673
manifest_destroy(pOPost);
582674
}
583675
if( fpid!=target ){
584676
@ %z(href("%R/forumpost/%S",zUuid))[link]</a>
585677
}
@@ -645,10 +737,11 @@
645737
** t=MODE Display mode.
646738
** 'c' for chronological
647739
** 'h' for hierarchical
648740
** 'a' for automatic
649741
** 'r' for raw
742
+** 'y' for history of post X only
650743
** raw If present, show only the post specified and
651744
** show its original unformatted source text.
652745
*/
653746
void forumpost_page(void){
654747
forumthread_page();
@@ -687,10 +780,12 @@
687780
** t=MODE Display mode. MODE is...
688781
** 'c' for chronological, or
689782
** 'h' for hierarchical, or
690783
** 'a' for automatic, or
691784
** 'r' for raw.
785
+** raw Show only the post given by name= and show it unformatted
786
+** hist Show only the edit history for the name= post
692787
*/
693788
void forumthread_page(void){
694789
int fpid;
695790
int froot;
696791
const char *zName = P("name");
@@ -718,11 +813,13 @@
718813
zMode = "c"; /* Default to chronological on mobile */
719814
}else{
720815
zMode = "h";
721816
}
722817
}
723
- forumthread_page_header(froot, fpid);
818
+ if( zMode[0]!='y' ){
819
+ forumthread_page_header(froot, fpid);
820
+ }
724821
if( bRaw && fpid ){
725822
Manifest *pPost;
726823
pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
727824
if( pPost==0 ){
728825
@ <p>No such forum post: %h(zName)
@@ -743,10 +840,14 @@
743840
forum_display_chronological(froot, fpid, 0);
744841
}else if( zMode[0]=='r' ){
745842
style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
746843
style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName);
747844
forum_display_chronological(froot, fpid, 1);
845
+ }else if( zMode[0]=='y' ){
846
+ style_header("Edit History Of A Forum Post");
847
+ style_submenu_element("Complete Thread", "%R/%s/%s?t=a", g.zPath, zName);
848
+ forum_display_history(froot, fpid, 0);
748849
}else{
749850
style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
750851
style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
751852
forum_display_hierarchical(froot, fpid);
752853
}
753854
--- src/forum.c
+++ src/forum.c
@@ -501,10 +501,101 @@
501 manifest_destroy(pPost);
502 @ </div>
503 }
504 forumthread_delete(pThread);
505 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
507 /*
508 ** Display all messages in a forumthread with indentation.
509 */
510 static int forum_display_hierarchical(int froot, int target){
@@ -576,10 +667,11 @@
576 if( g.perm.Debug ){
577 @ <span class="debug">\
578 @ <a href="%R/artifact/%h(p->pLeaf->zUuid)">\
579 @ (artifact-%d(p->pLeaf->fpid))</a></span>
580 }
 
581 manifest_destroy(pOPost);
582 }
583 if( fpid!=target ){
584 @ %z(href("%R/forumpost/%S",zUuid))[link]</a>
585 }
@@ -645,10 +737,11 @@
645 ** t=MODE Display mode.
646 ** 'c' for chronological
647 ** 'h' for hierarchical
648 ** 'a' for automatic
649 ** 'r' for raw
 
650 ** raw If present, show only the post specified and
651 ** show its original unformatted source text.
652 */
653 void forumpost_page(void){
654 forumthread_page();
@@ -687,10 +780,12 @@
687 ** t=MODE Display mode. MODE is...
688 ** 'c' for chronological, or
689 ** 'h' for hierarchical, or
690 ** 'a' for automatic, or
691 ** 'r' for raw.
 
 
692 */
693 void forumthread_page(void){
694 int fpid;
695 int froot;
696 const char *zName = P("name");
@@ -718,11 +813,13 @@
718 zMode = "c"; /* Default to chronological on mobile */
719 }else{
720 zMode = "h";
721 }
722 }
723 forumthread_page_header(froot, fpid);
 
 
724 if( bRaw && fpid ){
725 Manifest *pPost;
726 pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
727 if( pPost==0 ){
728 @ <p>No such forum post: %h(zName)
@@ -743,10 +840,14 @@
743 forum_display_chronological(froot, fpid, 0);
744 }else if( zMode[0]=='r' ){
745 style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
746 style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName);
747 forum_display_chronological(froot, fpid, 1);
 
 
 
 
748 }else{
749 style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
750 style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
751 forum_display_hierarchical(froot, fpid);
752 }
753
--- src/forum.c
+++ src/forum.c
@@ -501,10 +501,101 @@
501 manifest_destroy(pPost);
502 @ </div>
503 }
504 forumthread_delete(pThread);
505 }
506 /*
507 ** Display all the edit history of post "target".
508 */
509 static void forum_display_history(int froot, int target, int bRawMode){
510 ForumThread *pThread = forumthread_create(froot, 0);
511 ForumEntry *p;
512 int notAnon = login_is_individual();
513 char cMode = bRawMode ? 'r' : 'c';
514 ForumEntry *pLeaf = 0;
515 int cnt = 0;
516 for(p=pThread->pFirst; p; p=p->pNext){
517 if( p->fpid==target ){
518 pLeaf = p->pLeaf ? p->pLeaf : p;
519 break;
520 }
521 }
522 for(p=pThread->pFirst; p; p=p->pNext){
523 char *zDate;
524 Manifest *pPost;
525 int isPrivate; /* True for posts awaiting moderation */
526 int sameUser; /* True if author is also the reader */
527 const char *zUuid;
528 char *zDisplayName; /* The display name */
529
530 if( p->fpid!=pLeaf->fpid && p->pLeaf!=pLeaf ) continue;
531 cnt++;
532 pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0);
533 if( pPost==0 ) continue;
534 @ <div id="forum%d(p->fpid)" class="forumTime">
535 zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate);
536 zDisplayName = display_name_from_login(pPost->zUser);
537 @ <h3 class='forumPostHdr'>(%d(p->sid)) By %h(zDisplayName) on %h(zDate)
538 fossil_free(zDisplayName);
539 fossil_free(zDate);
540 if( g.perm.Debug ){
541 @ <span class="debug">\
542 @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span>
543 }
544 if( p->firt && cnt==1 ){
545 ForumEntry *pIrt = p->pPrev;
546 while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev;
547 if( pIrt ){
548 @ in reply to %z(href("%R/forumpost/%S?t=%c",pIrt->zUuid,cMode))\
549 @ %d(pIrt->sid)</a>
550 }
551 }
552 zUuid = p->zUuid;
553 @ %z(href("%R/forumpost/%S?t=c",zUuid))[link]</a>
554 if( !bRawMode ){
555 @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a>
556 }
557 isPrivate = content_is_private(p->fpid);
558 sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0;
559 @ </h3>
560 if( isPrivate && !g.perm.ModForum && !sameUser ){
561 @ <p><span class="modpending">Awaiting Moderator Approval</span></p>
562 }else{
563 forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki,
564 0, 1);
565 }
566 if( g.perm.WrForum && p->pLeaf==0 ){
567 int sameUser = login_is_individual()
568 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
569 @ <p><form action="%R/forumedit" method="POST">
570 @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
571 if( !isPrivate ){
572 /* Reply and Edit are only available if the post has already
573 ** been approved */
574 @ <input type="submit" name="reply" value="Reply">
575 if( g.perm.Admin || sameUser ){
576 @ <input type="submit" name="edit" value="Edit">
577 @ <input type="submit" name="nullout" value="Delete">
578 }
579 }else if( g.perm.ModForum ){
580 /* Provide moderators with moderation buttons for posts that
581 ** are pending moderation */
582 @ <input type="submit" name="approve" value="Approve">
583 @ <input type="submit" name="reject" value="Reject">
584 generateTrustControls(pPost);
585 }else if( sameUser ){
586 /* A post that is pending moderation can be deleted by the
587 ** person who originally submitted the post */
588 @ <input type="submit" name="reject" value="Delete">
589 }
590 @ </form></p>
591 }
592 manifest_destroy(pPost);
593 @ </div>
594 }
595 forumthread_delete(pThread);
596 }
597
598 /*
599 ** Display all messages in a forumthread with indentation.
600 */
601 static int forum_display_hierarchical(int froot, int target){
@@ -576,10 +667,11 @@
667 if( g.perm.Debug ){
668 @ <span class="debug">\
669 @ <a href="%R/artifact/%h(p->pLeaf->zUuid)">\
670 @ (artifact-%d(p->pLeaf->fpid))</a></span>
671 }
672 @ %z(href("%R/forumpost/%S?t=y",p->zUuid))[history]</a>
673 manifest_destroy(pOPost);
674 }
675 if( fpid!=target ){
676 @ %z(href("%R/forumpost/%S",zUuid))[link]</a>
677 }
@@ -645,10 +737,11 @@
737 ** t=MODE Display mode.
738 ** 'c' for chronological
739 ** 'h' for hierarchical
740 ** 'a' for automatic
741 ** 'r' for raw
742 ** 'y' for history of post X only
743 ** raw If present, show only the post specified and
744 ** show its original unformatted source text.
745 */
746 void forumpost_page(void){
747 forumthread_page();
@@ -687,10 +780,12 @@
780 ** t=MODE Display mode. MODE is...
781 ** 'c' for chronological, or
782 ** 'h' for hierarchical, or
783 ** 'a' for automatic, or
784 ** 'r' for raw.
785 ** raw Show only the post given by name= and show it unformatted
786 ** hist Show only the edit history for the name= post
787 */
788 void forumthread_page(void){
789 int fpid;
790 int froot;
791 const char *zName = P("name");
@@ -718,11 +813,13 @@
813 zMode = "c"; /* Default to chronological on mobile */
814 }else{
815 zMode = "h";
816 }
817 }
818 if( zMode[0]!='y' ){
819 forumthread_page_header(froot, fpid);
820 }
821 if( bRaw && fpid ){
822 Manifest *pPost;
823 pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
824 if( pPost==0 ){
825 @ <p>No such forum post: %h(zName)
@@ -743,10 +840,14 @@
840 forum_display_chronological(froot, fpid, 0);
841 }else if( zMode[0]=='r' ){
842 style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
843 style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName);
844 forum_display_chronological(froot, fpid, 1);
845 }else if( zMode[0]=='y' ){
846 style_header("Edit History Of A Forum Post");
847 style_submenu_element("Complete Thread", "%R/%s/%s?t=a", g.zPath, zName);
848 forum_display_history(froot, fpid, 0);
849 }else{
850 style_submenu_element("Chronological", "%R/%s/%s?t=c", g.zPath, zName);
851 style_submenu_element("Unformatted", "%R/%s/%s?t=r", g.zPath, zName);
852 forum_display_hierarchical(froot, fpid);
853 }
854

Keyboard Shortcuts

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