Fossil SCM

Minor internal cleanups. Add some tooltip help. Add a Stash button which closes a forum editor widget but retains any local edits and stays on the page. It cannot be called Close because there's a very different Close button already associated with posts.

stephan 2026-06-13 13:00 UTC forum-editor-2026
Commit 2e788c488bdc332a6c34aab2d4a075682e99d5d10324b0aee990686e71e275b6
1 file changed +48 -20
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -138,10 +138,11 @@
138138
}
139139
140140
{ /* Mimetype... */
141141
e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
142142
const sel = e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
143
+ sel.setAttribute('title', 'Markup format for this post.');
143144
this.#toDisable.push(sel);
144145
let i = 0;
145146
D.option(sel, '', '- Markup format -').disabled = true;
146147
for(const [k,v] of Object.entries({
147148
'text/x-markdown': 'Markdown',
@@ -163,14 +164,35 @@
163164
e.mimetype.wrapper.append(sel);
164165
}
165166
166167
e.buttons = D.addClass(D.div(), 'buttons');
167168
{ /* Preview/submit buttons... */
168
- e.button.preview = D.button("Preview", e=>this.#preview());
169
- e.button.submit = D.button("Submit");
169
+ e.button.preview = D.attr(
170
+ D.button("Preview", e=>this.#preview()),
171
+ 'title',
172
+ 'Preview your edits.'
173
+ );
174
+ e.button.submit = D.attr(
175
+ D.button("Submit"),
176
+ 'title',
177
+ 'Save any edits to the server. Not permitted until Preview has been used.'
178
+ );
179
+ e.button.stash = D.attr(
180
+ D.button(
181
+ "Stash", e=>this.close()
182
+ /* This could be called Close, but that would semantically
183
+ collide with the Close [this post] button. All "Stash"
184
+ does is close the widget. */
185
+ ),
186
+ 'title', "Close this editor and stash any edits locally."
187
+ );
170188
if( opt.ondiscard instanceof Function ){
171
- e.button.discard = D.button('Discard');
189
+ e.button.discard = D.attr(
190
+ D.button('Discard'),
191
+ 'title',
192
+ 'Close the editor and discard all local edits.'
193
+ );
172194
}
173195
if( 1 ){
174196
F.confirmer(e.button.submit, {
175197
confirmText: "Confirm submit...",
176198
onconfirm: ()=>this.#submit()
@@ -270,10 +292,11 @@
270292
271293
if( opt.edit
272294
&& !opt.inReplyTo
273295
&& F.config.forumStatuses?.length>0 ){
274296
const sel = e.status = D.select();
297
+ sel.setAttribute('title', 'The status tag value for this post.');
275298
D.option(sel, "", "- Status -").disabled = true;
276299
for( const status of F.config.forumStatuses ){
277300
D.option(sel, status.value, status.label);
278301
}
279302
e.buttons.append(sel);
@@ -302,11 +325,11 @@
302325
e.tabAttach.dataset.tabLabel = 'Attachments';
303326
this.#tabs.addTab(e.tabAttach);
304327
/* Reminder: we don't currently have a way to disable/enable
305328
an Attacher's controls during ajax traffic. */
306329
}
307
- e.buttons.append(e.button.preview, e.button.submit);
330
+ e.buttons.append(e.button.preview, e.button.submit, e.button.stash);
308331
if( e.button.discard ){
309332
e.buttons.append(e.button.discard);
310333
this.#toDisable.push(e.button.discard);
311334
}
312335
@@ -329,11 +352,16 @@
329352
'and edit modes, which is generally useful but some ',
330353
'software keyboards misinteract with it. If the preview ',
331354
'starts when tapping Enter, turn this setting off.'
332355
].join('')
333356
);
334
- eCb.checked = F.storage.getBool('edit-shift-enter-preview', true);
357
+ eCb.checked = F.storage.getBool(
358
+ 'edit-shift-enter-preview',
359
+ true
360
+ /* Maintenance reminder: this setting is shared across
361
+ several apps, like /chat, /wikiedit, and /fileedit. */
362
+ );
335363
eCb.addEventListener('change', (ev)=>{
336364
F.storage.set('edit-shift-enter-preview', eCb.checked);
337365
});
338366
F.helpButtonlets.setup(eHelp);
339367
eLbl.append("Shift-enter toggles preview?", eCb, eHelp);
@@ -351,13 +379,12 @@
351379
https://fossil-scm.org/forum/forumpost/dbd5b68366147ce8
352380
*/
353381
if(!isShiftEnter(ev)) return;
354382
ev.preventDefault();
355383
ev.stopPropagation();
356
- e.editor.blur(/*force change event, if needed*/);
384
+ e.editor.blur(/*force draft update if needed*/);
357385
this.#tabs.switchToTab(e.preview);
358
- this.#preview();
359386
}, false);
360387
// If we're in the preview tab, have ctrl-enter switch back to the editor.
361388
document.body.addEventListener('keydown',(ev)=>{
362389
if(!isShiftEnter(ev)) return;
363390
if(this.#activeTab !== e.tabEdit){
@@ -983,21 +1010,21 @@
9831010
}
9841011
9851012
/* Apply page-specific tweaks for ForumPostEditor instance fpe
9861013
then plug it into the UI at the end of ePost. */
9871014
const initFPEWidget = (fpe, ePost)=>{
988
- const w = fpe.widget;
989
- fpe.eUnhideThenWhenDone = [
1015
+ ePost.eUnhideThenWhenDone = [
9901016
/* List of elements to hide while editing/replying and reveal
9911017
when discarding or saving. */
9921018
];
9931019
for( const ee of ePost.querySelectorAll(
9941020
'.forumpost-single-controls, fieldset.forum-status-selection'
9951021
) ){
9961022
ee.hidden = true;
997
- fpe.eUnhideThenWhenDone.push(ee);
1023
+ ePost.eUnhideThenWhenDone.push(ee);
9981024
}
1025
+ const w = fpe.widget;
9991026
w.classList.add('animate-entrance');
10001027
ePost.append(w);
10011028
requestAnimationFrame(() => {
10021029
w.scrollIntoView({
10031030
behavior: 'smooth',
@@ -1070,22 +1097,23 @@
10701097
ePost.style.marginLeft = 'initial';
10711098
eButton.dataset.originalLabel = eButton.innerText;
10721099
};
10731100
10741101
/** Undoes the damage done by setupEditReplyElement(). */
1075
- const restoreEditReplyElement = (ePost, eButton, fpe)=>{
1102
+ const restoreEditReplyElement = (ePost, eButton)=>{
10761103
if( ePost.dataset.originalMarginLeft ){
10771104
ePost.style.marginLeft = ePost.dataset.originalMarginLeft;
10781105
delete ePost.dataset.originalMarginLeft;
10791106
}
10801107
if( eButton.dataset.originalLabel ){
10811108
eButton.innerText = eButton.dataset.originalLabel;
10821109
delete eButton.dataset.originalLabel;
10831110
}
1084
- for(const ee of (fpe?.eUnhideThenWhenDone || [])){
1111
+ for(const ee of (ePost.eUnhideThenWhenDone || [])){
10851112
ee.removeAttribute('hidden');
10861113
}
1114
+ ePost.eUnhideThenWhenDone = undefined;
10871115
};
10881116
10891117
/**
10901118
Reports an error regarding the forum post element
10911119
ePost, appending each entry in msg to a wrapper
@@ -1151,31 +1179,31 @@
11511179
11521180
setupEditReplyElement(ePost, eBtnReply);
11531181
eBtnReply.innerText = "Replying...";
11541182
const ondone = (fpe, response)=>{
11551183
/* onsubmit() and ondiscard() callback */
1156
- restoreEditReplyElement(ePost, eBtnReply, fpe);
1184
+ restoreEditReplyElement(ePost, eBtnReply);
11571185
//console.debug("ondiscard/onsubmit", fpe, artifact);
11581186
if( response/*onsubmit()*/ ){
11591187
window.location = F.repoUrl('forumpost/'+response.uuid);
11601188
setTimeout(()=>fpe.close(), 500/*just in case not redirected*/);
1161
- }else{/*ondiscard()*/
1189
+ }else{/*ondiscard() or onclose()*/
11621190
}
11631191
};
11641192
const fpe = new F.ForumPostEditor(F.nu({
11651193
hiddenFields: form.querySelectorAll(
11661194
'input[type=hidden][name=csrf]'
11671195
/* Do not inherit the fpid field, else this will become
11681196
an edit to that post rather than a response. */
11691197
),
1170
- ondiscard: ondone,
11711198
onsubmit: ondone,
11721199
onclose: ()=>{
11731200
if( releaseLock ){
11741201
releaseLock();
11751202
releaseLock = null;
11761203
}
1204
+ ondone();
11771205
},
11781206
inReplyTo: fpid,
11791207
draftKey
11801208
}));
11811209
initFPEWidget(fpe, ePost);
@@ -1231,32 +1259,32 @@
12311259
if( fpid === response.uuid
12321260
&& !response.statusModified
12331261
&& 0===response.attachedCount ){
12341262
fpe.reportError("No changes made.");
12351263
}else{
1236
- restoreEditReplyElement(ePost, eBtnEdit, fpe);
1264
+ restoreEditReplyElement(ePost, eBtnEdit);
12371265
window.location = F.repoUrl('forumpost/'+response.uuid);
12381266
setTimeout(()=>fpe.close(), 500/*just in case not redirected*/);
12391267
}
12401268
}else{
1241
- /*ondiscard()*/
1242
- restoreEditReplyElement(ePost, eBtnEdit, fpe);
1269
+ /*ondiscard() or onclose()*/
1270
+ restoreEditReplyElement(ePost, eBtnEdit);
12431271
}
12441272
};
12451273
const eStatusSelect = ePost.querySelector(
12461274
':scope > fieldset.forum-status-selection select[name=status]'
12471275
);
12481276
12491277
const fpe = new F.ForumPostEditor(F.nu({
12501278
hiddenFields: form.querySelectorAll('input[type=hidden]'),
1251
- ondiscard: ondone,
12521279
onsubmit: ondone,
12531280
onclose: ()=>{
12541281
if(releaseLock){
12551282
releaseLock();
12561283
releaseLock = null;
12571284
}
1285
+ ondone();
12581286
},
12591287
draftKey,
12601288
edit: artifact,
12611289
status: eStatusSelect?.value,
12621290
inReplyTo: firt
@@ -1266,11 +1294,11 @@
12661294
.catch(err=>{
12671295
if( releaseLock ){
12681296
releaseLock();
12691297
releaseLock = null;
12701298
}
1271
- restoreEditReplyElement(ePost, eBtnEdit, null);
1299
+ restoreEditReplyElement(ePost, eBtnEdit);
12721300
console.error("Error fetching post:", err);
12731301
reportFPEError(ePost, "Error fetching post: ", err.message);
12741302
});
12751303
}/*editClicked()*/;
12761304
12771305
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -138,10 +138,11 @@
138 }
139
140 { /* Mimetype... */
141 e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
142 const sel = e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
 
143 this.#toDisable.push(sel);
144 let i = 0;
145 D.option(sel, '', '- Markup format -').disabled = true;
146 for(const [k,v] of Object.entries({
147 'text/x-markdown': 'Markdown',
@@ -163,14 +164,35 @@
163 e.mimetype.wrapper.append(sel);
164 }
165
166 e.buttons = D.addClass(D.div(), 'buttons');
167 { /* Preview/submit buttons... */
168 e.button.preview = D.button("Preview", e=>this.#preview());
169 e.button.submit = D.button("Submit");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170 if( opt.ondiscard instanceof Function ){
171 e.button.discard = D.button('Discard');
 
 
 
 
172 }
173 if( 1 ){
174 F.confirmer(e.button.submit, {
175 confirmText: "Confirm submit...",
176 onconfirm: ()=>this.#submit()
@@ -270,10 +292,11 @@
270
271 if( opt.edit
272 && !opt.inReplyTo
273 && F.config.forumStatuses?.length>0 ){
274 const sel = e.status = D.select();
 
275 D.option(sel, "", "- Status -").disabled = true;
276 for( const status of F.config.forumStatuses ){
277 D.option(sel, status.value, status.label);
278 }
279 e.buttons.append(sel);
@@ -302,11 +325,11 @@
302 e.tabAttach.dataset.tabLabel = 'Attachments';
303 this.#tabs.addTab(e.tabAttach);
304 /* Reminder: we don't currently have a way to disable/enable
305 an Attacher's controls during ajax traffic. */
306 }
307 e.buttons.append(e.button.preview, e.button.submit);
308 if( e.button.discard ){
309 e.buttons.append(e.button.discard);
310 this.#toDisable.push(e.button.discard);
311 }
312
@@ -329,11 +352,16 @@
329 'and edit modes, which is generally useful but some ',
330 'software keyboards misinteract with it. If the preview ',
331 'starts when tapping Enter, turn this setting off.'
332 ].join('')
333 );
334 eCb.checked = F.storage.getBool('edit-shift-enter-preview', true);
 
 
 
 
 
335 eCb.addEventListener('change', (ev)=>{
336 F.storage.set('edit-shift-enter-preview', eCb.checked);
337 });
338 F.helpButtonlets.setup(eHelp);
339 eLbl.append("Shift-enter toggles preview?", eCb, eHelp);
@@ -351,13 +379,12 @@
351 https://fossil-scm.org/forum/forumpost/dbd5b68366147ce8
352 */
353 if(!isShiftEnter(ev)) return;
354 ev.preventDefault();
355 ev.stopPropagation();
356 e.editor.blur(/*force change event, if needed*/);
357 this.#tabs.switchToTab(e.preview);
358 this.#preview();
359 }, false);
360 // If we're in the preview tab, have ctrl-enter switch back to the editor.
361 document.body.addEventListener('keydown',(ev)=>{
362 if(!isShiftEnter(ev)) return;
363 if(this.#activeTab !== e.tabEdit){
@@ -983,21 +1010,21 @@
983 }
984
985 /* Apply page-specific tweaks for ForumPostEditor instance fpe
986 then plug it into the UI at the end of ePost. */
987 const initFPEWidget = (fpe, ePost)=>{
988 const w = fpe.widget;
989 fpe.eUnhideThenWhenDone = [
990 /* List of elements to hide while editing/replying and reveal
991 when discarding or saving. */
992 ];
993 for( const ee of ePost.querySelectorAll(
994 '.forumpost-single-controls, fieldset.forum-status-selection'
995 ) ){
996 ee.hidden = true;
997 fpe.eUnhideThenWhenDone.push(ee);
998 }
 
999 w.classList.add('animate-entrance');
1000 ePost.append(w);
1001 requestAnimationFrame(() => {
1002 w.scrollIntoView({
1003 behavior: 'smooth',
@@ -1070,22 +1097,23 @@
1070 ePost.style.marginLeft = 'initial';
1071 eButton.dataset.originalLabel = eButton.innerText;
1072 };
1073
1074 /** Undoes the damage done by setupEditReplyElement(). */
1075 const restoreEditReplyElement = (ePost, eButton, fpe)=>{
1076 if( ePost.dataset.originalMarginLeft ){
1077 ePost.style.marginLeft = ePost.dataset.originalMarginLeft;
1078 delete ePost.dataset.originalMarginLeft;
1079 }
1080 if( eButton.dataset.originalLabel ){
1081 eButton.innerText = eButton.dataset.originalLabel;
1082 delete eButton.dataset.originalLabel;
1083 }
1084 for(const ee of (fpe?.eUnhideThenWhenDone || [])){
1085 ee.removeAttribute('hidden');
1086 }
 
1087 };
1088
1089 /**
1090 Reports an error regarding the forum post element
1091 ePost, appending each entry in msg to a wrapper
@@ -1151,31 +1179,31 @@
1151
1152 setupEditReplyElement(ePost, eBtnReply);
1153 eBtnReply.innerText = "Replying...";
1154 const ondone = (fpe, response)=>{
1155 /* onsubmit() and ondiscard() callback */
1156 restoreEditReplyElement(ePost, eBtnReply, fpe);
1157 //console.debug("ondiscard/onsubmit", fpe, artifact);
1158 if( response/*onsubmit()*/ ){
1159 window.location = F.repoUrl('forumpost/'+response.uuid);
1160 setTimeout(()=>fpe.close(), 500/*just in case not redirected*/);
1161 }else{/*ondiscard()*/
1162 }
1163 };
1164 const fpe = new F.ForumPostEditor(F.nu({
1165 hiddenFields: form.querySelectorAll(
1166 'input[type=hidden][name=csrf]'
1167 /* Do not inherit the fpid field, else this will become
1168 an edit to that post rather than a response. */
1169 ),
1170 ondiscard: ondone,
1171 onsubmit: ondone,
1172 onclose: ()=>{
1173 if( releaseLock ){
1174 releaseLock();
1175 releaseLock = null;
1176 }
 
1177 },
1178 inReplyTo: fpid,
1179 draftKey
1180 }));
1181 initFPEWidget(fpe, ePost);
@@ -1231,32 +1259,32 @@
1231 if( fpid === response.uuid
1232 && !response.statusModified
1233 && 0===response.attachedCount ){
1234 fpe.reportError("No changes made.");
1235 }else{
1236 restoreEditReplyElement(ePost, eBtnEdit, fpe);
1237 window.location = F.repoUrl('forumpost/'+response.uuid);
1238 setTimeout(()=>fpe.close(), 500/*just in case not redirected*/);
1239 }
1240 }else{
1241 /*ondiscard()*/
1242 restoreEditReplyElement(ePost, eBtnEdit, fpe);
1243 }
1244 };
1245 const eStatusSelect = ePost.querySelector(
1246 ':scope > fieldset.forum-status-selection select[name=status]'
1247 );
1248
1249 const fpe = new F.ForumPostEditor(F.nu({
1250 hiddenFields: form.querySelectorAll('input[type=hidden]'),
1251 ondiscard: ondone,
1252 onsubmit: ondone,
1253 onclose: ()=>{
1254 if(releaseLock){
1255 releaseLock();
1256 releaseLock = null;
1257 }
 
1258 },
1259 draftKey,
1260 edit: artifact,
1261 status: eStatusSelect?.value,
1262 inReplyTo: firt
@@ -1266,11 +1294,11 @@
1266 .catch(err=>{
1267 if( releaseLock ){
1268 releaseLock();
1269 releaseLock = null;
1270 }
1271 restoreEditReplyElement(ePost, eBtnEdit, null);
1272 console.error("Error fetching post:", err);
1273 reportFPEError(ePost, "Error fetching post: ", err.message);
1274 });
1275 }/*editClicked()*/;
1276
1277
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -138,10 +138,11 @@
138 }
139
140 { /* Mimetype... */
141 e.mimetype.wrapper = D.addClass(D.div(), 'mimetype-wrapper');
142 const sel = e.mimetype.select = D.addClass(D.select(), 'mimetype-select');
143 sel.setAttribute('title', 'Markup format for this post.');
144 this.#toDisable.push(sel);
145 let i = 0;
146 D.option(sel, '', '- Markup format -').disabled = true;
147 for(const [k,v] of Object.entries({
148 'text/x-markdown': 'Markdown',
@@ -163,14 +164,35 @@
164 e.mimetype.wrapper.append(sel);
165 }
166
167 e.buttons = D.addClass(D.div(), 'buttons');
168 { /* Preview/submit buttons... */
169 e.button.preview = D.attr(
170 D.button("Preview", e=>this.#preview()),
171 'title',
172 'Preview your edits.'
173 );
174 e.button.submit = D.attr(
175 D.button("Submit"),
176 'title',
177 'Save any edits to the server. Not permitted until Preview has been used.'
178 );
179 e.button.stash = D.attr(
180 D.button(
181 "Stash", e=>this.close()
182 /* This could be called Close, but that would semantically
183 collide with the Close [this post] button. All "Stash"
184 does is close the widget. */
185 ),
186 'title', "Close this editor and stash any edits locally."
187 );
188 if( opt.ondiscard instanceof Function ){
189 e.button.discard = D.attr(
190 D.button('Discard'),
191 'title',
192 'Close the editor and discard all local edits.'
193 );
194 }
195 if( 1 ){
196 F.confirmer(e.button.submit, {
197 confirmText: "Confirm submit...",
198 onconfirm: ()=>this.#submit()
@@ -270,10 +292,11 @@
292
293 if( opt.edit
294 && !opt.inReplyTo
295 && F.config.forumStatuses?.length>0 ){
296 const sel = e.status = D.select();
297 sel.setAttribute('title', 'The status tag value for this post.');
298 D.option(sel, "", "- Status -").disabled = true;
299 for( const status of F.config.forumStatuses ){
300 D.option(sel, status.value, status.label);
301 }
302 e.buttons.append(sel);
@@ -302,11 +325,11 @@
325 e.tabAttach.dataset.tabLabel = 'Attachments';
326 this.#tabs.addTab(e.tabAttach);
327 /* Reminder: we don't currently have a way to disable/enable
328 an Attacher's controls during ajax traffic. */
329 }
330 e.buttons.append(e.button.preview, e.button.submit, e.button.stash);
331 if( e.button.discard ){
332 e.buttons.append(e.button.discard);
333 this.#toDisable.push(e.button.discard);
334 }
335
@@ -329,11 +352,16 @@
352 'and edit modes, which is generally useful but some ',
353 'software keyboards misinteract with it. If the preview ',
354 'starts when tapping Enter, turn this setting off.'
355 ].join('')
356 );
357 eCb.checked = F.storage.getBool(
358 'edit-shift-enter-preview',
359 true
360 /* Maintenance reminder: this setting is shared across
361 several apps, like /chat, /wikiedit, and /fileedit. */
362 );
363 eCb.addEventListener('change', (ev)=>{
364 F.storage.set('edit-shift-enter-preview', eCb.checked);
365 });
366 F.helpButtonlets.setup(eHelp);
367 eLbl.append("Shift-enter toggles preview?", eCb, eHelp);
@@ -351,13 +379,12 @@
379 https://fossil-scm.org/forum/forumpost/dbd5b68366147ce8
380 */
381 if(!isShiftEnter(ev)) return;
382 ev.preventDefault();
383 ev.stopPropagation();
384 e.editor.blur(/*force draft update if needed*/);
385 this.#tabs.switchToTab(e.preview);
 
386 }, false);
387 // If we're in the preview tab, have ctrl-enter switch back to the editor.
388 document.body.addEventListener('keydown',(ev)=>{
389 if(!isShiftEnter(ev)) return;
390 if(this.#activeTab !== e.tabEdit){
@@ -983,21 +1010,21 @@
1010 }
1011
1012 /* Apply page-specific tweaks for ForumPostEditor instance fpe
1013 then plug it into the UI at the end of ePost. */
1014 const initFPEWidget = (fpe, ePost)=>{
1015 ePost.eUnhideThenWhenDone = [
 
1016 /* List of elements to hide while editing/replying and reveal
1017 when discarding or saving. */
1018 ];
1019 for( const ee of ePost.querySelectorAll(
1020 '.forumpost-single-controls, fieldset.forum-status-selection'
1021 ) ){
1022 ee.hidden = true;
1023 ePost.eUnhideThenWhenDone.push(ee);
1024 }
1025 const w = fpe.widget;
1026 w.classList.add('animate-entrance');
1027 ePost.append(w);
1028 requestAnimationFrame(() => {
1029 w.scrollIntoView({
1030 behavior: 'smooth',
@@ -1070,22 +1097,23 @@
1097 ePost.style.marginLeft = 'initial';
1098 eButton.dataset.originalLabel = eButton.innerText;
1099 };
1100
1101 /** Undoes the damage done by setupEditReplyElement(). */
1102 const restoreEditReplyElement = (ePost, eButton)=>{
1103 if( ePost.dataset.originalMarginLeft ){
1104 ePost.style.marginLeft = ePost.dataset.originalMarginLeft;
1105 delete ePost.dataset.originalMarginLeft;
1106 }
1107 if( eButton.dataset.originalLabel ){
1108 eButton.innerText = eButton.dataset.originalLabel;
1109 delete eButton.dataset.originalLabel;
1110 }
1111 for(const ee of (ePost.eUnhideThenWhenDone || [])){
1112 ee.removeAttribute('hidden');
1113 }
1114 ePost.eUnhideThenWhenDone = undefined;
1115 };
1116
1117 /**
1118 Reports an error regarding the forum post element
1119 ePost, appending each entry in msg to a wrapper
@@ -1151,31 +1179,31 @@
1179
1180 setupEditReplyElement(ePost, eBtnReply);
1181 eBtnReply.innerText = "Replying...";
1182 const ondone = (fpe, response)=>{
1183 /* onsubmit() and ondiscard() callback */
1184 restoreEditReplyElement(ePost, eBtnReply);
1185 //console.debug("ondiscard/onsubmit", fpe, artifact);
1186 if( response/*onsubmit()*/ ){
1187 window.location = F.repoUrl('forumpost/'+response.uuid);
1188 setTimeout(()=>fpe.close(), 500/*just in case not redirected*/);
1189 }else{/*ondiscard() or onclose()*/
1190 }
1191 };
1192 const fpe = new F.ForumPostEditor(F.nu({
1193 hiddenFields: form.querySelectorAll(
1194 'input[type=hidden][name=csrf]'
1195 /* Do not inherit the fpid field, else this will become
1196 an edit to that post rather than a response. */
1197 ),
 
1198 onsubmit: ondone,
1199 onclose: ()=>{
1200 if( releaseLock ){
1201 releaseLock();
1202 releaseLock = null;
1203 }
1204 ondone();
1205 },
1206 inReplyTo: fpid,
1207 draftKey
1208 }));
1209 initFPEWidget(fpe, ePost);
@@ -1231,32 +1259,32 @@
1259 if( fpid === response.uuid
1260 && !response.statusModified
1261 && 0===response.attachedCount ){
1262 fpe.reportError("No changes made.");
1263 }else{
1264 restoreEditReplyElement(ePost, eBtnEdit);
1265 window.location = F.repoUrl('forumpost/'+response.uuid);
1266 setTimeout(()=>fpe.close(), 500/*just in case not redirected*/);
1267 }
1268 }else{
1269 /*ondiscard() or onclose()*/
1270 restoreEditReplyElement(ePost, eBtnEdit);
1271 }
1272 };
1273 const eStatusSelect = ePost.querySelector(
1274 ':scope > fieldset.forum-status-selection select[name=status]'
1275 );
1276
1277 const fpe = new F.ForumPostEditor(F.nu({
1278 hiddenFields: form.querySelectorAll('input[type=hidden]'),
 
1279 onsubmit: ondone,
1280 onclose: ()=>{
1281 if(releaseLock){
1282 releaseLock();
1283 releaseLock = null;
1284 }
1285 ondone();
1286 },
1287 draftKey,
1288 edit: artifact,
1289 status: eStatusSelect?.value,
1290 inReplyTo: firt
@@ -1266,11 +1294,11 @@
1294 .catch(err=>{
1295 if( releaseLock ){
1296 releaseLock();
1297 releaseLock = null;
1298 }
1299 restoreEditReplyElement(ePost, eBtnEdit);
1300 console.error("Error fetching post:", err);
1301 reportFPEError(ePost, "Error fetching post: ", err.message);
1302 });
1303 }/*editClicked()*/;
1304
1305

Keyboard Shortcuts

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