alchemy_cms 5.1.0.beta2 → 5.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e12f510dae37d181a93e110634f158c8f3fac7231c489579d61118528c1174a
4
- data.tar.gz: 467204837b948c660077c45e0dab282d23fff3c79a1fea854658d05098a3b8b7
3
+ metadata.gz: de384cea86fc5b57fd32980a289b81cc172a08bd6d9bea7f2fce58764247d5af
4
+ data.tar.gz: d82439febbc4a16884d31dcf84bf206ee7d886c2793ffa35d634611a522966ea
5
5
  SHA512:
6
- metadata.gz: 3037cd0a408e63b6edde1c58bc398ec4d377d6a9452caf0e6d8b418b438eb8e7176ca8336f5987089caf355c90e68fbca04ab7df3ac67fca76654efcf00d2cab
7
- data.tar.gz: d5a363910f6e4bfb221094c15f33c550dc3650c5eae35a375ea187e92bdac102e31c155168f336c1fa8f11a22235ff1558cc5433ad34fadc79cf59d28e0d883e
6
+ metadata.gz: cf29a07639284f89bac148065a3d2fdac90f8b24fba245d1af97e7dbb045bf7ee59f88b56a16c7f2211d99c9160605bd9be24ba7a333771b08a96d9c53450d60
7
+ data.tar.gz: 59d1b77141ab07bd6faa3733e730fb03e47bafa60ea855b339ca202239c99052c968b9419a6fd6bd7378250335d378fb883d2b1de638c7f14bc68204c32cac9c
@@ -8,6 +8,7 @@
8
8
  - Store current pictures size in session [#1927](https://github.com/AlchemyCMS/alchemy_cms/pull/1927) ([tvdeyen](https://github.com/tvdeyen))
9
9
  - Add support for custom mount points in Page::UrlPath [#1921](https://github.com/AlchemyCMS/alchemy_cms/pull/1921) ([tvdeyen](https://github.com/tvdeyen))
10
10
  - Allow to set a custom Page::UrlPath class [#1919](https://github.com/AlchemyCMS/alchemy_cms/pull/1919) ([tvdeyen](https://github.com/tvdeyen))
11
+ - Introduce a pages list view [#1906](https://github.com/AlchemyCMS/alchemy_cms/pull/1906) ([tvdeyen](https://github.com/tvdeyen))
11
12
 
12
13
  ### Changes
13
14
 
@@ -54,6 +54,7 @@ Gem::Specification.new do |gem|
54
54
  gem.add_development_dependency 'webdrivers', ['~> 4.0']
55
55
  gem.add_development_dependency 'webmock', ['~> 3.3']
56
56
  gem.add_development_dependency 'shoulda-matchers', ['~> 4.0']
57
+ gem.add_development_dependency 'timecop', ['~> 0.9']
57
58
 
58
59
  gem.post_install_message = <<-MSG
59
60
  -------------------------------------------------------------
@@ -1,4 +1,7 @@
1
- button, input[type="submit"], a.button, input.button {
1
+ button,
2
+ input[type="submit"],
3
+ a.button,
4
+ input.button {
2
5
  @include button-defaults;
3
6
  position: relative;
4
7
 
@@ -14,7 +17,8 @@ button, input[type="submit"], a.button, input.button {
14
17
  );
15
18
  }
16
19
 
17
- &:active, &:active:focus {
20
+ &:active,
21
+ &:active:focus {
18
22
  border-color: $button-hover-border-color;
19
23
  box-shadow: none;
20
24
  }
@@ -23,7 +27,7 @@ button, input[type="submit"], a.button, input.button {
23
27
  &.small {
24
28
  padding: $small-button-padding;
25
29
  vertical-align: inherit;
26
- line-height: 4*$default-padding;
30
+ line-height: 4 * $default-padding;
27
31
  font-size: inherit;
28
32
  }
29
33
 
@@ -83,13 +87,14 @@ button, input[type="submit"], a.button, input.button {
83
87
  border: $default-border-width $default-border-style $icon-color;
84
88
  color: $icon-color;
85
89
 
86
- .icon { color: inherit }
90
+ .icon {
91
+ color: inherit;
92
+ }
87
93
  }
88
94
  }
89
95
 
90
96
  &.disabled,
91
97
  &[disabled] {
92
-
93
98
  span {
94
99
  opacity: 0.3;
95
100
  cursor: not-allowed;
@@ -118,7 +123,8 @@ button.icon_button {
118
123
  border: 0 none;
119
124
  box-shadow: none;
120
125
 
121
- &:disabled, &.disabled {
126
+ &:disabled,
127
+ &.disabled {
122
128
  background: transparent;
123
129
  }
124
130
  }
@@ -131,10 +137,15 @@ button.icon_button {
131
137
  position: relative;
132
138
  display: inline-block;
133
139
  text-align: center;
134
- margin: 0 2*$default-margin;
135
140
 
136
- &.active, &:active, &:hover {
137
- .icon_button:not([disabled]) {
141
+ .toolbar_buttons & {
142
+ margin: 0 2 * $default-margin;
143
+ }
144
+
145
+ &.active,
146
+ &:active,
147
+ &:hover {
148
+ .icon_button:not([disabled]) {
138
149
  background-color: $default-border-color;
139
150
  cursor: pointer;
140
151
  }
@@ -161,8 +172,8 @@ button.icon_button {
161
172
  }
162
173
  }
163
174
 
164
- .button_with_label, .button_group {
165
-
175
+ .button_with_label,
176
+ .button_group {
166
177
  .icon_button {
167
178
  width: 29px;
168
179
  height: 29px;
@@ -179,16 +190,16 @@ button.icon_button {
179
190
  z-index: 30;
180
191
  background-color: $tooltip-background-color;
181
192
  color: $white;
182
- padding: $default-padding 2*$default-padding 1.5*$default-padding;
193
+ padding: $default-padding 2 * $default-padding 1.5 * $default-padding;
183
194
  line-height: 1;
184
195
  box-shadow: 0 0 4px $default-border-color;
185
196
  white-space: nowrap;
186
197
  pointer-events: none;
187
198
  opacity: 0;
188
- transition: .3s;
199
+ transition: 0.3s;
189
200
 
190
201
  &:before {
191
- content: '';
202
+ content: "";
192
203
  position: absolute;
193
204
  bottom: -10px;
194
205
  left: 8px;
@@ -238,6 +249,6 @@ button.icon_button {
238
249
  visibility: visible;
239
250
  opacity: 1;
240
251
  top: -25px;
241
- transition-delay: .2s;
252
+ transition-delay: 0.2s;
242
253
  }
243
254
  }
@@ -6,7 +6,8 @@ table {
6
6
  width: 100%;
7
7
 
8
8
  &.list .tools {
9
- button, a {
9
+ button,
10
+ a {
10
11
  display: inline-block;
11
12
  width: 18px;
12
13
  height: 18px;
@@ -22,8 +23,9 @@ table {
22
23
  }
23
24
  }
24
25
 
25
- .list td, .list th {
26
- padding: 2*$default-padding;
26
+ .list td,
27
+ .list th {
28
+ padding: 2 * $default-padding;
27
29
  vertical-align: top;
28
30
  line-height: 18px;
29
31
  border-right: 1px solid $medium-gray;
@@ -93,9 +95,10 @@ td.heading {
93
95
  background-color: $table-row-hover-color;
94
96
  }
95
97
 
96
- td, th {
97
-
98
- &.center, &.boolean {
98
+ td,
99
+ th {
100
+ &.center,
101
+ &.boolean {
99
102
  text-align: center;
100
103
  }
101
104
 
@@ -105,7 +108,6 @@ td, th {
105
108
  }
106
109
 
107
110
  td {
108
-
109
111
  &.file_name {
110
112
  word-break: break-all;
111
113
  }
@@ -118,7 +120,8 @@ td {
118
120
  width: 80px;
119
121
  }
120
122
 
121
- &.date, &.datetime {
123
+ &.date,
124
+ &.datetime {
122
125
  width: 150px;
123
126
  }
124
127
 
@@ -137,9 +140,35 @@ td {
137
140
  &.rights {
138
141
  width: 60px;
139
142
  }
143
+
144
+ &.page_layout {
145
+ width: 160px;
146
+ }
147
+
148
+ &.status {
149
+ width: 80px;
150
+
151
+ .page_status {
152
+ margin: 0 $default-margin;
153
+ }
154
+ }
155
+
156
+ &.tags {
157
+ width: 180px;
158
+
159
+ .tag {
160
+ margin: 0;
161
+ padding: 0 2 + $default-padding;
162
+
163
+ &:before {
164
+ padding-right: $default-padding;
165
+ }
166
+ }
167
+ }
140
168
  }
141
169
 
142
- th.count, td.count {
170
+ th.count,
171
+ td.count {
143
172
  width: 120px;
144
173
  text-align: right;
145
174
  padding-right: 16px;
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Alchemy
4
4
  module Admin
5
- class PagesController < Alchemy::Admin::BaseController
5
+ class PagesController < ResourcesController
6
6
  include OnPageLayout::CallbacksRunner
7
7
 
8
8
  helper "alchemy/pages"
9
9
 
10
- before_action :load_page, except: [:index, :flush, :new, :order, :create, :copy_language_tree, :link, :sort]
10
+ before_action :load_resource, except: [:index, :flush, :new, :order, :create, :copy_language_tree, :link, :sort]
11
11
 
12
12
  authorize_resource class: Alchemy::Page, except: [:index, :tree]
13
13
 
@@ -27,11 +27,33 @@ module Alchemy
27
27
  if: :run_on_page_layout_callbacks?,
28
28
  only: [:show]
29
29
 
30
+ before_action :load_languages_and_layouts,
31
+ unless: -> { @page_root },
32
+ only: [:index]
33
+
34
+ before_action :set_view, only: [:index]
35
+
30
36
  def index
31
- if !@page_root
32
- @language = @current_language
33
- @languages_with_page_tree = Language.on_current_site.with_root_page
34
- @page_layouts = PageLayout.layouts_for_select(@language.id)
37
+ @query = @current_language.pages.contentpages.ransack(search_filter_params[:q])
38
+
39
+ if @view == "list"
40
+ @query.sorts = default_sort_order if @query.sorts.empty?
41
+ items = @query.result
42
+
43
+ if search_filter_params[:tagged_with].present?
44
+ items = items.tagged_with(search_filter_params[:tagged_with])
45
+ end
46
+
47
+ if search_filter_params[:filter].present?
48
+ items = items.public_send(sanitized_filter_params)
49
+ end
50
+
51
+ if search_filter_params[:page_layout].present?
52
+ items = items.where(page_layout: search_filter_params[:page_layout])
53
+ end
54
+
55
+ items = items.page(params[:page] || 1).per(items_per_page)
56
+ @pages = items
35
57
  end
36
58
  end
37
59
 
@@ -229,6 +251,19 @@ module Alchemy
229
251
 
230
252
  private
231
253
 
254
+ def resource_handler
255
+ @_resource_handler ||= Alchemy::Resource.new(controller_path, alchemy_module, Alchemy::Page)
256
+ end
257
+
258
+ def common_search_filter_includes
259
+ super.push(:page_layout, :view)
260
+ end
261
+
262
+ def set_view
263
+ @view = params[:view] || session[:alchemy_pages_view] || "tree"
264
+ session[:alchemy_pages_view] = @view
265
+ end
266
+
232
267
  def copy_of_language_root
233
268
  Page.copy(
234
269
  language_root_to_copy_from,
@@ -310,7 +345,7 @@ module Alchemy
310
345
  { my_urlname: default_urlname, children_path: default_urlname }
311
346
  end
312
347
 
313
- def load_page
348
+ def load_resource
314
349
  @page = Page.find(params[:id])
315
350
  end
316
351
 
@@ -373,6 +408,12 @@ module Alchemy
373
408
  user: current_alchemy_user,
374
409
  full: params[:full] == "true")
375
410
  end
411
+
412
+ def load_languages_and_layouts
413
+ @language = @current_language
414
+ @languages_with_page_tree = Language.on_current_site.with_root_page
415
+ @page_layouts = PageLayout.layouts_for_select(@language.id)
416
+ end
376
417
  end
377
418
  end
378
419
  end
@@ -164,6 +164,14 @@ module Alchemy
164
164
  @_url_path_class = klass
165
165
  end
166
166
 
167
+ def alchemy_resource_filters
168
+ %w[published not_public restricted]
169
+ end
170
+
171
+ def searchable_alchemy_resource_attributes
172
+ %w[name urlname title]
173
+ end
174
+
167
175
  # Used to store the current page previewed in the edit page template.
168
176
  #
169
177
  def current_preview=(page)
@@ -25,10 +25,38 @@ module Alchemy
25
25
  end
26
26
  end
27
27
 
28
- # Returns site's layout definition
28
+ # Returns sites layout definition
29
29
  #
30
30
  def definition
31
- self.class.definitions.detect { |l| l["name"] == partial_name }
31
+ self.class.definitions.detect { |l| l["name"] == partial_name } || {}
32
+ end
33
+
34
+ # Returns sites page layout names
35
+ #
36
+ # If no site layout file is defined all page layouts are returned
37
+ #
38
+ # @param [Boolean] layoutpages Return layout pages only (default false)
39
+ #
40
+ # @return [Array<String>] Array of page layout names
41
+ #
42
+ def page_layout_names(layoutpages: false)
43
+ page_layout_definitions.select do |layout|
44
+ !!layout["layoutpage"] && layoutpages || !layout["layoutpage"] && !layoutpages
45
+ end.collect { |layout| layout["name"] }
46
+ end
47
+
48
+ # Returns sites page layout definitions
49
+ #
50
+ # If no site layout file is defined all page layouts are returned
51
+ #
52
+ def page_layout_definitions
53
+ if definition["page_layouts"].presence
54
+ Alchemy::PageLayout.all.select do |layout|
55
+ layout["name"].in?(definition["page_layouts"])
56
+ end
57
+ else
58
+ Alchemy::PageLayout.all
59
+ end
32
60
  end
33
61
 
34
62
  # Returns the name for the layout partial
@@ -1,8 +1,7 @@
1
1
  <div class="panel">
2
2
  <%= render_message do %>
3
- <p><%= Alchemy.t(:language_does_not_exist) %></p>
3
+ <p><%= Alchemy.t(:homepage_does_not_exist) %></p>
4
4
  <% end %>
5
- <%- if @language -%>
6
5
 
7
6
  <%- if @languages_with_page_tree.size >= 1 -%>
8
7
  <%= form_tag(alchemy.copy_language_tree_admin_pages_path) do %>
@@ -19,32 +18,23 @@
19
18
  <% end %>
20
19
  <%- end -%>
21
20
 
22
- <%- if params[:action] == "index" -%>
23
- <%= alchemy_form_for([:admin, Alchemy::Page.new], id: 'create_language_tree') do |form| %>
24
- <% if @languages_with_page_tree.size >= 1 %>
25
- <h3><%= Alchemy.t(:create_language_tree_heading) %></h3>
26
- <p><%= Alchemy.t(:want_to_create_new_language) %></p>
27
- <% end %>
28
- <%= form.input :name, input_html: {value: @language.frontpage_name} %>
29
- <%= form.input :page_layout,
30
- collection: @page_layouts,
31
- selected: @language.page_layout,
32
- label: Alchemy.t(:page_type),
33
- include_blank: Alchemy.t('Please choose'),
34
- required: true,
35
- input_html: {class: 'alchemy_selectbox'} %>
36
- <%= form.hidden_field :language_id, value: @language.id %>
37
- <%= form.hidden_field :language_code, value: @language.code %>
38
- <%= form.hidden_field :language_root, value: true %>
39
- <%= form.hidden_field :public, value: Alchemy::Language.all.size == 1 %>
40
- <%= form.submit Alchemy.t("create_tree_as_new_language", language: @language.name), autofocus: true %>
21
+ <%= alchemy_form_for([:admin, Alchemy::Page.new], id: 'create_language_tree') do |form| %>
22
+ <% if @languages_with_page_tree.size >= 1 %>
23
+ <h3><%= Alchemy.t(:create_language_tree_heading) %></h3>
24
+ <p><%= Alchemy.t(:want_to_create_new_language) %></p>
41
25
  <% end %>
42
- <%- end -%>
43
-
44
- <%- else -%>
45
-
46
- <p><%= Alchemy.t("Actually this language does not exist. Please create this language first.") %></p>
47
-
48
- <%- end -%>
49
-
26
+ <%= form.input :name, input_html: {value: @language.frontpage_name} %>
27
+ <%= form.input :page_layout,
28
+ collection: @page_layouts,
29
+ selected: @language.page_layout,
30
+ label: Alchemy.t(:page_type),
31
+ include_blank: Alchemy.t('Please choose'),
32
+ required: true,
33
+ input_html: {class: 'alchemy_selectbox'} %>
34
+ <%= form.hidden_field :language_id, value: @language.id %>
35
+ <%= form.hidden_field :language_code, value: @language.code %>
36
+ <%= form.hidden_field :language_root, value: true %>
37
+ <%= form.hidden_field :public, value: Alchemy::Language.all.size == 1 %>
38
+ <%= form.submit Alchemy.t(:create), autofocus: true %>
39
+ <% end %>
50
40
  </div>
@@ -1,5 +1,14 @@
1
1
  <%= alchemy_form_for([:admin, @page]) do |f| %>
2
- <%= f.hidden_field(:parent_id) %>
2
+ <% if @page.parent_id || @page.layoutpage %>
3
+ <%= f.hidden_field(:parent_id) %>
4
+ <% else %>
5
+ <% @page.parent = @current_language.root_page %>
6
+ <%= f.input :parent_id,
7
+ collection: @current_language.pages.contentpages,
8
+ label_method: :name,
9
+ value_method: :id,
10
+ input_html: { class: "alchemy_selectbox" } %>
11
+ <% end %>
3
12
  <%= f.hidden_field(:language_id) %>
4
13
  <%= f.hidden_field(:layoutpage) %>
5
14
  <%= f.input :page_layout,
@@ -0,0 +1,29 @@
1
+ <div id="page_layout_filter">
2
+ <label>
3
+ <h3><%= Alchemy::Page.human_attribute_name(:page_layout) %></h3>
4
+ <%= select_tag(
5
+ "page_layout",
6
+ options_for_select(
7
+ @current_language.site.page_layout_names.map do |layout|
8
+ [
9
+ Alchemy::PageLayout.human_layout_name(layout),
10
+ layout
11
+ ]
12
+ end,
13
+ search_filter_params[:page_layout]
14
+ ),
15
+ include_blank: Alchemy.t(:all, scope: ["resources", "page", "filters"]),
16
+ class: "alchemy_selectbox full_width"
17
+ ) %>
18
+ </label>
19
+ </div>
20
+
21
+ <script type="text/javascript">
22
+ $(function() {
23
+ $("#page_layout").on("change", function(e) {
24
+ var url = "<%= alchemy.admin_pages_path(search_filter_params.except(:page_layout, :page).merge(view: "list")) %>";
25
+ delimiter = url.match(/\?/) ? "&" : "?";
26
+ Turbolinks.visit(url + delimiter + "page_layout=" + encodeURIComponent($(this).val()));
27
+ });
28
+ });
29
+ </script>
@@ -0,0 +1,27 @@
1
+ <table class="list">
2
+ <thead>
3
+ <tr>
4
+ <th class="icon"></th>
5
+ <th class="string name">
6
+ <%= sort_link [:alchemy, @query],
7
+ "name",
8
+ Alchemy::Page.human_attribute_name(:name),
9
+ default_order: "asc" %>
10
+ </th>
11
+ <th><%= Alchemy::Page.human_attribute_name(:urlname) %></th>
12
+ <th><%= Alchemy::Page.human_attribute_name(:page_type) %></th>
13
+ <th><%= Alchemy::Page.human_attribute_name(:tag_list) %></th>
14
+ <th>
15
+ <%= sort_link [:alchemy, @query],
16
+ :updated_at,
17
+ Alchemy::Page.human_attribute_name(:updated_at),
18
+ default_order: "desc" %>
19
+ </th>
20
+ <th class="status center"><%= Alchemy::Page.human_attribute_name(:status) %></th>
21
+ <th class="tools"></th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <%= render partial: "table_row", collection: @pages, as: "page" %>
26
+ </tbody>
27
+ </table>
@@ -0,0 +1,107 @@
1
+ <tr class="<%= cycle(:even, :odd) %>" data-page-id="<%= page.id %>">
2
+ <td class="icon">
3
+ <% if can?(:edit_content, page) %>
4
+ <% if page.locked? %>
5
+ <span class="with-hint">
6
+ <i class="icon fas fa-edit fa-fw"></i>
7
+ <span class="hint-bubble">
8
+ <%= Alchemy.t("This page is locked", name: page.locker_name) %>
9
+ </span>
10
+ </span>
11
+ <% else %>
12
+ <i class="icon far fa-file fa-lg"></i>
13
+ <% end %>
14
+ <% else %>
15
+ <span class="with-hint">
16
+ <i class="icon fas fa-ban fa-fw"></i>
17
+ <span class="hint-bubble">
18
+ <%= Alchemy.t("Your user role does not allow you to edit this page") %>
19
+ </span>
20
+ </span>
21
+ <% end %>
22
+ </td>
23
+ <td class="string name">
24
+ <%= link_to_if(
25
+ can?(:edit_content, page),
26
+ page.name,
27
+ alchemy.edit_admin_page_path(page),
28
+ title: Alchemy.t(:edit_page),
29
+ ) { content_tag(:span, page.name) } -%>
30
+ </td>
31
+ <td class="url">
32
+ <%= page.url_path %>
33
+ </td>
34
+ <td class="page_layout">
35
+ <%= Alchemy.t(page.page_layout, scope: "page_layout_names", default: page.page_layout.to_s.humanize) %>
36
+ </td>
37
+ <td class="tags">
38
+ <% page.tag_list.each do |tag| %>
39
+ <%= content_tag(:span, tag, class: "tag") %>
40
+ <% end %>
41
+ </td>
42
+ <td class="date">
43
+ <%= l(page.updated_at, format: :"alchemy.default") %>
44
+ </td>
45
+ <td class="status center">
46
+ <span class="page_status with-hint">
47
+ <i class="icon fas fa-fw fa-compass <% unless page.public? %>disabled<% end %>" data-fa-transform="shrink-2"></i>
48
+ <span class="hint-bubble"><%= page.status_title(:public) %></span>
49
+ </span>
50
+ <span class="page_status with-hint">
51
+ <i class="icon fas fa-fw fa-lock <% unless page.restricted? %>disabled<% end %>" data-fa-transform="shrink-2"></i>
52
+ <span class="hint-bubble"><%= page.status_title(:restricted) %></span>
53
+ </span>
54
+ </td>
55
+ <td class="tools">
56
+ <% if can?(:info, page) %>
57
+ <div class="button_with_label">
58
+ <%= link_to_dialog(
59
+ render_icon('info-circle'),
60
+ alchemy.info_admin_page_path(page),
61
+ {
62
+ title: Alchemy.t(:page_infos),
63
+ size: '520x290'
64
+ }
65
+ ) %>
66
+ <label class="center"><%= Alchemy.t(:page_infos) %></label>
67
+ </div>
68
+ <% end %>
69
+ <% if can?(:configure, page) %>
70
+ <div class="button_with_label sitemap_tool">
71
+ <%= link_to_dialog(
72
+ render_icon(:cog),
73
+ alchemy.configure_admin_page_path(page),
74
+ {
75
+ title: Alchemy.t(:edit_page_properties),
76
+ size: '450x680'
77
+ }
78
+ ) -%>
79
+ <label class="center"><%= Alchemy.t(:edit_page_properties) %></label>
80
+ </div>
81
+ <% end %>
82
+ <% if can?(:copy, page) %>
83
+ <div class="button_with_label sitemap_tool">
84
+ <%= link_to(
85
+ render_icon(:copy),
86
+ alchemy.insert_admin_clipboard_path(
87
+ remarkable_type: :pages,
88
+ remarkable_id: page.id,
89
+ ),
90
+ remote: true,
91
+ method: :post
92
+ ) %>
93
+ <label class="center"><%= Alchemy.t(:copy_page) %></label>
94
+ </div>
95
+ <% end %>
96
+ <% if can?(:destroy, page) %>
97
+ <div class="button_with_label">
98
+ <%= link_to_confirm_dialog(
99
+ render_icon(:minus),
100
+ Alchemy.t(:confirm_to_delete_page),
101
+ alchemy.admin_page_path(page)
102
+ ) -%>
103
+ <label class="center"><%= Alchemy.t(:delete_page) %></label>
104
+ </div>
105
+ <% end %>
106
+ </td>
107
+ </tr>
@@ -0,0 +1,77 @@
1
+ <div class="toolbar_buttons">
2
+ <%= render "alchemy/admin/partials/site_select" %>
3
+ <%= render "alchemy/admin/partials/language_tree_select" %>
4
+ <%= toolbar_button(
5
+ icon: :plus,
6
+ url: alchemy.new_admin_page_path(language: @current_language),
7
+ hotkey: 'alt+n',
8
+ dialog_options: {
9
+ title: Alchemy.t('Add a page'),
10
+ size: '340x215',
11
+ overflow: true
12
+ },
13
+ title: Alchemy.t('Add a page'),
14
+ label: Alchemy.t('Add a page'),
15
+ if_permitted_to: [:create, Alchemy::Page]
16
+ ) %>
17
+ <div class="toolbar_spacer"></div>
18
+ <% if can?(:flush, Alchemy::Page) %>
19
+ <div class="button_with_label">
20
+ <%= link_to(
21
+ render_icon(:eraser),
22
+ alchemy.flush_admin_pages_path,
23
+ remote: true,
24
+ method: :post,
25
+ class: "icon_button please_wait",
26
+ title: Alchemy.t("Flush page cache")
27
+ ) %>
28
+ <label><%= Alchemy.t("Flush page cache") %></label>
29
+ </div>
30
+ <% end %>
31
+ <% if can?(:sort, Alchemy::Page) %>
32
+ <div class="button_with_label">
33
+ <%= link_to(
34
+ render_icon(:random),
35
+ alchemy.sort_admin_pages_path,
36
+ method: :get,
37
+ class: "icon_button",
38
+ title: Alchemy.t("Sort pages")
39
+ ) %>
40
+ <label><%= Alchemy.t("Sort pages") %></label>
41
+ </div>
42
+ <% end %>
43
+ <div class="button_with_label" id="clipboard_button">
44
+ <%= link_to_dialog(
45
+ render_icon(clipboard_empty?("pages") ? :clipboard : :paste),
46
+ alchemy.admin_clipboard_path(remarkable_type: "pages"),
47
+ {
48
+ title: Alchemy.t("Clipboard"),
49
+ size: "380x305"
50
+ },
51
+ class: "icon_button",
52
+ title: Alchemy.t("Show clipboard")
53
+ ) %>
54
+ <label><%= Alchemy.t("Show clipboard") %></label>
55
+ </div>
56
+ <div class="toolbar_spacer"></div>
57
+ <div class="button_with_label<%= @view != "list" ? " active" : nil %>">
58
+ <%= link_to(
59
+ render_icon(:stream),
60
+ alchemy.admin_pages_path(view: "tree"),
61
+ class: "icon_button"
62
+ ) %>
63
+ <label><%= Alchemy.t("Hierarchical") %></label>
64
+ </div>
65
+ <div class="button_with_label<%= @view == "list" ? " active" : nil %>">
66
+ <%= link_to(
67
+ render_icon("sort-amount-down-alt"),
68
+ alchemy.admin_pages_path(view: "list"),
69
+ class: "icon_button"
70
+ ) %>
71
+ <label><%= Alchemy.t("Sortable List") %></label>
72
+ </div>
73
+ </div>
74
+ <% search_filter_params[:view] = "list" %>
75
+ <%= render "alchemy/admin/partials/search_form",
76
+ url: alchemy.admin_pages_path(search_filter_params.except(:q, :page)),
77
+ additional_params: [:view, :page_layout, :tagged_with, :filter] %>
@@ -3,81 +3,48 @@
3
3
  <% end %>
4
4
 
5
5
  <% content_for :toolbar do %>
6
- <div class="toolbar_buttons">
7
- <%= render 'alchemy/admin/partials/site_select' %>
8
- <%= render 'alchemy/admin/partials/language_tree_select' %>
9
- <% if can?(:flush, Alchemy::Page) %>
10
- <div class="button_with_label">
11
- <%= link_to(
12
- render_icon(:eraser),
13
- alchemy.flush_admin_pages_path,
14
- :remote => true,
15
- :method => :post,
16
- :class => 'icon_button please_wait',
17
- :title => Alchemy.t('Flush page cache')
18
- ) %>
19
- <label><%= Alchemy.t('Flush page cache') %></label>
20
- </div>
21
- <% end %>
22
- <% if can?(:sort, Alchemy::Page) %>
23
- <div class="button_with_label">
24
- <%= link_to(
25
- render_icon(:random),
26
- alchemy.sort_admin_pages_path,
27
- method: :get,
28
- class: 'icon_button',
29
- title: Alchemy.t('Sort pages')
30
- ) %>
31
- <label><%= Alchemy.t('Sort pages') %></label>
32
- </div>
33
- <% end %>
34
- <div class="button_with_label" id="clipboard_button">
35
- <%= link_to_dialog(
36
- render_icon(clipboard_empty?('pages') ? :clipboard : :paste),
37
- alchemy.admin_clipboard_path(:remarkable_type => 'pages'),
38
- {
39
- :title => Alchemy.t('Clipboard'),
40
- :size => '380x305'
41
- },
42
- :class => 'icon_button',
43
- :title => Alchemy.t('Show clipboard')
44
- ) %>
45
- <label><%= Alchemy.t('Show clipboard') %></label>
46
- </div>
47
- </div>
48
- <div class="search_form">
49
- <div class="search_field">
50
- <label>
51
- <%= text_field_tag 'filter', '',
52
- class: 'search_input_field',
53
- placeholder: Alchemy.t(:search),
54
- id: nil %>
55
- <%= render_icon :search %>
56
- </label>
57
- <%= link_to(render_icon(:times, size: 'xs'), '#', {
58
- class: "search_field_clear",
59
- title: Alchemy.t(:click_to_show_all)
60
- }) %>
61
- </div>
62
- </div>
6
+ <%= render "alchemy/admin/pages/toolbar" %>
63
7
  <% end %>
64
8
 
65
- <div id="archive_all">
66
- <% if @page_root %>
67
- <h2 id="page_filter_result"></h2>
68
-
69
- <%= render 'sitemap', page_partial: 'page', full: !!@sorting %>
70
-
71
- <% elsif can?(:create, Alchemy::Page) %>
72
-
73
- <%= render partial: 'create_language_form' %>
74
-
75
- <% else %>
76
-
77
- <%= render_message :warn do %>
78
- <h2>No language root page found.</h2>
79
- <p>Please ask the admin to create one.</p>
9
+ <%= content_tag :div,
10
+ id: "archive_all",
11
+ class: [@view == "list" && "resources-table-wrapper with_tag_filter"] do %>
12
+ <% if @view == "list" %>
13
+ <%= render "alchemy/admin/resources/table_header", resources_instance_variable: @pages %>
14
+ <% if @pages.any? %>
15
+ <%= render "table" %>
16
+ <% elsif search_filter_params.present? %>
17
+ <%= render_message do %>
18
+ <%= Alchemy.t("No pages found") %>
19
+ <% end %>
20
+ <% elsif can?(:create, Alchemy::Page) %>
21
+ <%= render partial: "create_language_form" %>
22
+ <% end %>
23
+
24
+ <%= paginate @pages, scope: alchemy, theme: "alchemy" %>
25
+
26
+ <div id="library_sidebar">
27
+ <%= render "page_layout_filter" %>
28
+
29
+ <%= render "filter_bar",
30
+ label: Alchemy::Page.human_attribute_name(:status),
31
+ url: alchemy.admin_pages_path(search_filter_params.except(:filter, :page).merge(view: "list")) %>
32
+
33
+ <% if resource_has_tags %>
34
+ <%= render "tag_list" %>
35
+ <% end %>
36
+ </div>
37
+ <% else %>
38
+ <% if @page_root %>
39
+ <h2 id="page_filter_result"></h2>
40
+ <%= render "sitemap", page_partial: "page", full: !!@sorting %>
41
+ <% elsif can?(:create, Alchemy::Page) %>
42
+ <%= render partial: "create_language_form" %>
43
+ <% else %>
44
+ <%= render_message :warn do %>
45
+ <h2>No language root page found.</h2>
46
+ <p>Please ask the admin to create one.</p>
47
+ <% end %>
48
+ <% end %>
80
49
  <% end %>
81
-
82
50
  <% end %>
83
- </div>
@@ -0,0 +1,31 @@
1
+ <% if @pages.any? %>
2
+ <table class="list">
3
+ <thead>
4
+ <tr>
5
+ <th class="icon"></th>
6
+ <th class="string name">
7
+ <%= sort_link [:alchemy, @query],
8
+ "name",
9
+ Alchemy::Page.human_attribute_name(:name),
10
+ default_order: "asc" %>
11
+ </th>
12
+ <th><%= Alchemy::Page.human_attribute_name(:urlname) %></th>
13
+ <th><%= Alchemy::Page.human_attribute_name(:page_type) %></th>
14
+ <th><%= Alchemy::Page.human_attribute_name(:tag_list) %></th>
15
+ <th class="status center"><%= Alchemy::Page.human_attribute_name(:status) %></th>
16
+ <th class="tools"></th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <%= render partial: "page", collection: @pages %>
21
+ </tbody>
22
+ </table>
23
+ <% elsif search_filter_params.present? %>
24
+ <%= render_message do %>
25
+ <%= Alchemy.t('No pages found') %>
26
+ <% end %>
27
+ <% else %>
28
+ <%= render partial: 'alchemy/admin/pages/create_language_form' %>
29
+ <% end %>
30
+
31
+ <%= paginate @pages, scope: alchemy, theme: 'alchemy' %>
@@ -2,12 +2,12 @@
2
2
  var locked_page_tab = document.querySelector('#locked_page_<%= @page.id -%>')
3
3
  var locked_page_icon = document.querySelector(
4
4
  '#page_<%= @page.id -%> > .sitemap_page > .sitemap_left_images .with-hint'
5
- )
5
+ ) || document.querySelector('[data-page-id="<%= @page.id -%>"] > .icon')
6
6
  if (locked_page_tab) {
7
7
  locked_page_tab.remove()
8
8
  }
9
9
  if (locked_page_icon) {
10
- locked_page_icon.innerHTML = '<%= j render_icon(:file, style: 'regular', size: 'lg') %>'
10
+ locked_page_icon.innerHTML = '<i class="icon far fa-file fa-lg"></i>'
11
11
  }
12
12
  Alchemy.growl('<%= flash[:notice] -%>')
13
13
  })()
@@ -1,5 +1,5 @@
1
1
  (function() {
2
- var $page;
2
+ var page = document.querySelector('#page_<%= @page.id %>');
3
3
 
4
4
  <% if @old_page_layout != @page.page_layout -%>
5
5
  Alchemy.ElementsWindow.reload();
@@ -9,18 +9,27 @@
9
9
  <% if @while_page_edit -%>
10
10
 
11
11
  Alchemy.reloadPreview();
12
- $('#page_<%= @page.id %>_status').replaceWith('<%= j render("current_page", current_page: @page) %>');
12
+ document.querySelector('#page_<%= @page.id %>_status').outerHTML = '<%= j render("current_page", current_page: @page) %>';
13
+ Alchemy.growl("<%= j @notice %>");
14
+ Alchemy.closeCurrentDialog();
13
15
 
14
16
  <% else -%>
15
17
 
16
- var page_html = "<%= j render('page', page: @page) %>";
17
- var compiler = Handlebars.compile(page_html);
18
- var tree = <%== @tree.to_json %>;
19
- var html = compiler(tree.pages[0]);
20
- $('#page_<%= @page.id %>').replaceWith(html);
18
+ if (page) {
19
+ var page_html = "<%= j render('page', page: @page) %>";
20
+ var compiler = Handlebars.compile(page_html);
21
+ var tree = <%== @tree.to_json %>;
22
+ page.outerHTML = compiler(tree.pages[0]);
23
+ Alchemy.growl("<%= j @notice %>");
24
+ Alchemy.closeCurrentDialog();
25
+ } else {
26
+ document.addEventListener('turbolinks:load', function () {
27
+ Alchemy.growl("<%= j @notice %>");
28
+ }, { once: true })
29
+ Alchemy.closeCurrentDialog(function() {
30
+ Turbolinks.visit(location.toString(), { action: "replace" });
31
+ });
32
+ }
21
33
 
22
34
  <% end -%>
23
-
24
- Alchemy.growl("<%= j @notice %>");
25
- Alchemy.closeCurrentDialog();
26
35
  })()
@@ -1,21 +1,23 @@
1
1
  <div id="filter_bar">
2
- <h3><%= Alchemy.t('Filter') %></h3>
3
- <%= select_tag(
4
- 'resource_filter',
5
- options_for_select(
6
- resource_filter_select, search_filter_params[:filter]
7
- ),
8
- include_blank: Alchemy.t(:all, scope: ['resources', resource_name, 'filters']),
9
- data: { remote: !!request.xhr? },
10
- class: 'alchemy_selectbox'
11
- ) %>
2
+ <label>
3
+ <h3><%= local_assigns[:label] || Alchemy.t('Filter') %></h3>
4
+ <%= select_tag(
5
+ 'resource_filter',
6
+ options_for_select(
7
+ resource_filter_select, search_filter_params[:filter]
8
+ ),
9
+ include_blank: Alchemy.t(:all, scope: ['resources', resource_name, 'filters']),
10
+ data: { remote: !!request.xhr? },
11
+ class: 'alchemy_selectbox'
12
+ ) %>
13
+ </label>
12
14
  </div>
13
15
 
14
16
  <script type="text/javascript">
15
17
  $(function() {
16
18
  $('#resource_filter').on('change', function(e) {
17
19
  var $this = $(this);
18
- var url = '<%= resources_path(resource_handler.namespaced_resources_name, search_filter_params.except(:filter).to_h) %>';
20
+ var url = '<%= local_assigns[:url] || resources_path(resource_handler.namespaced_resources_name, search_filter_params.except(:filter).to_h) %>';
19
21
  if ($this.data('remote') === true) {
20
22
  $.get(url, {filter: $this.val()}, null, 'script');
21
23
  } else {
@@ -171,8 +171,8 @@ en:
171
171
  anchor_link_headline: "You can link to an element anchor from the actual page."
172
172
  attribute_fixed: Value can't be changed for this page type
173
173
  back: 'back'
174
- create_tree_as_new_language: "Create %{language} as a new language tree"
175
174
  locked_pages: "Active pages"
175
+ "Add a page": "Add a page"
176
176
  "Add global page": "Add global page"
177
177
  "Add page link": "Add page link"
178
178
  "Alchemy is open software and itself uses open software and free resources:": "Alchemy is open software and itself uses open software and free resources:"
@@ -339,13 +339,13 @@ en:
339
339
  copy_element: "Copy this element"
340
340
  copy_page: "Copy page"
341
341
  "Could not delete Pictures": "Could not delete Pictures"
342
- copy_language_tree_heading: "Copy page tree"
342
+ copy_language_tree_heading: "Copy pages"
343
343
  country_code_placeholder: 'i.e. US (optional)'
344
344
  country_code_foot_note: "You only need to set a country code if you want to support multiple countries with the same language."
345
345
  create: "create"
346
346
  "Create language": "Create a new language"
347
347
  "Create site": "Create a new site"
348
- create_language_tree_heading: "Create empty language tree"
348
+ create_language_tree_heading: "Create new homepage"
349
349
  create_menu: "Add a menu"
350
350
  create_node: "Add a menu node"
351
351
  create_page: "Create a new subpage"
@@ -402,6 +402,7 @@ en:
402
402
  "Open upload form": "Open upload form"
403
403
  "Select all pictures": "Select all pictures"
404
404
  hide_element_content: "Hide this elements content."
405
+ homepage_does_not_exist: "This language has no homepage yet"
405
406
  dashboard: "Dashboard"
406
407
  image_alt_tag: "Alt-tag"
407
408
  image_caption: "Caption"
@@ -415,7 +416,6 @@ en:
415
416
  javascript_disabled_headline: "Javascript is disabled!"
416
417
  javascript_disabled_text: "Alchemy needs Javascript to run smoothly. Please enable it in your browser settings."
417
418
  language_code_placeholder: 'i.e. en'
418
- language_does_not_exist: "This language tree does not exist"
419
419
  language_pages_copied: "Language tree successfully copied."
420
420
  last_upload_only: "Last upload only"
421
421
  left: "left"
@@ -220,6 +220,7 @@ module Alchemy
220
220
  :update,
221
221
  :unlock,
222
222
  :visit,
223
+ :tree,
223
224
  to: :edit_content
224
225
  end
225
226
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "5.1.0.beta2"
4
+ VERSION = "5.1.0.rc1"
5
5
 
6
6
  def self.version
7
7
  VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0.beta2
4
+ version: 5.1.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -583,6 +583,20 @@ dependencies:
583
583
  - - "~>"
584
584
  - !ruby/object:Gem::Version
585
585
  version: '4.0'
586
+ - !ruby/object:Gem::Dependency
587
+ name: timecop
588
+ requirement: !ruby/object:Gem::Requirement
589
+ requirements:
590
+ - - "~>"
591
+ - !ruby/object:Gem::Version
592
+ version: '0.9'
593
+ type: :development
594
+ prerelease: false
595
+ version_requirements: !ruby/object:Gem::Requirement
596
+ requirements:
597
+ - - "~>"
598
+ - !ruby/object:Gem::Version
599
+ version: '0.9'
586
600
  description: Alchemy is a powerful, userfriendly and flexible Rails CMS.
587
601
  email:
588
602
  - hello@alchemy-cms.com
@@ -928,10 +942,14 @@ files:
928
942
  - app/views/alchemy/admin/pages/_new_page_form.html.erb
929
943
  - app/views/alchemy/admin/pages/_page.html.erb
930
944
  - app/views/alchemy/admin/pages/_page_infos.html.erb
945
+ - app/views/alchemy/admin/pages/_page_layout_filter.html.erb
931
946
  - app/views/alchemy/admin/pages/_page_status.html.erb
932
947
  - app/views/alchemy/admin/pages/_publication_fields.html.erb
933
948
  - app/views/alchemy/admin/pages/_sitemap.html.erb
949
+ - app/views/alchemy/admin/pages/_table.html.erb
950
+ - app/views/alchemy/admin/pages/_table_row.html.erb
934
951
  - app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb
952
+ - app/views/alchemy/admin/pages/_toolbar.html.erb
935
953
  - app/views/alchemy/admin/pages/configure.html.erb
936
954
  - app/views/alchemy/admin/pages/edit.html.erb
937
955
  - app/views/alchemy/admin/pages/flush.js.erb
@@ -939,6 +957,7 @@ files:
939
957
  - app/views/alchemy/admin/pages/index.html.erb
940
958
  - app/views/alchemy/admin/pages/info.html.erb
941
959
  - app/views/alchemy/admin/pages/link.html.erb
960
+ - app/views/alchemy/admin/pages/list/_table.html.erb
942
961
  - app/views/alchemy/admin/pages/locked.html.erb
943
962
  - app/views/alchemy/admin/pages/new.html.erb
944
963
  - app/views/alchemy/admin/pages/show.html.erb