Fossil SCM

Connect the forum post pin/unpin button, which only appears when a setup user is specifically visiting that post. Fix a recent refactoring bug in forumpost_tag().

stephan 2026-05-25 15:08 UTC pinned-forum-posts
Commit 26931c82508b05a4d65cd49dae034e1a8747bc972307294096964d9be2e2bbe6
+12 -11
--- src/forum.c
+++ src/forum.c
@@ -316,11 +316,11 @@
316316
int trid; /* RID of new control artifact */
317317
char *zUuid; /* UUID of head version of post */
318318
319319
db_begin_transaction();
320320
frid = forumpost_head_rid(frid);
321
- iTagged = forum_rid_is_tagged(frid, "closed", 1);
321
+ iTagged = forum_rid_is_tagged(frid, zTagName, 1);
322322
if( (iTagged && addTag
323323
/* Already tagged, noting that in the case of (addTag<0) it may
324324
** actually be a parent which is tagged. */)
325325
|| (iTagged<=0 && !addTag
326326
/* This entry is not tagged, but a parent post may be. */) ){
@@ -1066,14 +1066,15 @@
10661066
const ForumPost *pHead = p->pEditHead ? p->pEditHead : p;
10671067
if( forumpost_may_close() && iClosed>=0 ){
10681068
@ <form method="post" \
10691069
@ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
10701070
login_insert_csrf_secret();
1071
- @ <input type="hidden" name="fpid" value="%s(pHead->zUuid)" />
1071
+ @ <input type="hidden" name="fpid" value="%s(p->zUuid)" />
10721072
if( moderation_pending(p->fpid)==0 ){
10731073
@ <input type="button" value='%s(iClosed ? "Re-open" : "Close")' \
1074
- @ class='%s(iClosed ? "action-reopen" : "action-close")'/>
1074
+ @ class='hidden %s(iClosed ? "action-reopen" : "action-close")'/>
1075
+ /* ^^^ activated by fossil.page.forumpost.js */
10751076
}
10761077
@ </form>
10771078
}
10781079
if( g.perm.Admin ||
10791080
(login_is_individual()
@@ -1090,15 +1091,16 @@
10901091
@ </form>
10911092
}
10921093
if( !p->pIrt && g.perm.Setup ){
10931094
const int isPinned = forum_rid_is_tagged(pHead->fpid, "pinned", 0);
10941095
@ <form method="post" \
1095
- @ action='%R/forumpost_%s(isPinned > 0 ? "unpin" : "pin")'>
1096
+ @ action='%R/forumpost_%s(isPinned ? "unpin" : "pin")'>
10961097
login_insert_csrf_secret();
1097
- @ <input type="hidden" name="fpid" value="%s(pHead->zUuid)" />
1098
+ @ <input type="hidden" name="fpid" value="%s(p->zUuid)" />
10981099
@ <input type="button" value='%s(isPinned ? "Unpin" : "Pin")' \
1099
- @ class='%s(isPinned ? "action-unpin" : "action-pin")'/>
1100
+ @ class='hidden %s(isPinned ? "action-unpin" : "action-pin")'/>
1101
+ /* ^^^ activated by fossil.page.forumpost.js */
11001102
@ </form>
11011103
}
11021104
}
11031105
@ </div>
11041106
}
@@ -1633,13 +1635,12 @@
16331635
*/
16341636
void forum_page_close(void){
16351637
login_check_credentials();
16361638
if( forumpost_may_close()==0 ){
16371639
login_needed(g.anon.Admin);
1638
- return;
16391640
}else{
1640
- int bIsAdd = sqlite3_strglob("*_close*", g.zPath)==0;
1641
+ const int bIsAdd = sqlite3_strglob("*_close*", g.zPath)==0;
16411642
char const *zReason = bIsAdd ? 0 : PD("reason", 0);
16421643
forumpost_action_helper("closed", zReason, bIsAdd);
16431644
}
16441645
}
16451646
@@ -1656,14 +1657,14 @@
16561657
*/
16571658
void forum_page_pin(void){
16581659
login_check_credentials();
16591660
if( !g.perm.Setup ){
16601661
login_needed(g.anon.Setup);
1661
- return;
1662
+ }else{
1663
+ const int bIsAdd = sqlite3_strglob("*_pin*", g.zPath)==0;
1664
+ forumpost_action_helper("pinned", 0, bIsAdd);
16621665
}
1663
- forumpost_action_helper("pinned", 0,
1664
- sqlite3_strglob("*_pin*", g.zPath)==0);
16651666
}
16661667
16671668
/*
16681669
** WEBPAGE: forumnew
16691670
** WEBPAGE: forumedit
16701671
--- src/forum.c
+++ src/forum.c
@@ -316,11 +316,11 @@
316 int trid; /* RID of new control artifact */
317 char *zUuid; /* UUID of head version of post */
318
319 db_begin_transaction();
320 frid = forumpost_head_rid(frid);
321 iTagged = forum_rid_is_tagged(frid, "closed", 1);
322 if( (iTagged && addTag
323 /* Already tagged, noting that in the case of (addTag<0) it may
324 ** actually be a parent which is tagged. */)
325 || (iTagged<=0 && !addTag
326 /* This entry is not tagged, but a parent post may be. */) ){
@@ -1066,14 +1066,15 @@
1066 const ForumPost *pHead = p->pEditHead ? p->pEditHead : p;
1067 if( forumpost_may_close() && iClosed>=0 ){
1068 @ <form method="post" \
1069 @ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
1070 login_insert_csrf_secret();
1071 @ <input type="hidden" name="fpid" value="%s(pHead->zUuid)" />
1072 if( moderation_pending(p->fpid)==0 ){
1073 @ <input type="button" value='%s(iClosed ? "Re-open" : "Close")' \
1074 @ class='%s(iClosed ? "action-reopen" : "action-close")'/>
 
1075 }
1076 @ </form>
1077 }
1078 if( g.perm.Admin ||
1079 (login_is_individual()
@@ -1090,15 +1091,16 @@
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 }
@@ -1633,13 +1635,12 @@
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
@@ -1656,14 +1657,14 @@
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
1670
--- src/forum.c
+++ src/forum.c
@@ -316,11 +316,11 @@
316 int trid; /* RID of new control artifact */
317 char *zUuid; /* UUID of head version of post */
318
319 db_begin_transaction();
320 frid = forumpost_head_rid(frid);
321 iTagged = forum_rid_is_tagged(frid, zTagName, 1);
322 if( (iTagged && addTag
323 /* Already tagged, noting that in the case of (addTag<0) it may
324 ** actually be a parent which is tagged. */)
325 || (iTagged<=0 && !addTag
326 /* This entry is not tagged, but a parent post may be. */) ){
@@ -1066,14 +1066,15 @@
1066 const ForumPost *pHead = p->pEditHead ? p->pEditHead : p;
1067 if( forumpost_may_close() && iClosed>=0 ){
1068 @ <form method="post" \
1069 @ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
1070 login_insert_csrf_secret();
1071 @ <input type="hidden" name="fpid" value="%s(p->zUuid)" />
1072 if( moderation_pending(p->fpid)==0 ){
1073 @ <input type="button" value='%s(iClosed ? "Re-open" : "Close")' \
1074 @ class='hidden %s(iClosed ? "action-reopen" : "action-close")'/>
1075 /* ^^^ activated by fossil.page.forumpost.js */
1076 }
1077 @ </form>
1078 }
1079 if( g.perm.Admin ||
1080 (login_is_individual()
@@ -1090,15 +1091,16 @@
1091 @ </form>
1092 }
1093 if( !p->pIrt && g.perm.Setup ){
1094 const int isPinned = forum_rid_is_tagged(pHead->fpid, "pinned", 0);
1095 @ <form method="post" \
1096 @ action='%R/forumpost_%s(isPinned ? "unpin" : "pin")'>
1097 login_insert_csrf_secret();
1098 @ <input type="hidden" name="fpid" value="%s(p->zUuid)" />
1099 @ <input type="button" value='%s(isPinned ? "Unpin" : "Pin")' \
1100 @ class='hidden %s(isPinned ? "action-unpin" : "action-pin")'/>
1101 /* ^^^ activated by fossil.page.forumpost.js */
1102 @ </form>
1103 }
1104 }
1105 @ </div>
1106 }
@@ -1633,13 +1635,12 @@
1635 */
1636 void forum_page_close(void){
1637 login_check_credentials();
1638 if( forumpost_may_close()==0 ){
1639 login_needed(g.anon.Admin);
 
1640 }else{
1641 const int bIsAdd = sqlite3_strglob("*_close*", g.zPath)==0;
1642 char const *zReason = bIsAdd ? 0 : PD("reason", 0);
1643 forumpost_action_helper("closed", zReason, bIsAdd);
1644 }
1645 }
1646
@@ -1656,14 +1657,14 @@
1657 */
1658 void forum_page_pin(void){
1659 login_check_credentials();
1660 if( !g.perm.Setup ){
1661 login_needed(g.anon.Setup);
1662 }else{
1663 const int bIsAdd = sqlite3_strglob("*_pin*", g.zPath)==0;
1664 forumpost_action_helper("pinned", 0, bIsAdd);
1665 }
 
 
1666 }
1667
1668 /*
1669 ** WEBPAGE: forumnew
1670 ** WEBPAGE: forumedit
1671
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -100,11 +100,12 @@
100100
101101
if(F.pikchr){
102102
F.pikchr.addSrcView();
103103
}
104104
105
- /* Attempt to keep stray double-clicks from double-posting. */
105
+ /* Attempt to keep stray double-clicks from double-posting.
106
+ https://fossil-scm.org/forum/info/6bd02466533aa131 */
106107
const formSubmitted = function(event){
107108
const form = event.target;
108109
if( form.dataset.submitted ){
109110
event.preventDefault();
110111
return;
@@ -120,16 +121,28 @@
120121
document.querySelectorAll("form").forEach(function(form){
121122
form.addEventListener('submit',formSubmitted);
122123
form
123124
.querySelectorAll("input.action-close, input.action-reopen")
124125
.forEach(function(e){
126
+ e.classList.remove('hidden');
125127
F.confirmer(e, {
126128
confirmText: (e.classList.contains('action-reopen')
127129
? "Confirm re-open"
128130
: "Confirm close"),
129131
onconfirm: ()=>form.submit()
130132
});
131133
});
134
+ form
135
+ .querySelectorAll("input.action-pin, input.action-unpin")
136
+ .forEach(function(e){
137
+ e.classList.remove('hidden');
138
+ F.confirmer(e, {
139
+ confirmText: (e.classList.contains('action-unpin')
140
+ ? "Confirm unpin"
141
+ : "Confirm pin"),
142
+ onconfirm: ()=>form.submit()
143
+ });
144
+ });
132145
});
133146
134147
})/*F.onPageLoad callback*/;
135148
})(window.fossil);
136149
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -100,11 +100,12 @@
100
101 if(F.pikchr){
102 F.pikchr.addSrcView();
103 }
104
105 /* Attempt to keep stray double-clicks from double-posting. */
 
106 const formSubmitted = function(event){
107 const form = event.target;
108 if( form.dataset.submitted ){
109 event.preventDefault();
110 return;
@@ -120,16 +121,28 @@
120 document.querySelectorAll("form").forEach(function(form){
121 form.addEventListener('submit',formSubmitted);
122 form
123 .querySelectorAll("input.action-close, input.action-reopen")
124 .forEach(function(e){
 
125 F.confirmer(e, {
126 confirmText: (e.classList.contains('action-reopen')
127 ? "Confirm re-open"
128 : "Confirm close"),
129 onconfirm: ()=>form.submit()
130 });
131 });
 
 
 
 
 
 
 
 
 
 
 
132 });
133
134 })/*F.onPageLoad callback*/;
135 })(window.fossil);
136
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -100,11 +100,12 @@
100
101 if(F.pikchr){
102 F.pikchr.addSrcView();
103 }
104
105 /* Attempt to keep stray double-clicks from double-posting.
106 https://fossil-scm.org/forum/info/6bd02466533aa131 */
107 const formSubmitted = function(event){
108 const form = event.target;
109 if( form.dataset.submitted ){
110 event.preventDefault();
111 return;
@@ -120,16 +121,28 @@
121 document.querySelectorAll("form").forEach(function(form){
122 form.addEventListener('submit',formSubmitted);
123 form
124 .querySelectorAll("input.action-close, input.action-reopen")
125 .forEach(function(e){
126 e.classList.remove('hidden');
127 F.confirmer(e, {
128 confirmText: (e.classList.contains('action-reopen')
129 ? "Confirm re-open"
130 : "Confirm close"),
131 onconfirm: ()=>form.submit()
132 });
133 });
134 form
135 .querySelectorAll("input.action-pin, input.action-unpin")
136 .forEach(function(e){
137 e.classList.remove('hidden');
138 F.confirmer(e, {
139 confirmText: (e.classList.contains('action-unpin')
140 ? "Confirm unpin"
141 : "Confirm pin"),
142 onconfirm: ()=>form.submit()
143 });
144 });
145 });
146
147 })/*F.onPageLoad callback*/;
148 })(window.fossil);
149

Keyboard Shortcuts

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