Fossil SCM

Integrate a status-selection widget into the new editor but disable it for reasons described in the code comments.

stephan 2026-06-06 16:56 UTC forum-editor-2026
Commit bd2bb5faccc4ad3d85164afced0c15130582e1872fc36150d02985b8a6892676
--- src/builtin.c
+++ src/builtin.c
@@ -679,10 +679,27 @@
679679
CX("isDark: %s"
680680
"/*true if the current skin has the 'white-foreground' detail*/",
681681
skin_detail_boolean("white-foreground") ? "true" : "false");
682682
CX("}\n"/*fossil.config.skin*/);
683683
CX("};\n"/* fossil.config */);
684
+ CX("window.fossil.config.forumStatuses =");
685
+ if( forum_statuses()->n>1 ){
686
+ const ForumStatusList * fsl = forum_statuses();
687
+ int i;
688
+ CX("[");
689
+ for(i = 0; i < fsl->n; ++i){
690
+ const ForumStatus *fs = &fsl->aStatus[i];
691
+ if(i){
692
+ CX(",");
693
+ }
694
+ CX("{\"label\":%!j,\"value\":%!j}",
695
+ fs->zLabel, fs->zValue);
696
+ }
697
+ CX("];\n");
698
+ }else{
699
+ CX("[];\n");
700
+ }
684701
CX("window.fossil.user = {");
685702
CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
686703
CX("isAdmin: %s,", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
687704
CX("mayAttachForum: %s,", g.perm.AttachForum ? "true" : "false");
688705
CX("enableDebug: %s", (g.perm.Debug || g.perm.Admin) ? "true" : "false");
689706
--- src/builtin.c
+++ src/builtin.c
@@ -679,10 +679,27 @@
679 CX("isDark: %s"
680 "/*true if the current skin has the 'white-foreground' detail*/",
681 skin_detail_boolean("white-foreground") ? "true" : "false");
682 CX("}\n"/*fossil.config.skin*/);
683 CX("};\n"/* fossil.config */);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684 CX("window.fossil.user = {");
685 CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
686 CX("isAdmin: %s,", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
687 CX("mayAttachForum: %s,", g.perm.AttachForum ? "true" : "false");
688 CX("enableDebug: %s", (g.perm.Debug || g.perm.Admin) ? "true" : "false");
689
--- src/builtin.c
+++ src/builtin.c
@@ -679,10 +679,27 @@
679 CX("isDark: %s"
680 "/*true if the current skin has the 'white-foreground' detail*/",
681 skin_detail_boolean("white-foreground") ? "true" : "false");
682 CX("}\n"/*fossil.config.skin*/);
683 CX("};\n"/* fossil.config */);
684 CX("window.fossil.config.forumStatuses =");
685 if( forum_statuses()->n>1 ){
686 const ForumStatusList * fsl = forum_statuses();
687 int i;
688 CX("[");
689 for(i = 0; i < fsl->n; ++i){
690 const ForumStatus *fs = &fsl->aStatus[i];
691 if(i){
692 CX(",");
693 }
694 CX("{\"label\":%!j,\"value\":%!j}",
695 fs->zLabel, fs->zValue);
696 }
697 CX("];\n");
698 }else{
699 CX("[];\n");
700 }
701 CX("window.fossil.user = {");
702 CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
703 CX("isAdmin: %s,", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
704 CX("mayAttachForum: %s,", g.perm.AttachForum ? "true" : "false");
705 CX("enableDebug: %s", (g.perm.Debug || g.perm.Admin) ? "true" : "false");
706
+4 -2
--- src/forum.c
+++ src/forum.c
@@ -96,11 +96,11 @@
9696
9797
/*
9898
** Returns a high-level representation of the forum-statuses setting.
9999
** This is a singleton, cached across calls.
100100
*/
101
-static const ForumStatusList * forum_statuses(void){
101
+const ForumStatusList * forum_statuses(void){
102102
static ForumStatusList fses = {0,0};
103103
static int once = 0;
104104
while( !once ){
105105
++once;
106106
/* Read `forum-statuses` setting and transform it into the
@@ -151,11 +151,13 @@
151151
** found, the corresponding object is returned. If no match is found
152152
** then (A) if bFirst is false then 0 is returned, else (B) the first
153153
** entry in the list is returned, noting that the list may be empty,
154154
** in which case 0 is returned.
155155
*/
156
-const ForumStatus * forum_status_by_value(const char *z, int bFirst){
156
+static const ForumStatus * forum_status_by_value(
157
+ const char *z, int bFirst
158
+){
157159
const ForumStatusList * const fses = forum_statuses();
158160
const ForumStatus * fs0 = 0;
159161
unsigned int i;
160162
if( !fses->n ) return 0;
161163
for( i = 0; i < fses->n; ++i ){
162164
--- src/forum.c
+++ src/forum.c
@@ -96,11 +96,11 @@
96
97 /*
98 ** Returns a high-level representation of the forum-statuses setting.
99 ** This is a singleton, cached across calls.
100 */
101 static const ForumStatusList * forum_statuses(void){
102 static ForumStatusList fses = {0,0};
103 static int once = 0;
104 while( !once ){
105 ++once;
106 /* Read `forum-statuses` setting and transform it into the
@@ -151,11 +151,13 @@
151 ** found, the corresponding object is returned. If no match is found
152 ** then (A) if bFirst is false then 0 is returned, else (B) the first
153 ** entry in the list is returned, noting that the list may be empty,
154 ** in which case 0 is returned.
155 */
156 const ForumStatus * forum_status_by_value(const char *z, int bFirst){
 
 
157 const ForumStatusList * const fses = forum_statuses();
158 const ForumStatus * fs0 = 0;
159 unsigned int i;
160 if( !fses->n ) return 0;
161 for( i = 0; i < fses->n; ++i ){
162
--- src/forum.c
+++ src/forum.c
@@ -96,11 +96,11 @@
96
97 /*
98 ** Returns a high-level representation of the forum-statuses setting.
99 ** This is a singleton, cached across calls.
100 */
101 const ForumStatusList * forum_statuses(void){
102 static ForumStatusList fses = {0,0};
103 static int once = 0;
104 while( !once ){
105 ++once;
106 /* Read `forum-statuses` setting and transform it into the
@@ -151,11 +151,13 @@
151 ** found, the corresponding object is returned. If no match is found
152 ** then (A) if bFirst is false then 0 is returned, else (B) the first
153 ** entry in the list is returned, noting that the list may be empty,
154 ** in which case 0 is returned.
155 */
156 static const ForumStatus * forum_status_by_value(
157 const char *z, int bFirst
158 ){
159 const ForumStatusList * const fses = forum_statuses();
160 const ForumStatus * fs0 = 0;
161 unsigned int i;
162 if( !fses->n ) return 0;
163 for( i = 0; i < fses->n; ++i ){
164
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -69,27 +69,30 @@
6969
});
7070
e.title.value = F.storage.get(key,'');
7171
}
7272
wrapper.append(e.titleBar);
7373
}
74
- e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
75
- e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
76
- this.#toDisable.push(e.mimetype.select);
77
- e.mimetype.label = D.span();
78
- e.mimetype.label.append(
79
- D.a(F.repoUrl('markup_help'), 'Markup style'),
80
- ':'
81
- );
82
- e.mimetype.wrapper.append(e.mimetype.label, e.mimetype.select);
83
- let i = 0;
84
- for(const [k,v] of Object.entries({
85
- 'text/x-markdown': 'Markdown',
86
- 'text/x-fossil-wiki': 'Fossil Wiki',
87
- 'text/plain': 'Plain text'
88
- })) {
89
- const o = D.option(e.mimetype.select, k, v);
90
- if( !i++ ) o.setAttribute('selected', '');
74
+
75
+ { /* Mimetype bits... */
76
+ e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
77
+ e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
78
+ this.#toDisable.push(e.mimetype.select);
79
+ let i = 0;
80
+ for(const [k,v] of Object.entries({
81
+ 'text/x-markdown': 'Markdown',
82
+ 'text/x-fossil-wiki': 'Fossil Wiki',
83
+ 'text/plain': 'Plain text'
84
+ })) {
85
+ const o = D.option(e.mimetype.select, k, v);
86
+ if( !i++ ) o.setAttribute('selected', '');
87
+ }
88
+ e.mimetype.label = D.span();
89
+ e.mimetype.label.append(
90
+ D.a(F.repoUrl('markup_help'), 'Markup style'),
91
+ ':'
92
+ );
93
+ e.mimetype.wrapper.append(e.mimetype.label, e.mimetype.select);
9194
}
9295
9396
e.button.preview = D.button("Preview", e=>this.#preview());
9497
e.button.submit = D.button("Submit");
9598
if( 1 ){
@@ -161,10 +164,41 @@
161164
e.debug.append(lbl);
162165
}
163166
this.#tabs.addTab(e.debug);
164167
}
165168
e.buttons.append(e.mimetype.wrapper);
169
+
170
+ if( 0 ){
171
+ /*
172
+ Status selection. We probably don't _really_ want this in
173
+ the editor because people will open the editor, change the
174
+ status, and tap submit, resulting in a whole new, unedited
175
+ copy of the post, differing only in the new 'status' tag
176
+ added to it.
177
+ */
178
+ let i = 0;
179
+ for(const [k,v] of Object.entries({
180
+ 'text/x-markdown': 'Markdown',
181
+ 'text/x-fossil-wiki': 'Fossil Wiki',
182
+ 'text/plain': 'Plain text'
183
+ })) {
184
+ const o = D.option(e.mimetype.select, k, v);
185
+ if( !i++ ) o.setAttribute('selected', '');
186
+ }
187
+ if( F.config.forumStatuses?.length>0 ){
188
+ const sel = e.status = D.select();
189
+ D.option(sel, "", "- Status -").disabled = true;
190
+ for( const status of F.config.forumStatuses ){
191
+ D.option(sel, status.value, status.label);
192
+ }
193
+ e.buttons.append(sel);
194
+ if( opt.status ){
195
+ sel.value = opt.status;
196
+ }
197
+ }
198
+ }
199
+
166200
if( F.user.mayAttachForum ){
167201
this.#att = new F.Attacher({
168202
reverse: true
169203
});
170204
//e.buttons.append( e.button.addAttach = this.#att.takeAddButton() );
@@ -250,10 +284,14 @@
250284
}
251285
252286
set editorContent(v){
253287
this.#e.editor.value = v;
254288
}
289
+
290
+ get status(){
291
+ return this.#e.status?.value;
292
+ }
255293
256294
/** Clears any draft state. */
257295
clearDraft(){
258296
const k = this.#opt.draftKey;
259297
if( k ){
@@ -396,10 +434,13 @@
396434
const e = this.#e;
397435
D.disable(e.button.submit);
398436
this.reportError("Submit is TODO.");
399437
const fd = this.#newFormData();
400438
this.#att.populateFormData(fd);
439
+ if( this.#e.status ){
440
+ fd.append( "status", this.status );
441
+ }
401442
console.warn("Ready to submit",fd);
402443
/*
403444
TODO: save it, set #isWaiting=false, then handle error or
404445
redirect to the post (if this is a new post) or, if replying
405446
inline, replace this object with a static rendering from the
406447
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -69,27 +69,30 @@
69 });
70 e.title.value = F.storage.get(key,'');
71 }
72 wrapper.append(e.titleBar);
73 }
74 e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
75 e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
76 this.#toDisable.push(e.mimetype.select);
77 e.mimetype.label = D.span();
78 e.mimetype.label.append(
79 D.a(F.repoUrl('markup_help'), 'Markup style'),
80 ':'
81 );
82 e.mimetype.wrapper.append(e.mimetype.label, e.mimetype.select);
83 let i = 0;
84 for(const [k,v] of Object.entries({
85 'text/x-markdown': 'Markdown',
86 'text/x-fossil-wiki': 'Fossil Wiki',
87 'text/plain': 'Plain text'
88 })) {
89 const o = D.option(e.mimetype.select, k, v);
90 if( !i++ ) o.setAttribute('selected', '');
 
 
 
91 }
92
93 e.button.preview = D.button("Preview", e=>this.#preview());
94 e.button.submit = D.button("Submit");
95 if( 1 ){
@@ -161,10 +164,41 @@
161 e.debug.append(lbl);
162 }
163 this.#tabs.addTab(e.debug);
164 }
165 e.buttons.append(e.mimetype.wrapper);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166 if( F.user.mayAttachForum ){
167 this.#att = new F.Attacher({
168 reverse: true
169 });
170 //e.buttons.append( e.button.addAttach = this.#att.takeAddButton() );
@@ -250,10 +284,14 @@
250 }
251
252 set editorContent(v){
253 this.#e.editor.value = v;
254 }
 
 
 
 
255
256 /** Clears any draft state. */
257 clearDraft(){
258 const k = this.#opt.draftKey;
259 if( k ){
@@ -396,10 +434,13 @@
396 const e = this.#e;
397 D.disable(e.button.submit);
398 this.reportError("Submit is TODO.");
399 const fd = this.#newFormData();
400 this.#att.populateFormData(fd);
 
 
 
401 console.warn("Ready to submit",fd);
402 /*
403 TODO: save it, set #isWaiting=false, then handle error or
404 redirect to the post (if this is a new post) or, if replying
405 inline, replace this object with a static rendering from the
406
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -69,27 +69,30 @@
69 });
70 e.title.value = F.storage.get(key,'');
71 }
72 wrapper.append(e.titleBar);
73 }
74
75 { /* Mimetype bits... */
76 e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
77 e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
78 this.#toDisable.push(e.mimetype.select);
79 let i = 0;
80 for(const [k,v] of Object.entries({
81 'text/x-markdown': 'Markdown',
82 'text/x-fossil-wiki': 'Fossil Wiki',
83 'text/plain': 'Plain text'
84 })) {
85 const o = D.option(e.mimetype.select, k, v);
86 if( !i++ ) o.setAttribute('selected', '');
87 }
88 e.mimetype.label = D.span();
89 e.mimetype.label.append(
90 D.a(F.repoUrl('markup_help'), 'Markup style'),
91 ':'
92 );
93 e.mimetype.wrapper.append(e.mimetype.label, e.mimetype.select);
94 }
95
96 e.button.preview = D.button("Preview", e=>this.#preview());
97 e.button.submit = D.button("Submit");
98 if( 1 ){
@@ -161,10 +164,41 @@
164 e.debug.append(lbl);
165 }
166 this.#tabs.addTab(e.debug);
167 }
168 e.buttons.append(e.mimetype.wrapper);
169
170 if( 0 ){
171 /*
172 Status selection. We probably don't _really_ want this in
173 the editor because people will open the editor, change the
174 status, and tap submit, resulting in a whole new, unedited
175 copy of the post, differing only in the new 'status' tag
176 added to it.
177 */
178 let i = 0;
179 for(const [k,v] of Object.entries({
180 'text/x-markdown': 'Markdown',
181 'text/x-fossil-wiki': 'Fossil Wiki',
182 'text/plain': 'Plain text'
183 })) {
184 const o = D.option(e.mimetype.select, k, v);
185 if( !i++ ) o.setAttribute('selected', '');
186 }
187 if( F.config.forumStatuses?.length>0 ){
188 const sel = e.status = D.select();
189 D.option(sel, "", "- Status -").disabled = true;
190 for( const status of F.config.forumStatuses ){
191 D.option(sel, status.value, status.label);
192 }
193 e.buttons.append(sel);
194 if( opt.status ){
195 sel.value = opt.status;
196 }
197 }
198 }
199
200 if( F.user.mayAttachForum ){
201 this.#att = new F.Attacher({
202 reverse: true
203 });
204 //e.buttons.append( e.button.addAttach = this.#att.takeAddButton() );
@@ -250,10 +284,14 @@
284 }
285
286 set editorContent(v){
287 this.#e.editor.value = v;
288 }
289
290 get status(){
291 return this.#e.status?.value;
292 }
293
294 /** Clears any draft state. */
295 clearDraft(){
296 const k = this.#opt.draftKey;
297 if( k ){
@@ -396,10 +434,13 @@
434 const e = this.#e;
435 D.disable(e.button.submit);
436 this.reportError("Submit is TODO.");
437 const fd = this.#newFormData();
438 this.#att.populateFormData(fd);
439 if( this.#e.status ){
440 fd.append( "status", this.status );
441 }
442 console.warn("Ready to submit",fd);
443 /*
444 TODO: save it, set #isWaiting=false, then handle error or
445 redirect to the post (if this is a new post) or, if replying
446 inline, replace this object with a static rendering from the
447

Keyboard Shortcuts

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