diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-08-14 16:35:02 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-08-14 16:35:02 +0200 |
| commit | b282797767e6980ebad340e352bef4b0552c150d (patch) | |
| tree | ce0c56245a76b8d15142fb7bd70489aacd47d844 | |
| parent | dcdc892d940adffced3d2bc272d813a47c7d4700 (diff) | |
Move the revision picker into admin_interface.js
| -rw-r--r-- | app/views/revisions/index.html.erb | 62 | ||||
| -rw-r--r-- | public/javascripts/admin_interface.js | 70 |
2 files changed, 70 insertions, 62 deletions
diff --git a/app/views/revisions/index.html.erb b/app/views/revisions/index.html.erb index e951016f..4f854518 100644 --- a/app/views/revisions/index.html.erb +++ b/app/views/revisions/index.html.erb | |||
| @@ -66,65 +66,3 @@ | |||
| 66 | <% end %> | 66 | <% end %> |
| 67 | </tbody> | 67 | </tbody> |
| 68 | </table> | 68 | </table> |
| 69 | |||
| 70 | <%= javascript_tag nonce: true do %> | ||
| 71 | (function () { | ||
| 72 | var table = document.getElementById('revisions'); | ||
| 73 | var form = document.getElementById('diff_form'); | ||
| 74 | if (!table || !form) { return; } | ||
| 75 | |||
| 76 | var from_field = form.querySelector('input[name="start_revision"]'); | ||
| 77 | var to_field = form.querySelector('input[name="end_revision"]'); | ||
| 78 | var from_label = document.getElementById('diff_from'); | ||
| 79 | var to_label = document.getElementById('diff_to'); | ||
| 80 | var readout = document.getElementById('diff_selection_label'); | ||
| 81 | var submit = form.querySelector('input[type="submit"]'); | ||
| 82 | var rows = table.querySelectorAll('tbody tr'); | ||
| 83 | |||
| 84 | // Two-slot FIFO: the newest pick becomes the target and the previous | ||
| 85 | // target becomes the source, so two taps anywhere give any pair. | ||
| 86 | // Picking the current target is a no-op; picking the current source | ||
| 87 | // swaps them. | ||
| 88 | var stack = [from_field.value, to_field.value].filter(function (v) { return v !== ''; }); | ||
| 89 | |||
| 90 | function render() { | ||
| 91 | var from = stack[0] || ''; | ||
| 92 | var to = stack[1] || ''; | ||
| 93 | from_field.value = from; | ||
| 94 | to_field.value = to; | ||
| 95 | from_label.textContent = from; | ||
| 96 | to_label.textContent = to; | ||
| 97 | readout.hidden = !(from && to); | ||
| 98 | submit.disabled = !(from && to && from !== to); | ||
| 99 | |||
| 100 | rows.forEach(function (row) { | ||
| 101 | var rev = row.dataset.revision; | ||
| 102 | row.classList.toggle('diff_source', rev === from); | ||
| 103 | row.classList.toggle('diff_target', rev === to); | ||
| 104 | row.setAttribute('aria-pressed', (rev === from || rev === to) ? 'true' : 'false'); | ||
| 105 | }); | ||
| 106 | } | ||
| 107 | |||
| 108 | function pick(rev) { | ||
| 109 | if (rev === stack[1]) { return; } | ||
| 110 | stack.push(rev); | ||
| 111 | if (stack.length > 2) { stack.shift(); } | ||
| 112 | render(); | ||
| 113 | } | ||
| 114 | |||
| 115 | rows.forEach(function (row) { | ||
| 116 | row.addEventListener('click', function (e) { | ||
| 117 | if (e.target.closest('a, button, input, label')) { return; } | ||
| 118 | pick(row.dataset.revision); | ||
| 119 | }); | ||
| 120 | row.addEventListener('keydown', function (e) { | ||
| 121 | if (e.key === 'Enter' || e.key === ' ') { | ||
| 122 | e.preventDefault(); | ||
| 123 | pick(row.dataset.revision); | ||
| 124 | } | ||
| 125 | }); | ||
| 126 | }); | ||
| 127 | |||
| 128 | render(); | ||
| 129 | })(); | ||
| 130 | <% end %> | ||
diff --git a/public/javascripts/admin_interface.js b/public/javascripts/admin_interface.js index cbfa4dc6..b7cb1964 100644 --- a/public/javascripts/admin_interface.js +++ b/public/javascripts/admin_interface.js | |||
| @@ -86,6 +86,10 @@ $(document).ready(function () { | |||
| 86 | cccms.preview.initialize(); | 86 | cccms.preview.initialize(); |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | if (document.getElementById('revisions')) { | ||
| 90 | initialize_revision_diff_picker.initialize(); | ||
| 91 | } | ||
| 92 | |||
| 89 | var metadata_details = document.getElementById('metadata_details'); | 93 | var metadata_details = document.getElementById('metadata_details'); |
| 90 | if (metadata_details) { | 94 | if (metadata_details) { |
| 91 | var desktop_mq = window.matchMedia('(min-width: 1016px)'); | 95 | var desktop_mq = window.matchMedia('(min-width: 1016px)'); |
| @@ -559,3 +563,69 @@ rrule_builder = { | |||
| 559 | } | 563 | } |
| 560 | } | 564 | } |
| 561 | }; | 565 | }; |
| 566 | |||
| 567 | initialize_revision_diff_picker = { | ||
| 568 | initialize : function() { | ||
| 569 | let table = document.getElementById('revisions'); | ||
| 570 | let rows = table.querySelectorAll('tbody tr'); | ||
| 571 | let form = document.getElementById('diff_form'); | ||
| 572 | let from_field = form.querySelector('input[name="start_revision"]'); | ||
| 573 | let to_field = form.querySelector('input[name="end_revision"]'); | ||
| 574 | |||
| 575 | // Two-slot FIFO: the newest pick becomes the target and the previous | ||
| 576 | // target becomes the source, so two taps anywhere give any pair. | ||
| 577 | // Picking the current target is a no-op, picking the current source | ||
| 578 | // swaps them. | ||
| 579 | this.stack = [from_field.value, to_field.value].filter(function (v) { return v !== ''; }); | ||
| 580 | |||
| 581 | rows.forEach(function (row) { | ||
| 582 | row.addEventListener('click', function (e) { | ||
| 583 | if (e.target.closest('a, button, input, label')) { return; } | ||
| 584 | initialize_revision_diff_picker.pick(row.dataset.revision); | ||
| 585 | }); | ||
| 586 | row.addEventListener('keydown', function (e) { | ||
| 587 | if (e.key === 'Enter' || e.key === ' ') { | ||
| 588 | e.preventDefault(); | ||
| 589 | initialize_revision_diff_picker.pick(row.dataset.revision); | ||
| 590 | } | ||
| 591 | }); | ||
| 592 | }); | ||
| 593 | |||
| 594 | this.render(); | ||
| 595 | }, | ||
| 596 | |||
| 597 | render : function() { | ||
| 598 | let table = document.getElementById('revisions'); | ||
| 599 | let rows = table.querySelectorAll('tbody tr'); | ||
| 600 | let form = document.getElementById('diff_form'); | ||
| 601 | let from_field = form.querySelector('input[name="start_revision"]'); | ||
| 602 | let to_field = form.querySelector('input[name="end_revision"]'); | ||
| 603 | let submit = form.querySelector('input[type="submit"]'); | ||
| 604 | let readout = document.getElementById('diff_selection_label'); | ||
| 605 | let from_label = document.getElementById('diff_from'); | ||
| 606 | let to_label = document.getElementById('diff_to'); | ||
| 607 | |||
| 608 | let from = this.stack[0] || ''; | ||
| 609 | let to = this.stack[1] || ''; | ||
| 610 | from_field.value = from; | ||
| 611 | from_label.textContent = from; | ||
| 612 | to_field.value = to; | ||
| 613 | to_label.textContent = to; | ||
| 614 | readout.hidden = !(from && to); | ||
| 615 | submit.disabled = !(from && to && from !== to); | ||
| 616 | |||
| 617 | rows.forEach(function (row) { | ||
| 618 | var rev = row.dataset.revision; | ||
| 619 | row.classList.toggle('diff_source', rev === from); | ||
| 620 | row.classList.toggle('diff_target', rev === to); | ||
| 621 | row.setAttribute('aria-pressed', (rev === from || rev === to) ? 'true' : 'false'); | ||
| 622 | }); | ||
| 623 | }, | ||
| 624 | |||
| 625 | pick : function(rev) { | ||
| 626 | if (rev === this.stack[1]) { return; } | ||
| 627 | this.stack.push(rev); | ||
| 628 | if (this.stack.length > 2) { this.stack.shift(); } | ||
| 629 | this.render(); | ||
| 630 | } | ||
| 631 | }; | ||
