alchemy_cms 5.1.0.beta2 → 5.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +126 -0
  3. data/CHANGELOG.md +29 -1
  4. data/Gemfile +1 -1
  5. data/README.md +1 -1
  6. data/alchemy_cms.gemspec +1 -1
  7. data/app/assets/javascripts/alchemy/admin.js +0 -1
  8. data/app/assets/stylesheets/alchemy/_variables.scss +5 -0
  9. data/app/assets/stylesheets/alchemy/admin.scss +0 -1
  10. data/app/assets/stylesheets/alchemy/buttons.scss +26 -15
  11. data/app/assets/stylesheets/alchemy/elements.scss +58 -19
  12. data/app/assets/stylesheets/alchemy/frame.scss +0 -1
  13. data/app/assets/stylesheets/alchemy/hints.scss +2 -1
  14. data/app/assets/stylesheets/alchemy/search.scss +1 -1
  15. data/app/assets/stylesheets/alchemy/selects.scss +23 -19
  16. data/app/assets/stylesheets/alchemy/tables.scss +38 -9
  17. data/app/controllers/alchemy/admin/pages_controller.rb +48 -7
  18. data/app/decorators/alchemy/element_editor.rb +67 -0
  19. data/app/models/alchemy/legacy_page_url.rb +1 -1
  20. data/app/models/alchemy/page.rb +8 -0
  21. data/app/models/alchemy/site/layout.rb +30 -2
  22. data/app/serializers/alchemy/page_tree_serializer.rb +4 -4
  23. data/app/views/alchemy/admin/elements/_element.html.erb +1 -1
  24. data/app/views/alchemy/admin/elements/_element_toolbar.html.erb +1 -1
  25. data/app/views/alchemy/admin/elements/publish.js.erb +1 -0
  26. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +19 -29
  27. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +10 -1
  28. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +29 -0
  29. data/app/views/alchemy/admin/pages/_table.html.erb +27 -0
  30. data/app/views/alchemy/admin/pages/_table_row.html.erb +107 -0
  31. data/app/views/alchemy/admin/pages/_toolbar.html.erb +77 -0
  32. data/app/views/alchemy/admin/pages/index.html.erb +41 -74
  33. data/app/views/alchemy/admin/pages/list/_table.html.erb +31 -0
  34. data/app/views/alchemy/admin/pages/unlock.js.erb +2 -2
  35. data/app/views/alchemy/admin/pages/update.js.erb +19 -10
  36. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +13 -11
  37. data/config/locales/alchemy.en.yml +4 -4
  38. data/lib/alchemy/permissions.rb +1 -0
  39. data/lib/alchemy/resource.rb +5 -3
  40. data/lib/alchemy/test_support/integration_helpers.rb +0 -7
  41. data/lib/alchemy/version.rb +1 -1
  42. data/lib/alchemy_cms.rb +0 -1
  43. data/vendor/assets/javascripts/jquery_plugins/select2.js +3729 -0
  44. data/vendor/assets/stylesheets/alchemy_admin/select2.scss +740 -0
  45. metadata +29 -29
  46. data/.travis.yml +0 -48
@@ -74,7 +74,6 @@ div#overlay_text_box {
74
74
 
75
75
  .page_name {
76
76
  display: inline-block;
77
- max-width: 100px;
78
77
  margin-right: $default-margin;
79
78
  line-height: $header-height;
80
79
  white-space: nowrap;
@@ -27,7 +27,8 @@
27
27
 
28
28
  > .hint-bubble {
29
29
  visibility: hidden;
30
- background: $light_yellow;
30
+ background-color: $hint-background-color;
31
+ color: $hint-text-color;
31
32
  border-radius: $default-border-radius;
32
33
  box-shadow: 0px 4px 8px rgba(0, 0, 0, .3);
33
34
  position: absolute;
@@ -54,7 +54,7 @@
54
54
 
55
55
  .search_input_field {
56
56
  width: 0;
57
- height: inherit;
57
+ height: 100%;
58
58
  border: none;
59
59
  background-color: transparentize($form-field-background-color, 0.25);
60
60
  transition:
@@ -1,13 +1,16 @@
1
+ @import "alchemy_admin/select2";
2
+
1
3
  select {
2
4
  @include button-defaults(
3
5
  $background-color: $form-field-background-color,
4
6
  $hover-color: $form-field-background-color,
5
7
  $hover-border-color: darken($default-border-color, 10%),
6
- $padding: 0 2*$default-padding,
8
+ $padding: 0 2 * $default-padding,
7
9
  $border: 1px solid $default-border-color,
8
10
  $box-shadow: none,
9
11
  $color: $text-color,
10
- $margin: 0);
12
+ $margin: 0
13
+ );
11
14
  height: $form-field-height;
12
15
  padding: 0.4em 0.6em;
13
16
  max-width: 100%;
@@ -32,7 +35,8 @@ select {
32
35
  $border: 1px solid $default-border-color,
33
36
  $box-shadow: none,
34
37
  $color: $text-color,
35
- $margin: 0);
38
+ $margin: 0
39
+ );
36
40
  background-image: none;
37
41
  display: block;
38
42
  font-weight: normal;
@@ -79,14 +83,13 @@ select {
79
83
  }
80
84
 
81
85
  &.select2-container-active {
82
-
83
- .select2-choice, .select2-choices {
86
+ .select2-choice,
87
+ .select2-choices {
84
88
  @include default-focus-style($box-shadow: 0 0 0 1px $focus-color);
85
89
  }
86
90
  }
87
91
 
88
92
  &.select2-container-disabled {
89
-
90
93
  &:hover {
91
94
  + .with-hint > .hint-bubble {
92
95
  @include hint-hover-style;
@@ -98,7 +101,8 @@ select {
98
101
  top: 0;
99
102
  }
100
103
 
101
- .select2-choice, .select2-choice:hover {
104
+ .select2-choice,
105
+ .select2-choice:hover {
102
106
  background-image: none;
103
107
  background-color: $light-gray;
104
108
  box-shadow: none;
@@ -108,7 +112,9 @@ select {
108
112
  .select2-arrow {
109
113
  border-color: $border-inset-color;
110
114
 
111
- b { color: $border-inset-color; }
115
+ b {
116
+ color: $border-inset-color;
117
+ }
112
118
  }
113
119
  }
114
120
  }
@@ -142,7 +148,6 @@ select {
142
148
  margin-top: 0 !important;
143
149
 
144
150
  &.select2-container-active {
145
-
146
151
  .select2-choices {
147
152
  @include default-focus-style($box-shadow: 0 0 0 1px $focus-color);
148
153
  }
@@ -214,7 +219,8 @@ select {
214
219
  }
215
220
  }
216
221
 
217
- .select2-no-results, .select2-searching {
222
+ .select2-no-results,
223
+ .select2-searching {
218
224
  padding: 8px;
219
225
  margin: 0;
220
226
  }
@@ -235,41 +241,39 @@ select {
235
241
 
236
242
  .select2-more-results,
237
243
  .select2-ajax-error {
238
- padding: 2*$default-padding;
244
+ padding: 2 * $default-padding;
239
245
  margin-bottom: 0;
240
246
  }
241
247
  }
242
248
 
243
- .window_form, #filter_bar {
244
-
249
+ .window_form,
250
+ #filter_bar {
245
251
  .select2-container {
246
252
  width: 100%;
247
253
  }
248
254
  }
249
255
 
250
256
  .select_with_label {
251
- margin: 0 3*$default-margin;
257
+ margin: 0 3 * $default-margin;
252
258
  display: inline-block;
253
259
  vertical-align: middle;
254
260
 
255
261
  label {
256
262
  display: inline-block;
257
263
  vertical-align: middle;
258
- margin-right: 2*$default-margin;
264
+ margin-right: 2 * $default-margin;
259
265
  }
260
266
  }
261
267
 
262
268
  // overriding important of select2 default style for retina screens
263
269
  @media only screen and (-webkit-min-device-pixel-ratio: 1.5),
264
- only screen and (min-resolution: 2dppx) {
265
-
270
+ only screen and (min-resolution: 2dppx) {
266
271
  #alchemy {
267
-
268
272
  .select2-search input,
269
273
  .select2-search-choice-close,
270
274
  .select2-container .select2-choice abbr,
271
275
  .select2-container .select2-choice .select2-arrow b {
272
- background-image: none !important;
276
+ background-image: none !important;
273
277
  }
274
278
  }
275
279
  }
@@ -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
@@ -8,6 +8,17 @@ module Alchemy
8
8
  "alchemy/admin/elements/element"
9
9
  end
10
10
 
11
+ # Returns content editor instances for defined contents
12
+ #
13
+ # Creates contents on demand if the content is not yet present on the element
14
+ #
15
+ # @return Array<Alchemy::ContentEditor>
16
+ def contents
17
+ element.definition.fetch(:contents, []).map do |content|
18
+ Alchemy::ContentEditor.new(find_or_create_content(content[:name]))
19
+ end
20
+ end
21
+
11
22
  # CSS classes for the element editor partial.
12
23
  def css_classes
13
24
  [
@@ -18,6 +29,7 @@ module Alchemy
18
29
  folded ? "folded" : "expanded",
19
30
  compact? ? "compact" : nil,
20
31
  fixed? ? "is-fixed" : "not-fixed",
32
+ public? ? "visible" : "hidden",
21
33
  ].join(" ")
22
34
  end
23
35
 
@@ -35,5 +47,60 @@ module Alchemy
35
47
 
36
48
  super
37
49
  end
50
+
51
+ # Returns a deprecation notice for elements marked deprecated
52
+ #
53
+ # You can either use localizations or pass a String as notice
54
+ # in the element definition.
55
+ #
56
+ # == Custom deprecation notices
57
+ #
58
+ # Use general element deprecation notice
59
+ #
60
+ # - name: old_element
61
+ # deprecated: true
62
+ #
63
+ # Add a translation to your locale file for a per element notice.
64
+ #
65
+ # en:
66
+ # alchemy:
67
+ # element_deprecation_notices:
68
+ # old_element: Foo baz widget is deprecated
69
+ #
70
+ # or use the global translation that apply to all deprecated elements.
71
+ #
72
+ # en:
73
+ # alchemy:
74
+ # element_deprecation_notice: Foo baz widget is deprecated
75
+ #
76
+ # or pass string as deprecation notice.
77
+ #
78
+ # - name: old_element
79
+ # deprecated: This element will be removed soon.
80
+ #
81
+ def deprecation_notice
82
+ case definition["deprecated"]
83
+ when String
84
+ definition["deprecated"]
85
+ when TrueClass
86
+ Alchemy.t(name,
87
+ scope: :element_deprecation_notices,
88
+ default: Alchemy.t(:element_deprecated))
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def find_or_create_content(name)
95
+ find_content(name) || create_content(name)
96
+ end
97
+
98
+ def find_content(name)
99
+ element.contents.find { |content| content.name == name }
100
+ end
101
+
102
+ def create_content(name)
103
+ Alchemy::Content.create(element: element, name: name)
104
+ end
38
105
  end
39
106
  end
@@ -18,5 +18,5 @@ class Alchemy::LegacyPageUrl < ActiveRecord::Base
18
18
 
19
19
  validates :urlname,
20
20
  presence: true,
21
- format: {with: /\A[:\.\w\-+_\/\?&%;=]*\z/}
21
+ format: {with: /\A[:\.\w\-+_\/\?&%;=#]*\z/}
22
22
  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)