Fossil SCM

Initial pieces for extending attachment input to support multiple attachments at a time, drag-and-drop, and clipboard paste. WIP and currently requires the dev console to try out.

stephan 2026-06-02 12:37 UTC trunk
Commit 2d39f606703f4f0d372ef0ea6c90a9375d58495c74614b8982a3711776ae61ec
--- src/attach.c
+++ src/attach.c
@@ -533,10 +533,11 @@
533533
@ <input type="submit" name="ok" value="Add Attachment">
534534
@ <input type="submit" name="cancel" value="Cancel">
535535
@ </div>
536536
captcha_generate(0);
537537
@ </form>
538
+ builtin_fossil_js_bundle_or("attach", NULL);
538539
style_finish_page();
539540
fossil_free(zTargetType);
540541
fossil_free(zExtraFree);
541542
}
542543
543544
--- src/attach.c
+++ src/attach.c
@@ -533,10 +533,11 @@
533 @ <input type="submit" name="ok" value="Add Attachment">
534 @ <input type="submit" name="cancel" value="Cancel">
535 @ </div>
536 captcha_generate(0);
537 @ </form>
 
538 style_finish_page();
539 fossil_free(zTargetType);
540 fossil_free(zExtraFree);
541 }
542
543
--- src/attach.c
+++ src/attach.c
@@ -533,10 +533,11 @@
533 @ <input type="submit" name="ok" value="Add Attachment">
534 @ <input type="submit" name="cancel" value="Cancel">
535 @ </div>
536 captcha_generate(0);
537 @ </form>
538 builtin_fossil_js_bundle_or("attach", NULL);
539 style_finish_page();
540 fossil_free(zTargetType);
541 fossil_free(zExtraFree);
542 }
543
544
--- src/builtin.c
+++ src/builtin.c
@@ -732,10 +732,11 @@
732732
** entries: all known deps of this one. Each
733733
** REQUIRES an EXPLICIT trailing \0, including
734734
** the final one! */
735735
} fjs[] = {
736736
/* This list ordering isn't strictly important. */
737
+ {"attach", 0, "dom\0"},
737738
{"confirmer", 0, 0},
738739
{"copybutton", 0, "dom\0"},
739740
{"diff", 0, "dom\0fetch\0storage\0"
740741
/* maintenance note: "diff" needs "storage" for storing the
741742
** sbs-sync-scroll toggle. */},
742743
--- src/builtin.c
+++ src/builtin.c
@@ -732,10 +732,11 @@
732 ** entries: all known deps of this one. Each
733 ** REQUIRES an EXPLICIT trailing \0, including
734 ** the final one! */
735 } fjs[] = {
736 /* This list ordering isn't strictly important. */
 
737 {"confirmer", 0, 0},
738 {"copybutton", 0, "dom\0"},
739 {"diff", 0, "dom\0fetch\0storage\0"
740 /* maintenance note: "diff" needs "storage" for storing the
741 ** sbs-sync-scroll toggle. */},
742
--- src/builtin.c
+++ src/builtin.c
@@ -732,10 +732,11 @@
732 ** entries: all known deps of this one. Each
733 ** REQUIRES an EXPLICIT trailing \0, including
734 ** the final one! */
735 } fjs[] = {
736 /* This list ordering isn't strictly important. */
737 {"attach", 0, "dom\0"},
738 {"confirmer", 0, 0},
739 {"copybutton", 0, "dom\0"},
740 {"diff", 0, "dom\0fetch\0storage\0"
741 /* maintenance note: "diff" needs "storage" for storing the
742 ** sbs-sync-scroll toggle. */},
743
--- src/default.css
+++ src/default.css
@@ -2007,10 +2007,75 @@
20072007
margin: 0;
20082008
}
20092009
div.helpPage blockquote {
20102010
margin-left: 0.2em;
20112011
}
2012
+
2013
+/* .attach* = styles for file attachments */
2014
+.attach-container {
2015
+ margin-bottom: 1em;
2016
+ display: flex;
2017
+ flex-direction: column;
2018
+ gap: 0.75em;
2019
+}
2020
+.attach-row {
2021
+ display: flex;
2022
+ flex-direction: column;
2023
+ gap: 0.5em;
2024
+ padding: 0.75em;
2025
+ border: 1px dashed #ccc;
2026
+ border-radius: 4px;
2027
+ background-color: #fafafa;
2028
+}
2029
+.attach-dropzone {
2030
+ padding: 1em;
2031
+ text-align: center;
2032
+ background: #ffffff;
2033
+ border: 1px solid #ddd;
2034
+ cursor: pointer;
2035
+ border-radius: 2px;
2036
+ transition: background-color 0.15s ease-in-out;
2037
+}
2038
+.attach-dropzone.dragover {
2039
+ background-color: #e1f5fe;
2040
+ border-color: #03a9f4;
2041
+}
2042
+.attach-dropzone.row-populated {
2043
+ background-color: #f1f8e9;
2044
+ border-color: #8bc34a;
2045
+ border-style: solid;
2046
+}
2047
+.attach-row-info {
2048
+ font-family: monospace;
2049
+ font-size: 0.9em;
2050
+ color: #555;
2051
+}
2052
+.attach-desc-input {
2053
+ width: 100%;
2054
+ box-sizing: border-box;
2055
+ min-height: 4em;
2056
+ padding: 0.5em;
2057
+ font-family: inherit;
2058
+ font-size: 0.9em;
2059
+ resize: vertical;
2060
+}
2061
+.attach-row-remove {
2062
+ align-self: flex-end;
2063
+ padding: 0.25em 0.75em;
2064
+ background-color: #d32f2f;
2065
+ color: #fff;
2066
+ border: none;
2067
+ border-radius: 2px;
2068
+ cursor: pointer;
2069
+}
2070
+.attach-row-remove:hover {
2071
+ background-color: #b71c1c;
2072
+}
2073
+.attach-add-button {
2074
+ padding: 0.5em 1em;
2075
+ cursor: pointer;
2076
+}
20122077
20132078
/* Objects in the "desktoponly" class are invisible on mobile */
20142079
@media screen and (max-width: 600px) {
20152080
.desktoponly {
20162081
display: none;
20172082
--- src/default.css
+++ src/default.css
@@ -2007,10 +2007,75 @@
2007 margin: 0;
2008 }
2009 div.helpPage blockquote {
2010 margin-left: 0.2em;
2011 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2012
2013 /* Objects in the "desktoponly" class are invisible on mobile */
2014 @media screen and (max-width: 600px) {
2015 .desktoponly {
2016 display: none;
2017
--- src/default.css
+++ src/default.css
@@ -2007,10 +2007,75 @@
2007 margin: 0;
2008 }
2009 div.helpPage blockquote {
2010 margin-left: 0.2em;
2011 }
2012
2013 /* .attach* = styles for file attachments */
2014 .attach-container {
2015 margin-bottom: 1em;
2016 display: flex;
2017 flex-direction: column;
2018 gap: 0.75em;
2019 }
2020 .attach-row {
2021 display: flex;
2022 flex-direction: column;
2023 gap: 0.5em;
2024 padding: 0.75em;
2025 border: 1px dashed #ccc;
2026 border-radius: 4px;
2027 background-color: #fafafa;
2028 }
2029 .attach-dropzone {
2030 padding: 1em;
2031 text-align: center;
2032 background: #ffffff;
2033 border: 1px solid #ddd;
2034 cursor: pointer;
2035 border-radius: 2px;
2036 transition: background-color 0.15s ease-in-out;
2037 }
2038 .attach-dropzone.dragover {
2039 background-color: #e1f5fe;
2040 border-color: #03a9f4;
2041 }
2042 .attach-dropzone.row-populated {
2043 background-color: #f1f8e9;
2044 border-color: #8bc34a;
2045 border-style: solid;
2046 }
2047 .attach-row-info {
2048 font-family: monospace;
2049 font-size: 0.9em;
2050 color: #555;
2051 }
2052 .attach-desc-input {
2053 width: 100%;
2054 box-sizing: border-box;
2055 min-height: 4em;
2056 padding: 0.5em;
2057 font-family: inherit;
2058 font-size: 0.9em;
2059 resize: vertical;
2060 }
2061 .attach-row-remove {
2062 align-self: flex-end;
2063 padding: 0.25em 0.75em;
2064 background-color: #d32f2f;
2065 color: #fff;
2066 border: none;
2067 border-radius: 2px;
2068 cursor: pointer;
2069 }
2070 .attach-row-remove:hover {
2071 background-color: #b71c1c;
2072 }
2073 .attach-add-button {
2074 padding: 0.5em 1em;
2075 cursor: pointer;
2076 }
2077
2078 /* Objects in the "desktoponly" class are invisible on mobile */
2079 @media screen and (max-width: 600px) {
2080 .desktoponly {
2081 display: none;
2082
+2 -1
--- src/forum.c
+++ src/forum.c
@@ -1279,11 +1279,12 @@
12791279
&& forumpost_is_owner(p/*not pHead*/->fpid, 0)) ){
12801280
/* When an admin edits someone else's post, the admin
12811281
** effectively takes over ownership of it (and we currently
12821282
** have no way of passing it back). Because of this, we
12831283
** check the ownership of `p` instead of `pHead`. */
1284
- @ <form method="post" action="%R/attachadd">\
1284
+ @ <form method="post" action="%R/attachadd" \
1285
+ @ class='file-attach'>\
12851286
@ <input type="hidden" name="forumpost" value="%T(pHead->zUuid)">
12861287
@ <input type="submit" value="Attach...">
12871288
login_insert_csrf_secret();
12881289
moderation_pending_www(p->fpid);
12891290
@ </form>
12901291
--- src/forum.c
+++ src/forum.c
@@ -1279,11 +1279,12 @@
1279 && forumpost_is_owner(p/*not pHead*/->fpid, 0)) ){
1280 /* When an admin edits someone else's post, the admin
1281 ** effectively takes over ownership of it (and we currently
1282 ** have no way of passing it back). Because of this, we
1283 ** check the ownership of `p` instead of `pHead`. */
1284 @ <form method="post" action="%R/attachadd">\
 
1285 @ <input type="hidden" name="forumpost" value="%T(pHead->zUuid)">
1286 @ <input type="submit" value="Attach...">
1287 login_insert_csrf_secret();
1288 moderation_pending_www(p->fpid);
1289 @ </form>
1290
--- src/forum.c
+++ src/forum.c
@@ -1279,11 +1279,12 @@
1279 && forumpost_is_owner(p/*not pHead*/->fpid, 0)) ){
1280 /* When an admin edits someone else's post, the admin
1281 ** effectively takes over ownership of it (and we currently
1282 ** have no way of passing it back). Because of this, we
1283 ** check the ownership of `p` instead of `pHead`. */
1284 @ <form method="post" action="%R/attachadd" \
1285 @ class='file-attach'>\
1286 @ <input type="hidden" name="forumpost" value="%T(pHead->zUuid)">
1287 @ <input type="submit" value="Attach...">
1288 login_insert_csrf_secret();
1289 moderation_pending_www(p->fpid);
1290 @ </form>
1291
--- src/main.mk
+++ src/main.mk
@@ -225,10 +225,11 @@
225225
$(SRCDIR)/copybtn.js \
226226
$(SRCDIR)/default.css \
227227
$(SRCDIR)/diff.js \
228228
$(SRCDIR)/diff.tcl \
229229
$(SRCDIR)/forum.js \
230
+ $(SRCDIR)/fossil.attach.js \
230231
$(SRCDIR)/fossil.bootstrap.js \
231232
$(SRCDIR)/fossil.confirmer.js \
232233
$(SRCDIR)/fossil.copybutton.js \
233234
$(SRCDIR)/fossil.diff.js \
234235
$(SRCDIR)/fossil.dom.js \
235236
--- src/main.mk
+++ src/main.mk
@@ -225,10 +225,11 @@
225 $(SRCDIR)/copybtn.js \
226 $(SRCDIR)/default.css \
227 $(SRCDIR)/diff.js \
228 $(SRCDIR)/diff.tcl \
229 $(SRCDIR)/forum.js \
 
230 $(SRCDIR)/fossil.bootstrap.js \
231 $(SRCDIR)/fossil.confirmer.js \
232 $(SRCDIR)/fossil.copybutton.js \
233 $(SRCDIR)/fossil.diff.js \
234 $(SRCDIR)/fossil.dom.js \
235
--- src/main.mk
+++ src/main.mk
@@ -225,10 +225,11 @@
225 $(SRCDIR)/copybtn.js \
226 $(SRCDIR)/default.css \
227 $(SRCDIR)/diff.js \
228 $(SRCDIR)/diff.tcl \
229 $(SRCDIR)/forum.js \
230 $(SRCDIR)/fossil.attach.js \
231 $(SRCDIR)/fossil.bootstrap.js \
232 $(SRCDIR)/fossil.confirmer.js \
233 $(SRCDIR)/fossil.copybutton.js \
234 $(SRCDIR)/fossil.diff.js \
235 $(SRCDIR)/fossil.dom.js \
236
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -611,10 +611,11 @@
611611
$(SRCDIR)/copybtn.js \
612612
$(SRCDIR)/default.css \
613613
$(SRCDIR)/diff.js \
614614
$(SRCDIR)/diff.tcl \
615615
$(SRCDIR)/forum.js \
616
+ $(SRCDIR)/fossil.attach.js \
616617
$(SRCDIR)/fossil.bootstrap.js \
617618
$(SRCDIR)/fossil.confirmer.js \
618619
$(SRCDIR)/fossil.copybutton.js \
619620
$(SRCDIR)/fossil.diff.js \
620621
$(SRCDIR)/fossil.dom.js \
621622
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -611,10 +611,11 @@
611 $(SRCDIR)/copybtn.js \
612 $(SRCDIR)/default.css \
613 $(SRCDIR)/diff.js \
614 $(SRCDIR)/diff.tcl \
615 $(SRCDIR)/forum.js \
 
616 $(SRCDIR)/fossil.bootstrap.js \
617 $(SRCDIR)/fossil.confirmer.js \
618 $(SRCDIR)/fossil.copybutton.js \
619 $(SRCDIR)/fossil.diff.js \
620 $(SRCDIR)/fossil.dom.js \
621
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -611,10 +611,11 @@
611 $(SRCDIR)/copybtn.js \
612 $(SRCDIR)/default.css \
613 $(SRCDIR)/diff.js \
614 $(SRCDIR)/diff.tcl \
615 $(SRCDIR)/forum.js \
616 $(SRCDIR)/fossil.attach.js \
617 $(SRCDIR)/fossil.bootstrap.js \
618 $(SRCDIR)/fossil.confirmer.js \
619 $(SRCDIR)/fossil.copybutton.js \
620 $(SRCDIR)/fossil.diff.js \
621 $(SRCDIR)/fossil.dom.js \
622
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -576,10 +576,11 @@
576576
"$(SRCDIR)\copybtn.js" \
577577
"$(SRCDIR)\default.css" \
578578
"$(SRCDIR)\diff.js" \
579579
"$(SRCDIR)\diff.tcl" \
580580
"$(SRCDIR)\forum.js" \
581
+ "$(SRCDIR)\fossil.attach.js" \
581582
"$(SRCDIR)\fossil.bootstrap.js" \
582583
"$(SRCDIR)\fossil.confirmer.js" \
583584
"$(SRCDIR)\fossil.copybutton.js" \
584585
"$(SRCDIR)\fossil.diff.js" \
585586
"$(SRCDIR)\fossil.dom.js" \
@@ -1214,10 +1215,11 @@
12141215
echo "$(SRCDIR)\copybtn.js" >> $@
12151216
echo "$(SRCDIR)\default.css" >> $@
12161217
echo "$(SRCDIR)\diff.js" >> $@
12171218
echo "$(SRCDIR)\diff.tcl" >> $@
12181219
echo "$(SRCDIR)\forum.js" >> $@
1220
+ echo "$(SRCDIR)\fossil.attach.js" >> $@
12191221
echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
12201222
echo "$(SRCDIR)\fossil.confirmer.js" >> $@
12211223
echo "$(SRCDIR)\fossil.copybutton.js" >> $@
12221224
echo "$(SRCDIR)\fossil.diff.js" >> $@
12231225
echo "$(SRCDIR)\fossil.dom.js" >> $@
12241226
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -576,10 +576,11 @@
576 "$(SRCDIR)\copybtn.js" \
577 "$(SRCDIR)\default.css" \
578 "$(SRCDIR)\diff.js" \
579 "$(SRCDIR)\diff.tcl" \
580 "$(SRCDIR)\forum.js" \
 
581 "$(SRCDIR)\fossil.bootstrap.js" \
582 "$(SRCDIR)\fossil.confirmer.js" \
583 "$(SRCDIR)\fossil.copybutton.js" \
584 "$(SRCDIR)\fossil.diff.js" \
585 "$(SRCDIR)\fossil.dom.js" \
@@ -1214,10 +1215,11 @@
1214 echo "$(SRCDIR)\copybtn.js" >> $@
1215 echo "$(SRCDIR)\default.css" >> $@
1216 echo "$(SRCDIR)\diff.js" >> $@
1217 echo "$(SRCDIR)\diff.tcl" >> $@
1218 echo "$(SRCDIR)\forum.js" >> $@
 
1219 echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
1220 echo "$(SRCDIR)\fossil.confirmer.js" >> $@
1221 echo "$(SRCDIR)\fossil.copybutton.js" >> $@
1222 echo "$(SRCDIR)\fossil.diff.js" >> $@
1223 echo "$(SRCDIR)\fossil.dom.js" >> $@
1224
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -576,10 +576,11 @@
576 "$(SRCDIR)\copybtn.js" \
577 "$(SRCDIR)\default.css" \
578 "$(SRCDIR)\diff.js" \
579 "$(SRCDIR)\diff.tcl" \
580 "$(SRCDIR)\forum.js" \
581 "$(SRCDIR)\fossil.attach.js" \
582 "$(SRCDIR)\fossil.bootstrap.js" \
583 "$(SRCDIR)\fossil.confirmer.js" \
584 "$(SRCDIR)\fossil.copybutton.js" \
585 "$(SRCDIR)\fossil.diff.js" \
586 "$(SRCDIR)\fossil.dom.js" \
@@ -1214,10 +1215,11 @@
1215 echo "$(SRCDIR)\copybtn.js" >> $@
1216 echo "$(SRCDIR)\default.css" >> $@
1217 echo "$(SRCDIR)\diff.js" >> $@
1218 echo "$(SRCDIR)\diff.tcl" >> $@
1219 echo "$(SRCDIR)\forum.js" >> $@
1220 echo "$(SRCDIR)\fossil.attach.js" >> $@
1221 echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
1222 echo "$(SRCDIR)\fossil.confirmer.js" >> $@
1223 echo "$(SRCDIR)\fossil.copybutton.js" >> $@
1224 echo "$(SRCDIR)\fossil.diff.js" >> $@
1225 echo "$(SRCDIR)\fossil.dom.js" >> $@
1226

Keyboard Shortcuts

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