Fossil SCM
Add image attachment thumbnails to the attachment widget.
Commit
81389347e5337459ac712f1f25c339037123534cddb046fb5aeb007db643c85c
Parent
c3c649c92cf7889…
2 files changed
+4
+42
-20
+4
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -2045,10 +2045,14 @@ | ||
| 2045 | 2045 | .attach-container > .attach-row > .attach-dropzone.populated { |
| 2046 | 2046 | background-color: #f1f8e9; |
| 2047 | 2047 | border-color: #8bc34a; |
| 2048 | 2048 | border-style: solid; |
| 2049 | 2049 | text-align: left; |
| 2050 | +} | |
| 2051 | +.attach-container > .attach-row > .attach-dropzone > .thumbnail { | |
| 2052 | + max-width: 10em; | |
| 2053 | + max-height: 10em; | |
| 2050 | 2054 | } |
| 2051 | 2055 | .attach-container > .attach-row .attach-row-info { |
| 2052 | 2056 | font-family: monospace; |
| 2053 | 2057 | flex-grow: 1; |
| 2054 | 2058 | } |
| 2055 | 2059 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -2045,10 +2045,14 @@ | |
| 2045 | .attach-container > .attach-row > .attach-dropzone.populated { |
| 2046 | background-color: #f1f8e9; |
| 2047 | border-color: #8bc34a; |
| 2048 | border-style: solid; |
| 2049 | text-align: left; |
| 2050 | } |
| 2051 | .attach-container > .attach-row .attach-row-info { |
| 2052 | font-family: monospace; |
| 2053 | flex-grow: 1; |
| 2054 | } |
| 2055 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -2045,10 +2045,14 @@ | |
| 2045 | .attach-container > .attach-row > .attach-dropzone.populated { |
| 2046 | background-color: #f1f8e9; |
| 2047 | border-color: #8bc34a; |
| 2048 | border-style: solid; |
| 2049 | text-align: left; |
| 2050 | } |
| 2051 | .attach-container > .attach-row > .attach-dropzone > .thumbnail { |
| 2052 | max-width: 10em; |
| 2053 | max-height: 10em; |
| 2054 | } |
| 2055 | .attach-container > .attach-row .attach-row-info { |
| 2056 | font-family: monospace; |
| 2057 | flex-grow: 1; |
| 2058 | } |
| 2059 |
+42
-20
| --- src/fossil.attach.js | ||
| +++ src/fossil.attach.js | ||
| @@ -34,36 +34,44 @@ | ||
| 34 | 34 | opt.limit: optional max number of attachments to allow. This |
| 35 | 35 | defaults to "some sensible value". |
| 36 | 36 | |
| 37 | 37 | opt.startWith[=0]: if >0 then that many file selection widgets |
| 38 | 38 | are automatically activated, as if the user had tapped the Add |
| 39 | - button that many times. | |
| 39 | + button that many times. As a special case, if this is >0 | |
| 40 | + and the user removes the last entry, a new one is added. | |
| 41 | + | |
| 42 | + opt.controls = [array of DOM elements]. Optional DOM elements | |
| 43 | + to inject into the UI element which wraps the "Add" button. | |
| 44 | + See this.controlsElement. | |
| 40 | 45 | |
| 41 | 46 | opt.listener = {add: func, remove: func, populate: func}: if |
| 42 | 47 | these are functions they are registered as listeners for |
| 43 | 48 | 'entry-added', 'entry-removed', and/or 'entry-populated' |
| 44 | - events, described below. | |
| 49 | + events, described below. opt.listener.all, if set, is used | |
| 50 | + as a fallback for any of 'add', 'remove', or 'populate' | |
| 51 | + which are not set. | |
| 45 | 52 | |
| 46 | 53 | Events: |
| 47 | 54 | |
| 48 | 55 | This class fires CustomEvents for certain changes: |
| 49 | 56 | |
| 50 | 57 | 'entry-added' and 'entry-removed' trigger when an attachment |
| 51 | 58 | entry row is added/removed. Its event.detail is {attacher: |
| 52 | - this, row: object}. | |
| 59 | + this, row: object, type: 'same as event type'}. | |
| 53 | 60 | |
| 54 | 61 | 'entry-populated' is triggered when a visible entry gets |
| 55 | - content attached to it. | |
| 62 | + content attached to it, with the same detail structure as | |
| 63 | + described above. | |
| 56 | 64 | |
| 57 | 65 | The public structure of the row object passed to each is |
| 58 | 66 | currently TBD. |
| 59 | 67 | */ |
| 60 | 68 | constructor(opt){ |
| 61 | 69 | this.#opt = opt = F.nu({ |
| 62 | 70 | addButtonLabel: false, |
| 63 | 71 | startWith: 0, |
| 64 | - limit: 7 | |
| 72 | + limit: 0 | |
| 65 | 73 | }, opt); |
| 66 | 74 | const eBtnAdd = this.#e.btnAdd = D.addClass( |
| 67 | 75 | D.button(this.#opt.addButtonLabel || 'Add attachment', |
| 68 | 76 | ()=>this.#addRow()), |
| 69 | 77 | 'attach-add-button' |
| @@ -74,20 +82,23 @@ | ||
| 74 | 82 | eControls.append(eBtnAdd); |
| 75 | 83 | this.#e.list = D.addClass(D.div(), 'attach-container'); |
| 76 | 84 | opt.container.appendChild(this.#e.list); |
| 77 | 85 | this.#e.list.appendChild(eControls); |
| 78 | 86 | if( opt.listener ){ |
| 79 | - if( opt.listener.add instanceof Function ){ | |
| 87 | + if( (opt.listener.add || opt.listener.all) instanceof Function ){ | |
| 80 | 88 | this.addEventListener('entry-added', opt.listener.add); |
| 81 | 89 | } |
| 82 | - if( opt.listener.remove instanceof Function ){ | |
| 90 | + if( (opt.listener.remove || opt.listener.all) instanceof Function ){ | |
| 83 | 91 | this.addEventListener('entry-removed', opt.listener.remove); |
| 84 | 92 | } |
| 85 | - if( opt.listener.populate instanceof Function ){ | |
| 93 | + if( (opt.listener.populate || opt.listener.all) instanceof Function ){ | |
| 86 | 94 | this.addEventListener('entry-populated', opt.listener.populate); |
| 87 | 95 | } |
| 88 | 96 | } |
| 97 | + if( Array.isArray(opt.controls) ){ | |
| 98 | + eControls.append(...opt.controls); | |
| 99 | + } | |
| 89 | 100 | if( opt.startWith > 0 ){ |
| 90 | 101 | for(let i = 0; i < opt.startWith; ++i ){ |
| 91 | 102 | this.#addRow(); |
| 92 | 103 | } |
| 93 | 104 | }else{ |
| @@ -101,17 +112,23 @@ | ||
| 101 | 112 | |
| 102 | 113 | removeEventListener(...args){ |
| 103 | 114 | return this.#events.removeEventListener(...args); |
| 104 | 115 | } |
| 105 | 116 | |
| 117 | + /** Returns true if any visible input widgets have content | |
| 118 | + selected. */ | |
| 106 | 119 | get isPopulated(){ |
| 107 | 120 | for(let r of this.#rows){ |
| 108 | 121 | if( r.file ) return true; |
| 109 | 122 | } |
| 110 | 123 | return false; |
| 111 | 124 | } |
| 112 | 125 | |
| 126 | + /** | |
| 127 | + Returns the DOM element (div.attach-controls) which wraps the | |
| 128 | + "Add" button. Clients may add buttons to it. | |
| 129 | + */ | |
| 113 | 130 | get controlsElement(){ |
| 114 | 131 | return this.#e.controls; |
| 115 | 132 | } |
| 116 | 133 | |
| 117 | 134 | #removeRow(rowObj){ |
| @@ -119,17 +136,18 @@ | ||
| 119 | 136 | this.#rows = this.#rows.filter(v=>v!==rowObj); |
| 120 | 137 | this.#updateControls(); |
| 121 | 138 | this.#events.dispatchEvent( |
| 122 | 139 | new CustomEvent('entry-removed',{ |
| 123 | 140 | detail: F.nu({ |
| 141 | + type: 'entry-removed', | |
| 124 | 142 | row: rowObj, |
| 125 | 143 | attacher: this |
| 126 | 144 | }) |
| 127 | 145 | }) |
| 128 | 146 | ); |
| 129 | 147 | if( 0===this.#rows.length |
| 130 | - && 1===this.#opt.startWith ){ | |
| 148 | + && this.#opt.startWith>0 ){ | |
| 131 | 149 | /* Intended primarily for /addattach. */ |
| 132 | 150 | this.#addRow(); |
| 133 | 151 | } |
| 134 | 152 | } |
| 135 | 153 | |
| @@ -226,16 +244,18 @@ | ||
| 226 | 244 | D.append(eRow, eDropzone, eDesc); |
| 227 | 245 | rowObj.eDropzone = eDropzone; |
| 228 | 246 | rowObj.eInfo = eInfo; |
| 229 | 247 | rowObj.eDesc = eDesc; |
| 230 | 248 | rowObj.eRow = eRow; |
| 249 | + rowObj.eRemove = eRemove; | |
| 231 | 250 | this.#e.list.append(eRow); |
| 232 | 251 | this.#rows.push( rowObj ); |
| 233 | 252 | this.#updateControls(); |
| 234 | 253 | this.#events.dispatchEvent( |
| 235 | 254 | new CustomEvent('entry-added',{ |
| 236 | 255 | detail: F.nu({ |
| 256 | + type: 'entry-added', | |
| 237 | 257 | row: rowObj, |
| 238 | 258 | attacher: this |
| 239 | 259 | }) |
| 240 | 260 | }) |
| 241 | 261 | ); |
| @@ -293,13 +313,22 @@ | ||
| 293 | 313 | D.clearElement(rowObj.eInfo), |
| 294 | 314 | lbl, D.br(), szLbl, ' ', rowObj.mimeType || '' |
| 295 | 315 | ); |
| 296 | 316 | rowObj.eDropzone.classList.add('populated'); |
| 297 | 317 | rowObj.eDesc.classList.remove('hidden'); |
| 318 | + if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){ | |
| 319 | + const img = D.img(); | |
| 320 | + img.classList.add('thumbnail'); | |
| 321 | + rowObj.eDropzone.insertBefore(img, rowObj.eRemove); | |
| 322 | + const reader = new FileReader(); | |
| 323 | + reader.onload = (e)=>img.setAttribute('src', e.target.result); | |
| 324 | + reader.readAsDataURL(file); | |
| 325 | + } | |
| 298 | 326 | this.#events.dispatchEvent( |
| 299 | 327 | new CustomEvent('entry-populated',{ |
| 300 | 328 | detail: F.nu({ |
| 329 | + type: 'entry-populated', | |
| 301 | 330 | row: rowObj, |
| 302 | 331 | attacher: this |
| 303 | 332 | }) |
| 304 | 333 | }) |
| 305 | 334 | ); |
| @@ -360,29 +389,22 @@ | ||
| 360 | 389 | eBtnSubmit.removeAttribute('disabled'); |
| 361 | 390 | }else{ |
| 362 | 391 | eBtnSubmit.setAttribute('disabled', ''); |
| 363 | 392 | } |
| 364 | 393 | }; |
| 365 | - const cbAdd = (ev)=>{ | |
| 366 | - const a = ev.detail.attacher; | |
| 367 | - updateBtnSubmit(a); | |
| 368 | - }; | |
| 369 | - const cbRm = (ev)=>{ | |
| 370 | - const a = ev.detail.attacher; | |
| 371 | - updateBtnSubmit(a); | |
| 372 | - }; | |
| 373 | - const cbPopulated = (ev)=>{ | |
| 394 | + const cbAttacherChange = (ev)=>{ | |
| 374 | 395 | const a = ev.detail.attacher; |
| 375 | 396 | updateBtnSubmit(a); |
| 376 | 397 | }; |
| 377 | 398 | const cbSubmit = (ev)=>{ |
| 378 | 399 | }; |
| 379 | 400 | eBtnSubmit.addEventListener('click', cbSubmit, false); |
| 380 | 401 | const att = new Attacher({ |
| 381 | 402 | container: eFormDiv, |
| 382 | 403 | startWith: 1, |
| 383 | - listener: {add: cbAdd, remove: cbRm, populate: cbPopulated} | |
| 404 | + listener: F.nu({all: cbAttacherChange}), | |
| 405 | + controls: [eBtnSubmit] | |
| 384 | 406 | }); |
| 385 | - att.controlsElement.append(eBtnSubmit); | |
| 407 | + updateBtnSubmit(att); | |
| 386 | 408 | }/* /attachaddV2 */ |
| 387 | 409 | |
| 388 | 410 | })(window.fossil); |
| 389 | 411 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -34,36 +34,44 @@ | |
| 34 | opt.limit: optional max number of attachments to allow. This |
| 35 | defaults to "some sensible value". |
| 36 | |
| 37 | opt.startWith[=0]: if >0 then that many file selection widgets |
| 38 | are automatically activated, as if the user had tapped the Add |
| 39 | button that many times. |
| 40 | |
| 41 | opt.listener = {add: func, remove: func, populate: func}: if |
| 42 | these are functions they are registered as listeners for |
| 43 | 'entry-added', 'entry-removed', and/or 'entry-populated' |
| 44 | events, described below. |
| 45 | |
| 46 | Events: |
| 47 | |
| 48 | This class fires CustomEvents for certain changes: |
| 49 | |
| 50 | 'entry-added' and 'entry-removed' trigger when an attachment |
| 51 | entry row is added/removed. Its event.detail is {attacher: |
| 52 | this, row: object}. |
| 53 | |
| 54 | 'entry-populated' is triggered when a visible entry gets |
| 55 | content attached to it. |
| 56 | |
| 57 | The public structure of the row object passed to each is |
| 58 | currently TBD. |
| 59 | */ |
| 60 | constructor(opt){ |
| 61 | this.#opt = opt = F.nu({ |
| 62 | addButtonLabel: false, |
| 63 | startWith: 0, |
| 64 | limit: 7 |
| 65 | }, opt); |
| 66 | const eBtnAdd = this.#e.btnAdd = D.addClass( |
| 67 | D.button(this.#opt.addButtonLabel || 'Add attachment', |
| 68 | ()=>this.#addRow()), |
| 69 | 'attach-add-button' |
| @@ -74,20 +82,23 @@ | |
| 74 | eControls.append(eBtnAdd); |
| 75 | this.#e.list = D.addClass(D.div(), 'attach-container'); |
| 76 | opt.container.appendChild(this.#e.list); |
| 77 | this.#e.list.appendChild(eControls); |
| 78 | if( opt.listener ){ |
| 79 | if( opt.listener.add instanceof Function ){ |
| 80 | this.addEventListener('entry-added', opt.listener.add); |
| 81 | } |
| 82 | if( opt.listener.remove instanceof Function ){ |
| 83 | this.addEventListener('entry-removed', opt.listener.remove); |
| 84 | } |
| 85 | if( opt.listener.populate instanceof Function ){ |
| 86 | this.addEventListener('entry-populated', opt.listener.populate); |
| 87 | } |
| 88 | } |
| 89 | if( opt.startWith > 0 ){ |
| 90 | for(let i = 0; i < opt.startWith; ++i ){ |
| 91 | this.#addRow(); |
| 92 | } |
| 93 | }else{ |
| @@ -101,17 +112,23 @@ | |
| 101 | |
| 102 | removeEventListener(...args){ |
| 103 | return this.#events.removeEventListener(...args); |
| 104 | } |
| 105 | |
| 106 | get isPopulated(){ |
| 107 | for(let r of this.#rows){ |
| 108 | if( r.file ) return true; |
| 109 | } |
| 110 | return false; |
| 111 | } |
| 112 | |
| 113 | get controlsElement(){ |
| 114 | return this.#e.controls; |
| 115 | } |
| 116 | |
| 117 | #removeRow(rowObj){ |
| @@ -119,17 +136,18 @@ | |
| 119 | this.#rows = this.#rows.filter(v=>v!==rowObj); |
| 120 | this.#updateControls(); |
| 121 | this.#events.dispatchEvent( |
| 122 | new CustomEvent('entry-removed',{ |
| 123 | detail: F.nu({ |
| 124 | row: rowObj, |
| 125 | attacher: this |
| 126 | }) |
| 127 | }) |
| 128 | ); |
| 129 | if( 0===this.#rows.length |
| 130 | && 1===this.#opt.startWith ){ |
| 131 | /* Intended primarily for /addattach. */ |
| 132 | this.#addRow(); |
| 133 | } |
| 134 | } |
| 135 | |
| @@ -226,16 +244,18 @@ | |
| 226 | D.append(eRow, eDropzone, eDesc); |
| 227 | rowObj.eDropzone = eDropzone; |
| 228 | rowObj.eInfo = eInfo; |
| 229 | rowObj.eDesc = eDesc; |
| 230 | rowObj.eRow = eRow; |
| 231 | this.#e.list.append(eRow); |
| 232 | this.#rows.push( rowObj ); |
| 233 | this.#updateControls(); |
| 234 | this.#events.dispatchEvent( |
| 235 | new CustomEvent('entry-added',{ |
| 236 | detail: F.nu({ |
| 237 | row: rowObj, |
| 238 | attacher: this |
| 239 | }) |
| 240 | }) |
| 241 | ); |
| @@ -293,13 +313,22 @@ | |
| 293 | D.clearElement(rowObj.eInfo), |
| 294 | lbl, D.br(), szLbl, ' ', rowObj.mimeType || '' |
| 295 | ); |
| 296 | rowObj.eDropzone.classList.add('populated'); |
| 297 | rowObj.eDesc.classList.remove('hidden'); |
| 298 | this.#events.dispatchEvent( |
| 299 | new CustomEvent('entry-populated',{ |
| 300 | detail: F.nu({ |
| 301 | row: rowObj, |
| 302 | attacher: this |
| 303 | }) |
| 304 | }) |
| 305 | ); |
| @@ -360,29 +389,22 @@ | |
| 360 | eBtnSubmit.removeAttribute('disabled'); |
| 361 | }else{ |
| 362 | eBtnSubmit.setAttribute('disabled', ''); |
| 363 | } |
| 364 | }; |
| 365 | const cbAdd = (ev)=>{ |
| 366 | const a = ev.detail.attacher; |
| 367 | updateBtnSubmit(a); |
| 368 | }; |
| 369 | const cbRm = (ev)=>{ |
| 370 | const a = ev.detail.attacher; |
| 371 | updateBtnSubmit(a); |
| 372 | }; |
| 373 | const cbPopulated = (ev)=>{ |
| 374 | const a = ev.detail.attacher; |
| 375 | updateBtnSubmit(a); |
| 376 | }; |
| 377 | const cbSubmit = (ev)=>{ |
| 378 | }; |
| 379 | eBtnSubmit.addEventListener('click', cbSubmit, false); |
| 380 | const att = new Attacher({ |
| 381 | container: eFormDiv, |
| 382 | startWith: 1, |
| 383 | listener: {add: cbAdd, remove: cbRm, populate: cbPopulated} |
| 384 | }); |
| 385 | att.controlsElement.append(eBtnSubmit); |
| 386 | }/* /attachaddV2 */ |
| 387 | |
| 388 | })(window.fossil); |
| 389 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -34,36 +34,44 @@ | |
| 34 | opt.limit: optional max number of attachments to allow. This |
| 35 | defaults to "some sensible value". |
| 36 | |
| 37 | opt.startWith[=0]: if >0 then that many file selection widgets |
| 38 | are automatically activated, as if the user had tapped the Add |
| 39 | button that many times. As a special case, if this is >0 |
| 40 | and the user removes the last entry, a new one is added. |
| 41 | |
| 42 | opt.controls = [array of DOM elements]. Optional DOM elements |
| 43 | to inject into the UI element which wraps the "Add" button. |
| 44 | See this.controlsElement. |
| 45 | |
| 46 | opt.listener = {add: func, remove: func, populate: func}: if |
| 47 | these are functions they are registered as listeners for |
| 48 | 'entry-added', 'entry-removed', and/or 'entry-populated' |
| 49 | events, described below. opt.listener.all, if set, is used |
| 50 | as a fallback for any of 'add', 'remove', or 'populate' |
| 51 | which are not set. |
| 52 | |
| 53 | Events: |
| 54 | |
| 55 | This class fires CustomEvents for certain changes: |
| 56 | |
| 57 | 'entry-added' and 'entry-removed' trigger when an attachment |
| 58 | entry row is added/removed. Its event.detail is {attacher: |
| 59 | this, row: object, type: 'same as event type'}. |
| 60 | |
| 61 | 'entry-populated' is triggered when a visible entry gets |
| 62 | content attached to it, with the same detail structure as |
| 63 | described above. |
| 64 | |
| 65 | The public structure of the row object passed to each is |
| 66 | currently TBD. |
| 67 | */ |
| 68 | constructor(opt){ |
| 69 | this.#opt = opt = F.nu({ |
| 70 | addButtonLabel: false, |
| 71 | startWith: 0, |
| 72 | limit: 0 |
| 73 | }, opt); |
| 74 | const eBtnAdd = this.#e.btnAdd = D.addClass( |
| 75 | D.button(this.#opt.addButtonLabel || 'Add attachment', |
| 76 | ()=>this.#addRow()), |
| 77 | 'attach-add-button' |
| @@ -74,20 +82,23 @@ | |
| 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 | if( (opt.listener.add || opt.listener.all) instanceof Function ){ |
| 88 | this.addEventListener('entry-added', opt.listener.add); |
| 89 | } |
| 90 | if( (opt.listener.remove || opt.listener.all) instanceof Function ){ |
| 91 | this.addEventListener('entry-removed', opt.listener.remove); |
| 92 | } |
| 93 | if( (opt.listener.populate || opt.listener.all) instanceof Function ){ |
| 94 | this.addEventListener('entry-populated', opt.listener.populate); |
| 95 | } |
| 96 | } |
| 97 | if( Array.isArray(opt.controls) ){ |
| 98 | eControls.append(...opt.controls); |
| 99 | } |
| 100 | if( opt.startWith > 0 ){ |
| 101 | for(let i = 0; i < opt.startWith; ++i ){ |
| 102 | this.#addRow(); |
| 103 | } |
| 104 | }else{ |
| @@ -101,17 +112,23 @@ | |
| 112 | |
| 113 | removeEventListener(...args){ |
| 114 | return this.#events.removeEventListener(...args); |
| 115 | } |
| 116 | |
| 117 | /** Returns true if any visible input widgets have content |
| 118 | selected. */ |
| 119 | get isPopulated(){ |
| 120 | for(let r of this.#rows){ |
| 121 | if( r.file ) return true; |
| 122 | } |
| 123 | return false; |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | Returns the DOM element (div.attach-controls) which wraps the |
| 128 | "Add" button. Clients may add buttons to it. |
| 129 | */ |
| 130 | get controlsElement(){ |
| 131 | return this.#e.controls; |
| 132 | } |
| 133 | |
| 134 | #removeRow(rowObj){ |
| @@ -119,17 +136,18 @@ | |
| 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({ |
| 141 | type: 'entry-removed', |
| 142 | row: rowObj, |
| 143 | attacher: this |
| 144 | }) |
| 145 | }) |
| 146 | ); |
| 147 | if( 0===this.#rows.length |
| 148 | && this.#opt.startWith>0 ){ |
| 149 | /* Intended primarily for /addattach. */ |
| 150 | this.#addRow(); |
| 151 | } |
| 152 | } |
| 153 | |
| @@ -226,16 +244,18 @@ | |
| 244 | D.append(eRow, eDropzone, eDesc); |
| 245 | rowObj.eDropzone = eDropzone; |
| 246 | rowObj.eInfo = eInfo; |
| 247 | rowObj.eDesc = eDesc; |
| 248 | rowObj.eRow = eRow; |
| 249 | rowObj.eRemove = eRemove; |
| 250 | this.#e.list.append(eRow); |
| 251 | this.#rows.push( rowObj ); |
| 252 | this.#updateControls(); |
| 253 | this.#events.dispatchEvent( |
| 254 | new CustomEvent('entry-added',{ |
| 255 | detail: F.nu({ |
| 256 | type: 'entry-added', |
| 257 | row: rowObj, |
| 258 | attacher: this |
| 259 | }) |
| 260 | }) |
| 261 | ); |
| @@ -293,13 +313,22 @@ | |
| 313 | D.clearElement(rowObj.eInfo), |
| 314 | lbl, D.br(), szLbl, ' ', rowObj.mimeType || '' |
| 315 | ); |
| 316 | rowObj.eDropzone.classList.add('populated'); |
| 317 | rowObj.eDesc.classList.remove('hidden'); |
| 318 | if( file.type?.startsWith?.('image/') || file.type==='BITMAP' ){ |
| 319 | const img = D.img(); |
| 320 | img.classList.add('thumbnail'); |
| 321 | rowObj.eDropzone.insertBefore(img, rowObj.eRemove); |
| 322 | const reader = new FileReader(); |
| 323 | reader.onload = (e)=>img.setAttribute('src', e.target.result); |
| 324 | reader.readAsDataURL(file); |
| 325 | } |
| 326 | this.#events.dispatchEvent( |
| 327 | new CustomEvent('entry-populated',{ |
| 328 | detail: F.nu({ |
| 329 | type: 'entry-populated', |
| 330 | row: rowObj, |
| 331 | attacher: this |
| 332 | }) |
| 333 | }) |
| 334 | ); |
| @@ -360,29 +389,22 @@ | |
| 389 | eBtnSubmit.removeAttribute('disabled'); |
| 390 | }else{ |
| 391 | eBtnSubmit.setAttribute('disabled', ''); |
| 392 | } |
| 393 | }; |
| 394 | const cbAttacherChange = (ev)=>{ |
| 395 | const a = ev.detail.attacher; |
| 396 | updateBtnSubmit(a); |
| 397 | }; |
| 398 | const cbSubmit = (ev)=>{ |
| 399 | }; |
| 400 | eBtnSubmit.addEventListener('click', cbSubmit, false); |
| 401 | const att = new Attacher({ |
| 402 | container: eFormDiv, |
| 403 | startWith: 1, |
| 404 | listener: F.nu({all: cbAttacherChange}), |
| 405 | controls: [eBtnSubmit] |
| 406 | }); |
| 407 | updateBtnSubmit(att); |
| 408 | }/* /attachaddV2 */ |
| 409 | |
| 410 | })(window.fossil); |
| 411 |