diff options
Diffstat (limited to 'app/views/revisions')
| -rw-r--r-- | app/views/revisions/index.html.erb | 123 |
1 files changed, 72 insertions, 51 deletions
diff --git a/app/views/revisions/index.html.erb b/app/views/revisions/index.html.erb index c913b2a9..e951016f 100644 --- a/app/views/revisions/index.html.erb +++ b/app/views/revisions/index.html.erb | |||
| @@ -18,11 +18,11 @@ | |||
| 18 | </p> | 18 | </p> |
| 19 | <% end %> | 19 | <% end %> |
| 20 | 20 | ||
| 21 | <% pages = (@pages || @node.pages.all).reverse %> | ||
| 22 | |||
| 21 | <table id="revisions" class="admin_table revisions_table"> | 23 | <table id="revisions" class="admin_table revisions_table"> |
| 22 | <thead> | 24 | <thead> |
| 23 | <tr class="header"> | 25 | <tr class="header"> |
| 24 | <th><%= t(".first") %></th> | ||
| 25 | <th><%= t(".last") %></th> | ||
| 26 | <th><%= t("admin.columns.rev") %></th> | 26 | <th><%= t("admin.columns.rev") %></th> |
| 27 | <th><%= t("admin.columns.title") %></th> | 27 | <th><%= t("admin.columns.title") %></th> |
| 28 | <th><%= t("admin.columns.editor") %></th> | 28 | <th><%= t("admin.columns.editor") %></th> |
| @@ -31,24 +31,27 @@ | |||
| 31 | <th></th> | 31 | <th></th> |
| 32 | </tr> | 32 | </tr> |
| 33 | <tr class="diff_sticky_bar"> | 33 | <tr class="diff_sticky_bar"> |
| 34 | <td colspan="8"> | 34 | <td colspan="6"> |
| 35 | <%= button_to t(".diff_revisions"), diff_node_revisions_path(@node), | 35 | <%= form_tag diff_node_revisions_path(@node), :method => :post, |
| 36 | method: :post, | 36 | :id => "diff_form", :class => "button_to computation" do %> |
| 37 | params: { translation_locale: @translation_locale }, | 37 | <%= hidden_field_tag :translation_locale, @translation_locale %> |
| 38 | form: { id: 'diff_form', class: 'button_to computation' }, | 38 | <%= hidden_field_tag :start_revision, pages[1]&.revision %> |
| 39 | disabled: true %> | 39 | <%= hidden_field_tag :end_revision, pages[0]&.revision %> |
| 40 | <span id="diff_selection_label" data-against="<%= t(".against_word") %>" data-selected="<%= t(".selected_word") %>"></span> | 40 | <%= submit_tag t(".diff_revisions") %> |
| 41 | <label><%= radio_button_tag :view, 'inline', true %> <%= t("revisions.inline") %></label> | 41 | <span id="diff_selection_label" aria-live="polite"> |
| 42 | <label><%= radio_button_tag :view, 'side_by_side', false %> <%= t("revisions.side_by_side") %></label> | 42 | <%= t(".diff_selection_html", |
| 43 | :from => tag.span(:id => "diff_from"), | ||
| 44 | :to => tag.span(:id => "diff_to")) %> | ||
| 45 | </span> | ||
| 46 | <label><%= radio_button_tag :view, 'inline', true %> <%= t("revisions.inline") %></label> | ||
| 47 | <label><%= radio_button_tag :view, 'side_by_side', false %> <%= t("revisions.side_by_side") %></label> | ||
| 48 | <% end %> | ||
| 43 | </td> | 49 | </td> |
| 44 | </tr> | 50 | </tr> |
| 45 | </thead> | 51 | </thead> |
| 46 | <tbody> | 52 | <tbody> |
| 47 | <% pages = (@pages || @node.pages.all).reverse %> | 53 | <% pages.each do |page| %> |
| 48 | <% pages.each_with_index do |page, index| %> | 54 | <tr data-revision="<%= page.revision %>" tabindex="0" aria-pressed="false"> |
| 49 | <tr> | ||
| 50 | <td><%= radio_button_tag :start_revision, page.revision, index == 1 %></td> | ||
| 51 | <td><%= radio_button_tag :end_revision, page.revision, index == 0 %></td> | ||
| 52 | <td class="revision"><%= page.revision %></td> | 55 | <td class="revision"><%= page.revision %></td> |
| 53 | <td class="title"><%= page.translations.find_by(:locale => @translation_locale)&.title || "—" %></td> | 56 | <td class="title"><%= page.translations.find_by(:locale => @translation_locale)&.title || "—" %></td> |
| 54 | <td class="user"><%= page.editor.try(:login) %></td> | 57 | <td class="user"><%= page.editor.try(:login) %></td> |
| @@ -65,45 +68,63 @@ | |||
| 65 | </table> | 68 | </table> |
| 66 | 69 | ||
| 67 | <%= javascript_tag nonce: true do %> | 70 | <%= javascript_tag nonce: true do %> |
| 68 | function update_diff_button_state() { | 71 | (function () { |
| 69 | var start = document.querySelector('input[name="start_revision"]:checked'); | 72 | var table = document.getElementById('revisions'); |
| 70 | var end = document.querySelector('input[name="end_revision"]:checked'); | 73 | var form = document.getElementById('diff_form'); |
| 71 | var valid = start && end && start.value !== end.value; | 74 | if (!table || !form) { return; } |
| 72 | document.querySelector('#diff_form button[type="submit"]').disabled = !valid; | ||
| 73 | 75 | ||
| 74 | var label = document.getElementById('diff_selection_label'); | 76 | var from_field = form.querySelector('input[name="start_revision"]'); |
| 75 | if (start && end) { | 77 | var to_field = form.querySelector('input[name="end_revision"]'); |
| 76 | label.textContent = start.value + ' ' + label.dataset.against + ' ' + end.value; | 78 | var from_label = document.getElementById('diff_from'); |
| 77 | } else if (start || end) { | 79 | var to_label = document.getElementById('diff_to'); |
| 78 | label.textContent = (start || end).value + ' ' + label.dataset.selected; | 80 | var readout = document.getElementById('diff_selection_label'); |
| 79 | } else { | 81 | var submit = form.querySelector('input[type="submit"]'); |
| 80 | label.textContent = ''; | 82 | var rows = table.querySelectorAll('tbody tr'); |
| 81 | } | ||
| 82 | } | ||
| 83 | 83 | ||
| 84 | document.querySelectorAll('input[name="start_revision"], input[name="end_revision"]') | 84 | // Two-slot FIFO: the newest pick becomes the target and the previous |
| 85 | .forEach(function(radio) { radio.addEventListener('change', update_diff_button_state); }); | 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 !== ''; }); | ||
| 86 | 89 | ||
| 87 | update_diff_button_state(); | 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); | ||
| 88 | 99 | ||
| 89 | document.getElementById('diff_form').addEventListener('submit', function(e) { | 100 | rows.forEach(function (row) { |
| 90 | var start = document.querySelector('input[name="start_revision"]:checked'); | 101 | var rev = row.dataset.revision; |
| 91 | var end = document.querySelector('input[name="end_revision"]:checked'); | 102 | row.classList.toggle('diff_source', rev === from); |
| 92 | var view = document.querySelector('input[name="view"]:checked'); | 103 | row.classList.toggle('diff_target', rev === to); |
| 93 | if (start) { | 104 | row.setAttribute('aria-pressed', (rev === from || rev === to) ? 'true' : 'false'); |
| 94 | var s = document.createElement('input'); | 105 | }); |
| 95 | s.type = 'hidden'; s.name = 'start_revision'; s.value = start.value; | ||
| 96 | this.appendChild(s); | ||
| 97 | } | ||
| 98 | if (end) { | ||
| 99 | var en = document.createElement('input'); | ||
| 100 | en.type = 'hidden'; en.name = 'end_revision'; en.value = end.value; | ||
| 101 | this.appendChild(en); | ||
| 102 | } | 106 | } |
| 103 | if (view) { | 107 | |
| 104 | var v = document.createElement('input'); | 108 | function pick(rev) { |
| 105 | v.type = 'hidden'; v.name = 'view'; v.value = view.value; | 109 | if (rev === stack[1]) { return; } |
| 106 | this.appendChild(v); | 110 | stack.push(rev); |
| 111 | if (stack.length > 2) { stack.shift(); } | ||
| 112 | render(); | ||
| 107 | } | 113 | } |
| 108 | }); | 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 | })(); | ||
| 109 | <% end %> | 130 | <% end %> |
