summaryrefslogtreecommitdiff
path: root/app/views
diff options
context:
space:
mode:
Diffstat (limited to 'app/views')
-rw-r--r--app/views/admin/_recent_changes.html.erb24
-rw-r--r--app/views/admin/index.html.erb23
-rw-r--r--app/views/custom/page_templates/public/chapter_detail.html.erb1
-rw-r--r--app/views/custom/partials/_chapter.html.erb37
-rw-r--r--app/views/events/_rrule_builder.html.erb33
-rw-r--r--app/views/events/edit.html.erb28
-rw-r--r--app/views/events/new.html.erb5
-rw-r--r--app/views/layouts/admin.html.erb5
-rw-r--r--app/views/layouts/application.html.erb18
-rw-r--r--app/views/node_actions/_action_row.html.erb18
-rw-r--r--app/views/node_actions/_change_details.html.erb27
-rw-r--r--app/views/node_actions/index.html.erb13
-rw-r--r--app/views/nodes/_recent_change_item.html.erb9
-rw-r--r--app/views/nodes/destroy.html.erb2
-rw-r--r--app/views/nodes/edit.html.erb5
-rw-r--r--app/views/nodes/new.html.erb4
-rw-r--r--app/views/nodes/recent.html.erb6
-rw-r--r--app/views/nodes/show.html.erb64
-rw-r--r--app/views/nodes/trashed.html.erb42
-rw-r--r--app/views/page_translations/edit.html.erb9
20 files changed, 267 insertions, 106 deletions
diff --git a/app/views/admin/_recent_changes.html.erb b/app/views/admin/_recent_changes.html.erb
deleted file mode 100644
index 88b5e93..0000000
--- a/app/views/admin/_recent_changes.html.erb
+++ /dev/null
@@ -1,24 +0,0 @@
1<h2>Recent Changes</h2>
2<div id="draft_list">
3 <table>
4 <tr class="header">
5 <th>Title</th>
6 <th>path</th>
7 <th>user</th>
8 <th>date</th>
9 <th></th>
10 </tr>
11 <% @recent_changes.each do |node| %>
12 <tr>
13 <td><%= truncated_title_for_node node %></td>
14 <td><%= node.unique_name %></td>
15 <td><%= node.draft.user.login rescue "" %></td>
16 <td><%= node.updated_at.to_fs(:db) %></td>
17 <td class="actions">
18 <%= link_to 'Show', node_path(node) %>
19 <%= link_to "Revisions", revision_path(:id => node.id) %>
20 </td>
21 </tr>
22 <% end %>
23 </table>
24</div> \ No newline at end of file
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb
index bdb555e..319530d 100644
--- a/app/views/admin/index.html.erb
+++ b/app/views/admin/index.html.erb
@@ -42,21 +42,12 @@
42 42
43 <div class="dashboard_widget"> 43 <div class="dashboard_widget">
44 <h3>Recent changes</h3> 44 <h3>Recent changes</h3>
45 <ul> 45 <table id="node_action_list">
46 <% @recent_changes.each do |node| %> 46 <%= render partial: "node_actions/action_row", collection: @actions, as: :action %>
47 <li> 47 </table>
48 <div> 48 <%= link_to "See all recent changes →", admin_log_path %>
49 <%= link_to title_for_node(node), node_path(node) %>
50 <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span>
51 </div>
52 <span class="dashboard_widget_meta">
53 <%= (editor = node_head_editor(node)) ? t("published_by", editor: editor) : t("published") %>, <%= relative_time_phrase(node.head.updated_at) %>
54 </span>
55 </li>
56 <% end %>
57 </ul>
58 <%= link_to "See all recent changes →", recent_nodes_path %>
59 </div> 49 </div>
50
60</div> 51</div>
61 52
62<div id="dashboard_housekeeping"> 53<div id="dashboard_housekeeping">
@@ -77,5 +68,9 @@
77 <%= link_to menu_items_path, class: "action_button" do %> 68 <%= link_to menu_items_path, class: "action_button" do %>
78 <%= icon("menu-2", library: "tabler", "aria-hidden": true) %> Navigation 69 <%= icon("menu-2", library: "tabler", "aria-hidden": true) %> Navigation
79 <% end %> 70 <% end %>
71 <% trash_count = Node.trash.children.count %>
72 <%= link_to trashed_nodes_path, class: "action_button" do %>
73 <%= icon("trash", library: "tabler", "aria-hidden": true) %> Trash<%= " (#{trash_count})" if trash_count > 0 %>
74 <% end %>
80 </div> 75 </div>
81</div> 76</div>
diff --git a/app/views/custom/page_templates/public/chapter_detail.html.erb b/app/views/custom/page_templates/public/chapter_detail.html.erb
index f47353c..c4c2598 100644
--- a/app/views/custom/page_templates/public/chapter_detail.html.erb
+++ b/app/views/custom/page_templates/public/chapter_detail.html.erb
@@ -1,5 +1,6 @@
1<div class="article" lang="<%= @page.effective_lang %>"> 1<div class="article" lang="<%= @page.effective_lang %>">
2 <h2 class="headline"><%= @page.title %></h2> 2 <h2 class="headline"><%= @page.title %></h2>
3 <%= headline_image %>
3 <% if @page.node.external_url.present? %> 4 <% if @page.node.external_url.present? %>
4 <div class="chapter_url"><%= link_to @page.node.external_url, @page.node.external_url, target: '_blank', rel: 'noopener' %></div> 5 <div class="chapter_url"><%= link_to @page.node.external_url, @page.node.external_url, target: '_blank', rel: 'noopener' %></div>
5 <% end %> 6 <% end %>
diff --git a/app/views/custom/partials/_chapter.html.erb b/app/views/custom/partials/_chapter.html.erb
index 805559b..47f3950 100644
--- a/app/views/custom/partials/_chapter.html.erb
+++ b/app/views/custom/partials/_chapter.html.erb
@@ -1,19 +1,26 @@
1<div class="article_partial chapter_partial" lang="<%= page.effective_lang %>"> 1<div class="article_partial chapter_partial" lang="<%= page.effective_lang %>">
2 <h2 class="headline"><%= link_to_path page.title, page.node.unique_name %></h2> 2 <div class="chapter_partial_layout">
3 <% if page.abstract.present? %> 3 <% if page.assets.images.any? %>
4 <div class="chapter_location"><%= page.abstract %></div> 4 <%= link_to_path image_tag(page.assets.images.first.upload.url(:thumb), :alt => ""), page.node.unique_name, class: "chapter_thumbnail" %>
5 <% end %> 5 <% end %>
6 <% if page.node.external_url.present? %> 6 <div class="chapter_partial_content">
7 <div class="chapter_url"><%= link_to page.node.external_url, page.node.external_url, target: '_blank', rel: 'noopener' %></div> 7 <h2 class="headline"><%= link_to_path page.title, page.node.unique_name %></h2>
8 <% end %> 8 <% if page.abstract.present? %>
9 <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %> 9 <div class="chapter_location"><%= page.abstract %></div>
10 <% if open_days.any? %>
11 <div class="chapter_open_days">
12 <span class="open_days_label"><%= t(:open_days_label) %>: </span>
13 <% open_days.each do |event| %>
14 <span class="event_schedule"><%= event_schedule_text(event) %></span>
15 <% end %> 10 <% end %>
11 <% if page.node.external_url.present? %>
12 <div class="chapter_url"><%= link_to page.node.external_url, page.node.external_url, target: '_blank', rel: 'noopener' %></div>
13 <% end %>
14 <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %>
15 <% if open_days.any? %>
16 <div class="chapter_open_days">
17 <span class="open_days_label"><%= t(:open_days_label) %>: </span>
18 <% open_days.each do |event| %>
19 <span class="event_schedule"><%= event_schedule_text(event) %></span>
20 <% end %>
21 </div>
22 <% end %>
23 <p class="excerpt"><%= sanitize page.body %></p>
16 </div> 24 </div>
17 <% end %> 25 </div>
18 <p class="excerpt"><%= sanitize page.body %></p>
19</div> 26</div>
diff --git a/app/views/events/_rrule_builder.html.erb b/app/views/events/_rrule_builder.html.erb
new file mode 100644
index 0000000..1ffec0a
--- /dev/null
+++ b/app/views/events/_rrule_builder.html.erb
@@ -0,0 +1,33 @@
1<div id="rrule_builder">
2 <p>
3 <label><%= radio_button_tag "rrule_freq", "weekly", true %> Weekly</label>
4 <label><%= radio_button_tag "rrule_freq", "monthly" %> Monthly</label>
5 </p>
6 <div id="rrule_weekly_options">
7 <p><label><%= check_box_tag "rrule_biweekly" %> Every 2 weeks</label></p>
8 <p>
9 <% %w[MO TU WE TH FR SA SU].each do |code| %>
10 <label><%= check_box_tag "rrule_byday_#{code}" %> <%= RruleHumanizer::WEEKDAY_NAMES_ABBR[:de][code] %></label>
11 <% end %>
12 </p>
13 </div>
14 <div id="rrule_monthly_options" style="display: none;">
15 <p><label><%= check_box_tag "rrule_monthly_ordinal" %> On a specific weekday each month</label></p>
16 <p id="rrule_ordinal_fields" style="display: none;">
17 <%= select_tag "rrule_ordinal", options_for_select([["1.", 1], ["2.", 2], ["3.", 3], ["4.", 4], ["letzter", -1], ["vorletzter", -2], ["Selected weeks", "custom"]]) %>
18 <%= select_tag "rrule_ordinal_day", options_for_select(%w[MO TU WE TH FR SA SU].map { |c| [RruleHumanizer::WEEKDAY_NAMES[:de][c], c] }) %>
19 </p>
20 <p id="rrule_custom_ordinal_fields" style="display: none;">
21 Weeks of the month:
22 <% (1..5).each do |ordinal| %>
23 <label><%= check_box_tag "rrule_custom_ordinal_#{ordinal}" %> <%= ordinal %>.</label>
24 <% end %>
25 </p>
26 </div>
27 <p>
28 <label><%= check_box_tag "rrule_exclude_month" %> Except in one month</label>
29 <%= select_tag "rrule_excluded_month", options_for_select((1..12).map { |m| [RruleHumanizer::MONTH_NAMES[:de][m-1], m] }), style: "display: none;" %>
30 </p>
31 <span class="field_hint">Builds the field below automatically. If your pattern is more complex than this covers, just edit it directly below - these controls won't touch it unless you use them.</span>
32</div>
33<%= f.text_field :rrule, id: "event_rrule" %>
diff --git a/app/views/events/edit.html.erb b/app/views/events/edit.html.erb
index b6564a4..4532ff2 100644
--- a/app/views/events/edit.html.erb
+++ b/app/views/events/edit.html.erb
@@ -40,33 +40,7 @@
40 40
41 <div class="node_description">Recurrence</div> 41 <div class="node_description">Recurrence</div>
42 <div class="node_content"> 42 <div class="node_content">
43 <div id="rrule_builder"> 43 <%= render "rrule_builder", f: f %>
44 <p>
45 <label><%= radio_button_tag "rrule_freq", "weekly", true %> Weekly</label>
46 <label><%= radio_button_tag "rrule_freq", "monthly" %> Monthly</label>
47 </p>
48 <div id="rrule_weekly_options">
49 <p><label><%= check_box_tag "rrule_biweekly" %> Every 2 weeks</label></p>
50 <p>
51 <% %w[MO TU WE TH FR SA SU].each do |code| %>
52 <label><%= check_box_tag "rrule_byday_#{code}" %> <%= RruleHumanizer::WEEKDAY_NAMES_ABBR[:de][code] %></label>
53 <% end %>
54 </p>
55 </div>
56 <div id="rrule_monthly_options" style="display: none;">
57 <p><label><%= check_box_tag "rrule_monthly_ordinal" %> On a specific weekday each month</label></p>
58 <p id="rrule_ordinal_fields" style="display: none;">
59 <%= select_tag "rrule_ordinal", options_for_select([["1.", 1], ["2.", 2], ["3.", 3], ["4.", 4], ["letzter", -1], ["vorletzter", -2]]) %>
60 <%= select_tag "rrule_ordinal_day", options_for_select(%w[MO TU WE TH FR SA SU].map { |c| [RruleHumanizer::WEEKDAY_NAMES[:de][c], c] }) %>
61 </p>
62 </div>
63 <p>
64 <label><%= check_box_tag "rrule_exclude_month" %> Except in one month</label>
65 <%= select_tag "rrule_excluded_month", options_for_select((1..12).map { |m| [RruleHumanizer::MONTH_NAMES[:de][m-1], m] }), style: "display: none;" %>
66 </p>
67 <span class="field_hint">Builds the field below automatically. If your pattern is more complex than this covers, just edit it directly below - these controls won't touch it unless you use them.</span>
68 </div>
69 <%= f.text_field :rrule, id: "event_rrule" %>
70 </div> 44 </div>
71 45
72 <div class="node_description">Title</div> 46 <div class="node_description">Title</div>
diff --git a/app/views/events/new.html.erb b/app/views/events/new.html.erb
index 7a1ee7a..028fce7 100644
--- a/app/views/events/new.html.erb
+++ b/app/views/events/new.html.erb
@@ -21,8 +21,8 @@
21 <div class="node_description">End time</div> 21 <div class="node_description">End time</div>
22 <div class="node_content"><%= f.datetime_select :end_time %></div> 22 <div class="node_content"><%= f.datetime_select :end_time %></div>
23 23
24 <div class="node_description">Rrule</div> 24 <div class="node_description">Recurrence</div>
25 <div class="node_content"><%= f.text_field :rrule %></div> 25 <div class="node_content"><%= render "rrule_builder", f: f %></div>
26 26
27 <div class="node_description">Title</div> 27 <div class="node_description">Title</div>
28 <div class="node_content"> 28 <div class="node_content">
@@ -53,4 +53,3 @@
53 </div> 53 </div>
54 </div> 54 </div>
55<% end %> 55<% end %>
56
diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb
index 0856a0f..e220beb 100644
--- a/app/views/layouts/admin.html.erb
+++ b/app/views/layouts/admin.html.erb
@@ -7,19 +7,18 @@
7 <%= csrf_meta_tags %> 7 <%= csrf_meta_tags %>
8 8
9 <title><%= "#{params[:controller]} | #{params[:action]}" %></title> 9 <title><%= "#{params[:controller]} | #{params[:action]}" %></title>
10 <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>
11 <%= javascript_include_tag 'admin_bundle' %> 10 <%= javascript_include_tag 'admin_bundle' %>
12 <%= tinymce_assets %> 11 <%= tinymce_assets %>
13 <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/admin.css') %>"> 12 <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/admin.css') %>">
14 <script src="<%= mtime_busted_path('/javascripts/admin_search.js') %>"></script> 13 <script src="<%= mtime_busted_path('/javascripts/admin_search.js') %>"></script>
15 <script src="<%= mtime_busted_path('/javascripts/admin_interface.js') %>"></script> 14 <script src="<%= mtime_busted_path('/javascripts/admin_interface.js') %>"></script>
16 <script src="<%= mtime_busted_path('/javascripts/related_assets.js') %>"></script> 15 <script src="<%= mtime_busted_path('/javascripts/related_assets.js') %>"></script>
17 <script> 16 <%= javascript_tag nonce: true do %>
18 var ADMIN_SEARCH_URL = "<%= admin_search_path %>"; 17 var ADMIN_SEARCH_URL = "<%= admin_search_path %>";
19 var ADMIN_MENU_SEARCH_URL = "<%= admin_menu_search_path %>"; 18 var ADMIN_MENU_SEARCH_URL = "<%= admin_menu_search_path %>";
20 var PARAMETERIZE_PREVIEW_URL = "<%= parameterize_preview_nodes_path %>"; 19 var PARAMETERIZE_PREVIEW_URL = "<%= parameterize_preview_nodes_path %>";
21 var DASHBOARD_SEARCH_URL = "<%= admin_dashboard_search_path %>"; 20 var DASHBOARD_SEARCH_URL = "<%= admin_dashboard_search_path %>";
22 </script> 21 <% end %>
23 </head> 22 </head>
24 23
25 <body> 24 <body>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 57d12e6..ca867ab 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -10,20 +10,20 @@
10 <meta property="og:description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung." /> 10 <meta property="og:description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung." />
11 11
12 <title><%= page_title %></title> 12 <title><%= page_title %></title>
13 <link rel="stylesheet" href="/stylesheets/ccc.css"> 13 <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/ccc.css') %>">
14 <link rel="stylesheet" href="/stylesheets/glightbox.min.css"> 14 <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/glightbox.min.css') %>">
15 <script src="/javascripts/glightbox.min.js"></script> 15 <script src="<%= mtime_busted_path('/javascripts/glightbox.min.js') %>"></script>
16 <script src="/javascripts/public.js"></script> 16 <script src="<%= mtime_busted_path('/javascripts/public.js') %>"></script>
17 17
18 <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %> 18 <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %>
19 <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %> 19 <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %>
20 20
21 <script> 21 <%= javascript_tag nonce: true do %>
22 (function() { document.addEventListener("DOMContentLoaded", function() { 22 document.addEventListener("DOMContentLoaded", function() {
23 if (localStorage.getItem('override-prefers-color-scheme', false)) 23 if (localStorage.getItem('override-prefers-color-scheme'))
24 document.getElementById("light-mode").checked = true; 24 document.getElementById("light-mode").checked = true;
25 }); })(); 25 });
26 </script> 26 <% end %>
27 27
28 </head> 28 </head>
29 29
diff --git a/app/views/node_actions/_action_row.html.erb b/app/views/node_actions/_action_row.html.erb
new file mode 100644
index 0000000..a9a3b8d
--- /dev/null
+++ b/app/views/node_actions/_action_row.html.erb
@@ -0,0 +1,18 @@
1<tr class="node_action node_action--<%= action.action %>">
2 <td class="node_action_time">
3 <span class="node_action_date"><%= action.occurred_at.strftime("%Y-%m-%d") %></span>
4 <%= verb_icon(action) %>
5 <span class="node_action_clock"><%= action.occurred_at.strftime("%H:%M") %></span>
6 </td>
7 <td class="node_action_body">
8 <%= action_summary(action) %>
9 <% if action.node_id && params[:node_id].blank? %>
10 <%= link_to t("node_actions.node_history"), admin_log_path(:node_id => action.node_id), :class => "node_action_zoom" %>
11 <% end %>
12 <% if action.inferred_from %>
13 <span class="node_action_inferred" title="<%= action.inferred_from %>"><%= t("node_actions.backfilled") %></span>
14 <% end %>
15 <%= render "node_actions/change_details", :action_entry => action if action_details?(action) %>
16 </td>
17</tr>
18
diff --git a/app/views/node_actions/_change_details.html.erb b/app/views/node_actions/_change_details.html.erb
new file mode 100644
index 0000000..2583e8b
--- /dev/null
+++ b/app/views/node_actions/_change_details.html.erb
@@ -0,0 +1,27 @@
1<details class="node_action_details">
2 <summary><%= t("node_actions.show_changes") %></summary>
3 <table>
4 <% if (default_items = default_locale_changes(action_entry)).any? %>
5 <tr>
6 <th><%= I18n.default_locale.to_s.upcase %></th>
7 <td>
8 <%= safe_join(default_items, ", ") %>
9 <% if action_entry.page && action_entry.node %>
10 <%= link_to t("node_actions.view_revision"), node_revision_path(action_entry.node, action_entry.page) %>
11 <% end %>
12 </td>
13 </tr>
14 <% end %>
15 <% (action_entry.metadata["translation_diff"] || {}).each do |locale, diff| %>
16 <tr>
17 <th><%= locale.upcase %></th>
18 <td>
19 <%= safe_join(translation_changes(diff), ", ") %>
20 <% if action_entry.page && action_entry.node %>
21 <%= link_to t("node_actions.view_revision"), node_revision_path(action_entry.node, action_entry.page, :locale => locale) %>
22 <% end %>
23 </td>
24 </tr>
25 <% end %>
26 </table>
27</details>
diff --git a/app/views/node_actions/index.html.erb b/app/views/node_actions/index.html.erb
new file mode 100644
index 0000000..20ef5b3
--- /dev/null
+++ b/app/views/node_actions/index.html.erb
@@ -0,0 +1,13 @@
1<h1><%= t("node_actions.heading") %></h1>
2
3<% if params[:node_id].present? || params[:user_id].present? %>
4 <p><%= link_to t("node_actions.show_all"), admin_log_path %></p>
5<% end %>
6
7<%= will_paginate @actions %>
8
9<table id="node_action_list">
10 <%= render partial: "node_actions/action_row", collection: @actions, as: :action %>
11</table>
12
13<%= will_paginate @actions %>
diff --git a/app/views/nodes/_recent_change_item.html.erb b/app/views/nodes/_recent_change_item.html.erb
new file mode 100644
index 0000000..754a775
--- /dev/null
+++ b/app/views/nodes/_recent_change_item.html.erb
@@ -0,0 +1,9 @@
1<li>
2 <div>
3 <%= link_to title_for_node(node), node_path(node) %>
4 <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span>
5 </div>
6 <span class="dashboard_widget_meta">
7 <%= (editor = node_head_editor(node)) ? t("last_edited_by", editor: editor) : t("last_edited") %>, <%= relative_time_phrase(node.head.updated_at) %>
8 </span>
9</li>
diff --git a/app/views/nodes/destroy.html.erb b/app/views/nodes/destroy.html.erb
deleted file mode 100644
index 065cf1d..0000000
--- a/app/views/nodes/destroy.html.erb
+++ /dev/null
@@ -1,2 +0,0 @@
1<h1>Nodes#destroy</h1>
2<p>Find me in app/views/nodes/destroy.html.erb</p>
diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb
index 9506995..25f15c2 100644
--- a/app/views/nodes/edit.html.erb
+++ b/app/views/nodes/edit.html.erb
@@ -81,7 +81,10 @@
81 data-create-url="<%= node_related_assets_path(@node) %>"> 81 data-create-url="<%= node_related_assets_path(@node) %>">
82 <ul id="related_asset_list" class="thumbnail_list"> 82 <ul id="related_asset_list" class="thumbnail_list">
83 <% @page.related_assets.includes(:asset).each do |related| %> 83 <% @page.related_assets.includes(:asset).each do |related| %>
84 <li data-url="<%= node_related_asset_path(@node, related) %>"> 84 <li data-url="<%= node_related_asset_path(@node, related) %>"
85 data-large-url="<%= related.asset.upload.url(:large) %>"
86 data-original-url="<%= related.asset.upload.url %>"
87 data-name="<%= related.asset.name %>">
85 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span> 88 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span>
86 <%= image_tag related.asset.upload.url(:thumb) %> 89 <%= image_tag related.asset.upload.url(:thumb) %>
87 <button type="button" class="related_asset_remove" aria-label="Remove image"> 90 <button type="button" class="related_asset_remove" aria-label="Remove image">
diff --git a/app/views/nodes/new.html.erb b/app/views/nodes/new.html.erb
index b63a606..890d46e 100644
--- a/app/views/nodes/new.html.erb
+++ b/app/views/nodes/new.html.erb
@@ -32,8 +32,8 @@
32 <div id="parent_search_field" style="<%= @selected_kind == "generic" ? "" : "display: none;" %>"> 32 <div id="parent_search_field" style="<%= @selected_kind == "generic" ? "" : "display: none;" %>">
33 <div class="node_description">Parent</div> 33 <div class="node_description">Parent</div>
34 <div class="node_content"> 34 <div class="node_content">
35 <%= text_field_tag :parent_search_term, @parent_name %> 35 <%= text_field_tag :parent_search_term, @parent&.title %>
36 <%= hidden_field_tag :parent_id, @parent_id %> 36 <%= hidden_field_tag :parent_id, @parent&.id, data: { unique_name: @parent&.computed_unique_name } %>
37 <div id="parent_search_results" class="search_results"></div> 37 <div id="parent_search_results" class="search_results"></div>
38 </div> 38 </div>
39 </div> 39 </div>
diff --git a/app/views/nodes/recent.html.erb b/app/views/nodes/recent.html.erb
index 3602775..d256253 100644
--- a/app/views/nodes/recent.html.erb
+++ b/app/views/nodes/recent.html.erb
@@ -1,3 +1,7 @@
1<h1>Recently changed</h1> 1<h1>Recently changed</h1>
2 2
3<%= render 'node_list' %> 3<%= will_paginate @nodes %>
4<ul id="recent_changes_full_list">
5 <%= render partial: "nodes/recent_change_item", collection: @nodes, as: :node %>
6</ul>
7<%= will_paginate @nodes %>
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb
index 66f04f9..af05778 100644
--- a/app/views/nodes/show.html.erb
+++ b/app/views/nodes/show.html.erb
@@ -46,7 +46,7 @@
46 <% end %> 46 <% end %>
47 47
48 <% unless locked_by_other %> 48 <% unless locked_by_other %>
49 <% if @node.draft && !@node.autosave %> 49 <% if @node.draft && !@node.autosave && !@node.in_trash? && !@node.trash_node? %>
50 <div class="node_info_item"> 50 <div class="node_info_item">
51 <%= button_to 'Publish', publish_node_path(@node), method: :put, 51 <%= button_to 'Publish', publish_node_path(@node), method: :put,
52 form: { data: { confirm: "Publish this draft?" }, class: 'button_to state_changing' } %> 52 form: { data: { confirm: "Publish this draft?" }, class: 'button_to state_changing' } %>
@@ -62,6 +62,15 @@
62 <% end %> 62 <% end %>
63 </div> 63 </div>
64 <% end %> 64 <% end %>
65 <% unless @node.trash_node? || @node.in_trash? || @node.root? %>
66 <div class="node_info_item">
67 <%= button_to trash_node_path(@node), method: :put,
68 form: { data: { confirm: "Move this page and everything beneath it to the Trash? All published content in it will go offline." }, class: 'button_to destructive' } do %>
69 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
70 Move to Trash
71 <% end %>
72 </div>
73 <% end %>
65 <% end %> 74 <% end %>
66 </div> 75 </div>
67 76
@@ -70,6 +79,48 @@
70 <% end %> 79 <% end %>
71 </div> 80 </div>
72 81
82 <% if @node.in_trash? %>
83 <div class="node_description">Trash</div>
84 <div class="node_content node_info_group">
85 <div class="node_info_group_items">
86 <% if (entry = @node.last_trash_entry) && entry.metadata.dig("path", "from") %>
87 <div class="node_info_item">
88 <span class="node_info_label">Was at</span>
89 <%= entry.metadata.dig("path", "from") %>
90 </div>
91 <% end %>
92 <div class="node_info_item">
93 <span class="node_info_label">Restore to</span>
94 <% suggestion = @node.suggested_restore_parent %>
95 <%= form_tag restore_from_trash_node_path(@node), :method => :put, :class => "aligned_action_row" do %>
96 <div class="restore_picker">
97 <%= text_field_tag :restore_search_term,
98 suggestion && (suggestion.head&.title || suggestion.draft&.title || suggestion.slug),
99 :placeholder => "Search for a new parent…" %>
100 <div id="restore_search_results" class="search_results"></div>
101 </div>
102 <%= hidden_field_tag :parent_id, suggestion&.id %>
103 <%= submit_tag "Restore here", :class => "action_button action_button_no_margin_top" %>
104 <% end %>
105 <span class="field_hint">Restored pages come back unpublished. Republish each page deliberately.</span>
106 </div>
107 </div>
108 <div class="node_info_group_items">
109 <div class="node_info_item">
110 <% doomed_below = @node.descendants.count %>
111 <%= button_to node_path(@node), method: :delete,
112 form: { data: { confirm: doomed_below > 0 ?
113 "Delete this page and the #{doomed_below} pages beneath it permanently? This cannot be undone." :
114 "Delete this page permanently? This cannot be undone." },
115 class: 'button_to destructive' } do %>
116 <%= icon("trash-x", library: "tabler", "aria-hidden": true) %>
117 Delete permanently<%= " (including #{doomed_below} beneath)" if doomed_below > 0 %>
118 <% end %>
119 </div>
120 </div>
121 </div>
122 <% end %>
123
73 <div class="node_description">Translations</div> 124 <div class="node_description">Translations</div>
74 <div class="node_content node_info_group"> 125 <div class="node_content node_info_group">
75 <div class="node_info_group_items"> 126 <div class="node_info_group_items">
@@ -170,19 +221,22 @@
170 </div> 221 </div>
171 </div> 222 </div>
172 223
173 <div class="node_description">Revisions</div> 224 <div class="node_description">History</div>
174 <div class="node_content node_info_group"> 225 <div class="node_content node_info_group">
175 <details> 226 <details>
176 <summary> 227 <summary>
177 <%= pluralize(@node.pages.count, 'revision', 'revisions') %> 228 <%= pluralize(@node.pages.count, 'published revision', 'published revisions') %>
178 </summary> 229 </summary>
179 <ul> 230 <ul>
180 <% @node.pages.order(:revision).each do |page| %> 231 <% @node.pages.order(:revision).each do |page| %>
181 <li><%= link_to "##{page.revision} — #{page.title} (#{page.editor.try(:login)}, #{page.updated_at})", node_revision_path(@node, page) %></li> 232 <li>
233 <%= link_to "##{page.revision} — #{page.title} (#{page.editor.try(:login)}, #{page.updated_at})", node_revision_path(@node, page) %>
234 <span class="revision_lifecycle"><%= revision_lifecycle_badges(@page_actions[page.id]) %></span>
235 </li>
182 <% end %> 236 <% end %>
183 </ul> 237 </ul>
184 </details> 238 </details>
185 <p class="revisions_full_history_link"><%= link_to 'Full history (diff / restore)', node_revisions_path(@node) %></p> 239 <p class="revisions_full_history_link"><%= link_to 'Revision history (diff / restore)', node_revisions_path(@node) %> | <%= link_to t("node_actions.heading"), admin_log_path(:node_id => @node.id) %></p>
186 </div> 240 </div>
187 241
188 242
diff --git a/app/views/nodes/trashed.html.erb b/app/views/nodes/trashed.html.erb
new file mode 100644
index 0000000..9a4808e
--- /dev/null
+++ b/app/views/nodes/trashed.html.erb
@@ -0,0 +1,42 @@
1<h1>Trash</h1>
2
3<% if @nodes.empty? %>
4 <p class="field_hint">The Trash is empty.</p>
5<% else %>
6 <%= will_paginate @nodes %>
7 <table id="trashed_node_list">
8 <tr>
9 <th>Title</th>
10 <th>Was at</th>
11 <th>Trashed</th>
12 <th>Actions</th>
13 </tr>
14 <% @nodes.each do |node| %>
15 <% entry = node.last_trash_entry %>
16 <tr>
17 <% doomed_below = node.descendants.count %>
18 <td>
19 <%= link_to (node.draft&.title || node.slug), node_path(node) %><%= " (+ #{doomed_below} beneath)" if doomed_below > 0 %>
20 </td>
21 <td><%= entry&.metadata&.dig("path", "from") %></td>
22 <td>
23 <% if entry %>
24 <%= entry.occurred_at.strftime("%Y-%m-%d %H:%M") %> by <%= entry.actor_name %>
25 <% end %>
26 </td>
27 <td>
28 <%= button_to node_path(node), method: :delete,
29 form: { data: { confirm: doomed_below > 0 ?
30 "Delete \"#{node.draft&.title || node.slug}\" and the #{doomed_below} pages beneath it permanently? This cannot be undone." :
31 "Delete \"#{node.draft&.title || node.slug}\" permanently? This cannot be undone." },
32 class: 'button_to destructive' } do %>
33 <%= icon("trash-x", library: "tabler", "aria-hidden": true) %>
34 Delete permanently
35 <% end %>
36 </td>
37 </tr>
38 <% end %>
39 </table>
40 <%= will_paginate @nodes %>
41 <p class="field_hint">To restore a page, open it and pick a new parent in its Trash section.</p>
42<% end %>
diff --git a/app/views/page_translations/edit.html.erb b/app/views/page_translations/edit.html.erb
index 0f64d40..00bf221 100644
--- a/app/views/page_translations/edit.html.erb
+++ b/app/views/page_translations/edit.html.erb
@@ -20,6 +20,15 @@
20</div> 20</div>
21 21
22<div id="page_editor"> 22<div id="page_editor">
23 <ul id="related_asset_list" style="display:none">
24 <% @page.related_assets.includes(:asset).each do |related| %>
25 <li data-large-url="<%= related.asset.upload.url(:large) %>"
26 data-original-url="<%= related.asset.upload.url %>"
27 data-name="<%= related.asset.name %>">
28 <%= image_tag related.asset.upload.url(:thumb) %>
29 </li>
30 <% end %>
31 </ul>
23 <%= form_with url: node_translation_path(@node, @locale), method: :patch, local: true, id: "translation_edit_form", 32 <%= form_with url: node_translation_path(@node, @locale), method: :patch, local: true, id: "translation_edit_form",
24 data: { autosave_url: autosave_node_translation_path(@node, @locale), show_url: node_path(@node) } do |f| %> 33 data: { autosave_url: autosave_node_translation_path(@node, @locale), show_url: node_path(@node) } do |f| %>
25 <div id="content"> 34 <div id="content">