Fossil SCM

Make the draft's mimetype and status persistent.

stephan 2026-06-07 09:25 UTC forum-editor-2026
Commit 033d265fd057c6026d2bbbcf5f1925ac3990bf04d0b254bb348b50af05b6fc89
+2 -4
--- src/attach.c
+++ src/attach.c
@@ -782,21 +782,19 @@
782782
char *zExtraFree = 0;
783783
int eTgtType = 0;
784784
int bNeedsModeration = 0;
785785
int goodCaptcha = 1;
786786
int bRollback = 0; /* Roll back if true. */
787
- int bInTransaction = 0;
788787
789788
if( ! ajax_route_bootstrap(0, 1) ){
790789
return;
791790
}else if( !(goodCaptcha = captcha_is_correct(0)) ){
792791
goto ajax_err_403;
793792
}else if( !ajax_check_csrf(2) ){
794793
return;
795794
}
796795
db_begin_transaction();
797
- bInTransaction = 1;
798796
zTarget = P("target");
799797
eTgtType = attachment_target_type(zTarget, 1);
800798
CX("{");
801799
switch( eTgtType ){
802800
default:
@@ -874,17 +872,17 @@
874872
}/*else error response was set up*/
875873
fossil_free(zExtraFree);
876874
db_end_transaction(bRollback);
877875
return;
878876
ajax_err_403:
879
- if( bInTransaction ){
877
+ if( db_transaction_nesting_depth()>0 ){
880878
db_rollback_transaction();
881879
}
882880
ajax_route_error_forbidden();
883881
return;
884882
ajax_err_404:
885
- assert( bInTransaction );
883
+ assert( db_transaction_nesting_depth()>0 );
886884
db_rollback_transaction();
887885
ajax_route_error(404, "Target not found.");
888886
return;
889887
}
890888
891889
--- src/attach.c
+++ src/attach.c
@@ -782,21 +782,19 @@
782 char *zExtraFree = 0;
783 int eTgtType = 0;
784 int bNeedsModeration = 0;
785 int goodCaptcha = 1;
786 int bRollback = 0; /* Roll back if true. */
787 int bInTransaction = 0;
788
789 if( ! ajax_route_bootstrap(0, 1) ){
790 return;
791 }else if( !(goodCaptcha = captcha_is_correct(0)) ){
792 goto ajax_err_403;
793 }else if( !ajax_check_csrf(2) ){
794 return;
795 }
796 db_begin_transaction();
797 bInTransaction = 1;
798 zTarget = P("target");
799 eTgtType = attachment_target_type(zTarget, 1);
800 CX("{");
801 switch( eTgtType ){
802 default:
@@ -874,17 +872,17 @@
874 }/*else error response was set up*/
875 fossil_free(zExtraFree);
876 db_end_transaction(bRollback);
877 return;
878 ajax_err_403:
879 if( bInTransaction ){
880 db_rollback_transaction();
881 }
882 ajax_route_error_forbidden();
883 return;
884 ajax_err_404:
885 assert( bInTransaction );
886 db_rollback_transaction();
887 ajax_route_error(404, "Target not found.");
888 return;
889 }
890
891
--- src/attach.c
+++ src/attach.c
@@ -782,21 +782,19 @@
782 char *zExtraFree = 0;
783 int eTgtType = 0;
784 int bNeedsModeration = 0;
785 int goodCaptcha = 1;
786 int bRollback = 0; /* Roll back if true. */
 
787
788 if( ! ajax_route_bootstrap(0, 1) ){
789 return;
790 }else if( !(goodCaptcha = captcha_is_correct(0)) ){
791 goto ajax_err_403;
792 }else if( !ajax_check_csrf(2) ){
793 return;
794 }
795 db_begin_transaction();
 
796 zTarget = P("target");
797 eTgtType = attachment_target_type(zTarget, 1);
798 CX("{");
799 switch( eTgtType ){
800 default:
@@ -874,17 +872,17 @@
872 }/*else error response was set up*/
873 fossil_free(zExtraFree);
874 db_end_transaction(bRollback);
875 return;
876 ajax_err_403:
877 if( db_transaction_nesting_depth()>0 ){
878 db_rollback_transaction();
879 }
880 ajax_route_error_forbidden();
881 return;
882 ajax_err_404:
883 assert( db_transaction_nesting_depth()>0 );
884 db_rollback_transaction();
885 ajax_route_error(404, "Target not found.");
886 return;
887 }
888
889
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -48,16 +48,11 @@
4848
// edit: hash
4949
draftKey: undefined
5050
}, opt);
5151
opt.isNewThread = !opt.replyTo && !opt.edit;
5252
if( opt.draftKey ){
53
- this.#draft = F.storage.getJSON(opt.draftKey, F.nu({
54
- title: undefined,
55
- content: undefined,
56
- mimetype: undefined,
57
- status: undefined
58
- }));
53
+ this.#draft = F.nu(F.storage.getJSON(opt.draftKey, {}));
5954
}
6055
const e = this.#e = F.nu({
6156
mimetype: F.nu(),
6257
button: F.nu()
6358
});
@@ -88,27 +83,26 @@
8883
{ /* Mimetype... */
8984
e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
9085
e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
9186
this.#toDisable.push(e.mimetype.select);
9287
let i = 0;
93
- D.option(e.mimetype.select, '', 'Markdown format').disabled = true;
88
+ D.option(e.mimetype.select, '', 'Markup format').disabled = true;
9489
for(const [k,v] of Object.entries({
9590
'text/x-markdown': 'Markdown',
9691
'text/x-fossil-wiki': 'Fossil Wiki',
9792
'text/plain': 'Plain text'
9893
})) {
99
- const o = D.option(e.mimetype.select, k, v);
100
- if( (opt.isNewThread && !i++)
101
- || opt.mimetype===k ) o.setAttribute('selected', '');
102
- }
103
- if( 0 ){
104
- e.mimetype.label = D.span();
105
- e.mimetype.label.append(
106
- D.a(F.repoUrl('markup_help'), 'Markup style'),
107
- ':'
108
- );
109
- e.mimetype.wrapper.append(e.mimetype.label);
94
+ D.option(e.mimetype.select, k, v);
95
+ }
96
+ if( this.#draft ){
97
+ e.mimetype.select.value = opt.mimetype || this.#draft.mimetype;
98
+ e.mimetype.select.addEventListener('change',ev=>{
99
+ if( this.#draft.mimetype!==ev.target.value ){
100
+ this.#draft.mimetype = ev.target.value;
101
+ this.#storeDraft();
102
+ }
103
+ });
110104
}
111105
e.mimetype.wrapper.append(e.mimetype.select);
112106
}
113107
114108
e.buttons = D.addClass(D.div(), 'buttons');
@@ -213,29 +207,37 @@
213207
}
214208
this.#tabs.addTab(e.debug);
215209
}
216210
e.buttons.append(e.mimetype.wrapper);
217211
218
- if( 0 ){
219
- /*
220
- Status selection. We probably don't _really_ want this in
221
- the editor because people will open the editor, change the
222
- status, and tap submit, resulting in a whole new, unedited
223
- copy of the post, differing only in the new 'status' tag
224
- added to it.
225
- */
226
- if( F.config.forumStatuses?.length>0 ){
227
- const sel = e.status = D.select();
228
- D.option(sel, "", "- Status -").disabled = true;
229
- sel.dataset.originalValue = opt.status;
230
- for( const status of F.config.forumStatuses ){
231
- D.option(sel, status.value, status.label);
232
- }
233
- e.buttons.append(sel);
234
- if( opt.status ){
235
- sel.value = opt.status;
236
- }
212
+ if( 0 && F.config.forumStatuses?.length>0 ){
213
+ /* Status selection. We probably don't _really_ want this in
214
+ the editor because people will open the editor, change the
215
+ status, and tap submit, resulting in a whole new, unedited
216
+ copy of the post, differing only in the new 'status' tag
217
+ added to it. */
218
+ const sel = e.status = D.select();
219
+ D.option(sel, "", "- Status -").disabled = true;
220
+ for( const status of F.config.forumStatuses ){
221
+ D.option(sel, status.value, status.label);
222
+ }
223
+ e.buttons.append(sel);
224
+ if( opt.status ){
225
+ sel.value = opt.status;
226
+ }else if( this.#draft ){
227
+ if( this.#draft.status ){
228
+ sel.value = this.#draft.status;
229
+ }else{
230
+ this.#draft.status = sel.value = F.config.forumStatuses[0].value;
231
+ }
232
+ sel.addEventListener('change',ev=>{
233
+ const v = sel.value;
234
+ if( this.#draft.status !== v ){
235
+ this.#draft.status = v;
236
+ this.#storeDraft();
237
+ }
238
+ });
237239
}
238240
}
239241
240242
if( F.user.mayAttachForum ){
241243
//e.buttons.append( e.button.addAttach = this.#att.takeAddButton() );
242244
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -48,16 +48,11 @@
48 // edit: hash
49 draftKey: undefined
50 }, opt);
51 opt.isNewThread = !opt.replyTo && !opt.edit;
52 if( opt.draftKey ){
53 this.#draft = F.storage.getJSON(opt.draftKey, F.nu({
54 title: undefined,
55 content: undefined,
56 mimetype: undefined,
57 status: undefined
58 }));
59 }
60 const e = this.#e = F.nu({
61 mimetype: F.nu(),
62 button: F.nu()
63 });
@@ -88,27 +83,26 @@
88 { /* Mimetype... */
89 e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
90 e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
91 this.#toDisable.push(e.mimetype.select);
92 let i = 0;
93 D.option(e.mimetype.select, '', 'Markdown format').disabled = true;
94 for(const [k,v] of Object.entries({
95 'text/x-markdown': 'Markdown',
96 'text/x-fossil-wiki': 'Fossil Wiki',
97 'text/plain': 'Plain text'
98 })) {
99 const o = D.option(e.mimetype.select, k, v);
100 if( (opt.isNewThread && !i++)
101 || opt.mimetype===k ) o.setAttribute('selected', '');
102 }
103 if( 0 ){
104 e.mimetype.label = D.span();
105 e.mimetype.label.append(
106 D.a(F.repoUrl('markup_help'), 'Markup style'),
107 ':'
108 );
109 e.mimetype.wrapper.append(e.mimetype.label);
110 }
111 e.mimetype.wrapper.append(e.mimetype.select);
112 }
113
114 e.buttons = D.addClass(D.div(), 'buttons');
@@ -213,29 +207,37 @@
213 }
214 this.#tabs.addTab(e.debug);
215 }
216 e.buttons.append(e.mimetype.wrapper);
217
218 if( 0 ){
219 /*
220 Status selection. We probably don't _really_ want this in
221 the editor because people will open the editor, change the
222 status, and tap submit, resulting in a whole new, unedited
223 copy of the post, differing only in the new 'status' tag
224 added to it.
225 */
226 if( F.config.forumStatuses?.length>0 ){
227 const sel = e.status = D.select();
228 D.option(sel, "", "- Status -").disabled = true;
229 sel.dataset.originalValue = opt.status;
230 for( const status of F.config.forumStatuses ){
231 D.option(sel, status.value, status.label);
232 }
233 e.buttons.append(sel);
234 if( opt.status ){
235 sel.value = opt.status;
236 }
 
 
 
 
 
 
 
 
237 }
238 }
239
240 if( F.user.mayAttachForum ){
241 //e.buttons.append( e.button.addAttach = this.#att.takeAddButton() );
242
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -48,16 +48,11 @@
48 // edit: hash
49 draftKey: undefined
50 }, opt);
51 opt.isNewThread = !opt.replyTo && !opt.edit;
52 if( opt.draftKey ){
53 this.#draft = F.nu(F.storage.getJSON(opt.draftKey, {}));
 
 
 
 
 
54 }
55 const e = this.#e = F.nu({
56 mimetype: F.nu(),
57 button: F.nu()
58 });
@@ -88,27 +83,26 @@
83 { /* Mimetype... */
84 e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
85 e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
86 this.#toDisable.push(e.mimetype.select);
87 let i = 0;
88 D.option(e.mimetype.select, '', 'Markup format').disabled = true;
89 for(const [k,v] of Object.entries({
90 'text/x-markdown': 'Markdown',
91 'text/x-fossil-wiki': 'Fossil Wiki',
92 'text/plain': 'Plain text'
93 })) {
94 D.option(e.mimetype.select, k, v);
95 }
96 if( this.#draft ){
97 e.mimetype.select.value = opt.mimetype || this.#draft.mimetype;
98 e.mimetype.select.addEventListener('change',ev=>{
99 if( this.#draft.mimetype!==ev.target.value ){
100 this.#draft.mimetype = ev.target.value;
101 this.#storeDraft();
102 }
103 });
 
104 }
105 e.mimetype.wrapper.append(e.mimetype.select);
106 }
107
108 e.buttons = D.addClass(D.div(), 'buttons');
@@ -213,29 +207,37 @@
207 }
208 this.#tabs.addTab(e.debug);
209 }
210 e.buttons.append(e.mimetype.wrapper);
211
212 if( 0 && F.config.forumStatuses?.length>0 ){
213 /* Status selection. We probably don't _really_ want this in
214 the editor because people will open the editor, change the
215 status, and tap submit, resulting in a whole new, unedited
216 copy of the post, differing only in the new 'status' tag
217 added to it. */
218 const sel = e.status = D.select();
219 D.option(sel, "", "- Status -").disabled = true;
220 for( const status of F.config.forumStatuses ){
221 D.option(sel, status.value, status.label);
222 }
223 e.buttons.append(sel);
224 if( opt.status ){
225 sel.value = opt.status;
226 }else if( this.#draft ){
227 if( this.#draft.status ){
228 sel.value = this.#draft.status;
229 }else{
230 this.#draft.status = sel.value = F.config.forumStatuses[0].value;
231 }
232 sel.addEventListener('change',ev=>{
233 const v = sel.value;
234 if( this.#draft.status !== v ){
235 this.#draft.status = v;
236 this.#storeDraft();
237 }
238 });
239 }
240 }
241
242 if( F.user.mayAttachForum ){
243 //e.buttons.append( e.button.addAttach = this.#att.takeAddButton() );
244

Keyboard Shortcuts

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