Fossil SCM

Style tweaks and minor JS modernization. Remove some stray debug output.

stephan 2026-06-06 15:28 UTC forum-editor-2026
Commit ae9871601ef69b1cc914b273bc410dc6c64a30e077a209e2939d03bbc3e86bf1
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -185,15 +185,15 @@
185185
186186
{ /* Shift-enter pieces... */
187187
const eCb = D.checkbox(1);
188188
const eLbl = D.label();
189189
const eHelp = D.append(
190
- D.addClass(D.span(), "help-buttonlet"), [
190
+ D.span(), [
191191
'When checked, shift-enter will toggle between preview ',
192
- 'and edit modes. This is generally useful but some ',
192
+ 'and edit modes, which is generally useful but some ',
193193
'software keyboards misinteract with it. If the preview ',
194
- 'starts when you tap Enter, turn this setting off.'
194
+ 'starts when tapping Enter, turn this setting off.'
195195
].join('')
196196
);
197197
eCb.checked = F.storage.getBool('edit-shift-enter-preview', true);
198198
eCb.addEventListener('change', (ev)=>{
199199
F.storage.set('edit-shift-enter-preview', eCb.checked);
@@ -221,11 +221,10 @@
221221
this.#preview();
222222
}, false);
223223
// If we're in the preview tab, have ctrl-enter switch back to the editor.
224224
document.body.addEventListener('keydown',(ev)=>{
225225
if(!isShiftEnter(ev)) return;
226
- console.warn("this.#activeTab =",this.#activeTab);
227226
if(this.#activeTab !== e.tabEdit){
228227
ev.preventDefault();
229228
ev.stopPropagation();
230229
this.#tabs.switchToTab(e.tabEdit);
231230
e.editor.focus(/*slow as molasses for long docs, as focus()
232231
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -185,15 +185,15 @@
185
186 { /* Shift-enter pieces... */
187 const eCb = D.checkbox(1);
188 const eLbl = D.label();
189 const eHelp = D.append(
190 D.addClass(D.span(), "help-buttonlet"), [
191 'When checked, shift-enter will toggle between preview ',
192 'and edit modes. This is generally useful but some ',
193 'software keyboards misinteract with it. If the preview ',
194 'starts when you tap Enter, turn this setting off.'
195 ].join('')
196 );
197 eCb.checked = F.storage.getBool('edit-shift-enter-preview', true);
198 eCb.addEventListener('change', (ev)=>{
199 F.storage.set('edit-shift-enter-preview', eCb.checked);
@@ -221,11 +221,10 @@
221 this.#preview();
222 }, false);
223 // If we're in the preview tab, have ctrl-enter switch back to the editor.
224 document.body.addEventListener('keydown',(ev)=>{
225 if(!isShiftEnter(ev)) return;
226 console.warn("this.#activeTab =",this.#activeTab);
227 if(this.#activeTab !== e.tabEdit){
228 ev.preventDefault();
229 ev.stopPropagation();
230 this.#tabs.switchToTab(e.tabEdit);
231 e.editor.focus(/*slow as molasses for long docs, as focus()
232
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -185,15 +185,15 @@
185
186 { /* Shift-enter pieces... */
187 const eCb = D.checkbox(1);
188 const eLbl = D.label();
189 const eHelp = D.append(
190 D.span(), [
191 'When checked, shift-enter will toggle between preview ',
192 'and edit modes, which is generally useful but some ',
193 'software keyboards misinteract with it. If the preview ',
194 'starts when tapping Enter, turn this setting off.'
195 ].join('')
196 );
197 eCb.checked = F.storage.getBool('edit-shift-enter-preview', true);
198 eCb.addEventListener('change', (ev)=>{
199 F.storage.set('edit-shift-enter-preview', eCb.checked);
@@ -221,11 +221,10 @@
221 this.#preview();
222 }, false);
223 // If we're in the preview tab, have ctrl-enter switch back to the editor.
224 document.body.addEventListener('keydown',(ev)=>{
225 if(!isShiftEnter(ev)) return;
 
226 if(this.#activeTab !== e.tabEdit){
227 ev.preventDefault();
228 ev.stopPropagation();
229 this.#tabs.switchToTab(e.tabEdit);
230 e.editor.focus(/*slow as molasses for long docs, as focus()
231
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -55,11 +55,11 @@
5555
from the default), the class "fossil-PopupWidget" is always set
5656
in order to allow certain app-internal CSS to account for popup
5757
windows in special cases.
5858
5959
.style: optional object of properties to copy directly into
60
- the element's style object.
60
+ the element's style object.
6161
6262
The options passed to this constructor get normalized into a
6363
separate object which includes any default values for options not
6464
provided by the caller. That object is available this the
6565
resulting PopupWidget's options property. Default values for any
@@ -161,11 +161,11 @@
161161
Sidebar: showing/hiding the widget is, as is conventional for
162162
this framework, done by removing/adding the 'hidden' CSS class
163163
to it, so that class must be defined appropriately.
164164
*/
165165
show: function(){
166
- var x = undefined, y = undefined, showIt,
166
+ let x = undefined, y = undefined, showIt,
167167
wasShown = !this.e.classList.contains('hidden');
168168
if(2===arguments.length){
169169
x = arguments[0];
170170
y = arguments[1];
171171
showIt = true;
@@ -344,11 +344,12 @@
344344
- No arguments, which is equivalent to passing the string
345345
".help-buttonlet:not(.processed)".
346346
347347
Passing the same element(s) more than once is a no-op: during
348348
initialization, each elements get the class'processed' added to
349
- it, and any elements with that class are skipped.
349
+ it, and any elements with that class are skipped. Each element
350
+ gets the 'help-buttonlet' CSS class added to it.
350351
351352
All child nodes of a help buttonlet are removed from the button
352353
during initialization and stashed away for use in a PopupWidget
353354
when the botton is clicked.
354355
@@ -374,24 +375,24 @@
374375
calculate the resulting size, then move and/or resize it.
375376
376377
This algorithm/these heuristics can certainly be improved
377378
upon.
378379
*/
379
- var popupRect, rectElem = ev.target;
380
+ let popupRect, rectElem = ev.target;
380381
while(rectElem){
381382
popupRect = rectElem.getClientRects()[0]/*undefined if off-screen!*/;
382383
if(popupRect) break;
383384
rectElem = rectElem.parentNode;
384385
}
385386
if(!popupRect) popupRect = {x:0, y:0, left:0, right:0};
386
- var x = popupRect.left, y = popupRect.top;
387
+ let x = popupRect.left, y = popupRect.top;
387388
if(x<0) x = 0;
388389
if(y<0) y = 0;
389390
if(rectElem){
390391
/* Try to ensure that the popup's z-level is higher than this element's */
391392
const rz = window.getComputedStyle(rectElem).zIndex;
392
- var myZ;
393
+ let myZ;
393394
if(rz && !isNaN(+rz)){
394395
myZ = +rz + 1;
395396
}else{
396397
myZ = 10000/*guess!*/;
397398
}
@@ -416,11 +417,11 @@
416417
fch.popup.show(x, y);
417418
return false;
418419
};
419420
f.foreachElement = function(e){
420421
if(e.classList.contains('processed')) return;
421
- e.classList.add('processed');
422
+ e.classList.add('processed', 'help-buttonlet');
422423
e.$helpContent = [];
423424
/* We have to move all child nodes out of the way because we
424425
cannot hide TEXT nodes via CSS (which cannot select TEXT
425426
nodes). We have to do it in two steps to avoid invaliding
426427
the list during traversal. */
@@ -427,11 +428,11 @@
427428
e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
428429
e.$helpContent.forEach((ch)=>ch.remove());
429430
e.addEventListener('click', f.clickHandler, false);
430431
};
431432
}/*static init*/
432
- var elems;
433
+ let elems;
433434
if(!arguments.length){
434435
arguments[0] = '.help-buttonlet:not(.processed)';
435436
arguments.length = 1;
436437
}
437438
if(arguments.length){
@@ -443,11 +444,11 @@
443444
elems = arguments[0];
444445
}
445446
}
446447
if(elems) elems.forEach(f.foreachElement);
447448
},
448
-
449
+
449450
/**
450451
Sets up the given element as a "help buttonlet", adding the CSS
451452
class help-buttonlet to it. Any (optional) arguments after the
452453
first are appended to the element using fossil.dom.append(), so
453454
that they become the content for the buttonlet's popup help.
@@ -465,7 +466,6 @@
465466
return elem;
466467
}
467468
}/*helpButtonlets*/;
468469
469470
F.onDOMContentLoaded( ()=>F.helpButtonlets.setup() );
470
-
471471
})(window.fossil);
472472
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -55,11 +55,11 @@
55 from the default), the class "fossil-PopupWidget" is always set
56 in order to allow certain app-internal CSS to account for popup
57 windows in special cases.
58
59 .style: optional object of properties to copy directly into
60 the element's style object.
61
62 The options passed to this constructor get normalized into a
63 separate object which includes any default values for options not
64 provided by the caller. That object is available this the
65 resulting PopupWidget's options property. Default values for any
@@ -161,11 +161,11 @@
161 Sidebar: showing/hiding the widget is, as is conventional for
162 this framework, done by removing/adding the 'hidden' CSS class
163 to it, so that class must be defined appropriately.
164 */
165 show: function(){
166 var x = undefined, y = undefined, showIt,
167 wasShown = !this.e.classList.contains('hidden');
168 if(2===arguments.length){
169 x = arguments[0];
170 y = arguments[1];
171 showIt = true;
@@ -344,11 +344,12 @@
344 - No arguments, which is equivalent to passing the string
345 ".help-buttonlet:not(.processed)".
346
347 Passing the same element(s) more than once is a no-op: during
348 initialization, each elements get the class'processed' added to
349 it, and any elements with that class are skipped.
 
350
351 All child nodes of a help buttonlet are removed from the button
352 during initialization and stashed away for use in a PopupWidget
353 when the botton is clicked.
354
@@ -374,24 +375,24 @@
374 calculate the resulting size, then move and/or resize it.
375
376 This algorithm/these heuristics can certainly be improved
377 upon.
378 */
379 var popupRect, rectElem = ev.target;
380 while(rectElem){
381 popupRect = rectElem.getClientRects()[0]/*undefined if off-screen!*/;
382 if(popupRect) break;
383 rectElem = rectElem.parentNode;
384 }
385 if(!popupRect) popupRect = {x:0, y:0, left:0, right:0};
386 var x = popupRect.left, y = popupRect.top;
387 if(x<0) x = 0;
388 if(y<0) y = 0;
389 if(rectElem){
390 /* Try to ensure that the popup's z-level is higher than this element's */
391 const rz = window.getComputedStyle(rectElem).zIndex;
392 var myZ;
393 if(rz && !isNaN(+rz)){
394 myZ = +rz + 1;
395 }else{
396 myZ = 10000/*guess!*/;
397 }
@@ -416,11 +417,11 @@
416 fch.popup.show(x, y);
417 return false;
418 };
419 f.foreachElement = function(e){
420 if(e.classList.contains('processed')) return;
421 e.classList.add('processed');
422 e.$helpContent = [];
423 /* We have to move all child nodes out of the way because we
424 cannot hide TEXT nodes via CSS (which cannot select TEXT
425 nodes). We have to do it in two steps to avoid invaliding
426 the list during traversal. */
@@ -427,11 +428,11 @@
427 e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
428 e.$helpContent.forEach((ch)=>ch.remove());
429 e.addEventListener('click', f.clickHandler, false);
430 };
431 }/*static init*/
432 var elems;
433 if(!arguments.length){
434 arguments[0] = '.help-buttonlet:not(.processed)';
435 arguments.length = 1;
436 }
437 if(arguments.length){
@@ -443,11 +444,11 @@
443 elems = arguments[0];
444 }
445 }
446 if(elems) elems.forEach(f.foreachElement);
447 },
448
449 /**
450 Sets up the given element as a "help buttonlet", adding the CSS
451 class help-buttonlet to it. Any (optional) arguments after the
452 first are appended to the element using fossil.dom.append(), so
453 that they become the content for the buttonlet's popup help.
@@ -465,7 +466,6 @@
465 return elem;
466 }
467 }/*helpButtonlets*/;
468
469 F.onDOMContentLoaded( ()=>F.helpButtonlets.setup() );
470
471 })(window.fossil);
472
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -55,11 +55,11 @@
55 from the default), the class "fossil-PopupWidget" is always set
56 in order to allow certain app-internal CSS to account for popup
57 windows in special cases.
58
59 .style: optional object of properties to copy directly into
60 the element's style object.
61
62 The options passed to this constructor get normalized into a
63 separate object which includes any default values for options not
64 provided by the caller. That object is available this the
65 resulting PopupWidget's options property. Default values for any
@@ -161,11 +161,11 @@
161 Sidebar: showing/hiding the widget is, as is conventional for
162 this framework, done by removing/adding the 'hidden' CSS class
163 to it, so that class must be defined appropriately.
164 */
165 show: function(){
166 let x = undefined, y = undefined, showIt,
167 wasShown = !this.e.classList.contains('hidden');
168 if(2===arguments.length){
169 x = arguments[0];
170 y = arguments[1];
171 showIt = true;
@@ -344,11 +344,12 @@
344 - No arguments, which is equivalent to passing the string
345 ".help-buttonlet:not(.processed)".
346
347 Passing the same element(s) more than once is a no-op: during
348 initialization, each elements get the class'processed' added to
349 it, and any elements with that class are skipped. Each element
350 gets the 'help-buttonlet' CSS class added to it.
351
352 All child nodes of a help buttonlet are removed from the button
353 during initialization and stashed away for use in a PopupWidget
354 when the botton is clicked.
355
@@ -374,24 +375,24 @@
375 calculate the resulting size, then move and/or resize it.
376
377 This algorithm/these heuristics can certainly be improved
378 upon.
379 */
380 let popupRect, rectElem = ev.target;
381 while(rectElem){
382 popupRect = rectElem.getClientRects()[0]/*undefined if off-screen!*/;
383 if(popupRect) break;
384 rectElem = rectElem.parentNode;
385 }
386 if(!popupRect) popupRect = {x:0, y:0, left:0, right:0};
387 let x = popupRect.left, y = popupRect.top;
388 if(x<0) x = 0;
389 if(y<0) y = 0;
390 if(rectElem){
391 /* Try to ensure that the popup's z-level is higher than this element's */
392 const rz = window.getComputedStyle(rectElem).zIndex;
393 let myZ;
394 if(rz && !isNaN(+rz)){
395 myZ = +rz + 1;
396 }else{
397 myZ = 10000/*guess!*/;
398 }
@@ -416,11 +417,11 @@
417 fch.popup.show(x, y);
418 return false;
419 };
420 f.foreachElement = function(e){
421 if(e.classList.contains('processed')) return;
422 e.classList.add('processed', 'help-buttonlet');
423 e.$helpContent = [];
424 /* We have to move all child nodes out of the way because we
425 cannot hide TEXT nodes via CSS (which cannot select TEXT
426 nodes). We have to do it in two steps to avoid invaliding
427 the list during traversal. */
@@ -427,11 +428,11 @@
428 e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
429 e.$helpContent.forEach((ch)=>ch.remove());
430 e.addEventListener('click', f.clickHandler, false);
431 };
432 }/*static init*/
433 let elems;
434 if(!arguments.length){
435 arguments[0] = '.help-buttonlet:not(.processed)';
436 arguments.length = 1;
437 }
438 if(arguments.length){
@@ -443,11 +444,11 @@
444 elems = arguments[0];
445 }
446 }
447 if(elems) elems.forEach(f.foreachElement);
448 },
449
450 /**
451 Sets up the given element as a "help buttonlet", adding the CSS
452 class help-buttonlet to it. Any (optional) arguments after the
453 first are appended to the element using fossil.dom.append(), so
454 that they become the content for the buttonlet's popup help.
@@ -465,7 +466,6 @@
466 return elem;
467 }
468 }/*helpButtonlets*/;
469
470 F.onDOMContentLoaded( ()=>F.helpButtonlets.setup() );
 
471 })(window.fossil);
472
--- src/style.forum.css
+++ src/style.forum.css
@@ -69,9 +69,12 @@
6969
white-space: nowrap;
7070
display: flex;
7171
flex-direction: row;
7272
align-items: last baseline;
7373
cursor: pointer;
74
+ border: 1px inset rgba(128, 128, 128, 0.5);
75
+ border-radius: 0.25em;
76
+ padding: 0.1em;
7477
}
7578
.ForumPostEditor > .buttons > label > input[type=checkbox]{
7679
cursor: pointer;
7780
}
7881
--- src/style.forum.css
+++ src/style.forum.css
@@ -69,9 +69,12 @@
69 white-space: nowrap;
70 display: flex;
71 flex-direction: row;
72 align-items: last baseline;
73 cursor: pointer;
 
 
 
74 }
75 .ForumPostEditor > .buttons > label > input[type=checkbox]{
76 cursor: pointer;
77 }
78
--- src/style.forum.css
+++ src/style.forum.css
@@ -69,9 +69,12 @@
69 white-space: nowrap;
70 display: flex;
71 flex-direction: row;
72 align-items: last baseline;
73 cursor: pointer;
74 border: 1px inset rgba(128, 128, 128, 0.5);
75 border-radius: 0.25em;
76 padding: 0.1em;
77 }
78 .ForumPostEditor > .buttons > label > input[type=checkbox]{
79 cursor: pointer;
80 }
81

Keyboard Shortcuts

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