Fossil SCM
Fix display of attached filename when an attachment slot is re-selected. When pasting image data in the description field, attach that image (this is easier than first tapping the narrow border then ctrl-v).
Commit
69f1fe3ece563ff9d59146b3296ad1e123c5bda11c6ae2f4891b11b858b6704b
Parent
5e748a00bef4af8…
1 file changed
+42
-21
+42
-21
| --- src/fossil.attach.js | ||
| +++ src/fossil.attach.js | ||
| @@ -291,26 +291,43 @@ | ||
| 291 | 291 | ev.preventDefault(); |
| 292 | 292 | eDropzone.classList.remove('dragover'); |
| 293 | 293 | if( ev.dataTransfer.files.length ){ |
| 294 | 294 | this.#injestBlob(rowObj, ev.dataTransfer.files[0]); |
| 295 | 295 | } |
| 296 | + }); | |
| 297 | + const pasteImage = (event, item)=>{ | |
| 298 | + if( item.type.indexOf('image') === 0 ) { | |
| 299 | + event.preventDefault(); | |
| 300 | + const blob = item.getAsFile(); | |
| 301 | + this.#injestBlob(rowObj, blob); | |
| 302 | + return true; | |
| 303 | + } | |
| 304 | + return false; | |
| 305 | + }; | |
| 306 | + eDesc?.addEventListener?.('paste', (e) => { | |
| 307 | + e.stopPropagation(); | |
| 308 | + const items = (e.clipboardData || e.originalEvent.clipboardData)?.items; | |
| 309 | + if( !items ) return; | |
| 310 | + for( let i = 0; i < items.length; ++i ){ | |
| 311 | + const item = items[i]; | |
| 312 | + if( pasteImage(e, item) ){ | |
| 313 | + break; | |
| 314 | + } | |
| 315 | + } | |
| 296 | 316 | }); |
| 297 | 317 | eRow.addEventListener('paste', (e) => { |
| 298 | 318 | const items = (e.clipboardData || e.originalEvent.clipboardData)?.items; |
| 299 | 319 | if( !items ) return; |
| 300 | 320 | for( let i = 0; i < items.length; ++i ){ |
| 301 | 321 | const item = items[i]; |
| 302 | - if( item.type.indexOf('image') === 0 ) { | |
| 303 | - e.preventDefault(); | |
| 304 | - const blob = item.getAsFile(); | |
| 305 | - this.#injestBlob(rowObj, blob); | |
| 322 | + if( pasteImage(e, item) ){ | |
| 306 | 323 | break; |
| 307 | 324 | }else if( item.type === 'text/plain' ){ |
| 308 | 325 | e.preventDefault(); |
| 309 | 326 | item.getAsString((text) => { |
| 310 | - rowObj.name = `pasted-text-${Date.now()}.txt`; | |
| 311 | - const blob = new File([text], rowObj.name, | |
| 327 | + rowObj.overrideName = `pasted-text-${Date.now()}.txt`; | |
| 328 | + const blob = new File([text], rowObj.overrideName, | |
| 312 | 329 | {type: 'text/plain'}); |
| 313 | 330 | this.#injestBlob(rowObj, blob); |
| 314 | 331 | }); |
| 315 | 332 | break; |
| 316 | 333 | }else if(0){ |
| @@ -364,25 +381,12 @@ | ||
| 364 | 381 | if( file.name === 'image.png' ){ |
| 365 | 382 | /* Workaround to attempt to avoid name collisions when pasting |
| 366 | 383 | multiple images. We cannot, at this level, unambiguously |
| 367 | 384 | distinguish a ctrl-v of bitmap data vs a ctrl-v of an image |
| 368 | 385 | file copied via a desktop file manager. */ |
| 369 | - rowObj.name = `pasted-image-${Date.now()}.png`; | |
| 370 | - } | |
| 371 | - if( rowObj.name && rowObj.name!==file.name ){ | |
| 372 | - file = new File([file], rowObj.name, {type: file.type}); | |
| 373 | - } | |
| 374 | - | |
| 375 | - let szLbl; | |
| 376 | - if( file.size < 500000 ){ | |
| 377 | - szLbl = file.size + ' bytes'; | |
| 378 | - }else if( file.size < 1000000 ){ | |
| 379 | - szLbl = (file.size / 1024).toFixed(2)+' KB'; | |
| 380 | - }else{ | |
| 381 | - szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB'; | |
| 382 | - } | |
| 383 | - this.#rowError(rowObj); | |
| 386 | + rowObj.overrideName = `pasted-image-${Date.now()}.png`; | |
| 387 | + } | |
| 384 | 388 | const old = this.#rowMatchingName(file.name); |
| 385 | 389 | if( old && rowObj !== old ){ |
| 386 | 390 | /* |
| 387 | 391 | Fossil attachments treat the name as a unique-per-target |
| 388 | 392 | key, with the newest one being the primary. If a name is |
| @@ -395,11 +399,28 @@ | ||
| 395 | 399 | */ |
| 396 | 400 | /* recycle `old` instead to avoid UI flicker. */ |
| 397 | 401 | this.#rowError(old); |
| 398 | 402 | this.#removeRow(rowObj); |
| 399 | 403 | rowObj.e = old.e; |
| 404 | + //if( rowObj.e.eDesc ) rowObj.e.eDesc.value = ''; | |
| 405 | + } | |
| 406 | + console.warn("rowObj, old",rowObj, old); | |
| 407 | + if( rowObj.overrideName ){ | |
| 408 | + console.warn("Renaming file to",rowObj.overrideName); | |
| 409 | + file = new File([file], rowObj.overrideName, {type: file.type}); | |
| 410 | + rowObj.overrideName = undefined; | |
| 411 | + } | |
| 412 | + | |
| 413 | + let szLbl; | |
| 414 | + if( file.size < 500000 ){ | |
| 415 | + szLbl = file.size + ' bytes'; | |
| 416 | + }else if( file.size < 1000000 ){ | |
| 417 | + szLbl = (file.size / 1024).toFixed(2)+' KB'; | |
| 418 | + }else{ | |
| 419 | + szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB'; | |
| 400 | 420 | } |
| 421 | + this.#rowError(rowObj); | |
| 401 | 422 | rowObj.file = file; |
| 402 | 423 | rowObj.mimeType = file.type || 'application/octet-stream'; |
| 403 | 424 | D.clearElement(rowObj.e.filename).append(file.name || 'Pasted Content'); |
| 404 | 425 | D.clearElement(rowObj.e.size).append(szLbl, ' ', rowObj.mimeType || ''); |
| 405 | 426 | rowObj.e.dropzone.classList.add('populated'); |
| 406 | 427 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -291,26 +291,43 @@ | |
| 291 | ev.preventDefault(); |
| 292 | eDropzone.classList.remove('dragover'); |
| 293 | if( ev.dataTransfer.files.length ){ |
| 294 | this.#injestBlob(rowObj, ev.dataTransfer.files[0]); |
| 295 | } |
| 296 | }); |
| 297 | eRow.addEventListener('paste', (e) => { |
| 298 | const items = (e.clipboardData || e.originalEvent.clipboardData)?.items; |
| 299 | if( !items ) return; |
| 300 | for( let i = 0; i < items.length; ++i ){ |
| 301 | const item = items[i]; |
| 302 | if( item.type.indexOf('image') === 0 ) { |
| 303 | e.preventDefault(); |
| 304 | const blob = item.getAsFile(); |
| 305 | this.#injestBlob(rowObj, blob); |
| 306 | break; |
| 307 | }else if( item.type === 'text/plain' ){ |
| 308 | e.preventDefault(); |
| 309 | item.getAsString((text) => { |
| 310 | rowObj.name = `pasted-text-${Date.now()}.txt`; |
| 311 | const blob = new File([text], rowObj.name, |
| 312 | {type: 'text/plain'}); |
| 313 | this.#injestBlob(rowObj, blob); |
| 314 | }); |
| 315 | break; |
| 316 | }else if(0){ |
| @@ -364,25 +381,12 @@ | |
| 364 | if( file.name === 'image.png' ){ |
| 365 | /* Workaround to attempt to avoid name collisions when pasting |
| 366 | multiple images. We cannot, at this level, unambiguously |
| 367 | distinguish a ctrl-v of bitmap data vs a ctrl-v of an image |
| 368 | file copied via a desktop file manager. */ |
| 369 | rowObj.name = `pasted-image-${Date.now()}.png`; |
| 370 | } |
| 371 | if( rowObj.name && rowObj.name!==file.name ){ |
| 372 | file = new File([file], rowObj.name, {type: file.type}); |
| 373 | } |
| 374 | |
| 375 | let szLbl; |
| 376 | if( file.size < 500000 ){ |
| 377 | szLbl = file.size + ' bytes'; |
| 378 | }else if( file.size < 1000000 ){ |
| 379 | szLbl = (file.size / 1024).toFixed(2)+' KB'; |
| 380 | }else{ |
| 381 | szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB'; |
| 382 | } |
| 383 | this.#rowError(rowObj); |
| 384 | const old = this.#rowMatchingName(file.name); |
| 385 | if( old && rowObj !== old ){ |
| 386 | /* |
| 387 | Fossil attachments treat the name as a unique-per-target |
| 388 | key, with the newest one being the primary. If a name is |
| @@ -395,11 +399,28 @@ | |
| 395 | */ |
| 396 | /* recycle `old` instead to avoid UI flicker. */ |
| 397 | this.#rowError(old); |
| 398 | this.#removeRow(rowObj); |
| 399 | rowObj.e = old.e; |
| 400 | } |
| 401 | rowObj.file = file; |
| 402 | rowObj.mimeType = file.type || 'application/octet-stream'; |
| 403 | D.clearElement(rowObj.e.filename).append(file.name || 'Pasted Content'); |
| 404 | D.clearElement(rowObj.e.size).append(szLbl, ' ', rowObj.mimeType || ''); |
| 405 | rowObj.e.dropzone.classList.add('populated'); |
| 406 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -291,26 +291,43 @@ | |
| 291 | ev.preventDefault(); |
| 292 | eDropzone.classList.remove('dragover'); |
| 293 | if( ev.dataTransfer.files.length ){ |
| 294 | this.#injestBlob(rowObj, ev.dataTransfer.files[0]); |
| 295 | } |
| 296 | }); |
| 297 | const pasteImage = (event, item)=>{ |
| 298 | if( item.type.indexOf('image') === 0 ) { |
| 299 | event.preventDefault(); |
| 300 | const blob = item.getAsFile(); |
| 301 | this.#injestBlob(rowObj, blob); |
| 302 | return true; |
| 303 | } |
| 304 | return false; |
| 305 | }; |
| 306 | eDesc?.addEventListener?.('paste', (e) => { |
| 307 | e.stopPropagation(); |
| 308 | const items = (e.clipboardData || e.originalEvent.clipboardData)?.items; |
| 309 | if( !items ) return; |
| 310 | for( let i = 0; i < items.length; ++i ){ |
| 311 | const item = items[i]; |
| 312 | if( pasteImage(e, item) ){ |
| 313 | break; |
| 314 | } |
| 315 | } |
| 316 | }); |
| 317 | eRow.addEventListener('paste', (e) => { |
| 318 | const items = (e.clipboardData || e.originalEvent.clipboardData)?.items; |
| 319 | if( !items ) return; |
| 320 | for( let i = 0; i < items.length; ++i ){ |
| 321 | const item = items[i]; |
| 322 | if( pasteImage(e, item) ){ |
| 323 | break; |
| 324 | }else if( item.type === 'text/plain' ){ |
| 325 | e.preventDefault(); |
| 326 | item.getAsString((text) => { |
| 327 | rowObj.overrideName = `pasted-text-${Date.now()}.txt`; |
| 328 | const blob = new File([text], rowObj.overrideName, |
| 329 | {type: 'text/plain'}); |
| 330 | this.#injestBlob(rowObj, blob); |
| 331 | }); |
| 332 | break; |
| 333 | }else if(0){ |
| @@ -364,25 +381,12 @@ | |
| 381 | if( file.name === 'image.png' ){ |
| 382 | /* Workaround to attempt to avoid name collisions when pasting |
| 383 | multiple images. We cannot, at this level, unambiguously |
| 384 | distinguish a ctrl-v of bitmap data vs a ctrl-v of an image |
| 385 | file copied via a desktop file manager. */ |
| 386 | rowObj.overrideName = `pasted-image-${Date.now()}.png`; |
| 387 | } |
| 388 | const old = this.#rowMatchingName(file.name); |
| 389 | if( old && rowObj !== old ){ |
| 390 | /* |
| 391 | Fossil attachments treat the name as a unique-per-target |
| 392 | key, with the newest one being the primary. If a name is |
| @@ -395,11 +399,28 @@ | |
| 399 | */ |
| 400 | /* recycle `old` instead to avoid UI flicker. */ |
| 401 | this.#rowError(old); |
| 402 | this.#removeRow(rowObj); |
| 403 | rowObj.e = old.e; |
| 404 | //if( rowObj.e.eDesc ) rowObj.e.eDesc.value = ''; |
| 405 | } |
| 406 | console.warn("rowObj, old",rowObj, old); |
| 407 | if( rowObj.overrideName ){ |
| 408 | console.warn("Renaming file to",rowObj.overrideName); |
| 409 | file = new File([file], rowObj.overrideName, {type: file.type}); |
| 410 | rowObj.overrideName = undefined; |
| 411 | } |
| 412 | |
| 413 | let szLbl; |
| 414 | if( file.size < 500000 ){ |
| 415 | szLbl = file.size + ' bytes'; |
| 416 | }else if( file.size < 1000000 ){ |
| 417 | szLbl = (file.size / 1024).toFixed(2)+' KB'; |
| 418 | }else{ |
| 419 | szLbl = (file.size / (1024 * 1024)).toFixed(2)+' MB'; |
| 420 | } |
| 421 | this.#rowError(rowObj); |
| 422 | rowObj.file = file; |
| 423 | rowObj.mimeType = file.type || 'application/octet-stream'; |
| 424 | D.clearElement(rowObj.e.filename).append(file.name || 'Pasted Content'); |
| 425 | D.clearElement(rowObj.e.size).append(szLbl, ' ', rowObj.mimeType || ''); |
| 426 | rowObj.e.dropzone.classList.add('populated'); |
| 427 |