Fossil SCM

Rename sticky to pinned. Add the pin/unpin button to root posts for setup users but it's not yet tied to JS to activate it.

stephan 2026-05-25 14:38 UTC pinned-forum-posts
Commit 10375c36eee553a2fe960367406e0753f8d6faaf00c16d24d2136fddc95fe3a9
1 file changed +77 -23
+77 -23
--- src/forum.c
+++ src/forum.c
@@ -863,21 +863,25 @@
863863
static void forum_render_attachment_list2(ForumPost *p){
864864
if( p->pEditHead ) p = p->pEditHead;
865865
forum_render_attachment_list(p->zUuid);
866866
}
867867
868
+/* Flags for use with forum_display_post() */
869
+#define FDISPLAY_RAW 0x01 /* omit the border */
870
+#define FDISPLAY_UNFORMATTED 0x02 /* leave the post unformatted */
871
+#define FDISPLAY_HISTORY 0x04 /* Showing edit history */
872
+#define FDISPLAY_SELECTED 0x08 /* This is the selected post */
873
+#define FDISPLAY_ISROOT 0x10 /* This is the root post */
874
+
868875
/*
869876
** Display a single post in a forum thread.
870877
*/
871878
static void forum_display_post(
872879
ForumThread *pThread, /* The thread that this post is a member of */
873880
ForumPost *p, /* Forum post to display */
874881
int iIndentScale, /* Indent scale factor */
875
- int bRaw, /* True to omit the border */
876
- int bUnf, /* True to leave the post unformatted */
877
- int bHist, /* True if showing edit history */
878
- int bSelect, /* True if this is the selected post */
882
+ int flags, /* From the FDISPLAY_... enum */
879883
char *zQuery /* Common query string */
880884
){
881885
char *zPosterName; /* Name of user who originally made this post */
882886
char *zEditorName; /* Name of user who provided the current edit */
883887
char *zDate; /* The time/date string */
@@ -886,10 +890,14 @@
886890
Manifest *pManifest; /* Manifest comprising the current post */
887891
int bPrivate; /* True for posts awaiting moderation */
888892
int bSameUser; /* True if author is also the reader */
889893
int iIndent; /* Indent level */
890894
int iClosed; /* True if (sub)thread is closed */
895
+ const int bRaw = flags & FDISPLAY_RAW;
896
+ const int bUnf = flags & FDISPLAY_UNFORMATTED;
897
+ const int bHist = flags & FDISPLAY_HISTORY;
898
+ const int bSelect = flags & FDISPLAY_SELECTED;
891899
const char *zMimetype;/* Formatting MIME type */
892900
893901
/* Get the manifest for the post. Abort if not found (e.g. shunned). */
894902
pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
895903
if( !pManifest ) return;
@@ -1079,10 +1087,20 @@
10791087
@ <input type="submit" value="Attach...">
10801088
login_insert_csrf_secret();
10811089
moderation_pending_www(p->fpid);
10821090
@ </form>
10831091
}
1092
+ if( !p->pIrt && g.perm.Setup ){
1093
+ const int isPinned = forum_rid_is_tagged(pHead->fpid, "pinned", 0);
1094
+ @ <form method="post" \
1095
+ @ action='%R/forumpost_%s(isPinned > 0 ? "unpin" : "pin")'>
1096
+ login_insert_csrf_secret();
1097
+ @ <input type="hidden" name="fpid" value="%s(pHead->zUuid)" />
1098
+ @ <input type="button" value='%s(isPinned ? "Unpin" : "Pin")' \
1099
+ @ class='%s(isPinned ? "action-unpin" : "action-pin")'/>
1100
+ @ </form>
1101
+ }
10841102
}
10851103
@ </div>
10861104
}
10871105
@ </div>
10881106
}
@@ -1197,12 +1215,19 @@
11971215
}
11981216
11991217
/* Display the appropriate subset of posts in sequence. */
12001218
while( p ){
12011219
/* Display the post. */
1202
- forum_display_post(pThread, p, iIndentScale, mode==FD_RAW,
1203
- bUnf, bHist, p==pSelect, zQuery);
1220
+ forum_display_post(
1221
+ pThread, p, iIndentScale,
1222
+ (mode==FD_RAW ? FDISPLAY_RAW : 0) |
1223
+ (bUnf ? FDISPLAY_UNFORMATTED : 0) |
1224
+ (bHist ? FDISPLAY_HISTORY : 0) |
1225
+ (p==pSelect ? FDISPLAY_SELECTED : 0) |
1226
+ ((0==fpid || fpid==froot) ? FDISPLAY_ISROOT : 0),
1227
+ zQuery
1228
+ );
12041229
12051230
/* Advance to the next post in the thread. */
12061231
if( mode==FD_CHRONO ){
12071232
/* Chronological mode: display posts (optionally including edits) in their
12081233
** original commit order. */
@@ -1572,10 +1597,29 @@
15721597
mimetype_option_menu(zMimetype, "mimetype");
15731598
@ <div class="forum-editor-widget">
15741599
@ <textarea aria-label="Content:" name="content" class="wikiedit" \
15751600
@ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea></div>
15761601
}
1602
+
1603
+/*
1604
+** Internal helper for /forumpost_XYZ internal pages which tag/untag
1605
+** posts.
1606
+*/
1607
+static void forumpost_action_helper(const char *zTag, const char *zVal,
1608
+ int addTag){
1609
+ const char *zFpid = PD("fpid","");
1610
+ int fpid;
1611
+
1612
+ cgi_csrf_verify();
1613
+ fpid = symbolic_name_to_rid(zFpid, "f");
1614
+ if( fpid<=0 ){
1615
+ webpage_error("Missing or invalid fpid query parameter");
1616
+ }
1617
+ forumpost_tag(fpid, zTag, addTag, zVal);
1618
+ cgi_redirectf("%R/forumpost/%S",zFpid);
1619
+ return;
1620
+}
15771621
15781622
/*
15791623
** WEBPAGE: forumpost_close hidden
15801624
** WEBPAGE: forumpost_reopen hidden
15811625
**
@@ -1586,30 +1630,40 @@
15861630
** API for forumpost_tag(). After (perhaps) modifying the "closed"
15871631
** status of the given thread, it redirects to that post's thread
15881632
** view. Requires admin privileges.
15891633
*/
15901634
void forum_page_close(void){
1591
- const char *zFpid = PD("fpid","");
1592
- const char *zReason = 0;
1593
- int fClose;
1594
- int fpid;
1595
-
15961635
login_check_credentials();
15971636
if( forumpost_may_close()==0 ){
15981637
login_needed(g.anon.Admin);
15991638
return;
1600
- }
1601
- cgi_csrf_verify();
1602
- fpid = symbolic_name_to_rid(zFpid, "f");
1603
- if( fpid<=0 ){
1604
- webpage_error("Missing or invalid fpid query parameter");
1605
- }
1606
- fClose = sqlite3_strglob("*_close*", g.zPath)==0;
1607
- if( fClose ) zReason = PD("reason",0);
1608
- forumpost_tag(fpid, "closed", fClose, zReason);
1609
- cgi_redirectf("%R/forumpost/%S",zFpid);
1610
- return;
1639
+ }else{
1640
+ int bIsAdd = sqlite3_strglob("*_close*", g.zPath)==0;
1641
+ char const *zReason = bIsAdd ? 0 : PD("reason", 0);
1642
+ forumpost_action_helper("closed", zReason, bIsAdd);
1643
+ }
1644
+}
1645
+
1646
+/*
1647
+** WEBPAGE: forumpost_pin hidden
1648
+** WEBPAGE: forumpost_unpin hidden
1649
+**
1650
+** fpid=X Hash of the post to be edited. REQUIRED
1651
+**
1652
+** Pins or unpins the given forum post, within the bounds of the
1653
+** API for forumpost_tag(). After (perhaps) modifying the "pinned"
1654
+** tag of the given thread, it redirects to that post's thread
1655
+** view. Requires setup privileges.
1656
+*/
1657
+void forum_page_pin(void){
1658
+ login_check_credentials();
1659
+ if( !g.perm.Setup ){
1660
+ login_needed(g.anon.Setup);
1661
+ return;
1662
+ }
1663
+ forumpost_action_helper("pinned", 0,
1664
+ sqlite3_strglob("*_pin*", g.zPath)==0);
16111665
}
16121666
16131667
/*
16141668
** WEBPAGE: forumnew
16151669
** WEBPAGE: forumedit
@@ -2182,11 +2236,11 @@
21822236
" CASE WHEN"
21832237
" firt IS NULL AND"
21842238
" (SELECT 1 FROM tagxref ref, tag t"
21852239
" WHERE ref.rid=x.fpid AND ref.tagtype>0"
21862240
" AND ref.tagid=t.tagid"
2187
- " AND t.tagname='sticky')"
2241
+ " AND t.tagname='pinned')"
21882242
" THEN 1"
21892243
" ELSE 0"
21902244
" END"
21912245
" FROM forumpost AS x"
21922246
" WHERE %s"
21932247
--- src/forum.c
+++ src/forum.c
@@ -863,21 +863,25 @@
863 static void forum_render_attachment_list2(ForumPost *p){
864 if( p->pEditHead ) p = p->pEditHead;
865 forum_render_attachment_list(p->zUuid);
866 }
867
 
 
 
 
 
 
 
868 /*
869 ** Display a single post in a forum thread.
870 */
871 static void forum_display_post(
872 ForumThread *pThread, /* The thread that this post is a member of */
873 ForumPost *p, /* Forum post to display */
874 int iIndentScale, /* Indent scale factor */
875 int bRaw, /* True to omit the border */
876 int bUnf, /* True to leave the post unformatted */
877 int bHist, /* True if showing edit history */
878 int bSelect, /* True if this is the selected post */
879 char *zQuery /* Common query string */
880 ){
881 char *zPosterName; /* Name of user who originally made this post */
882 char *zEditorName; /* Name of user who provided the current edit */
883 char *zDate; /* The time/date string */
@@ -886,10 +890,14 @@
886 Manifest *pManifest; /* Manifest comprising the current post */
887 int bPrivate; /* True for posts awaiting moderation */
888 int bSameUser; /* True if author is also the reader */
889 int iIndent; /* Indent level */
890 int iClosed; /* True if (sub)thread is closed */
 
 
 
 
891 const char *zMimetype;/* Formatting MIME type */
892
893 /* Get the manifest for the post. Abort if not found (e.g. shunned). */
894 pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
895 if( !pManifest ) return;
@@ -1079,10 +1087,20 @@
1079 @ <input type="submit" value="Attach...">
1080 login_insert_csrf_secret();
1081 moderation_pending_www(p->fpid);
1082 @ </form>
1083 }
 
 
 
 
 
 
 
 
 
 
1084 }
1085 @ </div>
1086 }
1087 @ </div>
1088 }
@@ -1197,12 +1215,19 @@
1197 }
1198
1199 /* Display the appropriate subset of posts in sequence. */
1200 while( p ){
1201 /* Display the post. */
1202 forum_display_post(pThread, p, iIndentScale, mode==FD_RAW,
1203 bUnf, bHist, p==pSelect, zQuery);
 
 
 
 
 
 
 
1204
1205 /* Advance to the next post in the thread. */
1206 if( mode==FD_CHRONO ){
1207 /* Chronological mode: display posts (optionally including edits) in their
1208 ** original commit order. */
@@ -1572,10 +1597,29 @@
1572 mimetype_option_menu(zMimetype, "mimetype");
1573 @ <div class="forum-editor-widget">
1574 @ <textarea aria-label="Content:" name="content" class="wikiedit" \
1575 @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea></div>
1576 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1577
1578 /*
1579 ** WEBPAGE: forumpost_close hidden
1580 ** WEBPAGE: forumpost_reopen hidden
1581 **
@@ -1586,30 +1630,40 @@
1586 ** API for forumpost_tag(). After (perhaps) modifying the "closed"
1587 ** status of the given thread, it redirects to that post's thread
1588 ** view. Requires admin privileges.
1589 */
1590 void forum_page_close(void){
1591 const char *zFpid = PD("fpid","");
1592 const char *zReason = 0;
1593 int fClose;
1594 int fpid;
1595
1596 login_check_credentials();
1597 if( forumpost_may_close()==0 ){
1598 login_needed(g.anon.Admin);
1599 return;
1600 }
1601 cgi_csrf_verify();
1602 fpid = symbolic_name_to_rid(zFpid, "f");
1603 if( fpid<=0 ){
1604 webpage_error("Missing or invalid fpid query parameter");
1605 }
1606 fClose = sqlite3_strglob("*_close*", g.zPath)==0;
1607 if( fClose ) zReason = PD("reason",0);
1608 forumpost_tag(fpid, "closed", fClose, zReason);
1609 cgi_redirectf("%R/forumpost/%S",zFpid);
1610 return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1611 }
1612
1613 /*
1614 ** WEBPAGE: forumnew
1615 ** WEBPAGE: forumedit
@@ -2182,11 +2236,11 @@
2182 " CASE WHEN"
2183 " firt IS NULL AND"
2184 " (SELECT 1 FROM tagxref ref, tag t"
2185 " WHERE ref.rid=x.fpid AND ref.tagtype>0"
2186 " AND ref.tagid=t.tagid"
2187 " AND t.tagname='sticky')"
2188 " THEN 1"
2189 " ELSE 0"
2190 " END"
2191 " FROM forumpost AS x"
2192 " WHERE %s"
2193
--- src/forum.c
+++ src/forum.c
@@ -863,21 +863,25 @@
863 static void forum_render_attachment_list2(ForumPost *p){
864 if( p->pEditHead ) p = p->pEditHead;
865 forum_render_attachment_list(p->zUuid);
866 }
867
868 /* Flags for use with forum_display_post() */
869 #define FDISPLAY_RAW 0x01 /* omit the border */
870 #define FDISPLAY_UNFORMATTED 0x02 /* leave the post unformatted */
871 #define FDISPLAY_HISTORY 0x04 /* Showing edit history */
872 #define FDISPLAY_SELECTED 0x08 /* This is the selected post */
873 #define FDISPLAY_ISROOT 0x10 /* This is the root post */
874
875 /*
876 ** Display a single post in a forum thread.
877 */
878 static void forum_display_post(
879 ForumThread *pThread, /* The thread that this post is a member of */
880 ForumPost *p, /* Forum post to display */
881 int iIndentScale, /* Indent scale factor */
882 int flags, /* From the FDISPLAY_... enum */
 
 
 
883 char *zQuery /* Common query string */
884 ){
885 char *zPosterName; /* Name of user who originally made this post */
886 char *zEditorName; /* Name of user who provided the current edit */
887 char *zDate; /* The time/date string */
@@ -886,10 +890,14 @@
890 Manifest *pManifest; /* Manifest comprising the current post */
891 int bPrivate; /* True for posts awaiting moderation */
892 int bSameUser; /* True if author is also the reader */
893 int iIndent; /* Indent level */
894 int iClosed; /* True if (sub)thread is closed */
895 const int bRaw = flags & FDISPLAY_RAW;
896 const int bUnf = flags & FDISPLAY_UNFORMATTED;
897 const int bHist = flags & FDISPLAY_HISTORY;
898 const int bSelect = flags & FDISPLAY_SELECTED;
899 const char *zMimetype;/* Formatting MIME type */
900
901 /* Get the manifest for the post. Abort if not found (e.g. shunned). */
902 pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
903 if( !pManifest ) return;
@@ -1079,10 +1087,20 @@
1087 @ <input type="submit" value="Attach...">
1088 login_insert_csrf_secret();
1089 moderation_pending_www(p->fpid);
1090 @ </form>
1091 }
1092 if( !p->pIrt && g.perm.Setup ){
1093 const int isPinned = forum_rid_is_tagged(pHead->fpid, "pinned", 0);
1094 @ <form method="post" \
1095 @ action='%R/forumpost_%s(isPinned > 0 ? "unpin" : "pin")'>
1096 login_insert_csrf_secret();
1097 @ <input type="hidden" name="fpid" value="%s(pHead->zUuid)" />
1098 @ <input type="button" value='%s(isPinned ? "Unpin" : "Pin")' \
1099 @ class='%s(isPinned ? "action-unpin" : "action-pin")'/>
1100 @ </form>
1101 }
1102 }
1103 @ </div>
1104 }
1105 @ </div>
1106 }
@@ -1197,12 +1215,19 @@
1215 }
1216
1217 /* Display the appropriate subset of posts in sequence. */
1218 while( p ){
1219 /* Display the post. */
1220 forum_display_post(
1221 pThread, p, iIndentScale,
1222 (mode==FD_RAW ? FDISPLAY_RAW : 0) |
1223 (bUnf ? FDISPLAY_UNFORMATTED : 0) |
1224 (bHist ? FDISPLAY_HISTORY : 0) |
1225 (p==pSelect ? FDISPLAY_SELECTED : 0) |
1226 ((0==fpid || fpid==froot) ? FDISPLAY_ISROOT : 0),
1227 zQuery
1228 );
1229
1230 /* Advance to the next post in the thread. */
1231 if( mode==FD_CHRONO ){
1232 /* Chronological mode: display posts (optionally including edits) in their
1233 ** original commit order. */
@@ -1572,10 +1597,29 @@
1597 mimetype_option_menu(zMimetype, "mimetype");
1598 @ <div class="forum-editor-widget">
1599 @ <textarea aria-label="Content:" name="content" class="wikiedit" \
1600 @ cols="80" rows="25" wrap="virtual">%h(zContent)</textarea></div>
1601 }
1602
1603 /*
1604 ** Internal helper for /forumpost_XYZ internal pages which tag/untag
1605 ** posts.
1606 */
1607 static void forumpost_action_helper(const char *zTag, const char *zVal,
1608 int addTag){
1609 const char *zFpid = PD("fpid","");
1610 int fpid;
1611
1612 cgi_csrf_verify();
1613 fpid = symbolic_name_to_rid(zFpid, "f");
1614 if( fpid<=0 ){
1615 webpage_error("Missing or invalid fpid query parameter");
1616 }
1617 forumpost_tag(fpid, zTag, addTag, zVal);
1618 cgi_redirectf("%R/forumpost/%S",zFpid);
1619 return;
1620 }
1621
1622 /*
1623 ** WEBPAGE: forumpost_close hidden
1624 ** WEBPAGE: forumpost_reopen hidden
1625 **
@@ -1586,30 +1630,40 @@
1630 ** API for forumpost_tag(). After (perhaps) modifying the "closed"
1631 ** status of the given thread, it redirects to that post's thread
1632 ** view. Requires admin privileges.
1633 */
1634 void forum_page_close(void){
 
 
 
 
 
1635 login_check_credentials();
1636 if( forumpost_may_close()==0 ){
1637 login_needed(g.anon.Admin);
1638 return;
1639 }else{
1640 int bIsAdd = sqlite3_strglob("*_close*", g.zPath)==0;
1641 char const *zReason = bIsAdd ? 0 : PD("reason", 0);
1642 forumpost_action_helper("closed", zReason, bIsAdd);
1643 }
1644 }
1645
1646 /*
1647 ** WEBPAGE: forumpost_pin hidden
1648 ** WEBPAGE: forumpost_unpin hidden
1649 **
1650 ** fpid=X Hash of the post to be edited. REQUIRED
1651 **
1652 ** Pins or unpins the given forum post, within the bounds of the
1653 ** API for forumpost_tag(). After (perhaps) modifying the "pinned"
1654 ** tag of the given thread, it redirects to that post's thread
1655 ** view. Requires setup privileges.
1656 */
1657 void forum_page_pin(void){
1658 login_check_credentials();
1659 if( !g.perm.Setup ){
1660 login_needed(g.anon.Setup);
1661 return;
1662 }
1663 forumpost_action_helper("pinned", 0,
1664 sqlite3_strglob("*_pin*", g.zPath)==0);
1665 }
1666
1667 /*
1668 ** WEBPAGE: forumnew
1669 ** WEBPAGE: forumedit
@@ -2182,11 +2236,11 @@
2236 " CASE WHEN"
2237 " firt IS NULL AND"
2238 " (SELECT 1 FROM tagxref ref, tag t"
2239 " WHERE ref.rid=x.fpid AND ref.tagtype>0"
2240 " AND ref.tagid=t.tagid"
2241 " AND t.tagname='pinned')"
2242 " THEN 1"
2243 " ELSE 0"
2244 " END"
2245 " FROM forumpost AS x"
2246 " WHERE %s"
2247

Keyboard Shortcuts

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