summaryrefslogtreecommitdiff
path: root/app/views/revisions
diff options
context:
space:
mode:
Diffstat (limited to 'app/views/revisions')
-rw-r--r--app/views/revisions/index.html.erb123
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 %>