Fossil SCM

Cleanups. Need to veer off and refactor the attach code to support the next step.

stephan 2026-06-06 16:26 UTC forum-editor-2026
Commit c02e4fcb5cb165e03c3e0257a116d7a05139e2e277017922c35b190fa3c5c5bb
1 file changed +35 -18
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -271,25 +271,26 @@
271271
const e = this.#e.err;
272272
D.clearElement(e);
273273
if( msg.length ){
274274
e.classList.remove('hidden');
275275
e.append(...msg);
276
+ console.error('ForumPostEditor:',...msg);
276277
}else{
277278
e.classList.add('hidden');
278279
}
279280
}
280281
281282
/**
282283
Adds a list of input[type=hidden] form fields to this object,
283
- imported from the server-generated HTML. This is used for collecting,
284
- e.g., the CSRF token.
284
+ imported from the server-generated HTML. This is used for
285
+ collecting, e.g., the CSRF token and an initial page title.
285286
*/
286287
addHiddenFields(list){
287288
this.#extraFields ??= [];
288289
for( const f of list ){
289
- if( 'title'===f.name && this.#opt.isNewThread ){
290
- if( !this.#e.title.value ){
290
+ if( 'title'===f.name ){
291
+ if( f.value && this.#opt.isNewThread && !this.#e.title.value ){
291292
this.#e.title.value = f.value;
292293
}
293294
}else{
294295
this.#extraFields.push(f);
295296
}
@@ -298,19 +299,29 @@
298299
299300
get mimetype(){
300301
return this.#e.mimetype.select.value;
301302
}
302303
303
- async #fetchPreview(content){
304
- /* TODO: fetch preview */
305
- const e = this.#e;
304
+ get title(){
305
+ return this.#e.title.value;
306
+ }
307
+
308
+ #newFormData(addThisContent){
306309
const fd = new FormData;
307310
for(const f of this.#extraFields){
308311
fd.append(f.name, f.value);
309312
}
310313
fd.append('mimetype', this.mimetype);
311
- fd.append('content', content);
314
+ fd.append('title', this.title.trim());
315
+ fd.append('content', addThisContent || this.editorContent.trim());
316
+ return fd;
317
+ }
318
+
319
+ async #fetchPreview(content){
320
+ /* TODO: fetch preview */
321
+ const e = this.#e;
322
+ const fd = this.#newFormData(content);
312323
return window
313324
.fetch(F.repoUrl('wikiajax/preview'), {
314325
method: 'POST',
315326
body: fd
316327
})
@@ -352,11 +363,11 @@
352363
D.disable(this.#toDisable, e.button.submit);
353364
e.preview.textContent = "Fetching preview...";
354365
this.#fetchPreview(content)
355366
.then((c)=>{
356367
this.#setPreviewContent(c);
357
- D.enable(this.#toDisable, e.button.submit);
368
+ D.enable(e.button.submit);
358369
})
359370
.catch(err=>{
360371
e.preview.textContent = "Error fetching preview: "+err.message;
361372
console.error("Error fetching preview:",err);
362373
this.reportError(err.message);
@@ -365,15 +376,17 @@
365376
this.#isWaiting = false;
366377
D.enable(this.#toDisable);
367378
});
368379
}
369380
370
- #validate(){
371
- let v = this.#e.title.value.trim();
372
- if( !v ){
373
- this.reportError("A non-empty title is required.");
374
- return;
381
+ #validate(tgt){
382
+ if( this.#opt.isNewThread ){
383
+ let v = this.#e.title.value.trim();
384
+ if( !v ){
385
+ this.reportError("A non-empty title is required.");
386
+ return;
387
+ }
375388
}
376389
return true;
377390
}
378391
379392
#submit(){
@@ -381,20 +394,24 @@
381394
if( !this.#validate() ) return;
382395
this.#isWaiting = true;
383396
const e = this.#e;
384397
D.disable(e.button.submit);
385398
this.reportError("Submit is TODO.");
386
- if( opt.draftKey ){
387
- F.storage.remove(opt.draftKey+'.content');
388
- F.storage.remove(opt.draftKey+'.title');
389
- }
399
+ const fd = this.#newFormData();
400
+ this.#att.populateFormData(fd);
401
+ console.warn("Ready to submit",fd);
390402
/*
391403
TODO: save it, set #isWaiting=false, then handle error or
392404
redirect to the post (if this is a new post) or, if replying
393405
inline, replace this object with a static rendering from the
394406
response.
395407
*/
408
+ if( 0 && this.#opt.draftKey ){
409
+ F.storage.remove(this.#opt.draftKey+'.content');
410
+ F.storage.remove(this.#opt.draftKey+'.title');
411
+ }
412
+ this.#isWaiting = false;
396413
}
397414
398415
async #fetchPost(){
399416
/*
400417
TODO: when editing an existing post, fetch the raw body of the
401418
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -271,25 +271,26 @@
271 const e = this.#e.err;
272 D.clearElement(e);
273 if( msg.length ){
274 e.classList.remove('hidden');
275 e.append(...msg);
 
276 }else{
277 e.classList.add('hidden');
278 }
279 }
280
281 /**
282 Adds a list of input[type=hidden] form fields to this object,
283 imported from the server-generated HTML. This is used for collecting,
284 e.g., the CSRF token.
285 */
286 addHiddenFields(list){
287 this.#extraFields ??= [];
288 for( const f of list ){
289 if( 'title'===f.name && this.#opt.isNewThread ){
290 if( !this.#e.title.value ){
291 this.#e.title.value = f.value;
292 }
293 }else{
294 this.#extraFields.push(f);
295 }
@@ -298,19 +299,29 @@
298
299 get mimetype(){
300 return this.#e.mimetype.select.value;
301 }
302
303 async #fetchPreview(content){
304 /* TODO: fetch preview */
305 const e = this.#e;
 
 
306 const fd = new FormData;
307 for(const f of this.#extraFields){
308 fd.append(f.name, f.value);
309 }
310 fd.append('mimetype', this.mimetype);
311 fd.append('content', content);
 
 
 
 
 
 
 
 
312 return window
313 .fetch(F.repoUrl('wikiajax/preview'), {
314 method: 'POST',
315 body: fd
316 })
@@ -352,11 +363,11 @@
352 D.disable(this.#toDisable, e.button.submit);
353 e.preview.textContent = "Fetching preview...";
354 this.#fetchPreview(content)
355 .then((c)=>{
356 this.#setPreviewContent(c);
357 D.enable(this.#toDisable, e.button.submit);
358 })
359 .catch(err=>{
360 e.preview.textContent = "Error fetching preview: "+err.message;
361 console.error("Error fetching preview:",err);
362 this.reportError(err.message);
@@ -365,15 +376,17 @@
365 this.#isWaiting = false;
366 D.enable(this.#toDisable);
367 });
368 }
369
370 #validate(){
371 let v = this.#e.title.value.trim();
372 if( !v ){
373 this.reportError("A non-empty title is required.");
374 return;
 
 
375 }
376 return true;
377 }
378
379 #submit(){
@@ -381,20 +394,24 @@
381 if( !this.#validate() ) return;
382 this.#isWaiting = true;
383 const e = this.#e;
384 D.disable(e.button.submit);
385 this.reportError("Submit is TODO.");
386 if( opt.draftKey ){
387 F.storage.remove(opt.draftKey+'.content');
388 F.storage.remove(opt.draftKey+'.title');
389 }
390 /*
391 TODO: save it, set #isWaiting=false, then handle error or
392 redirect to the post (if this is a new post) or, if replying
393 inline, replace this object with a static rendering from the
394 response.
395 */
 
 
 
 
 
396 }
397
398 async #fetchPost(){
399 /*
400 TODO: when editing an existing post, fetch the raw body of the
401
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -271,25 +271,26 @@
271 const e = this.#e.err;
272 D.clearElement(e);
273 if( msg.length ){
274 e.classList.remove('hidden');
275 e.append(...msg);
276 console.error('ForumPostEditor:',...msg);
277 }else{
278 e.classList.add('hidden');
279 }
280 }
281
282 /**
283 Adds a list of input[type=hidden] form fields to this object,
284 imported from the server-generated HTML. This is used for
285 collecting, e.g., the CSRF token and an initial page title.
286 */
287 addHiddenFields(list){
288 this.#extraFields ??= [];
289 for( const f of list ){
290 if( 'title'===f.name ){
291 if( f.value && this.#opt.isNewThread && !this.#e.title.value ){
292 this.#e.title.value = f.value;
293 }
294 }else{
295 this.#extraFields.push(f);
296 }
@@ -298,19 +299,29 @@
299
300 get mimetype(){
301 return this.#e.mimetype.select.value;
302 }
303
304 get title(){
305 return this.#e.title.value;
306 }
307
308 #newFormData(addThisContent){
309 const fd = new FormData;
310 for(const f of this.#extraFields){
311 fd.append(f.name, f.value);
312 }
313 fd.append('mimetype', this.mimetype);
314 fd.append('title', this.title.trim());
315 fd.append('content', addThisContent || this.editorContent.trim());
316 return fd;
317 }
318
319 async #fetchPreview(content){
320 /* TODO: fetch preview */
321 const e = this.#e;
322 const fd = this.#newFormData(content);
323 return window
324 .fetch(F.repoUrl('wikiajax/preview'), {
325 method: 'POST',
326 body: fd
327 })
@@ -352,11 +363,11 @@
363 D.disable(this.#toDisable, e.button.submit);
364 e.preview.textContent = "Fetching preview...";
365 this.#fetchPreview(content)
366 .then((c)=>{
367 this.#setPreviewContent(c);
368 D.enable(e.button.submit);
369 })
370 .catch(err=>{
371 e.preview.textContent = "Error fetching preview: "+err.message;
372 console.error("Error fetching preview:",err);
373 this.reportError(err.message);
@@ -365,15 +376,17 @@
376 this.#isWaiting = false;
377 D.enable(this.#toDisable);
378 });
379 }
380
381 #validate(tgt){
382 if( this.#opt.isNewThread ){
383 let v = this.#e.title.value.trim();
384 if( !v ){
385 this.reportError("A non-empty title is required.");
386 return;
387 }
388 }
389 return true;
390 }
391
392 #submit(){
@@ -381,20 +394,24 @@
394 if( !this.#validate() ) return;
395 this.#isWaiting = true;
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 response.
407 */
408 if( 0 && this.#opt.draftKey ){
409 F.storage.remove(this.#opt.draftKey+'.content');
410 F.storage.remove(this.#opt.draftKey+'.title');
411 }
412 this.#isWaiting = false;
413 }
414
415 async #fetchPost(){
416 /*
417 TODO: when editing an existing post, fetch the raw body of the
418

Keyboard Shortcuts

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