Fossil SCM
Wrap setup of the attachment-related controls into an onPageLoad() handler. Minor doc additions.
Commit
feb95e6798275f93a063059903118c1acbbb2a9f05ac8f21d454a02712aa0252
Parent
f87586ee73b31e2…
2 files changed
+83
-81
+8
-3
+83
-81
| --- src/fossil.attach.js | ||
| +++ src/fossil.attach.js | ||
| @@ -504,88 +504,90 @@ | ||
| 504 | 504 | return i; |
| 505 | 505 | } |
| 506 | 506 | }/*Attacher*/; |
| 507 | 507 | F.Attacher = Attacher; |
| 508 | 508 | |
| 509 | - const eAttachWrapper = document.querySelector('#attachadd-form-wrapper'); | |
| 510 | - if( eAttachWrapper ){ | |
| 511 | - /* This page is /attachadd v2 or a workalike. eAttachWrapper holds | |
| 512 | - input[type=hidden] fields for use in attaching files and is | |
| 513 | - where we inject a file attachment widget. */ | |
| 514 | - eAttachWrapper.classList.remove('hidden'); | |
| 515 | - const urlArgs = new URLSearchParams(window.location.search); | |
| 516 | - let zTarget = urlArgs.get('target'); | |
| 517 | - let zTo = urlArgs.get('to') || urlArgs.get('from'); | |
| 518 | - const eBtnSubmit = D.button("Submit"); | |
| 519 | - eBtnSubmit.type = 'button'; | |
| 520 | - const updateBtnSubmit = (attacher)=>{ | |
| 521 | - if( attacher.isPopulated ){ | |
| 522 | - eBtnSubmit.removeAttribute('disabled'); | |
| 523 | - }else{ | |
| 524 | - eBtnSubmit.setAttribute('disabled', ''); | |
| 525 | - } | |
| 526 | - }; | |
| 527 | - const cbAttacherChange = (ev)=>{ | |
| 528 | - const a = ev.detail.attacher; | |
| 529 | - updateBtnSubmit(a); | |
| 530 | - }; | |
| 531 | - const att = new Attacher({ | |
| 532 | - container: eAttachWrapper, | |
| 533 | - startWith: 1, | |
| 534 | - listener: cbAttacherChange, | |
| 535 | - controls: [eBtnSubmit], | |
| 536 | - description: true | |
| 537 | - }); | |
| 538 | - eBtnSubmit.addEventListener('click', async (ev)=>{ | |
| 539 | - att.reportError(); | |
| 540 | - const li = att.collectState(); | |
| 541 | - if( !li.length ) return; | |
| 542 | - if( eBtnSubmit.dataset.submitted ) return; | |
| 543 | - eBtnSubmit.dataset.submitted = 1; | |
| 544 | - D.disable(eBtnSubmit); | |
| 545 | - const fd = new FormData(); | |
| 546 | - att.populateFormData(fd); | |
| 547 | - for( const eIn of eAttachWrapper.querySelectorAll( | |
| 548 | - 'input[type="hidden"]' | |
| 549 | - ) ){ | |
| 550 | - /* Copy over hidden input fields emitted by the server. */ | |
| 551 | - if( eIn.name==='target' ){ | |
| 552 | - zTarget = eIn.value; | |
| 553 | - }else if( eIn.name==='to' || (eIn.name==='from' && !zTo) ){ | |
| 554 | - zTo = eIn.value; | |
| 555 | - } | |
| 556 | - fd.append(eIn.name, eIn.value) | |
| 557 | - } | |
| 558 | - if( att.isDryRun ){ | |
| 559 | - fd.append('dryrun', '1'); | |
| 560 | - } | |
| 561 | - let err; | |
| 562 | - const resp = await window.fetch(F.repoUrl('attachadd_ajax_post'), { | |
| 563 | - method: 'POST', | |
| 564 | - body: fd | |
| 565 | - }).catch((e)=>{ | |
| 566 | - err = e; | |
| 567 | - }); | |
| 568 | - D.enable(eBtnSubmit); | |
| 569 | - delete eBtnSubmit.dataset.submitted; | |
| 570 | - const jr = err ? undefined : await resp.json().catch(()=>{}); | |
| 571 | - if( err || jr?.error || !resp.ok ){ | |
| 572 | - const msg = err ? err.message : (jr?.error || resp.statusText); | |
| 573 | - att.reportError("Attaching failed: ", msg); | |
| 574 | - }else{ | |
| 575 | - att.clear(); | |
| 576 | - let to = zTo || jr?.redirect; | |
| 577 | - if( to ){ | |
| 578 | - if( '/'!==to[0] ){ | |
| 579 | - to = F.repoUrl(to); | |
| 580 | - } | |
| 581 | - window.location = to; | |
| 582 | - }else if( zTarget ){ | |
| 583 | - window.location = '?target='+zTarget+'&'+Date.now(); | |
| 584 | - } | |
| 585 | - } | |
| 586 | - })/*submit handler*/; | |
| 587 | - updateBtnSubmit(att); | |
| 588 | - F.page.attacher = att /* only for testing via dev console */; | |
| 589 | - }/* /attachadd */ | |
| 509 | + F.onPageLoad(function(){ | |
| 510 | + const eAttachWrapper = document.querySelector('#attachadd-form-wrapper'); | |
| 511 | + if( eAttachWrapper ){ | |
| 512 | + /* This page is /attachadd v2 or a workalike. eAttachWrapper holds | |
| 513 | + input[type=hidden] fields for use in attaching files and is | |
| 514 | + where we inject a file attachment widget. */ | |
| 515 | + eAttachWrapper.classList.remove('hidden'); | |
| 516 | + const urlArgs = new URLSearchParams(window.location.search); | |
| 517 | + let zTarget = urlArgs.get('target'); | |
| 518 | + let zTo = urlArgs.get('to') || urlArgs.get('from'); | |
| 519 | + const eBtnSubmit = D.button("Submit"); | |
| 520 | + eBtnSubmit.type = 'button'; | |
| 521 | + const updateBtnSubmit = (attacher)=>{ | |
| 522 | + if( attacher.isPopulated ){ | |
| 523 | + eBtnSubmit.removeAttribute('disabled'); | |
| 524 | + }else{ | |
| 525 | + eBtnSubmit.setAttribute('disabled', ''); | |
| 526 | + } | |
| 527 | + }; | |
| 528 | + const cbAttacherChange = (ev)=>{ | |
| 529 | + const a = ev.detail.attacher; | |
| 530 | + updateBtnSubmit(a); | |
| 531 | + }; | |
| 532 | + const att = new Attacher({ | |
| 533 | + container: eAttachWrapper, | |
| 534 | + startWith: 1, | |
| 535 | + listener: cbAttacherChange, | |
| 536 | + controls: [eBtnSubmit], | |
| 537 | + description: true | |
| 538 | + }); | |
| 539 | + eBtnSubmit.addEventListener('click', async (ev)=>{ | |
| 540 | + att.reportError(); | |
| 541 | + const li = att.collectState(); | |
| 542 | + if( !li.length ) return; | |
| 543 | + if( eBtnSubmit.dataset.submitted ) return; | |
| 544 | + eBtnSubmit.dataset.submitted = 1; | |
| 545 | + D.disable(eBtnSubmit); | |
| 546 | + const fd = new FormData(); | |
| 547 | + att.populateFormData(fd); | |
| 548 | + for( const eIn of eAttachWrapper.querySelectorAll( | |
| 549 | + 'input[type="hidden"]' | |
| 550 | + ) ){ | |
| 551 | + /* Copy over hidden input fields emitted by the server. */ | |
| 552 | + if( eIn.name==='target' ){ | |
| 553 | + zTarget = eIn.value; | |
| 554 | + }else if( eIn.name==='to' || (eIn.name==='from' && !zTo) ){ | |
| 555 | + zTo = eIn.value; | |
| 556 | + } | |
| 557 | + fd.append(eIn.name, eIn.value) | |
| 558 | + } | |
| 559 | + if( att.isDryRun ){ | |
| 560 | + fd.append('dryrun', '1'); | |
| 561 | + } | |
| 562 | + let err; | |
| 563 | + const resp = await window.fetch(F.repoUrl('attachadd_ajax_post'), { | |
| 564 | + method: 'POST', | |
| 565 | + body: fd | |
| 566 | + }).catch((e)=>{ | |
| 567 | + err = e; | |
| 568 | + }); | |
| 569 | + D.enable(eBtnSubmit); | |
| 570 | + delete eBtnSubmit.dataset.submitted; | |
| 571 | + const jr = err ? undefined : await resp.json().catch(()=>{}); | |
| 572 | + if( err || jr?.error || !resp.ok ){ | |
| 573 | + const msg = err ? err.message : (jr?.error || resp.statusText); | |
| 574 | + att.reportError("Attaching failed: ", msg); | |
| 575 | + }else{ | |
| 576 | + att.clear(); | |
| 577 | + let to = zTo || jr?.redirect; | |
| 578 | + if( to ){ | |
| 579 | + if( '/'!==to[0] ){ | |
| 580 | + to = F.repoUrl(to); | |
| 581 | + } | |
| 582 | + window.location = to; | |
| 583 | + }else if( zTarget ){ | |
| 584 | + window.location = '?target='+zTarget+'&'+Date.now(); | |
| 585 | + } | |
| 586 | + } | |
| 587 | + })/*submit handler*/; | |
| 588 | + updateBtnSubmit(att); | |
| 589 | + F.page.attacher = att /* only for testing via dev console */; | |
| 590 | + }/* /attachadd */ | |
| 591 | + })/*onPageLoad()*/; | |
| 590 | 592 | |
| 591 | 593 | })(window.fossil); |
| 592 | 594 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -504,88 +504,90 @@ | |
| 504 | return i; |
| 505 | } |
| 506 | }/*Attacher*/; |
| 507 | F.Attacher = Attacher; |
| 508 | |
| 509 | const eAttachWrapper = document.querySelector('#attachadd-form-wrapper'); |
| 510 | if( eAttachWrapper ){ |
| 511 | /* This page is /attachadd v2 or a workalike. eAttachWrapper holds |
| 512 | input[type=hidden] fields for use in attaching files and is |
| 513 | where we inject a file attachment widget. */ |
| 514 | eAttachWrapper.classList.remove('hidden'); |
| 515 | const urlArgs = new URLSearchParams(window.location.search); |
| 516 | let zTarget = urlArgs.get('target'); |
| 517 | let zTo = urlArgs.get('to') || urlArgs.get('from'); |
| 518 | const eBtnSubmit = D.button("Submit"); |
| 519 | eBtnSubmit.type = 'button'; |
| 520 | const updateBtnSubmit = (attacher)=>{ |
| 521 | if( attacher.isPopulated ){ |
| 522 | eBtnSubmit.removeAttribute('disabled'); |
| 523 | }else{ |
| 524 | eBtnSubmit.setAttribute('disabled', ''); |
| 525 | } |
| 526 | }; |
| 527 | const cbAttacherChange = (ev)=>{ |
| 528 | const a = ev.detail.attacher; |
| 529 | updateBtnSubmit(a); |
| 530 | }; |
| 531 | const att = new Attacher({ |
| 532 | container: eAttachWrapper, |
| 533 | startWith: 1, |
| 534 | listener: cbAttacherChange, |
| 535 | controls: [eBtnSubmit], |
| 536 | description: true |
| 537 | }); |
| 538 | eBtnSubmit.addEventListener('click', async (ev)=>{ |
| 539 | att.reportError(); |
| 540 | const li = att.collectState(); |
| 541 | if( !li.length ) return; |
| 542 | if( eBtnSubmit.dataset.submitted ) return; |
| 543 | eBtnSubmit.dataset.submitted = 1; |
| 544 | D.disable(eBtnSubmit); |
| 545 | const fd = new FormData(); |
| 546 | att.populateFormData(fd); |
| 547 | for( const eIn of eAttachWrapper.querySelectorAll( |
| 548 | 'input[type="hidden"]' |
| 549 | ) ){ |
| 550 | /* Copy over hidden input fields emitted by the server. */ |
| 551 | if( eIn.name==='target' ){ |
| 552 | zTarget = eIn.value; |
| 553 | }else if( eIn.name==='to' || (eIn.name==='from' && !zTo) ){ |
| 554 | zTo = eIn.value; |
| 555 | } |
| 556 | fd.append(eIn.name, eIn.value) |
| 557 | } |
| 558 | if( att.isDryRun ){ |
| 559 | fd.append('dryrun', '1'); |
| 560 | } |
| 561 | let err; |
| 562 | const resp = await window.fetch(F.repoUrl('attachadd_ajax_post'), { |
| 563 | method: 'POST', |
| 564 | body: fd |
| 565 | }).catch((e)=>{ |
| 566 | err = e; |
| 567 | }); |
| 568 | D.enable(eBtnSubmit); |
| 569 | delete eBtnSubmit.dataset.submitted; |
| 570 | const jr = err ? undefined : await resp.json().catch(()=>{}); |
| 571 | if( err || jr?.error || !resp.ok ){ |
| 572 | const msg = err ? err.message : (jr?.error || resp.statusText); |
| 573 | att.reportError("Attaching failed: ", msg); |
| 574 | }else{ |
| 575 | att.clear(); |
| 576 | let to = zTo || jr?.redirect; |
| 577 | if( to ){ |
| 578 | if( '/'!==to[0] ){ |
| 579 | to = F.repoUrl(to); |
| 580 | } |
| 581 | window.location = to; |
| 582 | }else if( zTarget ){ |
| 583 | window.location = '?target='+zTarget+'&'+Date.now(); |
| 584 | } |
| 585 | } |
| 586 | })/*submit handler*/; |
| 587 | updateBtnSubmit(att); |
| 588 | F.page.attacher = att /* only for testing via dev console */; |
| 589 | }/* /attachadd */ |
| 590 | |
| 591 | })(window.fossil); |
| 592 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -504,88 +504,90 @@ | |
| 504 | return i; |
| 505 | } |
| 506 | }/*Attacher*/; |
| 507 | F.Attacher = Attacher; |
| 508 | |
| 509 | F.onPageLoad(function(){ |
| 510 | const eAttachWrapper = document.querySelector('#attachadd-form-wrapper'); |
| 511 | if( eAttachWrapper ){ |
| 512 | /* This page is /attachadd v2 or a workalike. eAttachWrapper holds |
| 513 | input[type=hidden] fields for use in attaching files and is |
| 514 | where we inject a file attachment widget. */ |
| 515 | eAttachWrapper.classList.remove('hidden'); |
| 516 | const urlArgs = new URLSearchParams(window.location.search); |
| 517 | let zTarget = urlArgs.get('target'); |
| 518 | let zTo = urlArgs.get('to') || urlArgs.get('from'); |
| 519 | const eBtnSubmit = D.button("Submit"); |
| 520 | eBtnSubmit.type = 'button'; |
| 521 | const updateBtnSubmit = (attacher)=>{ |
| 522 | if( attacher.isPopulated ){ |
| 523 | eBtnSubmit.removeAttribute('disabled'); |
| 524 | }else{ |
| 525 | eBtnSubmit.setAttribute('disabled', ''); |
| 526 | } |
| 527 | }; |
| 528 | const cbAttacherChange = (ev)=>{ |
| 529 | const a = ev.detail.attacher; |
| 530 | updateBtnSubmit(a); |
| 531 | }; |
| 532 | const att = new Attacher({ |
| 533 | container: eAttachWrapper, |
| 534 | startWith: 1, |
| 535 | listener: cbAttacherChange, |
| 536 | controls: [eBtnSubmit], |
| 537 | description: true |
| 538 | }); |
| 539 | eBtnSubmit.addEventListener('click', async (ev)=>{ |
| 540 | att.reportError(); |
| 541 | const li = att.collectState(); |
| 542 | if( !li.length ) return; |
| 543 | if( eBtnSubmit.dataset.submitted ) return; |
| 544 | eBtnSubmit.dataset.submitted = 1; |
| 545 | D.disable(eBtnSubmit); |
| 546 | const fd = new FormData(); |
| 547 | att.populateFormData(fd); |
| 548 | for( const eIn of eAttachWrapper.querySelectorAll( |
| 549 | 'input[type="hidden"]' |
| 550 | ) ){ |
| 551 | /* Copy over hidden input fields emitted by the server. */ |
| 552 | if( eIn.name==='target' ){ |
| 553 | zTarget = eIn.value; |
| 554 | }else if( eIn.name==='to' || (eIn.name==='from' && !zTo) ){ |
| 555 | zTo = eIn.value; |
| 556 | } |
| 557 | fd.append(eIn.name, eIn.value) |
| 558 | } |
| 559 | if( att.isDryRun ){ |
| 560 | fd.append('dryrun', '1'); |
| 561 | } |
| 562 | let err; |
| 563 | const resp = await window.fetch(F.repoUrl('attachadd_ajax_post'), { |
| 564 | method: 'POST', |
| 565 | body: fd |
| 566 | }).catch((e)=>{ |
| 567 | err = e; |
| 568 | }); |
| 569 | D.enable(eBtnSubmit); |
| 570 | delete eBtnSubmit.dataset.submitted; |
| 571 | const jr = err ? undefined : await resp.json().catch(()=>{}); |
| 572 | if( err || jr?.error || !resp.ok ){ |
| 573 | const msg = err ? err.message : (jr?.error || resp.statusText); |
| 574 | att.reportError("Attaching failed: ", msg); |
| 575 | }else{ |
| 576 | att.clear(); |
| 577 | let to = zTo || jr?.redirect; |
| 578 | if( to ){ |
| 579 | if( '/'!==to[0] ){ |
| 580 | to = F.repoUrl(to); |
| 581 | } |
| 582 | window.location = to; |
| 583 | }else if( zTarget ){ |
| 584 | window.location = '?target='+zTarget+'&'+Date.now(); |
| 585 | } |
| 586 | } |
| 587 | })/*submit handler*/; |
| 588 | updateBtnSubmit(att); |
| 589 | F.page.attacher = att /* only for testing via dev console */; |
| 590 | }/* /attachadd */ |
| 591 | })/*onPageLoad()*/; |
| 592 | |
| 593 | })(window.fossil); |
| 594 |
+8
-3
| --- src/fossil.page.forumpost.js | ||
| +++ src/fossil.page.forumpost.js | ||
| @@ -131,11 +131,14 @@ | ||
| 131 | 131 | browser's cancel button while waiting, they'll be stuck with |
| 132 | 132 | an unsubmittable form. */ |
| 133 | 133 | setTimeout(()=>{delete form.dataset.submitted}, 7000); |
| 134 | 134 | return; |
| 135 | 135 | }; |
| 136 | + | |
| 136 | 137 | document.querySelectorAll("form").forEach(function(form){ |
| 138 | + /* Set up controls for closing posts and setting thread | |
| 139 | + status. */ | |
| 137 | 140 | form.addEventListener('submit', formSubmitted); |
| 138 | 141 | form |
| 139 | 142 | .querySelectorAll("input.action-close, input.action-reopen") |
| 140 | 143 | .forEach(function(e){ |
| 141 | 144 | e.classList.remove('hidden'); |
| @@ -149,11 +152,13 @@ | ||
| 149 | 152 | form |
| 150 | 153 | .querySelectorAll("input[type='button'].action-status") |
| 151 | 154 | .forEach(function(btn){ |
| 152 | 155 | btn.classList.remove('hidden'); |
| 153 | 156 | const sel = btn.previousElementSibling; |
| 154 | - const updateAble = ()=>{ | |
| 157 | + const updateButton = ()=>{ | |
| 158 | + /* Enable btn only when the status has been locally | |
| 159 | + modified. */ | |
| 155 | 160 | if( sel.dataset.initialValue ){ |
| 156 | 161 | if( sel.dataset.initialValue===sel.value ){ |
| 157 | 162 | btn.setAttribute('disabled',''); |
| 158 | 163 | }else{ |
| 159 | 164 | btn.removeAttribute('disabled'); |
| @@ -164,12 +169,12 @@ | ||
| 164 | 169 | }else{ |
| 165 | 170 | btn.removeAttribute('disabled'); |
| 166 | 171 | } |
| 167 | 172 | } |
| 168 | 173 | }; |
| 169 | - sel.addEventListener('change', updateAble, true); | |
| 170 | - updateAble(); | |
| 174 | + sel.addEventListener('change', updateButton, true); | |
| 175 | + updateButton(); | |
| 171 | 176 | F.confirmer(btn, { |
| 172 | 177 | confirmText: "Confirm status change", |
| 173 | 178 | onconfirm: ()=>form.submit() |
| 174 | 179 | }); |
| 175 | 180 | }); |
| 176 | 181 |
| --- src/fossil.page.forumpost.js | |
| +++ src/fossil.page.forumpost.js | |
| @@ -131,11 +131,14 @@ | |
| 131 | browser's cancel button while waiting, they'll be stuck with |
| 132 | an unsubmittable form. */ |
| 133 | setTimeout(()=>{delete form.dataset.submitted}, 7000); |
| 134 | return; |
| 135 | }; |
| 136 | document.querySelectorAll("form").forEach(function(form){ |
| 137 | form.addEventListener('submit', formSubmitted); |
| 138 | form |
| 139 | .querySelectorAll("input.action-close, input.action-reopen") |
| 140 | .forEach(function(e){ |
| 141 | e.classList.remove('hidden'); |
| @@ -149,11 +152,13 @@ | |
| 149 | form |
| 150 | .querySelectorAll("input[type='button'].action-status") |
| 151 | .forEach(function(btn){ |
| 152 | btn.classList.remove('hidden'); |
| 153 | const sel = btn.previousElementSibling; |
| 154 | const updateAble = ()=>{ |
| 155 | if( sel.dataset.initialValue ){ |
| 156 | if( sel.dataset.initialValue===sel.value ){ |
| 157 | btn.setAttribute('disabled',''); |
| 158 | }else{ |
| 159 | btn.removeAttribute('disabled'); |
| @@ -164,12 +169,12 @@ | |
| 164 | }else{ |
| 165 | btn.removeAttribute('disabled'); |
| 166 | } |
| 167 | } |
| 168 | }; |
| 169 | sel.addEventListener('change', updateAble, true); |
| 170 | updateAble(); |
| 171 | F.confirmer(btn, { |
| 172 | confirmText: "Confirm status change", |
| 173 | onconfirm: ()=>form.submit() |
| 174 | }); |
| 175 | }); |
| 176 |
| --- src/fossil.page.forumpost.js | |
| +++ src/fossil.page.forumpost.js | |
| @@ -131,11 +131,14 @@ | |
| 131 | browser's cancel button while waiting, they'll be stuck with |
| 132 | an unsubmittable form. */ |
| 133 | setTimeout(()=>{delete form.dataset.submitted}, 7000); |
| 134 | return; |
| 135 | }; |
| 136 | |
| 137 | document.querySelectorAll("form").forEach(function(form){ |
| 138 | /* Set up controls for closing posts and setting thread |
| 139 | status. */ |
| 140 | form.addEventListener('submit', formSubmitted); |
| 141 | form |
| 142 | .querySelectorAll("input.action-close, input.action-reopen") |
| 143 | .forEach(function(e){ |
| 144 | e.classList.remove('hidden'); |
| @@ -149,11 +152,13 @@ | |
| 152 | form |
| 153 | .querySelectorAll("input[type='button'].action-status") |
| 154 | .forEach(function(btn){ |
| 155 | btn.classList.remove('hidden'); |
| 156 | const sel = btn.previousElementSibling; |
| 157 | const updateButton = ()=>{ |
| 158 | /* Enable btn only when the status has been locally |
| 159 | modified. */ |
| 160 | if( sel.dataset.initialValue ){ |
| 161 | if( sel.dataset.initialValue===sel.value ){ |
| 162 | btn.setAttribute('disabled',''); |
| 163 | }else{ |
| 164 | btn.removeAttribute('disabled'); |
| @@ -164,12 +169,12 @@ | |
| 169 | }else{ |
| 170 | btn.removeAttribute('disabled'); |
| 171 | } |
| 172 | } |
| 173 | }; |
| 174 | sel.addEventListener('change', updateButton, true); |
| 175 | updateButton(); |
| 176 | F.confirmer(btn, { |
| 177 | confirmText: "Confirm status change", |
| 178 | onconfirm: ()=>form.submit() |
| 179 | }); |
| 180 | }); |
| 181 |