Fossil SCM

Simplify CSS selectors. Improve handling of attaching a given filename twice.

stephan 2026-06-03 08:05 UTC attach-v2
Commit 13d99044c886640311e048d9ff8d501142b33dfdfba31df7b1def597f2b7f378
2 files changed +37 -34 +38 -33
+37 -34
--- src/default.css
+++ src/default.css
@@ -2009,29 +2009,29 @@
20092009
div.helpPage blockquote {
20102010
margin-left: 0.2em;
20112011
}
20122012
20132013
/* .attach* = styles for file attachments */
2014
-.attach-container {
2014
+.attach-widget {
20152015
margin-bottom: 1em;
20162016
display: flex;
20172017
flex-direction: column;
20182018
gap: 0.75em;
20192019
}
2020
-.attach-container > .attach-row {
2020
+.attach-widget .attach-row {
20212021
display: flex;
20222022
flex-direction: column;
20232023
gap: 0.5em;
20242024
padding: 0.75em;
20252025
border: 1px dashed #ccc;
20262026
border-radius: 0.25em;
20272027
background-color: #fafafa;
20282028
}
2029
-body.fossil-dark-style .attach-container > .attach-row {
2029
+body.fossil-dark-style .attach-widget .attach-row {
20302030
background-color: initial;
20312031
}
2032
-.attach-container > .attach-row > .attach-dropzone {
2032
+.attach-widget .attach-dropzone {
20332033
padding: 1em;
20342034
text-align: center;
20352035
background: #ffffff;
20362036
border: 1px solid #ddd;
20372037
cursor: pointer;
@@ -2039,70 +2039,73 @@
20392039
transition: background-color 0.15s ease-in-out;
20402040
display: flex;
20412041
flex-direction: row;
20422042
flex-wrap: nowrap;
20432043
}
2044
-body.fossil-dark-style .attach-container > .attach-row > .attach-dropzone{
2044
+body.fossil-dark-style .attach-widget .attach-dropzone{
20452045
background: initial;
20462046
}
2047
-.attach-container > .attach-row > .attach-dropzone.populated {
2047
+.attach-widget .attach-dropzone.populated {
20482048
background-color: #f1f8e9;
20492049
border-color: #8bc34a;
20502050
border-style: solid;
20512051
text-align: left;
20522052
}
2053
-body.fossil-dark-style .attach-container > .attach-row > .attach-dropzone.populated{
2054
- background-color: initial;
2055
- border-color: #8bc34a;
2056
-}
2057
-.attach-container > .attach-row > .attach-dropzone.dragover {
2058
- background-color: #e1f5fe;
2059
- border-color: #03a9f4;
2060
-}
2061
-body.fossil-dark-style .attach-container > .attach-row > .attach-dropzone.dragover{
2062
- border-color: #03a9f4;
2063
-}
2064
-body.fossil-dark-style > .attach-row > .attach-dropzone.dragover{
2065
- background-color: #e1f5fe;
2066
- border-color: #03a9f4;
2067
-}
2068
-.attach-container > .attach-row > .attach-dropzone > .thumbnail {
2069
- max-width: 10em;
2070
- max-height: 10em;
2071
-}
2072
-.attach-container > .attach-row .attach-row-info {
2073
- font-family: monospace;
2074
- flex-grow: 1;
2075
-}
2076
-.attach-container > .attach-row .attach-desc {
2053
+body.fossil-dark-style .attach-widget .attach-dropzone.populated{
2054
+ background-color: initial;
2055
+}
2056
+.attach-widget .attach-dropzone.dragover {
2057
+ background-color: #e1f5fe;
2058
+ border-color: #03a9f4;
2059
+}
2060
+body.fossil-dark-style .attach-widget .attach-dropzone.dragover{
2061
+ border-color: #03a9f4;
2062
+}
2063
+body.fossil-dark-style .attach-widget .attach-dropzone.dragover{
2064
+ background-color: #e1f5fe;
2065
+ border-color: #03a9f4;
2066
+}
2067
+.attach-widget .thumbnail {
2068
+ max-width: 10em;
2069
+ max-height: 10em;
2070
+}
2071
+.attach-widget .attach-row-info{
2072
+ font-family: monospace;
2073
+ flex-grow: 1;
2074
+ display: flex;
2075
+ flex-direction: column;
2076
+}
2077
+.attach-widget .attach-filename {}
2078
+.attach-widget .attach-size {/*size and mimetype*/}
2079
+.attach-widget .attach-desc {
20772080
max-width: initial;
20782081
width: 100%;
20792082
box-sizing: border-box;
20802083
min-height: 4em;
20812084
padding: 0.5em;
20822085
font-family: inherit;
20832086
resize: vertical;
20842087
}
2085
-.attach-container > .attach-row .attach-row-remove {
2088
+.attach-widget .attach-row-remove {
20862089
align-self: center;
20872090
padding: 0.25em 0.75em;
20882091
margin-left: 1em;
20892092
background-color: #d32f2f;
20902093
color: #fff;
20912094
border: none;
20922095
border-radius: 0.25em;
20932096
cursor: pointer;
20942097
}
2095
-.attach-container > .attach-row .attach-row-remove:hover {
2098
+.attach-widget .attach-row-remove:hover {
20962099
background-color: #b71c1c;
20972100
}
2098
-.attach-container > .attach-controls {
2101
+.attach-widget .attach-controls {
20992102
display: flex;
21002103
flex-direction: row;
21012104
gap: 1em;
21022105
}
2103
-.attach-container > .attach-controls .attach-add-button {
2106
+.attach-widget .attach-controls .attach-add-button {
21042107
padding: 0.5em 1em;
21052108
cursor: pointer;
21062109
flex-grow: 2;
21072110
}
21082111
21092112
--- src/default.css
+++ src/default.css
@@ -2009,29 +2009,29 @@
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-container > .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: 0.25em;
2027 background-color: #fafafa;
2028 }
2029 body.fossil-dark-style .attach-container > .attach-row {
2030 background-color: initial;
2031 }
2032 .attach-container > .attach-row > .attach-dropzone {
2033 padding: 1em;
2034 text-align: center;
2035 background: #ffffff;
2036 border: 1px solid #ddd;
2037 cursor: pointer;
@@ -2039,70 +2039,73 @@
2039 transition: background-color 0.15s ease-in-out;
2040 display: flex;
2041 flex-direction: row;
2042 flex-wrap: nowrap;
2043 }
2044 body.fossil-dark-style .attach-container > .attach-row > .attach-dropzone{
2045 background: initial;
2046 }
2047 .attach-container > .attach-row > .attach-dropzone.populated {
2048 background-color: #f1f8e9;
2049 border-color: #8bc34a;
2050 border-style: solid;
2051 text-align: left;
2052 }
2053 body.fossil-dark-style .attach-container > .attach-row > .attach-dropzone.populated{
2054 background-color: initial;
2055 border-color: #8bc34a;
2056 }
2057 .attach-container > .attach-row > .attach-dropzone.dragover {
2058 background-color: #e1f5fe;
2059 border-color: #03a9f4;
2060 }
2061 body.fossil-dark-style .attach-container > .attach-row > .attach-dropzone.dragover{
2062 border-color: #03a9f4;
2063 }
2064 body.fossil-dark-style > .attach-row > .attach-dropzone.dragover{
2065 background-color: #e1f5fe;
2066 border-color: #03a9f4;
2067 }
2068 .attach-container > .attach-row > .attach-dropzone > .thumbnail {
2069 max-width: 10em;
2070 max-height: 10em;
2071 }
2072 .attach-container > .attach-row .attach-row-info {
2073 font-family: monospace;
2074 flex-grow: 1;
2075 }
2076 .attach-container > .attach-row .attach-desc {
 
 
 
2077 max-width: initial;
2078 width: 100%;
2079 box-sizing: border-box;
2080 min-height: 4em;
2081 padding: 0.5em;
2082 font-family: inherit;
2083 resize: vertical;
2084 }
2085 .attach-container > .attach-row .attach-row-remove {
2086 align-self: center;
2087 padding: 0.25em 0.75em;
2088 margin-left: 1em;
2089 background-color: #d32f2f;
2090 color: #fff;
2091 border: none;
2092 border-radius: 0.25em;
2093 cursor: pointer;
2094 }
2095 .attach-container > .attach-row .attach-row-remove:hover {
2096 background-color: #b71c1c;
2097 }
2098 .attach-container > .attach-controls {
2099 display: flex;
2100 flex-direction: row;
2101 gap: 1em;
2102 }
2103 .attach-container > .attach-controls .attach-add-button {
2104 padding: 0.5em 1em;
2105 cursor: pointer;
2106 flex-grow: 2;
2107 }
2108
2109
--- src/default.css
+++ src/default.css
@@ -2009,29 +2009,29 @@
2009 div.helpPage blockquote {
2010 margin-left: 0.2em;
2011 }
2012
2013 /* .attach* = styles for file attachments */
2014 .attach-widget {
2015 margin-bottom: 1em;
2016 display: flex;
2017 flex-direction: column;
2018 gap: 0.75em;
2019 }
2020 .attach-widget .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: 0.25em;
2027 background-color: #fafafa;
2028 }
2029 body.fossil-dark-style .attach-widget .attach-row {
2030 background-color: initial;
2031 }
2032 .attach-widget .attach-dropzone {
2033 padding: 1em;
2034 text-align: center;
2035 background: #ffffff;
2036 border: 1px solid #ddd;
2037 cursor: pointer;
@@ -2039,70 +2039,73 @@
2039 transition: background-color 0.15s ease-in-out;
2040 display: flex;
2041 flex-direction: row;
2042 flex-wrap: nowrap;
2043 }
2044 body.fossil-dark-style .attach-widget .attach-dropzone{
2045 background: initial;
2046 }
2047 .attach-widget .attach-dropzone.populated {
2048 background-color: #f1f8e9;
2049 border-color: #8bc34a;
2050 border-style: solid;
2051 text-align: left;
2052 }
2053 body.fossil-dark-style .attach-widget .attach-dropzone.populated{
2054 background-color: initial;
2055 }
2056 .attach-widget .attach-dropzone.dragover {
2057 background-color: #e1f5fe;
2058 border-color: #03a9f4;
2059 }
2060 body.fossil-dark-style .attach-widget .attach-dropzone.dragover{
2061 border-color: #03a9f4;
2062 }
2063 body.fossil-dark-style .attach-widget .attach-dropzone.dragover{
2064 background-color: #e1f5fe;
2065 border-color: #03a9f4;
2066 }
2067 .attach-widget .thumbnail {
2068 max-width: 10em;
2069 max-height: 10em;
2070 }
2071 .attach-widget .attach-row-info{
2072 font-family: monospace;
2073 flex-grow: 1;
2074 display: flex;
2075 flex-direction: column;
2076 }
2077 .attach-widget .attach-filename {}
2078 .attach-widget .attach-size {/*size and mimetype*/}
2079 .attach-widget .attach-desc {
2080 max-width: initial;
2081 width: 100%;
2082 box-sizing: border-box;
2083 min-height: 4em;
2084 padding: 0.5em;
2085 font-family: inherit;
2086 resize: vertical;
2087 }
2088 .attach-widget .attach-row-remove {
2089 align-self: center;
2090 padding: 0.25em 0.75em;
2091 margin-left: 1em;
2092 background-color: #d32f2f;
2093 color: #fff;
2094 border: none;
2095 border-radius: 0.25em;
2096 cursor: pointer;
2097 }
2098 .attach-widget .attach-row-remove:hover {
2099 background-color: #b71c1c;
2100 }
2101 .attach-widget .attach-controls {
2102 display: flex;
2103 flex-direction: row;
2104 gap: 1em;
2105 }
2106 .attach-widget .attach-controls .attach-add-button {
2107 padding: 0.5em 1em;
2108 cursor: pointer;
2109 flex-grow: 2;
2110 }
2111
2112
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -78,11 +78,11 @@
7878
);
7979
eBtnAdd.type = 'button';
8080
const eControls = this.#e.controls =
8181
D.addClass(D.div(), 'attach-controls');
8282
eControls.append(eBtnAdd);
83
- this.#e.list = D.addClass(D.div(), 'attach-container');
83
+ this.#e.list = D.addClass(D.div(), 'attach-widget');
8484
opt.container.appendChild(this.#e.list);
8585
this.#e.list.appendChild(eControls);
8686
if( opt.listener ){
8787
const doCb = (eventType, cb)=>{
8888
const f = cb || opt.listener.all;
@@ -130,11 +130,11 @@
130130
get controlsElement(){
131131
return this.#e.controls;
132132
}
133133
134134
#removeRow(rowObj){
135
- rowObj.eRow.remove();
135
+ rowObj.e.row.remove();
136136
this.#rows = this.#rows.filter(v=>v!==rowObj);
137137
this.#updateControls();
138138
this.#events.dispatchEvent(
139139
new CustomEvent('entry-removed',{
140140
detail: F.nu({
@@ -176,16 +176,18 @@
176176
eRow.dataset.id = id;
177177
const eDropzone = D.addClass(D.div(), 'attach-dropzone');
178178
const eFile = D.addClass(
179179
D.input('file'), 'attach-file-input', 'hidden'
180180
);
181
- const eInfo = D.append(
182
- D.addClass(D.span(), 'attach-row-info'),
181
+ const eInfo = D.addClass(D.span(), 'attach-row-info');
182
+ const eFilename = D.append(
183
+ D.addClass(D.span(), 'attach-filename'),
183184
"Select/drop file or click the outer border and tap your "+
184185
"platform's conventional Paste keyboard shortcut."
185186
);
186
-
187
+ const eSize = D.addClass(D.span(), 'attach-size');
188
+ eInfo.append(eFilename, eSize);
187189
const eDesc = D.addClass(
188190
D.attr(D.textarea(), 'placeholder',
189191
'Optional description...'),
190192
'hidden', 'attach-desc'
191193
);
@@ -246,15 +248,19 @@
246248
break;
247249
}
248250
}
249251
});
250252
D.append(eRow, eDropzone, eDesc);
251
- rowObj.eDropzone = eDropzone;
252
- rowObj.eInfo = eInfo;
253
- rowObj.eDesc = eDesc;
254
- rowObj.eRow = eRow;
255
- rowObj.eRemove = eRemove;
253
+ rowObj.e = F.nu({
254
+ dropzone: eDropzone,
255
+ info: eInfo,
256
+ filename: eFilename,
257
+ size: eSize,
258
+ desc: eDesc,
259
+ row: eRow,
260
+ remove: eRemove
261
+ });
256262
this.#e.list.append(eRow);
257263
this.#rows.push( rowObj );
258264
this.#updateControls();
259265
this.#events.dispatchEvent(
260266
new CustomEvent('entry-added',{
@@ -290,47 +296,46 @@
290296
rowObj.name = `pasted-image-${Date.now()}.png`;
291297
}
292298
if( rowObj.name && rowObj.name!==file.name ){
293299
file = new File([file], rowObj.name, {type: file.type});
294300
}
295
- /*
296
- Fossil attachments treat the name as a unique-per-target key,
297
- with the newest one being the primary. If a name is given
298
- twice, replace the prior entry before adding the new
299
- one. There are conceivable, but also unlikely, cases where
300
- this will have unintended side-effects, but that seems like a
301
- lesser evil than attaching the same file N times, leading to N
302
- attachment artifacts.
303
- */
304
- rowObj.file = file;
305
- rowObj.mimeType = file.type || 'application/octet-stream';
306
-
307
- const lbl = file.name || 'Pasted Content';
301
+
308302
let szLbl;
309303
if( file.size < 500000 ){
310304
szLbl = file.size + ' bytes';
311305
}else if( file.size < 1000000 ){
312306
szLbl = (file.size / 1024).toFixed(2)+' KB';
313307
}else{
314308
szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB';
315309
}
316
- D.append(
317
- D.clearElement(rowObj.eInfo),
318
- lbl, D.br(), szLbl, ' ', rowObj.mimeType || ''
319
- );
320310
const old = this.#rowMatchingName(file.name);
321311
if( old && rowObj !== old){
322
- /* FIXME: recycle `old` instead to avoid UI flicker. */
323
- this.#removeRow(old);
312
+ /*
313
+ Fossil attachments treat the name as a unique-per-target
314
+ key, with the newest one being the primary. If a name is
315
+ given twice, remove the new entry and reuse the older
316
+ one. There are conceivable, but also unlikely, cases where
317
+ this will have unintended side-effects, e.g. attaching both
318
+ /foo/bar and /baz/bar, but that seems like a lesser evil
319
+ than attaching the same file N times, leading to N
320
+ attachment artifacts.
321
+ */
322
+ /* recycle `old` instead to avoid UI flicker. */
323
+ this.#removeRow(rowObj);
324
+ rowObj.e = old.e;
324325
}
325
- rowObj.eDropzone.classList.add('populated');
326
- rowObj.eDesc.classList.remove('hidden');
326
+ rowObj.file = file;
327
+ rowObj.mimeType = file.type || 'application/octet-stream';
328
+ D.clearElement(rowObj.e.filename).append(file.name || 'Pasted Content');
329
+ D.clearElement(rowObj.e.size).append(szLbl, ' ', rowObj.mimeType || '');
330
+ rowObj.e.dropzone.classList.add('populated');
331
+ rowObj.e.desc.classList.remove('hidden');
327332
if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){
328333
/* Add a thumbnail */
329
- const img = rowObj.eDropzone.querySelector('img.thumbnail') || D.img();
334
+ const img = rowObj.e.dropzone.querySelector('img.thumbnail') || D.img();
330335
img.classList.add('thumbnail');
331
- rowObj.eDropzone.insertBefore(img, rowObj.eRemove);
336
+ rowObj.e.dropzone.insertBefore(img, rowObj.e.remove);
332337
const reader = new FileReader();
333338
reader.onload = (e)=>img.setAttribute('src', e.target.result);
334339
reader.readAsDataURL(file);
335340
}
336341
this.#events.dispatchEvent(
337342
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -78,11 +78,11 @@
78 );
79 eBtnAdd.type = 'button';
80 const eControls = this.#e.controls =
81 D.addClass(D.div(), 'attach-controls');
82 eControls.append(eBtnAdd);
83 this.#e.list = D.addClass(D.div(), 'attach-container');
84 opt.container.appendChild(this.#e.list);
85 this.#e.list.appendChild(eControls);
86 if( opt.listener ){
87 const doCb = (eventType, cb)=>{
88 const f = cb || opt.listener.all;
@@ -130,11 +130,11 @@
130 get controlsElement(){
131 return this.#e.controls;
132 }
133
134 #removeRow(rowObj){
135 rowObj.eRow.remove();
136 this.#rows = this.#rows.filter(v=>v!==rowObj);
137 this.#updateControls();
138 this.#events.dispatchEvent(
139 new CustomEvent('entry-removed',{
140 detail: F.nu({
@@ -176,16 +176,18 @@
176 eRow.dataset.id = id;
177 const eDropzone = D.addClass(D.div(), 'attach-dropzone');
178 const eFile = D.addClass(
179 D.input('file'), 'attach-file-input', 'hidden'
180 );
181 const eInfo = D.append(
182 D.addClass(D.span(), 'attach-row-info'),
 
183 "Select/drop file or click the outer border and tap your "+
184 "platform's conventional Paste keyboard shortcut."
185 );
186
 
187 const eDesc = D.addClass(
188 D.attr(D.textarea(), 'placeholder',
189 'Optional description...'),
190 'hidden', 'attach-desc'
191 );
@@ -246,15 +248,19 @@
246 break;
247 }
248 }
249 });
250 D.append(eRow, eDropzone, eDesc);
251 rowObj.eDropzone = eDropzone;
252 rowObj.eInfo = eInfo;
253 rowObj.eDesc = eDesc;
254 rowObj.eRow = eRow;
255 rowObj.eRemove = eRemove;
 
 
 
 
256 this.#e.list.append(eRow);
257 this.#rows.push( rowObj );
258 this.#updateControls();
259 this.#events.dispatchEvent(
260 new CustomEvent('entry-added',{
@@ -290,47 +296,46 @@
290 rowObj.name = `pasted-image-${Date.now()}.png`;
291 }
292 if( rowObj.name && rowObj.name!==file.name ){
293 file = new File([file], rowObj.name, {type: file.type});
294 }
295 /*
296 Fossil attachments treat the name as a unique-per-target key,
297 with the newest one being the primary. If a name is given
298 twice, replace the prior entry before adding the new
299 one. There are conceivable, but also unlikely, cases where
300 this will have unintended side-effects, but that seems like a
301 lesser evil than attaching the same file N times, leading to N
302 attachment artifacts.
303 */
304 rowObj.file = file;
305 rowObj.mimeType = file.type || 'application/octet-stream';
306
307 const lbl = file.name || 'Pasted Content';
308 let szLbl;
309 if( file.size < 500000 ){
310 szLbl = file.size + ' bytes';
311 }else if( file.size < 1000000 ){
312 szLbl = (file.size / 1024).toFixed(2)+' KB';
313 }else{
314 szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB';
315 }
316 D.append(
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 }
336 this.#events.dispatchEvent(
337
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -78,11 +78,11 @@
78 );
79 eBtnAdd.type = 'button';
80 const eControls = this.#e.controls =
81 D.addClass(D.div(), 'attach-controls');
82 eControls.append(eBtnAdd);
83 this.#e.list = D.addClass(D.div(), 'attach-widget');
84 opt.container.appendChild(this.#e.list);
85 this.#e.list.appendChild(eControls);
86 if( opt.listener ){
87 const doCb = (eventType, cb)=>{
88 const f = cb || opt.listener.all;
@@ -130,11 +130,11 @@
130 get controlsElement(){
131 return this.#e.controls;
132 }
133
134 #removeRow(rowObj){
135 rowObj.e.row.remove();
136 this.#rows = this.#rows.filter(v=>v!==rowObj);
137 this.#updateControls();
138 this.#events.dispatchEvent(
139 new CustomEvent('entry-removed',{
140 detail: F.nu({
@@ -176,16 +176,18 @@
176 eRow.dataset.id = id;
177 const eDropzone = D.addClass(D.div(), 'attach-dropzone');
178 const eFile = D.addClass(
179 D.input('file'), 'attach-file-input', 'hidden'
180 );
181 const eInfo = D.addClass(D.span(), 'attach-row-info');
182 const eFilename = D.append(
183 D.addClass(D.span(), 'attach-filename'),
184 "Select/drop file or click the outer border and tap your "+
185 "platform's conventional Paste keyboard shortcut."
186 );
187 const eSize = D.addClass(D.span(), 'attach-size');
188 eInfo.append(eFilename, eSize);
189 const eDesc = D.addClass(
190 D.attr(D.textarea(), 'placeholder',
191 'Optional description...'),
192 'hidden', 'attach-desc'
193 );
@@ -246,15 +248,19 @@
248 break;
249 }
250 }
251 });
252 D.append(eRow, eDropzone, eDesc);
253 rowObj.e = F.nu({
254 dropzone: eDropzone,
255 info: eInfo,
256 filename: eFilename,
257 size: eSize,
258 desc: eDesc,
259 row: eRow,
260 remove: eRemove
261 });
262 this.#e.list.append(eRow);
263 this.#rows.push( rowObj );
264 this.#updateControls();
265 this.#events.dispatchEvent(
266 new CustomEvent('entry-added',{
@@ -290,47 +296,46 @@
296 rowObj.name = `pasted-image-${Date.now()}.png`;
297 }
298 if( rowObj.name && rowObj.name!==file.name ){
299 file = new File([file], rowObj.name, {type: file.type});
300 }
301
 
 
 
 
 
 
 
 
 
 
 
 
302 let szLbl;
303 if( file.size < 500000 ){
304 szLbl = file.size + ' bytes';
305 }else if( file.size < 1000000 ){
306 szLbl = (file.size / 1024).toFixed(2)+' KB';
307 }else{
308 szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB';
309 }
 
 
 
 
310 const old = this.#rowMatchingName(file.name);
311 if( old && rowObj !== old){
312 /*
313 Fossil attachments treat the name as a unique-per-target
314 key, with the newest one being the primary. If a name is
315 given twice, remove the new entry and reuse the older
316 one. There are conceivable, but also unlikely, cases where
317 this will have unintended side-effects, e.g. attaching both
318 /foo/bar and /baz/bar, but that seems like a lesser evil
319 than attaching the same file N times, leading to N
320 attachment artifacts.
321 */
322 /* recycle `old` instead to avoid UI flicker. */
323 this.#removeRow(rowObj);
324 rowObj.e = old.e;
325 }
326 rowObj.file = file;
327 rowObj.mimeType = file.type || 'application/octet-stream';
328 D.clearElement(rowObj.e.filename).append(file.name || 'Pasted Content');
329 D.clearElement(rowObj.e.size).append(szLbl, ' ', rowObj.mimeType || '');
330 rowObj.e.dropzone.classList.add('populated');
331 rowObj.e.desc.classList.remove('hidden');
332 if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){
333 /* Add a thumbnail */
334 const img = rowObj.e.dropzone.querySelector('img.thumbnail') || D.img();
335 img.classList.add('thumbnail');
336 rowObj.e.dropzone.insertBefore(img, rowObj.e.remove);
337 const reader = new FileReader();
338 reader.onload = (e)=>img.setAttribute('src', e.target.result);
339 reader.readAsDataURL(file);
340 }
341 this.#events.dispatchEvent(
342

Keyboard Shortcuts

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