summaryrefslogtreecommitdiff
path: root/app/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'app/views/nodes')
-rw-r--r--app/views/nodes/_node_list.html.erb41
-rw-r--r--app/views/nodes/chapters.html.erb11
-rw-r--r--app/views/nodes/drafts.html.erb3
-rw-r--r--app/views/nodes/edit.html.erb153
-rw-r--r--app/views/nodes/index.html.erb13
-rw-r--r--app/views/nodes/mine.html.erb3
-rw-r--r--app/views/nodes/new.html.erb75
-rw-r--r--app/views/nodes/recent.html.erb3
-rw-r--r--app/views/nodes/show.html.erb307
-rw-r--r--app/views/nodes/sitemap.html.erb32
-rw-r--r--app/views/nodes/tags.html.erb3
11 files changed, 485 insertions, 159 deletions
diff --git a/app/views/nodes/_node_list.html.erb b/app/views/nodes/_node_list.html.erb
new file mode 100644
index 0000000..f7210f1
--- /dev/null
+++ b/app/views/nodes/_node_list.html.erb
@@ -0,0 +1,41 @@
1<%= form_tag url_for(controller: params[:controller], action: params[:action]), method: :get, class: "node_search_form" do %>
2 <% Array(params[:kinds]).each do |kind| %>
3 <%= hidden_field_tag "kinds[]", kind %>
4 <% end %>
5 <%= hidden_field_tag :tags, params[:tags] if params[:tags].present? %>
6 <%= text_field_tag :q, params[:q], placeholder: "Search title, abstract, body…" %>
7 <%= button_tag type: "submit", class: "action_button" do %>
8 <%= icon("search", library: "tabler", "aria-hidden": true) %> Search
9 <% end %>
10 <% if params[:q].present? || params[:kinds].present? || params[:tags].present? %>
11 <%= link_to "Reset", url_for(controller: params[:controller], action: params[:action]) %>
12 <% end %>
13<% end %>
14
15<%= will_paginate @nodes %>
16<table class="node_table">
17 <tr class="header">
18 <th class="node_id">ID</th>
19 <th class="title">Title</th>
20 <th class="actions">Actions</th>
21 <th class="editor">Locked by</th>
22 <th class="revision">Rev.</th>
23 </tr>
24 <% @nodes.each do |node| %>
25 <tr class="<%= cycle("even", "odd") %>">
26 <td class="node_id"><%= node.id %></td>
27 <td class="title">
28 <h4><%= link_to title_for_node(node), node_path(node) %></h4>
29 <p><%= link_to_path(node.unique_name, node.unique_name) %></p>
30 </td>
31 <td class="actions">
32 <%= link_to 'show', node_path(node) %>
33 <%= link_to 'edit', edit_node_path(node) %>
34 <%= link_to 'revisions', node_revisions_path(node) %>
35 </td>
36 <td><%= node.lock_owner.login if node.lock_owner %></td>
37 <td><%= node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY") %></td>
38 </tr>
39 <% end %>
40</table>
41<%= will_paginate @nodes %>
diff --git a/app/views/nodes/chapters.html.erb b/app/views/nodes/chapters.html.erb
new file mode 100644
index 0000000..543bc53
--- /dev/null
+++ b/app/views/nodes/chapters.html.erb
@@ -0,0 +1,11 @@
1<h1>Chapters</h1>
2
3<%= form_tag chapters_nodes_path, method: :get, class: "node_search_form" do %>
4 <label><%= check_box_tag 'kinds[]', 'erfa', @kind_keys.include?('erfa') %> Erfa</label>
5 <label><%= check_box_tag 'kinds[]', 'chaostreff', @kind_keys.include?('chaostreff') %> Chaostreff</label>
6 <%= button_tag type: "submit", class: "action_button" do %>
7 <%= icon("filter", library: "tabler", "aria-hidden": true) %> Filter
8 <% end %>
9<% end %>
10
11<%= render 'node_list' %>
diff --git a/app/views/nodes/drafts.html.erb b/app/views/nodes/drafts.html.erb
new file mode 100644
index 0000000..6d0830c
--- /dev/null
+++ b/app/views/nodes/drafts.html.erb
@@ -0,0 +1,3 @@
1<h1>Nodes with drafts or autosaves</h1>
2
3<%= render 'node_list' %>
diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb
index 498fa1f..e0e51d8 100644
--- a/app/views/nodes/edit.html.erb
+++ b/app/views/nodes/edit.html.erb
@@ -1,79 +1,113 @@
1<% content_for :subnavigation do %> 1<h1><%= title_for_node(@node) %></h1>
2 <%= link_to 'metadata', '#', :id => 'button', :class => "unselected" %> 2
3 <%= link_to 'Show', @node %> 3<div class="node_action_bar">
4 <%= link_to 'Preview', preview_page_path(@draft) %> 4 <%= button_to 'Unlock + Back', unlock_node_path(@node), method: :put,
5 <%= button_to 'Publish', publish_node_path(@node), method: :put, form: { data: { confirm: "Publish this draft?" } } %> 5 form: { class: 'button_to state_changing' },
6 <%= link_to 'Revisions', node_revisions_path(@node) %> 6 disabled: @node.autosave.present? %>
7<% end %> 7
8 <% if @node.autosave || (@node.draft && @node.head) %>
9 <%= button_to revert_node_path(@node), method: :put,
10 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %>
11 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
12 <%= @node.draft && !@node.autosave ? "Destroy Draft" : "Discard Autosave" %>
13 <% end %>
14 <% if pair = @node.available_layer_pairs.find { |p| p.include?(:autosave) } %>
15 <%= button_to 'What changed?',
16 diff_node_revisions_path(@node),
17 method: :get,
18 params: { start_revision: pair.first, end_revision: pair.last },
19 form: { class: 'button_to computation' } %>
20 <% end %>
21 <% end %>
22
23 <%= submit_tag "Save Draft", form: dom_id(@node, :edit) %>
24 <%= submit_tag "Save + Unlock + Exit", form: dom_id(@node, :edit) %>
25 <%= link_to "Preview ↗", preview_page_path(@page), target: "_blank", rel: "noopener", class: "preview_link" %>
26</div>
8 27
9<div id="page_editor"> 28<div id="page_editor">
10<%= form_for(@node) do |f| %> 29 <%= form_for(@node, html: { data: { autosave_url: autosave_node_path(@node), show_url: node_path(@node) } }) do |f| %>
11 <% if @node.errors.any? %> 30 <% if @node.errors.any? %>
12 <div class="error_messages"> 31 <div class="error_messages">
13 <ul><% @node.errors.full_messages.each do |msg| %><li><%= msg %></li><% end %></ul> 32 <ul><% @node.errors.full_messages.each do |msg| %><li><%= msg %></li><% end %></ul>
14 </div> 33 </div>
15 <% end %> 34 <% end %>
16
17 <div id="metadata">
18 <div class="node_description">Event</div>
19 <div class="node_content"><%= event_information %></div>
20 35
21 <div class="node_description">Slug</div> 36 <details id="metadata_details">
22 <div class="node_content"> 37 <summary>Metadata (slug, parent, tags, template, author, images)</summary>
23 <%= f.text_field( 38 <div id="metadata">
24 :staged_slug, :value => @node.staged_slug || @node.slug 39 <div class="node_description">Slug</div>
25 ) 40 <div class="node_content">
26 %> 41 <%= f.text_field(
27 </div> 42 :staged_slug, :value => @node.staged_slug || @node.slug
28 43 )
29 <div class="node_description">parent</div> 44 %>
30 <div class="node_content"> 45 </div>
31 <%= text_field_tag :move_to_search_term, @node.parent.title rescue "" %>
32 <div id="search_results">
33 46
34 </div> 47 <div class="node_description">parent</div>
48 <div class="node_content">
49 <%= text_field_tag :move_to_search_term, @node.parent.title rescue "" %>
50 <div id="move_to_search_results" class="search_results"></div>
35 <%= f.hidden_field( 51 <%= f.hidden_field(
36 :staged_parent_id, 52 :staged_parent_id,
37 :value => @node.staged_parent_id || @node.parent_id 53 :value => @node.staged_parent_id || @node.parent_id
38 ) 54 )
39 %> 55 %>
40 </div> 56 </div>
41
42 <%= fields_for @draft do |d| %>
43 <div class="node_description">Tags - comma seperated</div>
44 <div class="node_content"><%= text_field_tag :tag_list, @draft.tag_list.join(', ') %></div>
45 57
46 <div class="node_description">Publish at</div> 58 <%= fields_for @page do |d| %>
47 <div class="node_content"><%= d.datetime_select :published_at, :value => @draft.published_at %></div> 59 <div class="node_description">Tags - comma seperated</div>
60 <div class="node_content"><%= text_field_tag :tag_list, @page.tag_list.join(', ') %></div>
48 61
49 <div class="node_description">Template</div> 62 <div class="node_description">Publish at</div>
50 <div class="node_content"><%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %></div> 63 <div class="node_content"><%= d.datetime_select :published_at, :value => @page.published_at %></div>
51 64
52 <div class="node_description">Author</div> 65 <div class="node_description">Template</div>
53 <div class="node_content"><%= d.select :user_id, user_list %></div> 66 <div class="node_content">
67 <%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %>
68 <span class="field_hint">Set automatically based on how this node was created - change it if needed.</span>
69 </div>
54 70
55 <div class="node_description">Images</div> 71 <div class="node_description">Author</div>
56 <div class="node_content"> 72 <div class="node_content">
57 <ul id="image_box" rel="<%= @draft.id %>"> 73 <%= d.select :user_id, user_list,
58 <% @draft.assets.images.each do |image| %> 74 :selected => @page.user_id || @node.draft&.user_id || @node.head&.user_id %>
59 <li rel="images_<%= image.id %>">
60 <%= image_tag(image.upload.url(:thumb)) %>
61 </li>
62 <% end %>
63 </ul>
64 <div class="clear_left right">
65 <a id="image_browser_toggle" class="unselected" href="#">image browser</a>
66 </div> 75 </div>
67 <div id="image_browser"> 76
68 <ul> 77 <div class="node_description">Images</div>
69 <% Asset.images.each do |image| %> 78 <div class="node_content">
70 <li rel="images_<%= image.id %>"><%= image_tag(image.upload.url(:thumb)) %></li> 79 <div id="related_assets"
71 <% end %> 80 data-search-url="<%= search_node_related_assets_path(@node) %>"
72 </ul> 81 data-create-url="<%= node_related_assets_path(@node) %>">
82 <ul id="related_asset_list" class="thumbnail_list">
83 <% @page.related_assets.includes(:asset).each do |related| %>
84 <li data-url="<%= node_related_asset_path(@node, related) %>">
85 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span>
86 <%= image_tag related.asset.upload.url(:thumb) %>
87 <button type="button" class="related_asset_remove" aria-label="Remove image">
88 <%= icon("x", library: "tabler", "aria-hidden": true) %>
89 </button>
90 </li>
91 <% end %>
92 </ul>
93 <%= text_field_tag nil, nil, id: "related_asset_search_term", placeholder: "Search images to attach…", autocomplete: "off" %>
94 <div id="related_asset_search_results" class="search_results"></div>
95 </div>
73 </div> 96 </div>
97
98 <template id="related_asset_template">
99 <li>
100 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span>
101 <img src="">
102 <button type="button" class="related_asset_remove" aria-label="Remove image">
103 <%= icon("x", library: "tabler", "aria-hidden": true) %>
104 </button>
105 </li>
106 </template>
107
74 </div> 108 </div>
75 </div> 109 </details>
76 110
77 <div id="content"> 111 <div id="content">
78 <div class="node_description">Title</div> 112 <div class="node_description">Title</div>
79 <div class="node_content"><%= d.text_field :title %></div> 113 <div class="node_content"><%= d.text_field :title %></div>
@@ -83,8 +117,11 @@
83 117
84 <div class="node_description">Body</div> 118 <div class="node_description">Body</div>
85 <div class="node_content"><%= d.text_area :body, :class => 'with_editor' %></div> 119 <div class="node_content"><%= d.text_area :body, :class => 'with_editor' %></div>
120 <% end %>
86 121
87 <div><%= d.submit 'save' %></div> 122 <div class="node_action_bar node_action_bar_save">
123 <%= f.submit 'Save Draft' %>
124 <%= f.submit 'Save + Unlock + Exit' %>
125 </div>
88 <% end %> 126 <% end %>
89<% end %>
90</div> 127</div>
diff --git a/app/views/nodes/index.html.erb b/app/views/nodes/index.html.erb
index e5a55d4..3bb251c 100644
--- a/app/views/nodes/index.html.erb
+++ b/app/views/nodes/index.html.erb
@@ -1,8 +1,12 @@
1<% content_for :subnavigation do %>
2 <%= link_to 'Create', new_node_path %>
3<% end %>
4<h1>Nodes</h1> 1<h1>Nodes</h1>
5 2
3<div>
4 <%= link_to new_node_path, class: 'action_button' do %>
5 <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create node
6 <% end %>
7 <span class="field_hint">Creates a node with no parent or kind set — for a specific page, use the wizard's create flow or "add child" from an existing node instead.</span>
8</div>
9
6<%= will_paginate @nodes %> 10<%= will_paginate @nodes %>
7 <table class="node_table"> 11 <table class="node_table">
8 <tr class="header"> 12 <tr class="header">
@@ -21,7 +25,8 @@
21 </td> 25 </td>
22 <td class="actions"> 26 <td class="actions">
23 <%= link_to 'show', node_path(node) %> 27 <%= link_to 'show', node_path(node) %>
24 <%= link_to 'Revisions', node_revisions_path(node) %> 28 <%= link_to 'edit', edit_node_path(node) %>
29 <%= link_to 'revisions', node_revisions_path(node) %>
25 </td> 30 </td>
26 <td> 31 <td>
27 <%= node.lock_owner.login if node.lock_owner %> 32 <%= node.lock_owner.login if node.lock_owner %>
diff --git a/app/views/nodes/mine.html.erb b/app/views/nodes/mine.html.erb
new file mode 100644
index 0000000..fc5680a
--- /dev/null
+++ b/app/views/nodes/mine.html.erb
@@ -0,0 +1,3 @@
1<h1>My work</h1>
2
3<%= render 'node_list' %>
diff --git a/app/views/nodes/new.html.erb b/app/views/nodes/new.html.erb
index 028d727..b63a606 100644
--- a/app/views/nodes/new.html.erb
+++ b/app/views/nodes/new.html.erb
@@ -6,48 +6,47 @@
6 </div> 6 </div>
7<% end %> 7<% end %>
8 8
9<p>What kind of node do you want to create?</p>
10
11<%= form_tag nodes_path do %> 9<%= form_tag nodes_path do %>
12<table id="new_node"> 10<div id="new_node">
13 <tr> 11
14 <td class="description">Type</td> 12 <div class="node_description">Type</div>
15 <td> 13 <div class="node_content">
16 <div> 14 <% CccConventions::NODE_KINDS.each do |kind, config| %>
17 <%= radio_button_tag :kind, "top_level" %>
18 Top Level
19 </div>
20 <p>
21 <%= radio_button_tag :kind, "generic", :selected => true %>
22 Generic ( can be created anywhere )
23 </p>
24 <p>
25 <%= radio_button_tag :kind, "update" %>
26 Update ( is automatically created in /updates/<%= Time.now.year.to_s %>/ and gets tag "update" )
27 </p>
28 <p> 15 <p>
29 <%= radio_button_tag :kind, "press_release" %> 16 <%= radio_button_tag :kind, kind, kind == @selected_kind,
30 Pressemitteilung ( is automatically created in /updates/<%= Time.now.year.to_s %>/ and gets tags "update, pressemitteilung" ) 17 data: { path_prefix: resolve_kind_text(config[:path_prefix]) } %>
18 <%= resolve_kind_text(config[:label]) %>
19 <% if config[:hint] %>
20 <span class="field_hint"><%= resolve_kind_text(config[:hint]) %></span>
21 <% end %>
31 </p> 22 </p>
32 </td> 23 <% end %>
33 </tr> 24 </div>
34 <tr> 25
35 <td class="description">Title</td> 26 <div class="node_description">Title</div>
36 <td><%= text_field_tag :title %></td> 27 <div class="node_content">
37 </tr> 28 <%= text_field_tag :title, nil, required: true %>
38 <tr id="parent_search_field"> 29 <span class="field_hint">A URL slug will be generated from this automatically. You can review or adjust it afterward under the "metadata" section's Slug field.</span>
39 <td class="description">Parent</td> 30 </div>
40 <td> 31
32 <div id="parent_search_field" style="<%= @selected_kind == "generic" ? "" : "display: none;" %>">
33 <div class="node_description">Parent</div>
34 <div class="node_content">
41 <%= text_field_tag :parent_search_term, @parent_name %> 35 <%= text_field_tag :parent_search_term, @parent_name %>
42 <%= hidden_field_tag :parent_id, @parent_id %> 36 <%= hidden_field_tag :parent_id, @parent_id %>
43 <div id="search_results"> 37 <div id="parent_search_results" class="search_results"></div>
38 </div>
39 </div>
40
41 <div class="node_description">Resulting path</div>
42 <div class="node_content">
43 <span id="resulting_path">—</span>
44 <button type="button" id="copy_resulting_path" class="unselected">copy</button>
45 <span class="field_hint">This preview updates as you type. The final path can still be changed afterward by editing the title (for the last segment) or moving the node to a different parent (for everything before it).</span>
46 </div>
47
48 <div class="node_description"></div>
49 <div class="node_content"><%= submit_tag "Create" %></div>
44 50
45 </div> 51</div>
46 </td>
47 </tr>
48 <tr>
49 <td></td>
50 <td class="right"><%= submit_tag "Create" %></td>
51 </tr>
52</table>
53<% end %> 52<% end %>
diff --git a/app/views/nodes/recent.html.erb b/app/views/nodes/recent.html.erb
new file mode 100644
index 0000000..3602775
--- /dev/null
+++ b/app/views/nodes/recent.html.erb
@@ -0,0 +1,3 @@
1<h1>Recently changed</h1>
2
3<%= render 'node_list' %>
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb
index de4d8a2..1469572 100644
--- a/app/views/nodes/show.html.erb
+++ b/app/views/nodes/show.html.erb
@@ -1,62 +1,251 @@
1<% content_for :subnavigation do %> 1<% locked_by_other = @node.locked? && @node.lock_owner != current_user %>
2 <%= link_to 'Edit', edit_node_path(@node), :class => "unselected" %> 2<div id="page_editor" class="show_node">
3 <%= link_to 'Preview', preview_page_path(@page) %> 3 <h1><%= title_for_node(@node) %> <small>(<%= I18n.default_locale.to_s.upcase %>)</small></h1>
4 <%= link_to 'Revisions', node_revisions_path(@node) %> 4 <div id="content">
5 <%= unlock_link if @node.locked? %> 5 <div class="node_description">Status</div>
6<% end %> 6 <div class="node_content node_info_group node_status">
7 <div class="node_info_group_items">
8 <div class="node_info_item">
9 <span class="node_info_label">Head</span>
10 <%= @node.head ? "#{@node.head.title} (rev #{@node.head.revision}, #{@node.head.updated_at})" : "none — never published" %>
11 </div>
12 <div class="node_info_item">
13 <span class="node_info_label">Draft</span>
14 <%= @node.draft ? "#{@node.draft.title} (rev #{@node.draft.revision}, saved #{@node.draft.updated_at})" : "none" %>
15 </div>
16 <div class="node_info_item">
17 <span class="node_info_label">Autosave</span>
18 <%= @node.autosave ? "#{@node.autosave.title} (unsaved, #{@node.autosave.updated_at})" : "none" %>
19 </div>
20 </div>
7 21
22 <% edit_label = @node.autosave ? "Continue Editing" : (@node.draft ? "Edit Draft" : "Edit") %>
23 <div class="node_info_group_items">
24 <div class="node_info_item">
25 <% if locked_by_other %>
26 <span class="disabled_action"><%= edit_label %></span>
27 <% else %>
28 <%= link_to edit_node_path(@node), class: "action_button" do %>
29 <%= icon("edit", library: "tabler", "aria-hidden": true) %>
30 <%= @node.autosave ? "Continue Editing" : (@node.draft ? "Edit Draft" : "Lock + Edit") %>
31 <% end %>
32 <% if !@node.draft && !@node.autosave %>
33 <span class="field_hint">Nothing pending — this will start a fresh draft.</span>
34 <% end %>
35 <% end %>
36 </div>
8 37
9<div id="page_editor" class="show_node"> 38 <% @node.available_layer_pairs.each do |pair| %>
10 <table id="content"> 39 <div class="node_info_item">
11 <tr> 40 <%= button_to "Diff #{pair.first.to_s.capitalize} vs. #{pair.last.to_s.capitalize}",
12 <td class="description">Public Link</td> 41 diff_node_revisions_path(@node),
13 <td><%= link_to @page.public_link, content_url(@node.unique_path) %></td> 42 method: :get,
14 </tr> 43 params: { start_revision: pair.first, end_revision: pair.last },
15 <tr> 44 form: { class: 'button_to computation' } %>
16 <td class="description">Author</td> 45 </div>
17 <td><%= @page.user.try(:login) %></td> 46 <% end %>
18 </tr> 47
19 <tr> 48 <% unless locked_by_other %>
20 <td class="description">Editor</td> 49 <% if @node.draft && !@node.autosave %>
21 <td><%= @page.editor.try(:login) %></td> 50 <div class="node_info_item">
22 </tr> 51 <%= button_to 'Publish', publish_node_path(@node), method: :put,
23 <% if @page.node.locked? %> 52 form: { data: { confirm: "Publish this draft?" }, class: 'button_to state_changing' } %>
24 <tr> 53 </div>
25 <td class="description">Locked by</td> 54 <% end %>
26 <td><span class="warning"><%= @page.node.lock_owner.login %></span></td> 55 <% if @node.autosave || (@node.draft && @node.head) %>
27 </tr> 56 <div class="node_info_item">
57 <%= button_to revert_node_path(@node), method: :put,
58 params: { return_to: request.path },
59 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %>
60 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
61 <%= @node.draft && !@node.autosave ? "Destroy Draft" : "Discard Autosave" %>
62 <% end %>
63 </div>
64 <% end %>
65 <% end %>
66 </div>
67
68 <% if locked_by_other %>
69 <span class="field_hint">Locked — see People below to unlock before editing, publishing, or discarding.</span>
70 <% end %>
71 </div>
72
73 <div class="node_description">Translations</div>
74 <div class="node_content node_info_group">
75 <div class="node_info_group_items">
76 <% @translations.each do |t| %>
77 <div class="node_info_item">
78 <span class="node_info_label"><%= t[:locale].to_s.upcase %></span>
79 <div class="aligned_action_row">
80 <% if t[:exists] %>
81 <%= link_to t[:title], node_translation_path(@node, t[:locale]) %> — updated <%= t[:updated_at] %>
82 <% if t[:outdated] %>
83 <span class="warning">may be outdated</span>
84 <% end %>
85 <% else %>
86 <span class="field_hint">Not yet translated.</span>
87 <% end %>
88 <% if locked_by_other %>
89 <span class="disabled_action"><%= t[:exists] ? "Lock + Edit" : "Create translation + Lock" %></span>
90 <% else %>
91 <%= link_to edit_node_translation_path(@node, t[:locale]), class: "action_button" do %>
92 <%= icon(t[:exists] ? "edit" : "language", library: "tabler", "aria-hidden": true) %>
93 <%= t[:exists] ? "Lock + Edit" : "Create translation + Lock" %>
94 <% end %>
95 <% if t[:exists] %>
96 <%= button_to node_translation_path(@node, t[:locale]), method: :delete,
97 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %>
98 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
99 Destroy Translation
100 <% end %>
101 <% end %>
102 <% end %>
103 </div>
104 </div>
105 <% end %>
106 </div>
107 </div>
108
109 <div class="node_description">People</div>
110 <div class="node_content node_info_group">
111 <div class="node_info_group_items">
112 <div class="node_info_item">
113 <span class="node_info_label">Author</span>
114 <%= @page.user.try(:login) %>
115 </div>
116 <div class="node_info_item">
117 <span class="node_info_label">Editor</span>
118 <%= @page.editor.try(:login) %>
119 </div>
120 <% if @node.locked? %>
121 <div class="node_info_item">
122 <span class="node_info_label">Locked by</span>
123 <span class="warning"><%= @node.lock_owner.login %></span>
124 <%= unlock_link %>
125 </div>
126 <% end %>
127 </div>
128 </div>
129
130 <div class="node_description">Dates</div>
131 <div class="node_content node_info_group">
132 <div class="node_info_group_items">
133 <div class="node_info_item">
134 <span class="node_info_label">Last updated</span>
135 <%= @page.updated_at %>
136 </div>
137 <% if @page.published_at.present? %>
138 <div class="node_info_item">
139 <span class="node_info_label"><%= @page.public? ? 'Published at' : 'Will publish at' %></span>
140 <%= @page.published_at %>
141 </div>
142 <% end %>
143 </div>
144 </div>
145
146 <div class="node_description">Links</div>
147 <div class="node_content node_info_group">
148 <div class="node_info_group_items">
149 <div class="node_info_item">
150 <span class="node_info_label">Public</span>
151 <%= link_to @page.public_link, content_url(@node.unique_path) %>
152 </div>
153 <% if @node.draft %>
154 <div class="node_info_item">
155 <span class="node_info_label">Admin Preview</span>
156 <%= link_to preview_page_path(@node.draft), preview_page_path(@node.draft) %>
157 </div>
158 <div class="node_info_item">
159 <span class="node_info_label">Public Preview</span>
160 <% if @node.draft.preview_token.present? %>
161 <div class="aligned_action_row">
162 <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %>
163 <%= button_to 'Revoke', revoke_shared_preview_node_path(@node), method: :put, form: { data: { confirm: "Revoke this preview link? Anyone currently using it will immediately lose access." }, class: 'button_to state_changing' } %>
164 </div>
165 <% else %>
166 <%= button_to 'Create public preview link', generate_shared_preview_node_path(@node), method: :put, form: { class: 'button_to state_changing' } %>
167 <% end %>
168 </div>
169 <% end %>
170 </div>
171 </div>
172
173 <div class="node_description">Revisions</div>
174 <div class="node_content node_info_group">
175 <details>
176 <summary>
177 <%= pluralize(@node.pages.count, 'revision', 'revisions') %>
178 </summary>
179 <ul>
180 <% @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>
182 <% end %>
183 </ul>
184 </details>
185 <p class="revisions_full_history_link"><%= link_to 'Full history (diff / restore)', node_revisions_path(@node) %></p>
186 </div>
187
188 <div class="node_description">Tags</div>
189 <div class="node_content node_info_group"><%= @page.tag_list %></div>
190
191 <% if @page.assets.images.any? %>
192 <div class="node_description">Images</div>
193 <div class="node_content node_info_group">
194 <ul class="thumbnail_list">
195 <% @page.assets.images.each do |asset| %>
196 <li><%= link_to image_tag(asset.upload.url(:thumb)), asset_path(asset) %></li>
197 <% end %>
198 </ul>
199 </div>
200 <% end %>
201
202 <div class="node_description">Events</div>
203 <div class="node_content node_info_group">
204 <ul>
205 <% @node.events.order(:start_time).each do |event| %>
206 <li>
207 <%= event_schedule_text(event) %>
208 [<%= link_to 'show', event_path(event, return_to: request.path) %>
209 | <%= link_to 'edit', edit_event_path(event, return_to: request.path) %>]
210 </li>
211 <% end %>
212 </ul>
213 <% mapping = default_event_tag_mapping(@page) %>
214 <%= link_to 'add event', new_event_path(node_id: @node.id, tag_list: mapping&.last, auto_tag_source: mapping&.first, return_to: request.path) %>
215 </div>
216
217 <% matches = matching_node_kinds(@node) %>
218 <% if @node.children.any? || matches.any? %>
219 <div class="node_description">Children</div>
220 <div class="node_content node_info_group">
221 <% if @node.children.any? %>
222 <details>
223 <summary><%= pluralize(@node.children.count, 'child', 'children') %></summary>
224 <ul>
225 <% @node.children.order(:slug).each do |child| %>
226 <li><%= link_to (child.head&.title || child.draft&.title || child.slug), node_path(child) %></li>
227 <% end %>
228 </ul>
229 </details>
230 <% end %>
231 <% if matches.any? %>
232 <p class="add_child_links">
233 <% matches.each_with_index do |(kind, config), index| %>
234 <%= " &middot; ".html_safe if index > 0 %>
235 <% link_params = { kind: kind } %>
236 <% link_params[:parent_id] = @node.id if kind == "generic" %>
237 <%= link_to "add '#{resolve_kind_text(config[:label])}' child", new_node_path(link_params) %>
238 <% end %>
239 </p>
240 <% end %>
241 </div>
28 <% end %> 242 <% end %>
29 <tr> 243
30 <td class="description">Last updated</td> 244 <div class="node_description">Abstract (<%= I18n.default_locale.to_s.upcase %>)</div>
31 <td><%= @page.updated_at %></td> 245 <div class="node_content"><%= sanitize(@page.abstract) %></div>
32 </tr> 246
33 <tr> 247 <div class="node_description">Body (<%= I18n.default_locale.to_s.upcase %>)</div>
34 <td class="description">Published at</td> 248 <div class="node_content"><%= sanitize(@page.body) %></div>
35 <td><%= @page.published_at %></td> 249
36 </tr> 250 </div>
37 <tr> 251</div>
38 <td class="description">Revision</td>
39 <td><%= @page.revision %></td>
40 </tr>
41 <tr>
42 <td class="description">Tagged with:</td>
43 <td><%= @page.tag_list %></td>
44 </tr>
45 <tr>
46 <td class="description"><strong>Title</strong></td>
47 <td><%= sanitize( @page.title ) %></td>
48 </tr>
49 <tr>
50 <td class="description"><strong>Abstract</strong></td>
51 <td><%= sanitize( @page.abstract ) %></td>
52 </tr>
53 <tr>
54 <td class="description"><strong>Body</strong></td>
55 <td><%= sanitize( @page.body ) %></td>
56 </tr>
57 <tr>
58 <td></td>
59 <td class="right"></td>
60 </tr>
61 </table>
62</div> \ No newline at end of file
diff --git a/app/views/nodes/sitemap.html.erb b/app/views/nodes/sitemap.html.erb
new file mode 100644
index 0000000..a799c17
--- /dev/null
+++ b/app/views/nodes/sitemap.html.erb
@@ -0,0 +1,32 @@
1<h1>Sitemap</h1>
2
3<div id="sitemap">
4<%
5 open_details = [] # levels with a currently-open <details>
6%>
7<% @sitemap.each_with_index do |(node, level), index| %>
8 <% while open_details.any? && open_details.last >= level %>
9 </details>
10 <% open_details.pop %>
11 <% end %>
12
13 <div class="sitemap_node">
14 <h4><%= link_to title_for_node(node), node_path(node) %></h4>
15 <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span>
16 <p class="sitemap_node_actions">
17 <%= link_to 'Show', node_path(node) %>
18 <%= link_to 'Create Child', new_node_path(:parent_id => node.id) %>
19 </p>
20 </div>
21
22 <% next_level = @sitemap[index + 1]&.last %>
23 <% if next_level && next_level > level %>
24 <details<%= ' open' if sitemap_node_open?(node) %>>
25 <summary>
26 <%= pluralize(@sitemap_descendant_counts[node.id], 'descendant', 'descendants') %>
27 </summary>
28 <% open_details.push(level) %>
29 <% end %>
30<% end %>
31<% open_details.length.times { %></details><% } %>
32</div>
diff --git a/app/views/nodes/tags.html.erb b/app/views/nodes/tags.html.erb
new file mode 100644
index 0000000..0ebc6ce
--- /dev/null
+++ b/app/views/nodes/tags.html.erb
@@ -0,0 +1,3 @@
1<h1>Nodes tagged: <%= params[:tags] %></h1>
2
3<%= render 'node_list' %>