diff options
Diffstat (limited to 'app/views/nodes')
| -rw-r--r-- | app/views/nodes/_node_list.html.erb | 41 | ||||
| -rw-r--r-- | app/views/nodes/chapters.html.erb | 11 | ||||
| -rw-r--r-- | app/views/nodes/drafts.html.erb | 3 | ||||
| -rw-r--r-- | app/views/nodes/edit.html.erb | 153 | ||||
| -rw-r--r-- | app/views/nodes/index.html.erb | 13 | ||||
| -rw-r--r-- | app/views/nodes/mine.html.erb | 3 | ||||
| -rw-r--r-- | app/views/nodes/new.html.erb | 75 | ||||
| -rw-r--r-- | app/views/nodes/recent.html.erb | 3 | ||||
| -rw-r--r-- | app/views/nodes/show.html.erb | 307 | ||||
| -rw-r--r-- | app/views/nodes/sitemap.html.erb | 32 | ||||
| -rw-r--r-- | app/views/nodes/tags.html.erb | 3 |
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 | <%= " · ".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' %> | ||
