Fossil SCM

Factor out extraneous thumbnail element creation when re-assigning an attachment slot to a different image. Add attachment size limit to JS's fossil.config for use in client-side validation.

stephan 2026-06-03 06:38 UTC attach-v2
Commit b3814a431a26024bb170caa72150f5aafddd009e6718b8816d1d2461046f6218
--- src/attach.c
+++ src/attach.c
@@ -654,10 +654,12 @@
654654
cgi_redirect(zTo ? zTo : zFrom);
655655
}
656656
#else
657657
(void)bNeedsModeration;
658658
(void)szLimit;
659
+ (void)szContent;
660
+ (void)zTo;
659661
#endif
660662
661663
style_set_current_feature("attach");
662664
style_header("Add Attachment");
663665
if( !goodCaptcha ){
664666
--- src/attach.c
+++ src/attach.c
@@ -654,10 +654,12 @@
654 cgi_redirect(zTo ? zTo : zFrom);
655 }
656 #else
657 (void)bNeedsModeration;
658 (void)szLimit;
 
 
659 #endif
660
661 style_set_current_feature("attach");
662 style_header("Add Attachment");
663 if( !goodCaptcha ){
664
--- src/attach.c
+++ src/attach.c
@@ -654,10 +654,12 @@
654 cgi_redirect(zTo ? zTo : zFrom);
655 }
656 #else
657 (void)bNeedsModeration;
658 (void)szLimit;
659 (void)szContent;
660 (void)zTo;
661 #endif
662
663 style_set_current_feature("attach");
664 style_header("Add Attachment");
665 if( !goodCaptcha ){
666
--- src/builtin.c
+++ src/builtin.c
@@ -668,10 +668,12 @@
668668
CX("editStateMarkers: {"
669669
"/*Symbolic markers to denote certain edit states.*/"
670670
"isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
671671
CX("confirmerButtonTicks: 3 "
672672
"/*default fossil.confirmer tick count.*/,\n");
673
+ CX("attachmentSizeLimit: %d,\n",
674
+ db_get_int("attachment-size-limit",0));
673675
/* Inject certain info about the current skin... */
674676
CX("skin:{");
675677
/* can leak a local filesystem path:
676678
CX("name: %!j,", skin_in_use());*/
677679
CX("isDark: %s"
678680
--- src/builtin.c
+++ src/builtin.c
@@ -668,10 +668,12 @@
668 CX("editStateMarkers: {"
669 "/*Symbolic markers to denote certain edit states.*/"
670 "isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
671 CX("confirmerButtonTicks: 3 "
672 "/*default fossil.confirmer tick count.*/,\n");
 
 
673 /* Inject certain info about the current skin... */
674 CX("skin:{");
675 /* can leak a local filesystem path:
676 CX("name: %!j,", skin_in_use());*/
677 CX("isDark: %s"
678
--- src/builtin.c
+++ src/builtin.c
@@ -668,10 +668,12 @@
668 CX("editStateMarkers: {"
669 "/*Symbolic markers to denote certain edit states.*/"
670 "isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
671 CX("confirmerButtonTicks: 3 "
672 "/*default fossil.confirmer tick count.*/,\n");
673 CX("attachmentSizeLimit: %d,\n",
674 db_get_int("attachment-size-limit",0));
675 /* Inject certain info about the current skin... */
676 CX("skin:{");
677 /* can leak a local filesystem path:
678 CX("name: %!j,", skin_in_use());*/
679 CX("isDark: %s"
680
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -317,17 +317,18 @@
317317
D.clearElement(rowObj.eInfo),
318318
lbl, D.br(), szLbl, ' ', rowObj.mimeType || ''
319319
);
320320
const old = this.#rowMatchingName(file.name);
321321
if( old && rowObj !== old){
322
+ /* FIXME: recycle `old` instead to avoid UI flicker. */
322323
this.#removeRow(old);
323324
}
324325
rowObj.eDropzone.classList.add('populated');
325326
rowObj.eDesc.classList.remove('hidden');
326327
if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){
327
- rowObj.eDropzone.querySelectorAll('img.thumbnail').forEach(e=>e.remove());
328
- const img = D.img();
328
+ /* Add a thumbnail */
329
+ const img = rowObj.eDropzone.querySelector('img.thumbnail') || D.img();
329330
img.classList.add('thumbnail');
330331
rowObj.eDropzone.insertBefore(img, rowObj.eRemove);
331332
const reader = new FileReader();
332333
reader.onload = (e)=>img.setAttribute('src', e.target.result);
333334
reader.readAsDataURL(file);
334335
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -317,17 +317,18 @@
317 D.clearElement(rowObj.eInfo),
318 lbl, D.br(), szLbl, ' ', rowObj.mimeType || ''
319 );
320 const old = this.#rowMatchingName(file.name);
321 if( old && rowObj !== old){
 
322 this.#removeRow(old);
323 }
324 rowObj.eDropzone.classList.add('populated');
325 rowObj.eDesc.classList.remove('hidden');
326 if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){
327 rowObj.eDropzone.querySelectorAll('img.thumbnail').forEach(e=>e.remove());
328 const img = D.img();
329 img.classList.add('thumbnail');
330 rowObj.eDropzone.insertBefore(img, rowObj.eRemove);
331 const reader = new FileReader();
332 reader.onload = (e)=>img.setAttribute('src', e.target.result);
333 reader.readAsDataURL(file);
334
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -317,17 +317,18 @@
317 D.clearElement(rowObj.eInfo),
318 lbl, D.br(), szLbl, ' ', rowObj.mimeType || ''
319 );
320 const old = this.#rowMatchingName(file.name);
321 if( old && rowObj !== old){
322 /* FIXME: recycle `old` instead to avoid UI flicker. */
323 this.#removeRow(old);
324 }
325 rowObj.eDropzone.classList.add('populated');
326 rowObj.eDesc.classList.remove('hidden');
327 if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){
328 /* Add a thumbnail */
329 const img = rowObj.eDropzone.querySelector('img.thumbnail') || D.img();
330 img.classList.add('thumbnail');
331 rowObj.eDropzone.insertBefore(img, rowObj.eRemove);
332 const reader = new FileReader();
333 reader.onload = (e)=>img.setAttribute('src', e.target.result);
334 reader.readAsDataURL(file);
335

Keyboard Shortcuts

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