diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 23:33:11 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 23:33:11 +0200 |
| commit | 8eab68f2c5a3c126e2fec2ecdfa7ace87ce0937b (patch) | |
| tree | f446ebc26a7707c7b64a937aa51a155df146c80a /app/views | |
| parent | 42714c697273a7117c6b355fab26c8c35e336ad1 (diff) | |
| parent | cdf5d9941ca866d437612d2f863eac6eb0b3db12 (diff) | |
Merge branch 'erdgeist-revive-events'
Diffstat (limited to 'app/views')
46 files changed, 1428 insertions, 817 deletions
diff --git a/app/views/admin/_drafts.html.erb b/app/views/admin/_drafts.html.erb index a35b0ab..4ef568f 100644 --- a/app/views/admin/_drafts.html.erb +++ b/app/views/admin/_drafts.html.erb | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | <td class="actions"> | 17 | <td class="actions"> |
| 18 | <%= link_to 'Show', node_path(draft.node) %> | 18 | <%= link_to 'Show', node_path(draft.node) %> |
| 19 | <%= link_to "Revisions", revision_path(draft.node.id) %> | 19 | <%= link_to "Revisions", revision_path(draft.node.id) %> |
| 20 | <%= button_to "Publish", publish_node_path(draft.node), method: :put, form: { data: { confirm: "Do you really want to publish?" } } %> | 20 | <%= button_to "Publish", publish_node_path(draft.node), method: :put, form: { data: { confirm: "Do you really want to publish?" }, class: 'button_to state_changing' } %> |
| 21 | </td> | 21 | </td> |
| 22 | </tr> | 22 | </tr> |
| 23 | <% end %> | 23 | <% end %> |
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 6dba085..970429d 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb | |||
| @@ -1,8 +1,5 @@ | |||
| 1 | <%= language_selector %> | 1 | <%= link_to icon("home", library: "tabler", "aria-hidden": true), admin_path, "aria-label": "Dashboard" %> |
| 2 | <%= button_to 'Logout', logout_path, method: :delete %> | 2 | <a href="#" onclick="admin_search.display_toggle(); return false;" aria-label="Search"><%= icon("search", library: "tabler", "aria-hidden": true) %></a> |
| 3 | <%= link_to 'Overview', admin_path %> | 3 | <%= button_to logout_path, method: :delete, aria: { label: "Log out" } do %> |
| 4 | <a href="#" onclick="admin_search.display_toggle(); return false;">search</a> | 4 | <%= icon("logout", library: "tabler", "aria-hidden": true) %> |
| 5 | <%= link_to 'Nodes', nodes_path, selected?('nodes') %> | 5 | <% end %> |
| 6 | <%= link_to 'Assets', assets_path, selected?('assets') %> | ||
| 7 | <%= link_to 'User', users_path, selected?('users') %> | ||
| 8 | <%= link_to 'Navigation', menu_items_path, selected?('menu_items') %> > | ||
diff --git a/app/views/admin/conventions.html.erb b/app/views/admin/conventions.html.erb new file mode 100644 index 0000000..72f6214 --- /dev/null +++ b/app/views/admin/conventions.html.erb | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | <h1>Node creation conventions</h1> | ||
| 2 | |||
| 3 | <table id="conventions"> | ||
| 4 | <tr><th>Kind</th><th>What happens</th></tr> | ||
| 5 | <% @node_kinds.each do |kind, config| %> | ||
| 6 | <tr> | ||
| 7 | <td><%= kind %></td> | ||
| 8 | <td><%= resolve_kind_text(config[:label]) %> — <%= resolve_kind_text(config[:hint]) %></td> | ||
| 9 | </tr> | ||
| 10 | <% end %> | ||
| 11 | </table> | ||
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb index 2741db3..bdb555e 100644 --- a/app/views/admin/index.html.erb +++ b/app/views/admin/index.html.erb | |||
| @@ -1,147 +1,81 @@ | |||
| 1 | <div id="admin_wizard"> | 1 | <h1>cccms dashboard</h1> |
| 2 | <div class="admin_wizard_button"><%= link_to 'Create Update or Pressemitteilung', new_node_path, :only_path => false %></div> | 2 | <div id="dashboard_search"> |
| 3 | <div class="admin_wizard_button"><a href="#" id="admin_wizard_my_work" class="button">Continue my work</a></div> | 3 | <%= form_tag admin_search_path, method: :get do %> |
| 4 | <div class="admin_wizard_button"><a href="#" id="admin_wizard_create_page" class="button">Add a page in the page tree</a></div> | 4 | <%= text_field_tag :search_term, nil, id: "dashboard_search_term", placeholder: "Search nodes and tags…", autocomplete: "off" %> |
| 5 | <div class="admin_wizard_button"><%= link_to("Upload a new asset", new_asset_path, :only_path => false) %></div> | 5 | <% end %> |
| 6 | <div id="dashboard_search_results" class="search_results"></div> | ||
| 6 | </div> | 7 | </div> |
| 7 | 8 | ||
| 8 | <p id="overview_toggle"> | 9 | <div id="dashboard_signposts" class="button_row"> |
| 9 | <a href="#" id="recent_changes_toggle" class="button">recent changes</a> | 10 | <%= link_to new_node_path, class: "action_button" do %> |
| 10 | <a href="#" id="my_work_toggle" class="button">my work</a> | 11 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create post |
| 11 | <a href="#" id="current_drafts_toggle" class="button">current drafts (<%= @drafts_count %>)</a> | 12 | <% end %> |
| 12 | <a href="#" id="admin_sitemap_toggle" class="button">site map</a> | 13 | <%= link_to chapters_nodes_path, class: "action_button" do %> |
| 13 | </p> | 14 | <%= icon("map-pin", library: "tabler", "aria-hidden": true) %> Find a chapter |
| 15 | <% end %> | ||
| 16 | <%= link_to new_asset_path, class: "action_button" do %> | ||
| 17 | <%= icon("upload", library: "tabler", "aria-hidden": true) %> Upload asset | ||
| 18 | <% end %> | ||
| 19 | <%= link_to sitemap_nodes_path, class: "action_button" do %> | ||
| 20 | <%= icon("list-tree", library: "tabler", "aria-hidden": true) %> Add a page in the page tree | ||
| 21 | <% end %> | ||
| 22 | </div> | ||
| 14 | 23 | ||
| 15 | <div id="recent_changes_table"> | 24 | <div id="dashboard_widgets"> |
| 16 | 25 | <div class="dashboard_widget"> | |
| 17 | <h1>Recent Changes</h1> | 26 | <h3>Drafts and autosaves</h3> |
| 27 | <ul> | ||
| 28 | <% @drafts.each do |node| %> | ||
| 29 | <li> | ||
| 30 | <div> | ||
| 31 | <%= link_to title_for_node(node), node_path(node) %> | ||
| 32 | <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span> | ||
| 33 | </div> | ||
| 34 | <span class="dashboard_widget_meta"> | ||
| 35 | <% if (editor = node_last_editor(node)) %><%= editor %>, <% end %><%= relative_time_phrase(node.updated_at) %> | ||
| 36 | </span> | ||
| 37 | </li> | ||
| 38 | <% end %> | ||
| 39 | </ul> | ||
| 40 | <%= link_to "See all drafts →", drafts_nodes_path %> | ||
| 41 | </div> | ||
| 18 | 42 | ||
| 19 | <table class="node_table"> | 43 | <div class="dashboard_widget"> |
| 20 | <tr class="header"> | 44 | <h3>Recent changes</h3> |
| 21 | <th class="node_id">ID</th> | 45 | <ul> |
| 22 | <th class="title">Title</th> | ||
| 23 | <th class="actions">Actions</th> | ||
| 24 | <th class="editor">Locked by</th> | ||
| 25 | <th class="revision">Rev.</th> | ||
| 26 | </tr> | ||
| 27 | <% @recent_changes.each do |node| %> | 46 | <% @recent_changes.each do |node| %> |
| 28 | <tr class="<%= cycle("even", "odd") %>"> | 47 | <li> |
| 29 | <td class="node_id"><%= node.id %></td> | 48 | <div> |
| 30 | <td class="title"> | 49 | <%= link_to title_for_node(node), node_path(node) %> |
| 31 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | 50 | <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span> |
| 32 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | 51 | </div> |
| 33 | </td> | 52 | <span class="dashboard_widget_meta"> |
| 34 | <td class="actions"> | 53 | <%= (editor = node_head_editor(node)) ? t("published_by", editor: editor) : t("published") %>, <%= relative_time_phrase(node.head.updated_at) %> |
| 35 | <%= link_to 'show', node_path(node) %> | 54 | </span> |
| 36 | <%= link_to 'Revisions', node_revisions_path(node) %> | 55 | </li> |
| 37 | </td> | ||
| 38 | <td> | ||
| 39 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 40 | </td> | ||
| 41 | <td> | ||
| 42 | <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %> | ||
| 43 | </td> | ||
| 44 | </tr> | ||
| 45 | <% end %> | 56 | <% end %> |
| 46 | </table> | 57 | </ul> |
| 58 | <%= link_to "See all recent changes →", recent_nodes_path %> | ||
| 59 | </div> | ||
| 47 | </div> | 60 | </div> |
| 48 | 61 | ||
| 49 | <div id="my_work_table"> | 62 | <div id="dashboard_housekeeping"> |
| 50 | 63 | <h3>Housekeeping</h3> | |
| 51 | <h1>My Work</h1> | 64 | <div class="button_row"> |
| 52 | 65 | <%= link_to nodes_path, class: "action_button" do %> | |
| 53 | <table class="node_table"> | 66 | <%= icon("list", library: "tabler", "aria-hidden": true) %> Nodes |
| 54 | <tr class="header"> | ||
| 55 | <th class="node_id">ID</th> | ||
| 56 | <th class="title">Title</th> | ||
| 57 | <th class="actions">Actions</th> | ||
| 58 | <th class="editor">Locked by</th> | ||
| 59 | <th class="revision">Rev.</th> | ||
| 60 | </tr> | ||
| 61 | <% @mynodes.each do |node| %> | ||
| 62 | <tr class="<%= cycle("even", "odd") %>"> | ||
| 63 | <td class="node_id"><%= node.id %></td> | ||
| 64 | <td class="title"> | ||
| 65 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | ||
| 66 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | ||
| 67 | </td> | ||
| 68 | <td class="actions"> | ||
| 69 | <%= link_to 'show', node_path(node) %> | ||
| 70 | <%= link_to 'Revisions', node_revisions_path(node) %> | ||
| 71 | </td> | ||
| 72 | <td> | ||
| 73 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 74 | </td> | ||
| 75 | <td> | ||
| 76 | <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %> | ||
| 77 | </td> | ||
| 78 | </tr> | ||
| 79 | <% end %> | 67 | <% end %> |
| 80 | </table> | 68 | <%= link_to events_path, class: "action_button" do %> |
| 81 | </div> | 69 | <%= icon("calendar", library: "tabler", "aria-hidden": true) %> Events |
| 82 | |||
| 83 | <div id="current_drafts_table"> | ||
| 84 | |||
| 85 | <h1>Current Drafts (<%= @drafts_count %>)</h1> | ||
| 86 | |||
| 87 | <table class="node_table"> | ||
| 88 | <tr class="header"> | ||
| 89 | <th class="node_id">ID</th> | ||
| 90 | <th class="title">Title</th> | ||
| 91 | <th class="actions">Actions</th> | ||
| 92 | <th class="editor">Locked by</th> | ||
| 93 | <th class="revision">Rev.</th> | ||
| 94 | </tr> | ||
| 95 | <% @drafts.each do |node| %> | ||
| 96 | <tr class="<%= cycle("even", "odd") %>"> | ||
| 97 | <td class="node_id"><%= node.id %></td> | ||
| 98 | <td class="title"> | ||
| 99 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | ||
| 100 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | ||
| 101 | </td> | ||
| 102 | <td class="actions"> | ||
| 103 | <%= link_to 'show', node_path(node) %> | ||
| 104 | <%= link_to 'Revisions', node_revisions_path(node) %> | ||
| 105 | </td> | ||
| 106 | <td> | ||
| 107 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 108 | </td> | ||
| 109 | <td> | ||
| 110 | <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %> | ||
| 111 | </td> | ||
| 112 | </tr> | ||
| 113 | <% end %> | 70 | <% end %> |
| 114 | </table> | 71 | <%= link_to assets_path, class: "action_button" do %> |
| 115 | </div> | 72 | <%= icon("folder", library: "tabler", "aria-hidden": true) %> Assets |
| 116 | 73 | <% end %> | |
| 117 | <div id="admin_sitemap_table"> | 74 | <%= link_to users_path, class: "action_button" do %> |
| 118 | 75 | <%= icon("users", library: "tabler", "aria-hidden": true) %> Users | |
| 119 | <h1>Sitemap</h1> | ||
| 120 | |||
| 121 | <table class="node_table"> | ||
| 122 | <tr class="header"> | ||
| 123 | <th class="node_id">ID</th> | ||
| 124 | <th class="title">Title</th> | ||
| 125 | <th class="actions">Actions</th> | ||
| 126 | <th class="editor">Locked by</th> | ||
| 127 | </tr> | ||
| 128 | <% @sitemap.each do |node| %> | ||
| 129 | <% if !node.nil? %> | ||
| 130 | <tr class="<%= cycle("even", "odd") %>"> | ||
| 131 | <td class="node_id" style="padding-left: <%= @sitemap_depth[node.id] * 30 %>px;"><%= node.id %></td> | ||
| 132 | <td class="title" style="padding-left: <%= @sitemap_depth[node.id] * 30 %>px;"> | ||
| 133 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | ||
| 134 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | ||
| 135 | </td> | ||
| 136 | <td class="actions"> | ||
| 137 | <%= link_to 'create subpage', new_node_path(:parent_id => node.id) %> | ||
| 138 | <%= link_to 'Revisions', node_revisions_path(node) %> | ||
| 139 | </td> | ||
| 140 | <td> | ||
| 141 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 142 | </td> | ||
| 143 | </tr> | ||
| 144 | <% end %> | 76 | <% end %> |
| 77 | <%= link_to menu_items_path, class: "action_button" do %> | ||
| 78 | <%= icon("menu-2", library: "tabler", "aria-hidden": true) %> Navigation | ||
| 145 | <% end %> | 79 | <% end %> |
| 146 | </table> | 80 | </div> |
| 147 | </div> | 81 | </div> |
diff --git a/app/views/admin/search_results.html.erb b/app/views/admin/search_results.html.erb index f8aece0..a757197 100644 --- a/app/views/admin/search_results.html.erb +++ b/app/views/admin/search_results.html.erb | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | <h1>Search Results</h1> | 1 | <h1>Search Results</h1> |
| 2 | 2 | ||
| 3 | <ul> | 3 | <ul class="search_results_list"> |
| 4 | <%- @results.each do |result| %> | 4 | <% @results.each do |result| %> |
| 5 | <li><%= link_to "#{result.title} (#{result.unique_name})", edit_node_path(result) %></li> | 5 | <li> |
| 6 | <% end %> | 6 | <%= link_to title_for_node(result), node_path(result) %> |
| 7 | <span class="field_hint"><%= link_to_path("#{result.unique_name} ↗", result.unique_name) %></span> | ||
| 8 | </li> | ||
| 9 | <% end %> | ||
| 7 | </ul> | 10 | </ul> |
diff --git a/app/views/assets/index.html.erb b/app/views/assets/index.html.erb index 51fc486..8c35561 100644 --- a/app/views/assets/index.html.erb +++ b/app/views/assets/index.html.erb | |||
| @@ -1,12 +1,19 @@ | |||
| 1 | <% content_for :subnavigation do %> | 1 | <h1>Assets</h1> |
| 2 | <%= link_to 'New asset', new_asset_path %> | ||
| 3 | <% end %> | ||
| 4 | 2 | ||
| 3 | <%= link_to new_asset_path, class: 'action_button' do %> | ||
| 4 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create asset | ||
| 5 | <% end %> | ||
| 5 | 6 | ||
| 6 | <%= will_paginate @assets %> | 7 | <%= will_paginate @assets %> |
| 7 | 8 | ||
| 8 | <table> | 9 | <table class="assets_table"> |
| 9 | <tr> | 10 | <tr class="header"> |
| 11 | <th>Preview</th> | ||
| 12 | <th>Name</th> | ||
| 13 | <th>Type</th> | ||
| 14 | <th></th> | ||
| 15 | <th></th> | ||
| 16 | <th></th> | ||
| 10 | </tr> | 17 | </tr> |
| 11 | <% @assets.each do |asset| %> | 18 | <% @assets.each do |asset| %> |
| 12 | <tr> | 19 | <tr> |
| @@ -15,7 +22,9 @@ | |||
| 15 | <td><%= asset.upload.content_type %></td> | 22 | <td><%= asset.upload.content_type %></td> |
| 16 | <td><%= link_to 'Show', asset %></td> | 23 | <td><%= link_to 'Show', asset %></td> |
| 17 | <td><%= link_to 'Edit', edit_asset_path(asset) %></td> | 24 | <td><%= link_to 'Edit', edit_asset_path(asset) %></td> |
| 18 | <td><%= button_to 'Destroy', asset, method: :delete, form: { data: { confirm: 'Are you sure?' } } %></td> | 25 | <td><%= button_to asset, method: :delete, form: { data: { confirm: 'Are you sure?' }, class: 'button_to destructive' } do %> |
| 26 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy | ||
| 27 | <% end %></td> | ||
| 19 | </tr> | 28 | </tr> |
| 20 | <% end %> | 29 | <% end %> |
| 21 | </table> | 30 | </table> |
diff --git a/app/views/assets/show.html.erb b/app/views/assets/show.html.erb index 694be5a..5717dd9 100644 --- a/app/views/assets/show.html.erb +++ b/app/views/assets/show.html.erb | |||
| @@ -1,23 +1,31 @@ | |||
| 1 | <% content_for :subnavigation do %> | 1 | <div id="page_editor"> |
| 2 | <%= link_to 'Edit', edit_asset_path(@asset) %> | 2 | <h1><%= @asset.name %></h1> |
| 3 | <%= link_to 'Back', assets_path %> | ||
| 4 | <% end %> | ||
| 5 | 3 | ||
| 6 | <table> | 4 | <div id="content"> |
| 7 | <tr> | 5 | <div class="node_description">Actions</div> |
| 8 | <td>Thumbnail</td> | 6 | <div class="node_content node_info_group"> |
| 9 | <td><%= image_tag @asset.upload.url(:medium), style: "max-width: 300px; max-height: 300px;" %></td> | 7 | <div class="node_info_group_items"> |
| 10 | </tr> | 8 | <div class="node_info_item"> |
| 11 | <tr> | 9 | <%= link_to edit_asset_path(@asset), class: 'action_button' do %> |
| 12 | <td>Public Path</td> | 10 | <%= icon("edit", library: "tabler", "aria-hidden": true) %> Edit |
| 13 | <td><%= @asset.upload.url.sub(/\?\d+$/, "") %></td> | 11 | <% end %> |
| 14 | </tr> | 12 | </div> |
| 15 | <tr> | 13 | <div class="node_info_item"> |
| 16 | <td>Content Type</td> | 14 | <%= link_to 'Back', assets_path %> |
| 17 | <td><%= @asset.upload.content_type %></td> | 15 | </div> |
| 18 | </tr> | 16 | </div> |
| 19 | <tr> | 17 | </div> |
| 20 | <td>Size</td> | 18 | |
| 21 | <td><%= "#{@asset.upload.size/1024} KB" %></td> | 19 | <div class="node_description">Thumbnail</div> |
| 22 | </tr> | 20 | <div class="node_content"><%= image_tag @asset.upload.url(:medium), style: "max-width: 300px; max-height: 300px;" %></div> |
| 23 | </table> | 21 | |
| 22 | <div class="node_description">Public Path</div> | ||
| 23 | <div class="node_content"><%= @asset.upload.url.sub(/\?\d+$/, "") %></div> | ||
| 24 | |||
| 25 | <div class="node_description">Content Type</div> | ||
| 26 | <div class="node_content"><%= @asset.upload.content_type %></div> | ||
| 27 | |||
| 28 | <div class="node_description">Size</div> | ||
| 29 | <div class="node_content"><%= "#{@asset.upload.size/1024} KB" %></div> | ||
| 30 | </div> | ||
| 31 | </div> | ||
diff --git a/app/views/content/_open_erfas_today.html.erb b/app/views/content/_open_erfas_today.html.erb new file mode 100644 index 0000000..468bedc --- /dev/null +++ b/app/views/content/_open_erfas_today.html.erb | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | <div id="open_erfas_today"> | ||
| 2 | <h2><%= t(:open_today) %></h2> | ||
| 3 | <ul class="teasertext"> | ||
| 4 | <% occurrences.each do |occurrence| %> | ||
| 5 | <li> | ||
| 6 | <%= link_to_path occurrence.node.head.title, occurrence.node.unique_name %> | ||
| 7 | <span class="event_time"><%= weekday_abbr(occurrence.start_time) %> <%= occurrence.start_time.strftime("%H:%M") %></span> | ||
| 8 | </li> | ||
| 9 | <% end %> | ||
| 10 | </ul> | ||
| 11 | </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 new file mode 100644 index 0000000..f47353c --- /dev/null +++ b/app/views/custom/page_templates/public/chapter_detail.html.erb | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | <div class="article" lang="<%= @page.effective_lang %>"> | ||
| 2 | <h2 class="headline"><%= @page.title %></h2> | ||
| 3 | <% 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 | <% end %> | ||
| 6 | <p><%= sanitize(@page.abstract) %></p> | ||
| 7 | <%= aggregate?(@page.body) %> | ||
| 8 | <% open_days = @page.node.events.tagged_with('open-day').order(:start_time) %> | ||
| 9 | <% other_events = @page.node.events.where.not(id: open_days.map(&:id)).order(:start_time) %> | ||
| 10 | <% if open_days.any? %> | ||
| 11 | <div class="chapter_events open_days"> | ||
| 12 | <h3><%= t(:open_days) %></h3> | ||
| 13 | <ul> | ||
| 14 | <% open_days.each do |event| %> | ||
| 15 | <li><%= event_schedule_text(event) %></li> | ||
| 16 | <% end %> | ||
| 17 | </ul> | ||
| 18 | </div> | ||
| 19 | <% end %> | ||
| 20 | <% if other_events.any? %> | ||
| 21 | <div class="chapter_events"> | ||
| 22 | <h3><%= t(:upcoming_events) %></h3> | ||
| 23 | <ul> | ||
| 24 | <% other_events.each do |event| %> | ||
| 25 | <li> | ||
| 26 | <span class="event_title"><%= event.display_title %></span> | ||
| 27 | <span class="event_schedule"><%= event_schedule_text(event) %></span> | ||
| 28 | </li> | ||
| 29 | <% end %> | ||
| 30 | </ul> | ||
| 31 | </div> | ||
| 32 | <% end %> | ||
| 33 | </div> | ||
diff --git a/app/views/custom/partials/_chapter.html.erb b/app/views/custom/partials/_chapter.html.erb new file mode 100644 index 0000000..805559b --- /dev/null +++ b/app/views/custom/partials/_chapter.html.erb | |||
| @@ -0,0 +1,19 @@ | |||
| 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> | ||
| 3 | <% if page.abstract.present? %> | ||
| 4 | <div class="chapter_location"><%= page.abstract %></div> | ||
| 5 | <% end %> | ||
| 6 | <% if page.node.external_url.present? %> | ||
| 7 | <div class="chapter_url"><%= link_to page.node.external_url, page.node.external_url, target: '_blank', rel: 'noopener' %></div> | ||
| 8 | <% end %> | ||
| 9 | <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %> | ||
| 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 %> | ||
| 16 | </div> | ||
| 17 | <% end %> | ||
| 18 | <p class="excerpt"><%= sanitize page.body %></p> | ||
| 19 | </div> | ||
diff --git a/app/views/events/edit.html.erb b/app/views/events/edit.html.erb index 17457df..b6564a4 100644 --- a/app/views/events/edit.html.erb +++ b/app/views/events/edit.html.erb | |||
| @@ -1,53 +1,97 @@ | |||
| 1 | <% content_for :subnavigation do %> | ||
| 2 | <%= link_to 'back', safe_return_to(params[:return_to] || events_path) %> | ||
| 3 | <% if @event.node %> | ||
| 4 | <%= link_to 'node', edit_node_path(@event.node) %> | ||
| 5 | <% end %> | ||
| 6 | <%= link_to 'show', @event %> | ||
| 7 | <% end %> | ||
| 8 | |||
| 9 | <h1>Editing event</h1> | 1 | <h1>Editing event</h1> |
| 10 | 2 | ||
| 3 | <div class="node_action_bar standalone_action_bar"> | ||
| 4 | <%= link_to 'Back', safe_return_to(params[:return_to] || events_path) %> | ||
| 5 | <%= button_to event_path(@event), method: :delete, | ||
| 6 | form: { data: { confirm: 'Delete this event?' }, class: 'button_to destructive' } do %> | ||
| 7 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy | ||
| 8 | <% end %> | ||
| 9 | </div> | ||
| 10 | |||
| 11 | <%= form_for(@event) do |f| %> | 11 | <%= form_for(@event) do |f| %> |
| 12 | <%= hidden_field_tag :return_to, @return_to %> | 12 | <%= hidden_field_tag :return_to, @return_to %> |
| 13 | <%= form_error_messages(f) %> | 13 | <%= form_error_messages(f) %> |
| 14 | 14 | ||
| 15 | <p> | 15 | <div id="page_editor"> |
| 16 | <%= f.label :start_time %><br /> | 16 | <div id="content"> |
| 17 | <%= f.datetime_select :start_time %> | 17 | <div class="node_description">Node</div> |
| 18 | </p> | 18 | <div class="node_content"> |
| 19 | <p> | 19 | <% if @event.node %> |
| 20 | <%= f.label :end_time %><br /> | 20 | <%= link_to @event.node.title, node_path(@event.node) %> |
| 21 | <%= f.datetime_select :end_time %> | 21 | <details> |
| 22 | </p> | 22 | <summary>Change node</summary> |
| 23 | <p> | 23 | <%= text_field_tag :event_node_search_term %> |
| 24 | <%= f.label :rrule %><br /> | 24 | <div id="event_search_results" class="search_results"></div> |
| 25 | <%= f.text_field :rrule %> | 25 | <span class="field_hint">This will re-link the event to a different node — rarely needed.</span> |
| 26 | </p> | 26 | </details> |
| 27 | <p> | 27 | <% else %> |
| 28 | <%= f.label :custom_rrule %><br /> | 28 | <%= text_field_tag :event_node_search_term %> |
| 29 | <%= f.check_box :custom_rrule %> | 29 | <div id="event_search_results" class="search_results"></div> |
| 30 | </p> | 30 | <span class="field_hint">Optional — search and pick a node to associate this event with a page.</span> |
| 31 | <p> | 31 | <% end %> |
| 32 | <%= f.label :allday %><br /> | 32 | <%= f.hidden_field :node_id %> |
| 33 | <%= f.check_box :allday %> | 33 | </div> |
| 34 | </p> | 34 | |
| 35 | <p> | 35 | <div class="node_description">Start time</div> |
| 36 | <%= f.label :url %><br /> | 36 | <div class="node_content"><%= f.datetime_select :start_time %></div> |
| 37 | <%= f.text_field :url %> | 37 | |
| 38 | </p> | 38 | <div class="node_description">End time</div> |
| 39 | <p> | 39 | <div class="node_content"><%= f.datetime_select :end_time %></div> |
| 40 | <%= f.label :latitude %><br /> | 40 | |
| 41 | <%= f.text_field :latitude %> | 41 | <div class="node_description">Recurrence</div> |
| 42 | </p> | 42 | <div class="node_content"> |
| 43 | <p> | 43 | <div id="rrule_builder"> |
| 44 | <%= f.label :longitude %><br /> | 44 | <p> |
| 45 | <%= f.text_field :longitude %> | 45 | <label><%= radio_button_tag "rrule_freq", "weekly", true %> Weekly</label> |
| 46 | </p> | 46 | <label><%= radio_button_tag "rrule_freq", "monthly" %> Monthly</label> |
| 47 | <p> | 47 | </p> |
| 48 | <%= f.hidden_field :node_id %> | 48 | <div id="rrule_weekly_options"> |
| 49 | </p> | 49 | <p><label><%= check_box_tag "rrule_biweekly" %> Every 2 weeks</label></p> |
| 50 | <p> | 50 | <p> |
| 51 | <%= f.submit 'Update' %> | 51 | <% %w[MO TU WE TH FR SA SU].each do |code| %> |
| 52 | </p> | 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> | ||
| 71 | |||
| 72 | <div class="node_description">Title</div> | ||
| 73 | <div class="node_content"> | ||
| 74 | <%= f.text_field :title %> | ||
| 75 | <span id="event_title_hint" class="field_hint">Optional — if left blank, the associated node's title is used.</span> | ||
| 76 | </div> | ||
| 77 | |||
| 78 | <div class="node_description">Tags</div> | ||
| 79 | <div class="node_content"><%= f.text_field :tag_list %></div> | ||
| 80 | |||
| 81 | <div class="node_description">Allday</div> | ||
| 82 | <div class="node_content"><%= f.check_box :allday %></div> | ||
| 83 | |||
| 84 | <div class="node_description">Url</div> | ||
| 85 | <div class="node_content"><%= f.text_field :url %></div> | ||
| 86 | |||
| 87 | <div class="node_description">Latitude</div> | ||
| 88 | <div class="node_content"><%= f.text_field :latitude %></div> | ||
| 89 | |||
| 90 | <div class="node_description">Longitude</div> | ||
| 91 | <div class="node_content"><%= f.text_field :longitude %></div> | ||
| 92 | |||
| 93 | <div class="node_description"></div> | ||
| 94 | <div class="node_content"><%= f.submit 'Update' %></div> | ||
| 95 | </div> | ||
| 96 | </div> | ||
| 53 | <% end %> | 97 | <% end %> |
diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb index 19b21ce..dde897e 100644 --- a/app/views/events/index.html.erb +++ b/app/views/events/index.html.erb | |||
| @@ -1,36 +1,40 @@ | |||
| 1 | <h1>Listing events</h1> | 1 | <h1>Events</h1> |
| 2 | 2 | ||
| 3 | <table> | 3 | <div class="button_row"> |
| 4 | <tr> | 4 | <%= link_to new_event_path, class: 'action_button' do %> |
| 5 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create event | ||
| 6 | <% end %> | ||
| 7 | <%= link_to 'View events without a page →', without_node_events_path %> | ||
| 8 | </div> | ||
| 9 | |||
| 10 | <%= will_paginate @events %> | ||
| 11 | |||
| 12 | <table class="events_table"> | ||
| 13 | <tr class="header"> | ||
| 14 | <th>Title</th> | ||
| 5 | <th>Start time</th> | 15 | <th>Start time</th> |
| 6 | <th>End time</th> | 16 | <th>End time</th> |
| 7 | <th>Rrule</th> | 17 | <th>Rrule</th> |
| 8 | <th>Custom rrule</th> | ||
| 9 | <th>Allday</th> | 18 | <th>Allday</th> |
| 10 | <th>Url</th> | 19 | <th>Url</th> |
| 11 | <th>Latitude</th> | ||
| 12 | <th>Longitude</th> | ||
| 13 | <th>Node</th> | 20 | <th>Node</th> |
| 21 | <th></th> | ||
| 14 | </tr> | 22 | </tr> |
| 15 | 23 | ||
| 16 | <% @events.each do |event| %> | 24 | <% @events.each do |event| %> |
| 17 | <tr> | 25 | <tr> |
| 26 | <td><%= link_to event.display_title, event %></td> | ||
| 18 | <td><%=h event.start_time %></td> | 27 | <td><%=h event.start_time %></td> |
| 19 | <td><%=h event.end_time %></td> | 28 | <td><%=h event.end_time %></td> |
| 20 | <td><%=h event.rrule %></td> | 29 | <td class="rrule_cell"><span class="rrule_text"><%= rrule_with_break_opportunities(event.rrule) %></span></td> |
| 21 | <td><%=h event.custom_rrule %></td> | ||
| 22 | <td><%=h event.allday %></td> | 30 | <td><%=h event.allday %></td> |
| 23 | <td><%=h event.url %></td> | 31 | <td class="url_cell"> |
| 24 | <td><%=h event.latitude %></td> | 32 | <% if event.url.present? %> |
| 25 | <td><%=h event.longitude %></td> | 33 | <span class="truncate"><%= link_to event.url, event.url %></span> |
| 26 | <td><%=h event.node_id %></td> | 34 | <% end %> |
| 27 | <td><%= link_to 'Show', event %></td> | 35 | </td> |
| 28 | <td><%= link_to 'Edit', edit_event_path(event) %></td> | 36 | <td><%= event.node ? link_to(event.node_id, node_path(event.node)) : '' %></td> |
| 29 | <td><%= button_to 'Destroy', event, method: :delete, form: { data: { confirm: 'Are you sure?' } } %></td> | 37 | <td><%= link_to 'edit', edit_event_path(event) %></td> |
| 30 | </tr> | 38 | </tr> |
| 31 | <% end %> | 39 | <% end %> |
| 32 | </table> | 40 | </table> |
| 33 | |||
| 34 | <br /> | ||
| 35 | |||
| 36 | <%= link_to 'New event', new_event_path %> | ||
diff --git a/app/views/events/new.html.erb b/app/views/events/new.html.erb index cd892c5..7a1ee7a 100644 --- a/app/views/events/new.html.erb +++ b/app/views/events/new.html.erb | |||
| @@ -1,46 +1,56 @@ | |||
| 1 | <h1>New event</h1> | 1 | <h1>New event</h1> |
| 2 | 2 | ||
| 3 | <%= link_to 'Back', safe_return_to(params[:return_to] || events_path) %> | ||
| 4 | |||
| 3 | <%= form_for(@event) do |f| %> | 5 | <%= form_for(@event) do |f| %> |
| 4 | <%= form_error_messages(f) %> | 6 | <%= form_error_messages(f) %> |
| 5 | 7 | ||
| 6 | <p> | 8 | <div id="page_editor"> |
| 7 | <%= f.label :start_time %><br /> | 9 | <div id="content"> |
| 8 | <%= f.datetime_select :start_time %> | 10 | <div class="node_description">Node</div> |
| 9 | </p> | 11 | <div class="node_content"> |
| 10 | <p> | 12 | <%= text_field_tag :event_node_search_term %> |
| 11 | <%= f.label :end_time %><br /> | 13 | <div id="event_search_results" class="search_results"></div> |
| 12 | <%= f.datetime_select :end_time %> | 14 | <%= f.hidden_field :node_id %> |
| 13 | </p> | 15 | <span class="field_hint">Optional — search and pick a node to associate this event with a page.</span> |
| 14 | <p> | 16 | </div> |
| 15 | <%= f.label :rrule %><br /> | 17 | |
| 16 | <%= f.text_field :rrule %> | 18 | <div class="node_description">Start time</div> |
| 17 | </p> | 19 | <div class="node_content"><%= f.datetime_select :start_time %></div> |
| 18 | <p> | 20 | |
| 19 | <%= f.label :custom_rrule %><br /> | 21 | <div class="node_description">End time</div> |
| 20 | <%= f.check_box :custom_rrule %> | 22 | <div class="node_content"><%= f.datetime_select :end_time %></div> |
| 21 | </p> | 23 | |
| 22 | <p> | 24 | <div class="node_description">Rrule</div> |
| 23 | <%= f.label :allday %><br /> | 25 | <div class="node_content"><%= f.text_field :rrule %></div> |
| 24 | <%= f.check_box :allday %> | 26 | |
| 25 | </p> | 27 | <div class="node_description">Title</div> |
| 26 | <p> | 28 | <div class="node_content"> |
| 27 | <%= f.label :url %><br /> | 29 | <%= f.text_field :title %> |
| 28 | <%= f.text_field :url %> | 30 | <span id="event_title_hint" class="field_hint">Optional — if left blank, the associated node's title is used.</span> |
| 29 | </p> | 31 | </div> |
| 30 | <p> | 32 | |
| 31 | <%= f.label :latitude %><br /> | 33 | <div class="node_description">Tags</div> |
| 32 | <%= f.text_field :latitude %> | 34 | <div class="node_content"><%= f.text_field :tag_list %></div> |
| 33 | </p> | 35 | |
| 34 | <p> | 36 | <div class="node_description">Allday</div> |
| 35 | <%= f.label :longitude %><br /> | 37 | <div class="node_content"><%= f.check_box :allday %></div> |
| 36 | <%= f.text_field :longitude %> | 38 | |
| 37 | </p> | 39 | <div class="node_description">Url</div> |
| 38 | <p> | 40 | <div class="node_content"><%= f.text_field :url %></div> |
| 39 | <%= f.hidden_field :node_id %> | 41 | |
| 40 | </p> | 42 | <div class="node_description">Latitude</div> |
| 41 | <p> | 43 | <div class="node_content"><%= f.text_field :latitude %></div> |
| 42 | <%= f.submit 'Create' %> | 44 | |
| 43 | </p> | 45 | <div class="node_description">Longitude</div> |
| 46 | <div class="node_content"><%= f.text_field :longitude %></div> | ||
| 47 | |||
| 48 | <div class="node_description"></div> | ||
| 49 | <div class="node_content"><%= hidden_field_tag :return_to, params[:return_to] %></div> | ||
| 50 | |||
| 51 | <div class="node_description"></div> | ||
| 52 | <div class="node_content"><%= f.submit 'Create' %></div> | ||
| 53 | </div> | ||
| 54 | </div> | ||
| 44 | <% end %> | 55 | <% end %> |
| 45 | 56 | ||
| 46 | <%= link_to 'Back', events_path %> | ||
diff --git a/app/views/events/show.html.erb b/app/views/events/show.html.erb index ba14a7d..ac084c9 100644 --- a/app/views/events/show.html.erb +++ b/app/views/events/show.html.erb | |||
| @@ -1,46 +1,55 @@ | |||
| 1 | <% content_for :subnavigation do %> | 1 | <div id="page_editor" class="show_node"> |
| 2 | <%= link_to 'back', edit_node_path(@event.node) %> | 2 | <h1><%= @event.node ? "Event for node #{@event.node.unique_name}" : "Event" %></h1> |
| 3 | <%= link_to 'edit', edit_event_path(@event) %> | ||
| 4 | <% end %> | ||
| 5 | 3 | ||
| 6 | <h2>Event for node <%= @event.node.unique_name %></h2> | 4 | <div id="content"> |
| 5 | <div class="node_description">Actions</div> | ||
| 6 | <div class="node_content node_info_group"> | ||
| 7 | <div class="node_info_group_items"> | ||
| 8 | <% if @event.node %> | ||
| 9 | <div class="node_info_item"> | ||
| 10 | <%= link_to 'Node', node_path(@event.node) %> | ||
| 11 | </div> | ||
| 12 | <% end %> | ||
| 13 | <div class="node_info_item"> | ||
| 14 | <%= link_to edit_event_path(@event, return_to: request.path), class: 'action_button' do %> | ||
| 15 | <%= icon("edit", library: "tabler", "aria-hidden": true) %> Edit | ||
| 16 | <% end %> | ||
| 17 | </div> | ||
| 18 | <div class="node_info_item"> | ||
| 19 | <%= button_to event_path(@event), method: :delete, form: { data: { confirm: 'Delete this event?' }, class: 'button_to destructive' } do %> | ||
| 20 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy | ||
| 21 | <% end %> | ||
| 22 | </div> | ||
| 23 | </div> | ||
| 24 | </div> | ||
| 7 | 25 | ||
| 8 | <p> | 26 | <div class="node_description">Start time</div> |
| 9 | <b>Start time:</b> | 27 | <div class="node_content"><%=h @event.start_time %></div> |
| 10 | <%=h @event.start_time %> | ||
| 11 | </p> | ||
| 12 | 28 | ||
| 13 | <p> | 29 | <div class="node_description">End time</div> |
| 14 | <b>End time:</b> | 30 | <div class="node_content"><%=h @event.end_time %></div> |
| 15 | <%=h @event.end_time %> | ||
| 16 | </p> | ||
| 17 | 31 | ||
| 18 | <p> | 32 | <div class="node_description">Rrule</div> |
| 19 | <b>Rrule:</b> | 33 | <div class="node_content"><%=h @event.rrule %></div> |
| 20 | <%=h @event.rrule %> | ||
| 21 | </p> | ||
| 22 | 34 | ||
| 23 | <p> | 35 | <% if (human = @event.humanize_rrule(I18n.locale)) %> |
| 24 | <b>Custom rrule:</b> | 36 | <div class="node_description">Recurrence</div> |
| 25 | <%=h @event.custom_rrule %> | 37 | <div class="node_content"><em><%= human %></em></div> |
| 26 | </p> | 38 | <% end %> |
| 27 | 39 | ||
| 28 | <p> | 40 | <div class="node_description">Tags</div> |
| 29 | <b>Allday:</b> | 41 | <div class="node_content"><%=h @event.tag_list %></div> |
| 30 | <%=h @event.allday %> | ||
| 31 | </p> | ||
| 32 | 42 | ||
| 33 | <p> | 43 | <div class="node_description">Allday</div> |
| 34 | <b>Url:</b> | 44 | <div class="node_content"><%=h @event.allday %></div> |
| 35 | <%=h @event.url %> | ||
| 36 | </p> | ||
| 37 | 45 | ||
| 38 | <p> | 46 | <div class="node_description">Url</div> |
| 39 | <b>Latitude:</b> | 47 | <div class="node_content"><%=h @event.url %></div> |
| 40 | <%=h @event.latitude %> | ||
| 41 | </p> | ||
| 42 | 48 | ||
| 43 | <p> | 49 | <div class="node_description">Latitude</div> |
| 44 | <b>Longitude:</b> | 50 | <div class="node_content"><%=h @event.latitude %></div> |
| 45 | <%=h @event.longitude %> | 51 | |
| 46 | </p> \ No newline at end of file | 52 | <div class="node_description">Longitude</div> |
| 53 | <div class="node_content"><%=h @event.longitude %></div> | ||
| 54 | </div> | ||
| 55 | </div> | ||
diff --git a/app/views/events/without_node.html.erb b/app/views/events/without_node.html.erb new file mode 100644 index 0000000..bb27173 --- /dev/null +++ b/app/views/events/without_node.html.erb | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | <h1>Events without a node</h1> | ||
| 2 | |||
| 3 | <%= link_to '← All events', events_path %> | ||
| 4 | <%= link_to new_event_path, class: 'action_button' do %> | ||
| 5 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create event | ||
| 6 | <% end %> | ||
| 7 | |||
| 8 | <%= will_paginate @events %> | ||
| 9 | |||
| 10 | <table class="events_table"> | ||
| 11 | <tr class="header"> | ||
| 12 | <th>Title</th> | ||
| 13 | <th>Start time</th> | ||
| 14 | <th>End time</th> | ||
| 15 | <th>Allday</th> | ||
| 16 | <th>Url</th> | ||
| 17 | <th></th> | ||
| 18 | </tr> | ||
| 19 | |||
| 20 | <% @events.each do |event| %> | ||
| 21 | <tr> | ||
| 22 | <td><%= link_to event.display_title, event %></td> | ||
| 23 | <td><%=h event.start_time %></td> | ||
| 24 | <td><%=h event.end_time %></td> | ||
| 25 | <td><%=h event.allday %></td> | ||
| 26 | <td><%=h event.url %></td> | ||
| 27 | <td><%= link_to 'edit', edit_event_path(event) %></td> | ||
| 28 | </tr> | ||
| 29 | <% end %> | ||
| 30 | </table> | ||
diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index 4536693..0856a0f 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb | |||
| @@ -10,12 +10,15 @@ | |||
| 10 | <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> | 10 | <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> |
| 11 | <%= javascript_include_tag 'admin_bundle' %> | 11 | <%= javascript_include_tag 'admin_bundle' %> |
| 12 | <%= tinymce_assets %> | 12 | <%= tinymce_assets %> |
| 13 | <link rel="stylesheet" href="/stylesheets/admin.css"> | 13 | <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/admin.css') %>"> |
| 14 | <script src="/javascripts/admin_search.js"></script> | 14 | <script src="<%= mtime_busted_path('/javascripts/admin_search.js') %>"></script> |
| 15 | <script src="/javascripts/admin_interface.js"></script> | 15 | <script src="<%= mtime_busted_path('/javascripts/admin_interface.js') %>"></script> |
| 16 | <script src="<%= mtime_busted_path('/javascripts/related_assets.js') %>"></script> | ||
| 16 | <script> | 17 | <script> |
| 17 | var ADMIN_SEARCH_URL = "<%= admin_search_path %>"; | 18 | var ADMIN_SEARCH_URL = "<%= admin_search_path %>"; |
| 18 | var ADMIN_MENU_SEARCH_URL = "<%= admin_menu_search_path %>"; | 19 | var ADMIN_MENU_SEARCH_URL = "<%= admin_menu_search_path %>"; |
| 20 | var PARAMETERIZE_PREVIEW_URL = "<%= parameterize_preview_nodes_path %>"; | ||
| 21 | var DASHBOARD_SEARCH_URL = "<%= admin_dashboard_search_path %>"; | ||
| 19 | </script> | 22 | </script> |
| 20 | </head> | 23 | </head> |
| 21 | 24 | ||
| @@ -25,33 +28,36 @@ | |||
| 25 | <div id="main_navigation"> | 28 | <div id="main_navigation"> |
| 26 | <%= render :partial => 'admin/menu' if current_user %> | 29 | <%= render :partial => 'admin/menu' if current_user %> |
| 27 | </div> | 30 | </div> |
| 28 | <div id="sub_navigation"> | 31 | <div id="search_widget" style="display: none;"> |
| 29 | <%= yield :subnavigation %> | 32 | <div> |
| 33 | <%= form_tag admin_search_path, method: :get do %> | ||
| 34 | <%= text_field_tag :search_term, nil, placeholder: "Search nodes…", autocomplete: "off" %> | ||
| 35 | <% end %> | ||
| 36 | </div> | ||
| 37 | <div id="menu_search_results" class="search_results" style="display: none"></div> | ||
| 30 | </div> | 38 | </div> |
| 31 | </div> | 39 | </div> |
| 32 | <div style="clear: both;"></div> | 40 | <div class="admin_content_spacer"></div> |
| 41 | <% if flash[:notice].present? || flash[:error].present? %> | ||
| 33 | <div id="flash"> | 42 | <div id="flash"> |
| 34 | <%= flash[:notice] %> | 43 | <%= flash[:notice] %> |
| 44 | <% if flash[:status_path] %> | ||
| 45 | <%= link_to 'Go to Status', flash[:status_path] %> | ||
| 46 | <% end %> | ||
| 47 | <% if flash[:stale_locale_path] %> | ||
| 48 | The <%= flash[:stale_locale] %> translation may be out of date — | ||
| 49 | <%= link_to 'review it', flash[:stale_locale_path] %> too. | ||
| 50 | <% end %> | ||
| 35 | <% if flash[:error] %> | 51 | <% if flash[:error] %> |
| 36 | <span id="flash_error"><%= flash[:error] %></span> | 52 | <span id="flash_error"><%= flash[:error] %></span> |
| 37 | <% end %> | 53 | <% end %> |
| 38 | </div> | 54 | </div> |
| 55 | <% end %> | ||
| 39 | <div id="content"> | 56 | <div id="content"> |
| 40 | <%= yield %> | 57 | <%= yield %> |
| 41 | </div> | 58 | </div> |
| 42 | 59 | ||
| 43 | <div id="results"></div> | 60 | <div id="results"></div> |
| 44 | </div> | 61 | </div> |
| 45 | |||
| 46 | <div id="search_widget" style="display: none;"> | ||
| 47 | <div> | ||
| 48 | <%= form_tag admin_search_path, method: :get do %> | ||
| 49 | <span>Search: </span><%= text_field_tag :search_term, nil, autocomplete: "off" %> | ||
| 50 | <% end %> | ||
| 51 | </div> | ||
| 52 | <div id="search_results" style="display: none"> | ||
| 53 | |||
| 54 | </div> | ||
| 55 | </div> | ||
| 56 | </body> | 62 | </body> |
| 57 | </html> | 63 | </html> |
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index edab5fc..57d12e6 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb | |||
| @@ -72,6 +72,7 @@ | |||
| 72 | </div> | 72 | </div> |
| 73 | </div> | 73 | </div> |
| 74 | <div id="right_column"> | 74 | <div id="right_column"> |
| 75 | <%= open_erfas_today %> | ||
| 75 | <%= tags %> | 76 | <%= tags %> |
| 76 | <%= featured_articles %> | 77 | <%= featured_articles %> |
| 77 | </div> | 78 | </div> |
diff --git a/app/views/menu_items/edit.html.erb b/app/views/menu_items/edit.html.erb index 9891708..44e5a79 100644 --- a/app/views/menu_items/edit.html.erb +++ b/app/views/menu_items/edit.html.erb | |||
| @@ -1,32 +1,25 @@ | |||
| 1 | <h1>Edit Menu Item</h1> | 1 | <h1>Edit Menu Item</h1> |
| 2 | 2 | ||
| 3 | <%= form_for @menu_item do |f| %> | 3 | <div id="page_editor"> |
| 4 | <table> | 4 | <%= form_for @menu_item do |f| %> |
| 5 | 5 | <div id="content"> | |
| 6 | <tr> | 6 | <div class="node_description">Search</div> |
| 7 | <td class="description">Search</td> | 7 | <div class="node_content"> |
| 8 | <td> | 8 | <%= text_field_tag :menu_search_term %> |
| 9 | <%= text_field_tag :menu_search_term %> | 9 | <div id="menu_item_search_results" class="search_results"></div> |
| 10 | <div id="search_results"> | 10 | </div> |
| 11 | 11 | ||
| 12 | </div> | 12 | <div class="node_description">Node Id</div> |
| 13 | </td> | 13 | <div class="node_content"><%= f.text_field :node_id %></div> |
| 14 | </tr> | 14 | |
| 15 | <tr> | 15 | <div class="node_description">Path</div> |
| 16 | <td class="description">Node Id</td> | 16 | <div class="node_content"><%= f.text_field :path %></div> |
| 17 | <td><%= f.text_field :node_id %></td> | 17 | |
| 18 | </tr> | 18 | <div class="node_description">Title</div> |
| 19 | <tr> | 19 | <div class="node_content"><%= f.text_field :title %></div> |
| 20 | <td class="description">Path</td> | 20 | |
| 21 | <td><%= f.text_field :path %></td> | 21 | <div class="node_description"></div> |
| 22 | </tr> | 22 | <div class="node_content"><%= f.submit 'Update' %></div> |
| 23 | <tr> | 23 | <% end %> |
| 24 | <td class="description">Title</td> | 24 | </div> |
| 25 | <td><%= f.text_field :title %></td> | 25 | </div> |
| 26 | </tr> | ||
| 27 | <tr> | ||
| 28 | <td></td> | ||
| 29 | <td class="right"><%= f.submit 'Update' %></td> | ||
| 30 | </tr> | ||
| 31 | </table> | ||
| 32 | <% end %> | ||
diff --git a/app/views/menu_items/index.html.erb b/app/views/menu_items/index.html.erb index c52c150..591eb68 100644 --- a/app/views/menu_items/index.html.erb +++ b/app/views/menu_items/index.html.erb | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | <% content_for :subnavigation do %> | ||
| 2 | <%= link_to "new", new_menu_item_path %> | ||
| 3 | <% end %> | ||
| 4 | |||
| 5 | |||
| 6 | <h1>Menu Items</h1> | 1 | <h1>Menu Items</h1> |
| 7 | 2 | ||
| 3 | <%= link_to new_menu_item_path, class: 'action_button' do %> | ||
| 4 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create menu item | ||
| 5 | <% end %> | ||
| 6 | |||
| 8 | <table id="menu_item_list"> | 7 | <table id="menu_item_list"> |
| 9 | <% @menu_items.each do |menu_item| %> | 8 | <% @menu_items.each do |menu_item| %> |
| 10 | <tr id="menu_items-<%= menu_item.id %>"> | 9 | <tr id="menu_items-<%= menu_item.id %>"> |
| @@ -14,9 +13,10 @@ | |||
| 14 | <td class="menu_item_title"><%= menu_item.title %></td> | 13 | <td class="menu_item_title"><%= menu_item.title %></td> |
| 15 | <td><%= link_to "Edit", edit_menu_item_path(menu_item) %></td> | 14 | <td><%= link_to "Edit", edit_menu_item_path(menu_item) %></td> |
| 16 | <td> | 15 | <td> |
| 17 | <%= button_to "Delete", menu_item_path(menu_item), | 16 | <%= button_to menu_item_path(menu_item), method: :delete, |
| 18 | method: :delete, | 17 | form: { data: { confirm: "Do you really want to destroy the menu entry?" }, class: 'button_to destructive' } do %> |
| 19 | form: { data: { confirm: "Are you sure?" } } %> | 18 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy |
| 19 | <% end %> | ||
| 20 | </td> | 20 | </td> |
| 21 | </tr> | 21 | </tr> |
| 22 | <% end %> | 22 | <% end %> |
diff --git a/app/views/menu_items/new.html.erb b/app/views/menu_items/new.html.erb index 68081d0..8957293 100644 --- a/app/views/menu_items/new.html.erb +++ b/app/views/menu_items/new.html.erb | |||
| @@ -1,32 +1,20 @@ | |||
| 1 | <h1>Add Menu Item</h1> | 1 | <h1>Add Menu Item</h1> |
| 2 | 2 | ||
| 3 | <%= form_for @menu_item do |f| %> | 3 | <%= form_for @menu_item do |f| %> |
| 4 | <table> | 4 | <div class="node_description">Search</div> |
| 5 | 5 | <div class="node_content"> | |
| 6 | <tr> | 6 | <%= text_field_tag :menu_search_term %> |
| 7 | <td class="description">Search</td> | 7 | <div id="menu_item_search_results" class="search_results"></div> |
| 8 | <td> | 8 | </div> |
| 9 | <%= text_field_tag :menu_search_term %> | ||
| 10 | <div id="search_results"> | ||
| 11 | 9 | ||
| 12 | </div> | 10 | <div class="node_description">Node Id</div> |
| 13 | </td> | 11 | <div class="node_content"><%= f.text_field :node_id %></div> |
| 14 | </tr> | 12 | |
| 15 | <tr> | 13 | <div class="node_description">Path</div> |
| 16 | <td class="description">Node Id</td> | 14 | <div class="node_content"><%= f.text_field :path %></div> |
| 17 | <td><%= f.text_field :node_id %></td> | 15 | |
| 18 | </tr> | 16 | <div class="node_description">Title</div> |
| 19 | <tr> | 17 | <div class="node_content"><%= f.text_field :title %></div> |
| 20 | <td class="description">Path</td> | 18 | |
| 21 | <td><%= f.text_field :path %></td> | 19 | <div class="node_content"><%= f.submit 'Create' %></div> |
| 22 | </tr> | ||
| 23 | <tr> | ||
| 24 | <td class="description">Title</td> | ||
| 25 | <td><%= f.text_field :title %></td> | ||
| 26 | </tr> | ||
| 27 | <tr> | ||
| 28 | <td></td> | ||
| 29 | <td class="right"><%= f.submit 'Create' %></td> | ||
| 30 | </tr> | ||
| 31 | </table> | ||
| 32 | <% end %> | 20 | <% end %> |
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' %> | ||
diff --git a/app/views/occurrences/index.html.erb b/app/views/occurrences/index.html.erb index 0e99857..aa084ed 100644 --- a/app/views/occurrences/index.html.erb +++ b/app/views/occurrences/index.html.erb | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | <h1>Listing occurrences</h1> | 1 | <h1>Occurrences</h1> |
| 2 | 2 | ||
| 3 | <table> | 3 | <table> |
| 4 | <tr> | 4 | <tr> |
| @@ -18,7 +18,9 @@ | |||
| 18 | <td><%=h occurrence.event_id %></td> | 18 | <td><%=h occurrence.event_id %></td> |
| 19 | <td><%= link_to 'Show', occurrence %></td> | 19 | <td><%= link_to 'Show', occurrence %></td> |
| 20 | <td><%= link_to 'Edit', edit_occurrence_path(occurrence) %></td> | 20 | <td><%= link_to 'Edit', edit_occurrence_path(occurrence) %></td> |
| 21 | <td><%= button_to 'Destroy', occurrence, method: :delete, form: { data: { confirm: 'Are you sure?' } } %></td> | 21 | <td><%= button_to occurrence, method: :delete, form: { data: { confirm: 'Are you sure?' }, class: 'button_to destructive' } do %> |
| 22 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy | ||
| 23 | <% end %></td> | ||
| 22 | </tr> | 24 | </tr> |
| 23 | <% end %> | 25 | <% end %> |
| 24 | </table> | 26 | </table> |
diff --git a/app/views/page_translations/edit.html.erb b/app/views/page_translations/edit.html.erb new file mode 100644 index 0000000..89b594e --- /dev/null +++ b/app/views/page_translations/edit.html.erb | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | <div class="translation_banner"> | ||
| 2 | Editing the <strong><%= @locale.to_s.upcase %></strong> translation of <strong><%= title_for_node(@node) %></strong>. | ||
| 3 | </div> | ||
| 4 | |||
| 5 | <p class="field_hint"> | ||
| 6 | Metadata such as images, tags, template, and author belong to the page | ||
| 7 | as a whole, not to a single translation — change those from the | ||
| 8 | <%= link_to 'default-locale editor', edit_node_path(@node) %>. | ||
| 9 | </p> | ||
| 10 | |||
| 11 | <div class="node_action_bar"> | ||
| 12 | <%= button_to 'Unlock + Back', unlock_node_path(@node), method: :put, | ||
| 13 | form: { class: 'button_to state_changing' }, | ||
| 14 | disabled: @node.autosave.present? %> | ||
| 15 | <%= submit_tag "Save #{@locale.to_s.upcase} translation", form: "translation_edit_form" %> | ||
| 16 | <%= submit_tag "Save + Unlock + Exit", form: "translation_edit_form" %> | ||
| 17 | <%= link_to "Preview ↗", preview_page_path(@page, :locale => @locale), target: "_blank", rel: "noopener", class: "preview_link" %> | ||
| 18 | </div> | ||
| 19 | |||
| 20 | <div id="page_editor"> | ||
| 21 | <%= form_with url: node_translation_path(@node, @locale), method: :patch, local: true, id: "translation_edit_form", | ||
| 22 | data: { autosave_url: autosave_node_translation_path(@node, @locale), show_url: node_path(@node) } do |f| %> | ||
| 23 | <div id="content"> | ||
| 24 | <div class="node_description">Title</div> | ||
| 25 | <div class="node_content"> | ||
| 26 | <%= text_field_tag "page[title]", @translation&.title %> | ||
| 27 | </div> | ||
| 28 | |||
| 29 | <div class="node_description">Abstract</div> | ||
| 30 | <div class="node_content"> | ||
| 31 | <%= text_area_tag "page[abstract]", @translation&.abstract %> | ||
| 32 | </div> | ||
| 33 | |||
| 34 | <div class="node_description">Body</div> | ||
| 35 | <div class="node_content"> | ||
| 36 | <%= text_area_tag "page[body]", @translation&.body, :class => 'with_editor' %> | ||
| 37 | </div> | ||
| 38 | </div> | ||
| 39 | <% end %> | ||
| 40 | </div> | ||
diff --git a/app/views/page_translations/index.html.erb b/app/views/page_translations/index.html.erb new file mode 100644 index 0000000..a8c4f5d --- /dev/null +++ b/app/views/page_translations/index.html.erb | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | <h1>Translations — <%= title_for_node(@node) %></h1> | ||
| 2 | |||
| 3 | <div class="node_content node_info_group"> | ||
| 4 | <div class="node_info_group_items"> | ||
| 5 | <% @translations.each do |t| %> | ||
| 6 | <div class="node_info_item"> | ||
| 7 | <span class="node_info_label"><%= t[:locale].to_s.upcase %></span> | ||
| 8 | <% if t[:exists] %> | ||
| 9 | <%= t[:title] %> — updated <%= t[:updated_at] %> | ||
| 10 | <% if t[:outdated] %><span class="warning">may be outdated</span><% end %> | ||
| 11 | <%= link_to 'Edit', edit_node_translation_path(@node, t[:locale]) %> | ||
| 12 | <% else %> | ||
| 13 | <span class="field_hint">Not yet translated.</span> | ||
| 14 | <%= link_to 'Add', edit_node_translation_path(@node, t[:locale]) %> | ||
| 15 | <% end %> | ||
| 16 | </div> | ||
| 17 | <% end %> | ||
| 18 | </div> | ||
| 19 | </div> | ||
diff --git a/app/views/page_translations/show.html.erb b/app/views/page_translations/show.html.erb new file mode 100644 index 0000000..c5bd151 --- /dev/null +++ b/app/views/page_translations/show.html.erb | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | <h1>Compare — <%= title_for_node(@node) %></h1> | ||
| 2 | |||
| 3 | <div class="translation_compare"> | ||
| 4 | <div class="translation_compare_column"> | ||
| 5 | <h2><%= @locale.to_s.upcase %></h2> | ||
| 6 | <div class="node_description">Title</div> | ||
| 7 | <div class="node_content"><%= @translation&.title %></div> | ||
| 8 | |||
| 9 | <div class="node_description">Abstract</div> | ||
| 10 | <div class="node_content"><%= sanitize(@translation&.abstract.to_s) %></div> | ||
| 11 | |||
| 12 | <div class="node_description">Body</div> | ||
| 13 | <div class="node_content"><%= sanitize(@translation&.body.to_s) %></div> | ||
| 14 | </div> | ||
| 15 | |||
| 16 | <div class="translation_compare_column"> | ||
| 17 | <h2><%= I18n.default_locale.to_s.upcase %> (default)</h2> | ||
| 18 | <div class="node_description">Title</div> | ||
| 19 | <div class="node_content"><%= @default_translation&.title %></div> | ||
| 20 | |||
| 21 | <div class="node_description">Abstract</div> | ||
| 22 | <div class="node_content"><%= sanitize(@default_translation&.abstract.to_s) %></div> | ||
| 23 | |||
| 24 | <div class="node_description">Body</div> | ||
| 25 | <div class="node_content"><%= sanitize(@default_translation&.body.to_s) %></div> | ||
| 26 | </div> | ||
| 27 | </div> | ||
diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb index 91e5359..da67871 100644 --- a/app/views/pages/index.html.erb +++ b/app/views/pages/index.html.erb | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | <h1>Listing pages</h1> | 1 | <h1>Pages</h1> |
| 2 | 2 | ||
| 3 | <table> | 3 | <table> |
| 4 | <tr> | 4 | <tr> |
| @@ -12,7 +12,9 @@ | |||
| 12 | <td><%=h page.title %></td> | 12 | <td><%=h page.title %></td> |
| 13 | <td><%= link_to 'Show', content_path(:page_path => page.node.unique_path) %></td> | 13 | <td><%= link_to 'Show', content_path(:page_path => page.node.unique_path) %></td> |
| 14 | <td><%= link_to 'Edit', edit_page_path(page) %></td> | 14 | <td><%= link_to 'Edit', edit_page_path(page) %></td> |
| 15 | <td><%= button_to 'Destroy', page, method: :delete, form: { data: { confirm: 'Are you sure?' } } %></td> | 15 | <td><%= button_to page, method: :delete, form: { data: { confirm: 'Are you sure?' }, class: 'button_to destructive' } do %> |
| 16 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy | ||
| 17 | <% end %></td> | ||
| 16 | </tr> | 18 | </tr> |
| 17 | <% end %> | 19 | <% end %> |
| 18 | </table> | 20 | </table> |
diff --git a/app/views/revisions/diff.html.erb b/app/views/revisions/diff.html.erb index b8d061d..7e7b729 100644 --- a/app/views/revisions/diff.html.erb +++ b/app/views/revisions/diff.html.erb | |||
| @@ -1,65 +1,134 @@ | |||
| 1 | <% content_for :subnavigation do %> | ||
| 2 | <%= link_to 'Edit', edit_node_path(@node) %> | ||
| 3 | <%= link_to 'Revisions', node_revisions_path(@node) %> | ||
| 4 | <% end %> | ||
| 5 | |||
| 6 | <h1>Revisions#diff</h1> | 1 | <h1>Revisions#diff</h1> |
| 7 | 2 | ||
| 8 | <%= form_tag diff_node_revisions_path do %> | 3 | <p class="node_action_bar standalone_action_bar"> |
| 9 | <%= select_tag :start_revision, options_for_select(@node.pages.map{|x| x.revision}, params[:start_revision].to_i) %> | 4 | <%= link_to 'Revisions', node_revisions_path(@node) %> |
| 10 | <%= select_tag :end_revision, options_for_select(@node.pages.map{|x| x.revision}, params[:end_revision].to_i) %> | 5 | </p> |
| 11 | <%= submit_tag 'Diff' %> | ||
| 12 | <% end %> | ||
| 13 | 6 | ||
| 14 | <div id="start_title" style="display: none;"> | 7 | <p class="diff_comparison_label"> |
| 15 | <%= h(@start.title) %> | 8 | Comparing <strong><%= describe_page_reference(params[:start_revision]) %></strong> |
| 16 | </div> | 9 | against <strong><%= describe_page_reference(params[:end_revision]) %></strong> |
| 10 | — showing the <strong><%= @locale.to_s.upcase %></strong> translation | ||
| 11 | </p> | ||
| 17 | 12 | ||
| 18 | <div id="end_title" style="display: none;"> | 13 | <% if @locale_summary.size > 1 %> |
| 19 | <%= h(@end.title) %> | 14 | <p class="diff_locale_toggle"> |
| 20 | </div> | 15 | Locale: |
| 16 | <% @locale_summary.each_with_index do |s, i| %> | ||
| 17 | <%= " · ".html_safe if i > 0 %> | ||
| 18 | <% label = "#{s[:locale].to_s.upcase}#{' *' if s[:changed]}" %> | ||
| 19 | <% if s[:locale] == @locale %> | ||
| 20 | <strong><%= label %></strong> | ||
| 21 | <% else %> | ||
| 22 | <%= link_to label, diff_node_revisions_path(@node, start_revision: params[:start_revision], end_revision: params[:end_revision], view: @diff_view, locale: s[:locale]) %> | ||
| 23 | <% end %> | ||
| 24 | <% end %> | ||
| 25 | </p> | ||
| 26 | <p class="field_hint">* has a difference between these two versions.</p> | ||
| 27 | <% end %> | ||
| 21 | 28 | ||
| 22 | <div id="start_abstract" style="display: none;"> | 29 | <p class="diff_view_toggle"> |
| 23 | <%= h(@start.abstract) %> | 30 | View: |
| 24 | </div> | 31 | <% if @diff_view == :inline %> |
| 32 | <strong>Inline</strong> | ||
| 33 | <% else %> | ||
| 34 | <%= link_to 'Inline', diff_node_revisions_path(@node, start_revision: params[:start_revision], end_revision: params[:end_revision], view: 'inline', locale: @locale) %> | ||
| 35 | <% end %> | ||
| 36 | · | ||
| 37 | <% if @diff_view == :side_by_side %> | ||
| 38 | <strong>Side by side</strong> | ||
| 39 | <% else %> | ||
| 40 | <%= link_to 'Side by side', diff_node_revisions_path(@node, start_revision: params[:start_revision], end_revision: params[:end_revision], view: 'side_by_side', locale: @locale) %> | ||
| 41 | <% end %> | ||
| 42 | </p> | ||
| 25 | 43 | ||
| 26 | <div id="end_abstract" style="display: none;"> | 44 | <% numeric_comparison = params[:start_revision].to_s =~ /\A\d+\z/ && params[:end_revision].to_s =~ /\A\d+\z/ %> |
| 27 | <%= h(@end.abstract) %> | ||
| 28 | </div> | ||
| 29 | 45 | ||
| 30 | <pre> | 46 | <% if numeric_comparison %> |
| 31 | <div id="start_body" style="display: none;"> | 47 | <%= form_tag diff_node_revisions_path do %> |
| 32 | <%= (@start.body) %> | 48 | <%= select_tag :start_revision, options_for_select(@node.pages.map{|x| x.revision}, params[:start_revision].to_i) %> |
| 33 | </div> | 49 | <%= select_tag :end_revision, options_for_select(@node.pages.map{|x| x.revision}, params[:end_revision].to_i) %> |
| 34 | </pre> | 50 | <%= hidden_field_tag :view, @diff_view %> |
| 35 | <pre> | 51 | <%= hidden_field_tag :locale, @locale %> |
| 36 | <div id="end_body" style="display: none;"> | 52 | <%= submit_tag 'Diff' %> |
| 37 | <%= (@end.body) %> | 53 | <% end %> |
| 38 | </div> | 54 | <% else %> |
| 39 | </pre> | 55 | <p class="node_action_bar standalone_action_bar"><%= link_to 'Compare two numbered revisions instead', node_revisions_path(@node) %></p> |
| 56 | <% end %> | ||
| 40 | 57 | ||
| 41 | <script src="/javascripts/cacycle_diff.js"></script> | 58 | <% if @available_layer_pairs.present? %> |
| 42 | <script type="text/javascript" charset="utf-8"> | 59 | <div class="node_action_bar standalone_action_bar"> |
| 43 | window.onload = function() { | 60 | <% @available_layer_pairs.each do |pair| %> |
| 44 | title1 = document.getElementById('start_title').innerHTML; | 61 | <% next if [params[:start_revision].to_s, params[:end_revision].to_s].sort == pair.map(&:to_s).sort %> |
| 45 | title2 = document.getElementById('end_title').innerHTML; | 62 | <%= button_to "Diff #{pair.first.to_s.capitalize} vs. #{pair.last.to_s.capitalize}", |
| 46 | abstract1 = document.getElementById('start_abstract').innerHTML; | 63 | diff_node_revisions_path(@node), |
| 47 | abstract2 = document.getElementById('end_abstract').innerHTML; | 64 | method: :get, |
| 48 | body1 = document.getElementById('start_body').innerHTML; | 65 | params: { start_revision: pair.first, end_revision: pair.last, view: @diff_view, locale: @locale }, |
| 49 | body2 = document.getElementById('end_body').innerHTML; | 66 | form: { class: 'button_to computation' } %> |
| 50 | document.getElementById('diffview_title').innerHTML = WDiffString(title1, title2); | 67 | <% end %> |
| 51 | document.getElementById('diffview_abstract').innerHTML = WDiffString(abstract1, abstract2); | 68 | <% if !@locked_by_other && (@node.autosave || @node.draft) %> |
| 52 | document.getElementById('diffview_body').innerHTML = WDiffString(body1, body2); | 69 | <%= button_to revert_node_path(@node), method: :put, |
| 53 | } | 70 | params: { return_to: request.fullpath }, |
| 54 | </script> | 71 | form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %> |
| 72 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> | ||
| 73 | <%= @node.draft && !@node.autosave ? "Destroy Draft" : "Discard Autosave" %> | ||
| 74 | <% end %> | ||
| 75 | <% end %> | ||
| 76 | </div> | ||
| 77 | <% end %> | ||
| 55 | 78 | ||
| 56 | <div id="diffview"> | 79 | <div id="diffview"> |
| 57 | <h3>Title</h3> | 80 | <% if @diff_view == :side_by_side %> |
| 58 | <p id="diffview_title"></p> | 81 | <div class="diff_side_by_side"> |
| 59 | 82 | <div class="diff_column"> | |
| 60 | <h3>Abstract</h3> | 83 | <h3>Title</h3> |
| 61 | <p id="diffview_abstract"></p> | 84 | <p><%= raw @diff[:title][0] %></p> |
| 62 | 85 | <h3>Abstract</h3> | |
| 63 | <h3>Body</h3> | 86 | <p><%= raw @diff[:abstract][0] %></p> |
| 64 | <p id="diffview_body"></p> | 87 | <h3>Body</h3> |
| 88 | <%= raw @diff[:body][0] %> | ||
| 89 | </div> | ||
| 90 | <div class="diff_column"> | ||
| 91 | <h3>Title</h3> | ||
| 92 | <p><%= raw @diff[:title][1] %></p> | ||
| 93 | <h3>Abstract</h3> | ||
| 94 | <p><%= raw @diff[:abstract][1] %></p> | ||
| 95 | <h3>Body</h3> | ||
| 96 | <%= raw @diff[:body][1] %> | ||
| 97 | </div> | ||
| 98 | </div> | ||
| 99 | <% else %> | ||
| 100 | <h3>Title</h3> | ||
| 101 | <p><%= raw @diff[:title] %></p> | ||
| 102 | <h3>Abstract</h3> | ||
| 103 | <p><%= raw @diff[:abstract] %></p> | ||
| 104 | <h3>Body</h3> | ||
| 105 | <%= raw @diff[:body] %> | ||
| 106 | <% end %> | ||
| 107 | |||
| 108 | <h3>Tags</h3> | ||
| 109 | <% if @diff[:tags][:added].empty? && @diff[:tags][:removed].empty? %> | ||
| 110 | <p class="diff_unchanged">No change.</p> | ||
| 111 | <% else %> | ||
| 112 | <ul class="diff_set_list"> | ||
| 113 | <% @diff[:tags][:added].each do |tag| %><li><ins><%= tag %></ins></li><% end %> | ||
| 114 | <% @diff[:tags][:removed].each do |tag| %><li><del><%= tag %></del></li><% end %> | ||
| 115 | </ul> | ||
| 116 | <% end %> | ||
| 117 | |||
| 118 | <h3>Template</h3> | ||
| 119 | <% if @diff[:template_name][:changed] %> | ||
| 120 | <p><del><%= @diff[:template_name][:from] || '(none)' %></del> <ins><%= @diff[:template_name][:to] || '(none)' %></ins></p> | ||
| 121 | <% else %> | ||
| 122 | <p class="diff_unchanged">No change.</p> | ||
| 123 | <% end %> | ||
| 124 | |||
| 125 | <h3>Assets</h3> | ||
| 126 | <% if @diff[:assets][:added].empty? && @diff[:assets][:removed].empty? %> | ||
| 127 | <p class="diff_unchanged">No change.</p> | ||
| 128 | <% else %> | ||
| 129 | <ul class="diff_set_list"> | ||
| 130 | <% @diff[:assets][:added].each do |asset| %><li><ins><%= asset.upload_file_name %></ins></li><% end %> | ||
| 131 | <% @diff[:assets][:removed].each do |asset| %><li><del><%= asset.upload_file_name %></del></li><% end %> | ||
| 132 | </ul> | ||
| 133 | <% end %> | ||
| 65 | </div> | 134 | </div> |
diff --git a/app/views/revisions/index.html.erb b/app/views/revisions/index.html.erb index b875a4f..4680ae2 100644 --- a/app/views/revisions/index.html.erb +++ b/app/views/revisions/index.html.erb | |||
| @@ -1,49 +1,80 @@ | |||
| 1 | <% content_for :subnavigation do %> | ||
| 2 | <%= link_to 'Edit', edit_node_path(@node) %> | ||
| 3 | <% end %> | ||
| 4 | |||
| 5 | <h2>Revisions for Node: <%= @node.unique_name %></h2> | 1 | <h2>Revisions for Node: <%= @node.unique_name %></h2> |
| 6 | 2 | ||
| 7 | <table id="revisions"> | 3 | <p class="node_action_bar standalone_action_bar"> |
| 8 | <tr class="header"> | 4 | <%= link_to 'Back to node', node_path(@node) %> |
| 9 | <th>First</th> | 5 | </p> |
| 10 | <th>Last</th> | 6 | |
| 11 | <th>Rev.</th> | 7 | <table id="revisions" class="revisions_table"> |
| 12 | <th>Title</th> | 8 | <thead> |
| 13 | <th>Editor</th> | 9 | <tr class="header"> |
| 14 | <th>Date</th> | 10 | <th>First</th> |
| 15 | <th></th> | 11 | <th>Last</th> |
| 16 | <th></th> | 12 | <th>Rev.</th> |
| 17 | </tr> | 13 | <th>Title</th> |
| 18 | <% (@pages || @node.pages.all).reverse.each do |page| %> | 14 | <th>Editor</th> |
| 19 | <tr> | 15 | <th>Date</th> |
| 20 | <td><%= radio_button_tag :start_revision, page.revision %></td> | 16 | <th></th> |
| 21 | <td><%= radio_button_tag :end_revision, page.revision %></td> | 17 | <th></th> |
| 22 | <td class="revision"><%= page.revision %></td> | 18 | </tr> |
| 23 | <td class="title"><%= page.title %></td> | 19 | <tr class="no_hover diff_sticky_bar"> |
| 24 | <td class="user"><%= page.editor.try(:login) %></td> | 20 | <td colspan="8"> |
| 25 | <td class="date"><%= page.updated_at %></td> | 21 | <%= button_to 'Diff revisions', diff_node_revisions_path(@node), |
| 26 | <td><%= link_to 'show', node_revision_path(@node, page) %></td> | 22 | method: :post, |
| 27 | <td> | 23 | form: { id: 'diff_form', class: 'button_to computation' }, |
| 28 | <%= button_to 'restore', restore_node_revision_path(@node, page), | 24 | disabled: true %> |
| 29 | method: :put, | 25 | <span id="diff_selection_label"></span> |
| 30 | form: { data: { confirm: "Restore this revision?" } } %> | 26 | <label><%= radio_button_tag :view, 'inline', true %> Inline</label> |
| 31 | </td> | 27 | <label><%= radio_button_tag :view, 'side_by_side', false %> Side by side</label> |
| 32 | </tr> | 28 | </td> |
| 33 | <% end %> | 29 | </tr> |
| 34 | <tr class="no_hover"> | 30 | </thead> |
| 35 | <td colspan="8" class="right"> | 31 | <tbody> |
| 36 | <%= button_to 'Diff revisions', diff_node_revisions_path(@node), | 32 | <% pages = (@pages || @node.pages.all).reverse %> |
| 37 | method: :post, | 33 | <% pages.each_with_index do |page, index| %> |
| 38 | form: { id: 'diff_form' } %> | 34 | <tr> |
| 39 | </td> | 35 | <td><%= radio_button_tag :start_revision, page.revision, index == 1 %></td> |
| 40 | </tr> | 36 | <td><%= radio_button_tag :end_revision, page.revision, index == 0 %></td> |
| 37 | <td class="revision"><%= page.revision %></td> | ||
| 38 | <td class="title"><%= page.title %></td> | ||
| 39 | <td class="user"><%= page.editor.try(:login) %></td> | ||
| 40 | <td class="date"><%= page.updated_at %></td> | ||
| 41 | <td><%= link_to 'show', node_revision_path(@node, page) %></td> | ||
| 42 | <td> | ||
| 43 | <%= button_to 'restore', restore_node_revision_path(@node, page), | ||
| 44 | method: :put, | ||
| 45 | form: { data: { confirm: "Restore this revision?" }, class: 'button_to state_changing' } %> | ||
| 46 | </td> | ||
| 47 | </tr> | ||
| 48 | <% end %> | ||
| 49 | </tbody> | ||
| 41 | </table> | 50 | </table> |
| 42 | 51 | ||
| 43 | <script> | 52 | <script> |
| 53 | function update_diff_button_state() { | ||
| 54 | var start = document.querySelector('input[name="start_revision"]:checked'); | ||
| 55 | var end = document.querySelector('input[name="end_revision"]:checked'); | ||
| 56 | var valid = start && end && start.value !== end.value; | ||
| 57 | document.querySelector('#diff_form button[type="submit"]').disabled = !valid; | ||
| 58 | |||
| 59 | var label = document.getElementById('diff_selection_label'); | ||
| 60 | if (start && end) { | ||
| 61 | label.textContent = start.value + ' against ' + end.value; | ||
| 62 | } else if (start || end) { | ||
| 63 | label.textContent = (start || end).value + ' selected'; | ||
| 64 | } else { | ||
| 65 | label.textContent = ''; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | document.querySelectorAll('input[name="start_revision"], input[name="end_revision"]') | ||
| 70 | .forEach(function(radio) { radio.addEventListener('change', update_diff_button_state); }); | ||
| 71 | |||
| 72 | update_diff_button_state(); | ||
| 73 | |||
| 44 | document.getElementById('diff_form').addEventListener('submit', function(e) { | 74 | document.getElementById('diff_form').addEventListener('submit', function(e) { |
| 45 | var start = document.querySelector('input[name="start_revision"]:checked'); | 75 | var start = document.querySelector('input[name="start_revision"]:checked'); |
| 46 | var end = document.querySelector('input[name="end_revision"]:checked'); | 76 | var end = document.querySelector('input[name="end_revision"]:checked'); |
| 77 | var view = document.querySelector('input[name="view"]:checked'); | ||
| 47 | if (start) { | 78 | if (start) { |
| 48 | var s = document.createElement('input'); | 79 | var s = document.createElement('input'); |
| 49 | s.type = 'hidden'; s.name = 'start_revision'; s.value = start.value; | 80 | s.type = 'hidden'; s.name = 'start_revision'; s.value = start.value; |
| @@ -54,5 +85,10 @@ | |||
| 54 | en.type = 'hidden'; en.name = 'end_revision'; en.value = end.value; | 85 | en.type = 'hidden'; en.name = 'end_revision'; en.value = end.value; |
| 55 | this.appendChild(en); | 86 | this.appendChild(en); |
| 56 | } | 87 | } |
| 88 | if (view) { | ||
| 89 | var v = document.createElement('input'); | ||
| 90 | v.type = 'hidden'; v.name = 'view'; v.value = view.value; | ||
| 91 | this.appendChild(v); | ||
| 92 | } | ||
| 57 | }); | 93 | }); |
| 58 | </script> | 94 | </script> |
diff --git a/app/views/revisions/show.html.erb b/app/views/revisions/show.html.erb index f2a2895..92d959b 100644 --- a/app/views/revisions/show.html.erb +++ b/app/views/revisions/show.html.erb | |||
| @@ -1,54 +1,38 @@ | |||
| 1 | <% content_for :subnavigation do %> | ||
| 2 | <%= link_to 'show all revisions', node_revisions_path(@node) %> | ||
| 3 | <% end %> | ||
| 4 | |||
| 5 | <div id="page_editor" class="show_node"> | 1 | <div id="page_editor" class="show_node"> |
| 6 | <table id="content"> | 2 | <h1>Revision <%= @page.revision %>: <%= @page.title %></h1> |
| 7 | <tr> | 3 | |
| 8 | <td class="description">Path</td> | 4 | <div id="content"> |
| 9 | <td><%= @page.public_link %></td> | 5 | <div class="node_description">Actions</div> |
| 10 | </tr> | 6 | <div class="node_content node_info_group"> |
| 11 | <tr> | 7 | <div class="node_info_group_items"> |
| 12 | <td class="description">Author</td> | 8 | <div class="node_info_item"> |
| 13 | <td><%= @page.user.try(:login) %></td> | 9 | <%= link_to 'Show all revisions', node_revisions_path(@node) %> |
| 14 | </tr> | 10 | </div> |
| 15 | <tr> | 11 | </div> |
| 16 | <td class="description">Editor</td> | 12 | </div> |
| 17 | <td><%= @page.editor.try(:login) %></td> | 13 | |
| 18 | </tr> | 14 | <div class="node_description">Path</div> |
| 19 | <% if @page.node.locked? %> | 15 | <div class="node_content"><%= @page.public_link %></div> |
| 20 | <tr> | 16 | |
| 21 | <td class="description">Locked by</td> | 17 | <div class="node_description">Author</div> |
| 22 | <td><%= @page.node.lock_owner.login %></td> | 18 | <div class="node_content"><%= @page.user.try(:login) %></div> |
| 23 | </tr> | 19 | |
| 24 | <% end %> | 20 | <div class="node_description">Editor</div> |
| 25 | <tr> | 21 | <div class="node_content"><%= @page.editor.try(:login) %></div> |
| 26 | <td class="description">Last updated</td> | 22 | |
| 27 | <td><%= @page.updated_at %></td> | 23 | <div class="node_description">Last updated</div> |
| 28 | </tr> | 24 | <div class="node_content"><%= @page.updated_at %></div> |
| 29 | <tr> | 25 | |
| 30 | <td class="description">Published at</td> | 26 | <div class="node_description">Published at</div> |
| 31 | <td><%= @page.published_at %></td> | 27 | <div class="node_content"><%= @page.published_at %></div> |
| 32 | </tr> | 28 | |
| 33 | <tr> | 29 | <div class="node_description">Title</div> |
| 34 | <td class="description">Revision</td> | 30 | <div class="node_content"><%= @page.title %></div> |
| 35 | <td><%= @page.revision %></td> | 31 | |
| 36 | </tr> | 32 | <div class="node_description">Abstract</div> |
| 37 | <tr> | 33 | <div class="node_content"><%= @page.abstract %></div> |
| 38 | <td class="description"><strong>Title</strong></td> | 34 | |
| 39 | <td><%= @page.title %></td> | 35 | <div class="node_description">Body</div> |
| 40 | </tr> | 36 | <div class="node_content"><%= raw @page.body %></div> |
| 41 | <tr> | 37 | </div> |
| 42 | <td class="description"><strong>Abstract</strong></td> | 38 | </div> |
| 43 | <td><%= @page.abstract %></td> | ||
| 44 | </tr> | ||
| 45 | <tr> | ||
| 46 | <td class="description"><strong>Body</strong></td> | ||
| 47 | <td><%= @page.body %></td> | ||
| 48 | </tr> | ||
| 49 | <tr> | ||
| 50 | <td></td> | ||
| 51 | <td class="right"></td> | ||
| 52 | </tr> | ||
| 53 | </table> | ||
| 54 | </div> \ No newline at end of file | ||
diff --git a/app/views/rss/updates.xml.builder b/app/views/rss/updates.xml.builder index 4b2e2f7..27845c4 100644 --- a/app/views/rss/updates.xml.builder +++ b/app/views/rss/updates.xml.builder | |||
| @@ -22,9 +22,7 @@ xml.feed(:xmlns => "http://www.w3.org/2005/Atom", "xml:base" => @host) do | |||
| 22 | xml.updated(item.updated_at.xmlschema) | 22 | xml.updated(item.updated_at.xmlschema) |
| 23 | xml.published(item.published_at.xmlschema) | 23 | xml.published(item.published_at.xmlschema) |
| 24 | xml.summary(CGI.escapeHTML(item.abstract.to_s)) | 24 | xml.summary(CGI.escapeHTML(item.abstract.to_s)) |
| 25 | xml.content(:type => "xhtml") do | 25 | xml.content(CGI.escapeHTML(item.body.to_s), :type => "html") |
| 26 | xml.div(item.body, :xmlns => "http://www.w3.org/1999/xhtml") | ||
| 27 | end | ||
| 28 | end | 26 | end |
| 29 | 27 | ||
| 30 | end | 28 | end |
diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 3c10303..23952b7 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb | |||
| @@ -1,24 +1,15 @@ | |||
| 1 | <div id="login_form"> | 1 | <div id="login_form"> |
| 2 | <%= form_tag session_path do -%> | 2 | <%= form_tag session_path do -%> |
| 3 | <table> | 3 | <% if flash[:error] %> |
| 4 | <tr> | 4 | <div class="error_messages"><%= flash[:error] %></div> |
| 5 | <td></td> | 5 | <% end %> |
| 6 | <td> | 6 | |
| 7 | <%= flash[:error] %> | 7 | <div class="node_description">Login</div> |
| 8 | </td> | 8 | <div class="node_content"><%= text_field_tag 'login', @login %></div> |
| 9 | </tr> | 9 | |
| 10 | <tr> | 10 | <div class="node_description">Password</div> |
| 11 | <td class="description">Login</td> | 11 | <div class="node_content"><%= password_field_tag 'password', nil %></div> |
| 12 | <td><%= text_field_tag 'login', @login %></td> | 12 | |
| 13 | </tr> | 13 | <div class="node_content"><%= submit_tag 'log in' %></div> |
| 14 | <tr> | ||
| 15 | <td class="description">Password</td> | ||
| 16 | <td><%= password_field_tag 'password', nil %></td> | ||
| 17 | </tr> | ||
| 18 | <tr> | ||
| 19 | <td></td> | ||
| 20 | <td class="right"><%= submit_tag 'log in' %></td> | ||
| 21 | </tr> | ||
| 22 | </table> | ||
| 23 | <% end -%> | 14 | <% end -%> |
| 24 | </div> | 15 | </div> |
diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb index ddb7afd..3a88f5e 100644 --- a/app/views/users/_user.html.erb +++ b/app/views/users/_user.html.erb | |||
| @@ -7,9 +7,10 @@ | |||
| 7 | <%= link_to "edit", edit_user_path(user) %> | 7 | <%= link_to "edit", edit_user_path(user) %> |
| 8 | </td> | 8 | </td> |
| 9 | <td> | 9 | <td> |
| 10 | <%= button_to "destroy", user_path(user), | 10 | <%= button_to user_path(user), method: :delete, |
| 11 | method: :delete, | 11 | form: { data: { confirm: "Do you really want to destroy user #{user.login}?" }, class: 'button_to destructive' } do %> |
| 12 | form: { data: { confirm: "Do you really want to delete user #{user.login}?" } } %> | 12 | <%= icon("trash", library: "tabler", "aria-hidden": true) %> Destroy |
| 13 | <% end %> | ||
| 13 | </td> | 14 | </td> |
| 14 | <% end %> | 15 | <% end %> |
| 15 | </tr> | 16 | </tr> |
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index df1005b..77b33c6 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb | |||
| @@ -2,38 +2,32 @@ | |||
| 2 | 2 | ||
| 3 | <% if @user.errors.any? %> | 3 | <% if @user.errors.any? %> |
| 4 | <div class="error_messages"> | 4 | <div class="error_messages"> |
| 5 | <ul><% @user.errors.full_messages.each do |msg| %><li><%= msg.gsub("Slug", "Title") %></li><% end %></ul> | 5 | <ul><% @user.errors.full_messages.each do |msg| %><li><%= msg %></li><% end %></ul> |
| 6 | </div> | 6 | </div> |
| 7 | <% end %> | 7 | <% end %> |
| 8 | 8 | ||
| 9 | <div id="page_editor"> | ||
| 10 | <%= form_for @user do |f| %> | ||
| 11 | <div id="content"> | ||
| 12 | <div class="node_description">Login</div> | ||
| 13 | <div class="node_content"><%= f.text_field :login %></div> | ||
| 9 | 14 | ||
| 10 | <%= form_for @user do |f| %> | 15 | <div class="node_description">E-Mail</div> |
| 11 | <table id="new_node"> | 16 | <div class="node_content"><%= f.text_field :email %></div> |
| 12 | <tr> | 17 | |
| 13 | <td class="description">Login</td> | 18 | <div class="node_description">Password</div> |
| 14 | <td><%= f.text_field :login %></td> | 19 | <div class="node_content"><%= f.password_field :password %></div> |
| 15 | </tr> | 20 | |
| 16 | <tr> | 21 | <div class="node_description">Confirm</div> |
| 17 | <td class="description">E-Mail</td> | 22 | <div class="node_content"><%= f.password_field :password_confirmation %></div> |
| 18 | <td><%= f.text_field :email %></td> | 23 | |
| 19 | </tr> | 24 | <% if current_user.admin? %> |
| 20 | <tr> | 25 | <div class="node_description">Admin?</div> |
| 21 | <td class="description">Password</td> | 26 | <div class="node_content"><%= f.check_box :admin %></div> |
| 22 | <td><%= f.password_field :password %></td> | 27 | <% end %> |
| 23 | </tr> | 28 | |
| 24 | <tr> | 29 | <div class="node_description"></div> |
| 25 | <td class="description">Confirm</td> | 30 | <div class="node_content"><%= f.submit "Update" %></div> |
| 26 | <td><%= f.password_field :password_confirmation %></td> | ||
| 27 | </tr> | ||
| 28 | <% if current_user.admin? %> | ||
| 29 | <tr> | ||
| 30 | <td class="description">Admin?</td> | ||
| 31 | <td><%= f.check_box :admin %></td> | ||
| 32 | </tr> | ||
| 33 | <% end %> | 31 | <% end %> |
| 34 | <tr> | 32 | </div> |
| 35 | <td class="description"></td> | 33 | </div> |
| 36 | <td class="right"><%= f.submit "Update" %></td> | ||
| 37 | </tr> | ||
| 38 | </table> | ||
| 39 | <% end %> | ||
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index 59806db..4f5266d 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb | |||
| @@ -1,14 +1,27 @@ | |||
| 1 | <table class="user_list"> | 1 | <h1>Admins</h1> |
| 2 | <tr> | 2 | <%= link_to new_user_path(admin: true), class: 'action_button' do %> |
| 3 | <td><h1>Admins</h1></td> | 3 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create admin user |
| 4 | <% end %> | ||
| 5 | <table class="user_table"> | ||
| 6 | <tr class="header"> | ||
| 7 | <th>Login</th> | ||
| 8 | <th></th> | ||
| 9 | <th></th> | ||
| 10 | <th></th> | ||
| 4 | </tr> | 11 | </tr> |
| 5 | <%= render :partial => "user", :locals => {:users => @users[:admin] ||= []} %> | 12 | <%= render :partial => "user", :locals => {:users => @users[:admin] ||= []} %> |
| 6 | <tr> | 13 | </table> |
| 7 | <td><h1>Users</h1></td> | 14 | |
| 15 | <h1>Users</h1> | ||
| 16 | <%= link_to new_user_path, class: 'action_button' do %> | ||
| 17 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create user | ||
| 18 | <% end %> | ||
| 19 | <table class="user_table"> | ||
| 20 | <tr class="header"> | ||
| 21 | <th>Login</th> | ||
| 22 | <th></th> | ||
| 23 | <th></th> | ||
| 24 | <th></th> | ||
| 8 | </tr> | 25 | </tr> |
| 9 | <%= render :partial => "user", :locals => {:users => @users[:user] ||= []} %> | 26 | <%= render :partial => "user", :locals => {:users => @users[:user] ||= []} %> |
| 10 | </table> | 27 | </table> |
| 11 | |||
| 12 | <% content_for :subnavigation do %> | ||
| 13 | <%= link_to "create", new_user_path %> | ||
| 14 | <% end %> \ No newline at end of file | ||
diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 6beda4f..ce38fdf 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb | |||
| @@ -2,36 +2,30 @@ | |||
| 2 | 2 | ||
| 3 | <% if @user.errors.any? %> | 3 | <% if @user.errors.any? %> |
| 4 | <div class="error_messages"> | 4 | <div class="error_messages"> |
| 5 | <ul><% @user.errors.full_messages.each do |msg| %><li><%= msg.gsub("Slug", "Title") %></li><% end %></ul> | 5 | <ul><% @user.errors.full_messages.each do |msg| %><li><%= msg %></li><% end %></ul> |
| 6 | </div> | 6 | </div> |
| 7 | <% end %> | 7 | <% end %> |
| 8 | 8 | ||
| 9 | <div id="page_editor"> | ||
| 10 | <%= form_for @user do |f| %> | ||
| 11 | <div id="content"> | ||
| 12 | <div class="node_description">Login</div> | ||
| 13 | <div class="node_content"><%= f.text_field :login %></div> | ||
| 9 | 14 | ||
| 10 | <%= form_for @user do |f| %> | 15 | <div class="node_description">E-Mail</div> |
| 11 | <table id="new_node"> | 16 | <div class="node_content"><%= f.text_field :email %></div> |
| 12 | <tr> | 17 | |
| 13 | <td class="description">Login</td> | 18 | <div class="node_description">Password</div> |
| 14 | <td><%= f.text_field :login %></td> | 19 | <div class="node_content"><%= f.password_field :password %></div> |
| 15 | </tr> | 20 | |
| 16 | <tr> | 21 | <div class="node_description">Confirm</div> |
| 17 | <td class="description">E-Mail</td> | 22 | <div class="node_content"><%= f.password_field :password_confirmation %></div> |
| 18 | <td><%= f.text_field :email %></td> | 23 | |
| 19 | </tr> | 24 | <div class="node_description">Admin?</div> |
| 20 | <tr> | 25 | <div class="node_content"><%= f.check_box :admin %></div> |
| 21 | <td class="description">Password</td> | 26 | |
| 22 | <td><%= f.password_field :password %></td> | 27 | <div class="node_description"></div> |
| 23 | </tr> | 28 | <div class="node_content"><%= f.submit "Create" %></div> |
| 24 | <tr> | 29 | <% end %> |
| 25 | <td class="description">Confirm</td> | 30 | </div> |
| 26 | <td><%= f.password_field :password_confirmation %></td> | 31 | </div> |
| 27 | </tr> | ||
| 28 | <tr> | ||
| 29 | <td class="description">Admin?</td> | ||
| 30 | <td><%= f.check_box :admin %></td> | ||
| 31 | </tr> | ||
| 32 | <tr> | ||
| 33 | <td class="description"></td> | ||
| 34 | <td class="right"><%= f.submit "Create" %></td> | ||
| 35 | </tr> | ||
| 36 | </table> | ||
| 37 | <% end %> | ||
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 80483d3..70881db 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb | |||
| @@ -1,20 +1,25 @@ | |||
| 1 | <% content_for :subnavigation do %> | 1 | <div id="page_editor"> |
| 2 | <%= link_to 'Edit', edit_user_path(@user) %> | 2 | <h1><%= @user.login %></h1> |
| 3 | <% end %> | ||
| 4 | 3 | ||
| 5 | <h1>User: <%= @user.login %></h1> | 4 | <div id="content"> |
| 5 | <div class="node_description">Actions</div> | ||
| 6 | <div class="node_content node_info_group"> | ||
| 7 | <div class="node_info_group_items"> | ||
| 8 | <div class="node_info_item"> | ||
| 9 | <%= link_to edit_user_path(@user), class: 'action_button' do %> | ||
| 10 | <%= icon("edit", library: "tabler", "aria-hidden": true) %> Edit | ||
| 11 | <% end %> | ||
| 12 | </div> | ||
| 13 | </div> | ||
| 14 | </div> | ||
| 6 | 15 | ||
| 7 | <table id="new_node"> | 16 | <div class="node_description">Login</div> |
| 8 | <tr> | 17 | <div class="node_content"><%= @user.login %></div> |
| 9 | <td class="description">Login</td> | 18 | |
| 10 | <td><%= @user.login %></td> | 19 | <div class="node_description">E-Mail</div> |
| 11 | </tr> | 20 | <div class="node_content"><%= @user.email %></div> |
| 12 | <tr> | 21 | |
| 13 | <td class="description">E-Mail</td> | 22 | <div class="node_description">Admin?</div> |
| 14 | <td><%= @user.email %></td> | 23 | <div class="node_content"><%= @user.admin ? "yes" : "no" %></div> |
| 15 | </tr> | 24 | </div> |
| 16 | <tr> | 25 | </div> |
| 17 | <td class="description">Admin?</td> | ||
| 18 | <td><%= @user.admin ? "yes" : "no" %></td> | ||
| 19 | </tr> | ||
| 20 | </table> \ No newline at end of file | ||
