alchemy_cms 4.1.2 → 4.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/Bug_report.md +0 -5
  3. data/.rubocop.yml +4 -1
  4. data/.travis.yml +3 -3
  5. data/CHANGELOG.md +29 -10
  6. data/Gemfile +5 -7
  7. data/README.md +114 -62
  8. data/Rakefile +2 -2
  9. data/alchemy_cms.gemspec +5 -5
  10. data/app/assets/images/alchemy/icon.svg +1 -1
  11. data/app/assets/javascripts/alchemy/admin.js +2 -0
  12. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -24
  13. data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +11 -9
  14. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +7 -24
  15. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +9 -8
  16. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +38 -0
  17. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +2 -4
  18. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +1 -1
  19. data/app/assets/stylesheets/alchemy/_mixins.scss +2 -1
  20. data/app/assets/stylesheets/alchemy/_variables.scss +7 -2
  21. data/app/assets/stylesheets/alchemy/admin.scss +2 -1
  22. data/app/assets/stylesheets/alchemy/archive.scss +18 -4
  23. data/app/assets/stylesheets/alchemy/buttons.scss +1 -1
  24. data/app/assets/stylesheets/alchemy/dialogs.scss +1 -1
  25. data/app/assets/stylesheets/alchemy/elements.scss +154 -90
  26. data/app/assets/stylesheets/alchemy/filter_field.scss +30 -0
  27. data/app/assets/stylesheets/alchemy/flatpickr.scss +839 -0
  28. data/app/assets/stylesheets/alchemy/forms.scss +5 -1
  29. data/app/assets/stylesheets/alchemy/frame.scss +6 -14
  30. data/app/assets/stylesheets/alchemy/navigation.scss +109 -98
  31. data/app/assets/stylesheets/alchemy/search.scss +11 -29
  32. data/app/assets/stylesheets/alchemy/tables.scss +0 -23
  33. data/app/assets/stylesheets/alchemy/tags.scss +4 -27
  34. data/app/assets/stylesheets/alchemy/toolbar.scss +12 -2
  35. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +4 -33
  36. data/app/controllers/alchemy/admin/attachments_controller.rb +1 -12
  37. data/app/controllers/alchemy/admin/contents_controller.rb +2 -24
  38. data/app/controllers/alchemy/admin/elements_controller.rb +11 -49
  39. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  40. data/app/controllers/alchemy/admin/pictures_controller.rb +1 -14
  41. data/app/controllers/alchemy/api/contents_controller.rb +1 -1
  42. data/app/controllers/alchemy/api/elements_controller.rb +1 -1
  43. data/app/controllers/alchemy/api/pages_controller.rb +1 -1
  44. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +20 -0
  45. data/app/helpers/alchemy/admin/base_helper.rb +8 -18
  46. data/app/helpers/alchemy/admin/elements_helper.rb +55 -85
  47. data/app/helpers/alchemy/admin/pictures_helper.rb +0 -23
  48. data/app/helpers/alchemy/elements_helper.rb +80 -120
  49. data/app/helpers/alchemy/pages_helper.rb +5 -24
  50. data/app/models/alchemy/content.rb +0 -1
  51. data/app/models/alchemy/content/factory.rb +33 -57
  52. data/app/models/alchemy/element.rb +46 -66
  53. data/app/models/alchemy/element/element_contents.rb +2 -2
  54. data/app/models/alchemy/page.rb +34 -4
  55. data/app/models/alchemy/page/page_elements.rb +30 -122
  56. data/app/serializers/alchemy/attachment_serializer.rb +0 -2
  57. data/app/serializers/alchemy/content_serializer.rb +0 -2
  58. data/app/serializers/alchemy/element_serializer.rb +0 -3
  59. data/app/serializers/alchemy/essence_boolean_serializer.rb +0 -2
  60. data/app/serializers/alchemy/essence_date_serializer.rb +0 -2
  61. data/app/serializers/alchemy/essence_file_serializer.rb +0 -2
  62. data/app/serializers/alchemy/essence_html_serializer.rb +0 -2
  63. data/app/serializers/alchemy/essence_link_serializer.rb +0 -2
  64. data/app/serializers/alchemy/essence_picture_serializer.rb +0 -2
  65. data/app/serializers/alchemy/essence_richtext_serializer.rb +0 -2
  66. data/app/serializers/alchemy/essence_select_serializer.rb +0 -2
  67. data/app/serializers/alchemy/essence_text_serializer.rb +0 -2
  68. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -3
  69. data/app/serializers/alchemy/page_serializer.rb +2 -8
  70. data/app/serializers/alchemy/page_tree_serializer.rb +1 -1
  71. data/app/serializers/alchemy/picture_serializer.rb +0 -2
  72. data/app/views/alchemy/admin/clipboard/index.html.erb +2 -2
  73. data/app/views/alchemy/admin/clipboard/insert.js.erb +9 -12
  74. data/app/views/alchemy/admin/contents/create.js.erb +4 -30
  75. data/app/views/alchemy/admin/elements/_element.html.erb +27 -12
  76. data/app/views/alchemy/admin/elements/_element_toolbar.html.erb +1 -1
  77. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +0 -10
  78. data/app/views/alchemy/admin/elements/create.js.erb +12 -12
  79. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  80. data/app/views/alchemy/admin/elements/index.html.erb +20 -19
  81. data/app/views/alchemy/admin/elements/publish.js.erb +5 -0
  82. data/app/views/alchemy/admin/elements/trash.js.erb +4 -1
  83. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -7
  84. data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +0 -22
  85. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +2 -4
  86. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  87. data/app/views/alchemy/admin/pages/index.html.erb +14 -10
  88. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  89. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +1 -1
  90. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +7 -5
  91. data/app/views/alchemy/admin/partials/_routes.html.erb +0 -1
  92. data/app/views/alchemy/admin/partials/_search_form.html.erb +6 -4
  93. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +6 -3
  94. data/app/views/alchemy/admin/pictures/index.html.erb +1 -1
  95. data/app/views/alchemy/admin/trash/index.html.erb +8 -7
  96. data/app/views/alchemy/elements/_editor_not_found.html.erb +1 -1
  97. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +4 -19
  98. data/app/views/layouts/alchemy/admin.html.erb +1 -0
  99. data/bin/rspec +0 -5
  100. data/config/alchemy/config.yml +3 -0
  101. data/config/brakeman.ignore +1 -1
  102. data/config/locales/alchemy.en.yml +6 -12
  103. data/config/routes.rb +1 -5
  104. data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -29
  105. data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +6 -0
  106. data/lib/alchemy/admin/locale.rb +1 -1
  107. data/lib/alchemy/cache_digests/template_tracker.rb +4 -27
  108. data/lib/alchemy/elements_finder.rb +111 -0
  109. data/lib/alchemy/errors.rb +0 -4
  110. data/lib/alchemy/modules.rb +49 -18
  111. data/lib/alchemy/tasks/tidy.rb +3 -40
  112. data/lib/alchemy/test_support/controller_requests.rb +1 -1
  113. data/lib/alchemy/test_support/essence_shared_examples.rb +1 -1
  114. data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -3
  115. data/lib/alchemy/test_support/factories/content_factory.rb +4 -4
  116. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +5 -5
  117. data/lib/alchemy/test_support/factories/element_factory.rb +12 -7
  118. data/lib/alchemy/test_support/factories/essence_text_factory.rb +1 -1
  119. data/lib/alchemy/test_support/factories/language_factory.rb +13 -13
  120. data/lib/alchemy/test_support/factories/page_factory.rb +18 -17
  121. data/lib/alchemy/test_support/factories/picture_factory.rb +6 -4
  122. data/lib/alchemy/test_support/factories/site_factory.rb +6 -6
  123. data/lib/alchemy/tinymce.rb +1 -1
  124. data/lib/alchemy/upgrader/four_point_two.rb +68 -0
  125. data/lib/alchemy/upgrader/tasks/cells_migration.rb +41 -0
  126. data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +146 -0
  127. data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +65 -0
  128. data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +195 -0
  129. data/lib/alchemy/version.rb +1 -1
  130. data/lib/alchemy_cms.rb +1 -0
  131. data/lib/rails/generators/alchemy/elements/elements_generator.rb +1 -0
  132. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +0 -3
  133. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +0 -3
  134. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +0 -3
  135. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +3 -14
  136. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +3 -10
  137. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +3 -10
  138. data/lib/tasks/alchemy/tidy.rake +1 -23
  139. data/lib/tasks/alchemy/upgrade.rake +44 -1
  140. data/vendor/assets/javascripts/flatpickr/flatpickr.min.js +2 -0
  141. data/vendor/assets/javascripts/tinymce/license.txt +0 -0
  142. data/vendor/assets/javascripts/tinymce/tinymce.min.js +2 -2
  143. metadata +25 -31
  144. data/app/assets/stylesheets/alchemy/jquery.datetimepicker.scss +0 -478
  145. data/app/models/alchemy/cell.rb +0 -95
  146. data/app/models/alchemy/page/page_cells.rb +0 -69
  147. data/app/serializers/alchemy/cell_serializer.rb +0 -19
  148. data/app/views/alchemy/admin/contents/new.html.erb +0 -11
  149. data/app/views/alchemy/admin/contents/order.js.erb +0 -3
  150. data/app/views/alchemy/admin/elements/_add_picture.html.erb +0 -14
  151. data/app/views/alchemy/admin/elements/_picture_gallery_editor.html.erb +0 -24
  152. data/bin/spring +0 -16
  153. data/lib/alchemy/test_support/factories/cell_factory.rb +0 -9
  154. data/vendor/assets/javascripts/date-formatter.js +0 -161
  155. data/vendor/assets/javascripts/jquery_plugins/jquery.datetimepicker.full.min.js +0 -2
@@ -24,12 +24,22 @@
24
24
  .toolbar_buttons {
25
25
  margin-right: 8px;
26
26
  white-space: nowrap;
27
+ overflow-x: auto;
28
+ overflow-y: visible;
29
+ max-width: calc(100vw - #{$collapsed-main-menu-width + 65px});
30
+ -webkit-overflow-scrolling: touch;
31
+
32
+ @media screen and (min-width: $medium-screen-break-point) {
33
+ overflow: visible;
34
+ }
27
35
 
28
36
  &.right {
29
37
  position: absolute;
30
- right: 0;
31
- top: 8px;
38
+ right: -8px;
39
+ top: 0;
32
40
  margin-left: 8px;
41
+ padding: 8px;
42
+ background-color: $toolbar-bg-color;
33
43
 
34
44
  label {
35
45
  left: auto;
@@ -28,9 +28,6 @@
28
28
  direction: ltr;
29
29
  }
30
30
 
31
- .mce-widget button {
32
- }
33
-
34
31
  .mce-container *[unselectable] {
35
32
  user-select: none;
36
33
  }
@@ -70,6 +67,8 @@
70
67
  overflow: hidden;
71
68
  height: 100%;
72
69
  z-index: 100;
70
+ background: #fff;
71
+ border-radius: 0;
73
72
 
74
73
  .mce-resizehandle {
75
74
  display: none;
@@ -337,21 +336,6 @@ div.mce-tinymce-inline {
337
336
  }
338
337
  }
339
338
 
340
- .mce-fullscreen {
341
- border: 0;
342
- padding: 0;
343
- margin: 0;
344
- overflow: hidden;
345
- background: #fff;
346
- height: 100%;
347
- }
348
-
349
- div.mce-fullscreen {
350
- position: fixed;
351
- top: 0;
352
- left: 0;
353
- }
354
-
355
339
  #mce-modal-block {
356
340
  opacity: 0;
357
341
  position: fixed;
@@ -722,9 +706,7 @@ body .mce-abs-layout-item {
722
706
 
723
707
  &.mce-active,
724
708
  &.mce-active:hover {
725
- background-color: #e6f0f5;
726
- background-image: linear-gradient(#e5e5e5, #cccccc);
727
- box-shadow: #c4c4c4 0 1px 2px inset;
709
+ background-color: $default-border-color;
728
710
 
729
711
  button i {
730
712
  color: #000;
@@ -732,18 +714,7 @@ body .mce-abs-layout-item {
732
714
  }
733
715
 
734
716
  &:not(.mce-disabled):active {
735
- background-color: #d6d6d6;
736
- background-image: -moz-linear-gradient(top,#e6e6e6,#c0c0c0);
737
- background-image: -webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#c0c0c0));
738
- background-image: -webkit-linear-gradient(top,#e6e6e6,#c0c0c0);
739
- background-image: -o-linear-gradient(top,#e6e6e6,#c0c0c0);
740
- background-image: linear-gradient(to bottom,#e6e6e6,#c0c0c0);
741
- background-repeat: repeat-x;
742
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#ffe6e6e6',endColorstr='#ffc0c0c0',GradientType=0);
743
- zoom: 1;
744
- -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
745
- -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
746
- box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
717
+ background-color: $default-border-color;
747
718
  }
748
719
  }
749
720
 
@@ -4,6 +4,7 @@ module Alchemy
4
4
  module Admin
5
5
  class AttachmentsController < ResourcesController
6
6
  include UploaderResponses
7
+ include ArchiveOverlay
7
8
 
8
9
  helper 'alchemy/admin/tags'
9
10
 
@@ -85,18 +86,6 @@ module Alchemy
85
86
  end
86
87
  end
87
88
 
88
- def in_overlay?
89
- params[:content_id].present?
90
- end
91
-
92
- def archive_overlay
93
- @content = Content.find_by(id: params[:content_id])
94
- respond_to do |format|
95
- format.html { render partial: 'archive_overlay' }
96
- format.js { render action: 'archive_overlay' }
97
- end
98
- end
99
-
100
89
  def attachment_attributes
101
90
  params.require(:attachment).permit(:file, :name, :file_name, :tag_list)
102
91
  end
@@ -8,36 +8,14 @@ module Alchemy
8
8
  authorize_resource class: Alchemy::Content
9
9
 
10
10
  def create
11
- @element = Element.find(params[:content][:element_id])
12
- @content = Content.create_from_scratch(@element, content_params)
11
+ @content = Content.create(content_params)
13
12
  @html_options = params[:html_options] || {}
14
- if picture_gallery_editor?
15
- @content.update_essence(picture_id: params[:picture_id])
16
- @gallery_pictures = @element.contents.gallery_pictures
17
- options_from_params[:sortable] = @gallery_pictures.size > 1
18
- @content_dom_id = "#add_picture_#{@element.id}"
19
- else
20
- @content_dom_id = "#add_content_for_element_#{@element.id}"
21
- end
22
- end
23
-
24
- def order
25
- Content.transaction do
26
- params[:content_ids].each_with_index do |id, idx|
27
- Content.where(id: id).update_all(position: idx + 1)
28
- end
29
- end
30
- @notice = Alchemy.t("Successfully saved content position")
31
13
  end
32
14
 
33
15
  private
34
16
 
35
17
  def content_params
36
- params.require(:content).permit(:element_id, :name, :ingredient, :essence_type)
37
- end
38
-
39
- def picture_gallery_editor?
40
- params[:content][:essence_type] == 'Alchemy::EssencePicture' && options_from_params[:grouped] == 'true'
18
+ params.require(:content).permit(:element_id, :name, :ingredient)
41
19
  end
42
20
  end
43
21
  end
@@ -8,12 +8,8 @@ module Alchemy
8
8
 
9
9
  def index
10
10
  @page = Page.find(params[:page_id])
11
- @cells = @page.cells
12
- if @cells.blank?
13
- @elements = @page.elements.not_trashed
14
- else
15
- @elements = @page.elements_grouped_by_cells
16
- end
11
+ @elements = @page.elements
12
+ @fixed_elements = @page.fixed_elements
17
13
  end
18
14
 
19
15
  def list
@@ -39,21 +35,14 @@ module Alchemy
39
35
  Element.transaction do
40
36
  if @paste_from_clipboard = params[:paste_from_clipboard].present?
41
37
  @element = paste_element_from_clipboard
42
- @cell = @element.cell
43
38
  else
44
- @element = Element.new_from_scratch(create_element_params)
45
- if @page.can_have_cells?
46
- @cell = find_or_create_cell
47
- @element.cell = @cell
48
- end
49
- @element.save
39
+ @element = Element.create(create_element_params)
50
40
  end
51
41
  if @page.definition['insert_elements_at'] == 'top'
52
42
  @insert_at_top = true
53
43
  @element.move_to_top
54
44
  end
55
45
  end
56
- @cell_name = @cell.nil? ? "for_other_elements" : @cell.name
57
46
  if @element.valid?
58
47
  render :create
59
48
  else
@@ -95,11 +84,10 @@ module Alchemy
95
84
  @parent_element = Element.find_by(id: params[:parent_element_id])
96
85
  Element.transaction do
97
86
  params.fetch(:element_ids, []).each_with_index do |element_id, idx|
98
- # Ensure to set page_id, cell_id and parent_element_id to the current page and
99
- # cell because of trashed elements could still have old values
87
+ # Ensure to set page_id and parent_element_id to the current
88
+ # because of trashed elements could still have old values
100
89
  Element.where(id: element_id).update_all(
101
90
  page_id: params[:page_id],
102
- cell_id: params[:cell_id],
103
91
  parent_element_id: params[:parent_element_id],
104
92
  position: idx + 1
105
93
  )
@@ -120,24 +108,6 @@ module Alchemy
120
108
  @element = Element.find(params[:id])
121
109
  end
122
110
 
123
- # Returns the cell for element name in params.
124
- # Creates the cell if necessary.
125
- def find_or_create_cell
126
- if @paste_from_clipboard
127
- element_with_cell_name = params[:paste_from_clipboard]
128
- else
129
- element_with_cell_name = params[:element][:name]
130
- end
131
- return nil if element_with_cell_name.blank?
132
- return nil unless element_with_cell_name.include?('#')
133
- cell_name = element_with_cell_name.split('#').last
134
- cell_definition = Cell.definition_for(cell_name)
135
- if cell_definition.blank?
136
- raise CellDefinitionError, "Cell definition not found for #{cell_name}"
137
- end
138
- @page.cells.find_or_create_by(name: cell_definition['name'])
139
- end
140
-
141
111
  def element_from_clipboard
142
112
  @element_from_clipboard ||= begin
143
113
  @clipboard = get_clipboard('elements')
@@ -147,26 +117,18 @@ module Alchemy
147
117
 
148
118
  def paste_element_from_clipboard
149
119
  @source_element = Element.find(element_from_clipboard['id'])
150
- new_attributes = {
120
+ element = Element.copy(@source_element, {
151
121
  parent_element_id: create_element_params[:parent_element_id],
152
- page_id: @page.id
153
- }
154
- if @page.can_have_cells?
155
- new_attributes = new_attributes.merge({cell_id: find_or_create_cell.try(:id)})
156
- end
157
- element = Element.copy(@source_element, new_attributes)
122
+ page_id: @page.id}
123
+ )
158
124
  if element_from_clipboard['action'] == 'cut'
159
- cut_element
125
+ @cut_element_id = @source_element.id
126
+ @clipboard.delete_if { |item| item['id'] == @source_element.id.to_s }
127
+ @source_element.destroy
160
128
  end
161
129
  element
162
130
  end
163
131
 
164
- def cut_element
165
- @cutted_element_id = @source_element.id
166
- @clipboard.delete_if { |item| item['id'] == @source_element.id.to_s }
167
- @source_element.destroy
168
- end
169
-
170
132
  def contents_params
171
133
  params.fetch(:contents, {}).permit!
172
134
  end
@@ -49,7 +49,7 @@ module Alchemy
49
49
  Page.current_preview = @page
50
50
  # Setting the locale to pages language, so the page content has it's correct translations.
51
51
  ::I18n.locale = @page.language.locale
52
- render layout: 'application'
52
+ render(layout: Alchemy::Config.get(:admin_page_preview_layout) || 'application')
53
53
  end
54
54
 
55
55
  def info
@@ -4,6 +4,7 @@ module Alchemy
4
4
  module Admin
5
5
  class PicturesController < Alchemy::Admin::ResourcesController
6
6
  include UploaderResponses
7
+ include ArchiveOverlay
7
8
 
8
9
  helper 'alchemy/admin/tags'
9
10
 
@@ -143,20 +144,6 @@ module Alchemy
143
144
  end
144
145
  end
145
146
 
146
- def in_overlay?
147
- params[:element_id].present?
148
- end
149
-
150
- def archive_overlay
151
- @content = Content.select('id').find_by(id: params[:content_id])
152
- @element = Element.select('id').find_by(id: params[:element_id])
153
-
154
- respond_to do |format|
155
- format.html { render partial: 'archive_overlay' }
156
- format.js { render action: 'archive_overlay' }
157
- end
158
- end
159
-
160
147
  def redirect_to_index
161
148
  do_redirect_to admin_pictures_path(search_filter_params)
162
149
  end
@@ -16,7 +16,7 @@ module Alchemy
16
16
  if params[:element_id].present?
17
17
  @contents = @contents.where(element_id: params[:element_id])
18
18
  end
19
- respond_with @contents
19
+ render json: @contents, adapter: :json, root: :contents
20
20
  end
21
21
 
22
22
  # Returns a json object for content
@@ -20,7 +20,7 @@ module Alchemy
20
20
  if params[:named].present?
21
21
  @elements = @elements.named(params[:named])
22
22
  end
23
- respond_with @elements
23
+ render json: @elements, adapter: :json, root: :elements
24
24
  end
25
25
 
26
26
  # Returns a json object for element
@@ -16,7 +16,7 @@ module Alchemy
16
16
  if params[:page_layout].present?
17
17
  @pages = @pages.where(page_layout: params[:page_layout])
18
18
  end
19
- respond_with @pages
19
+ render json: @pages, adapter: :json, root: :pages
20
20
  end
21
21
 
22
22
  # Returns all pages as nested json object for tree views
@@ -0,0 +1,20 @@
1
+ module Alchemy
2
+ module Admin
3
+ module ArchiveOverlay
4
+ private
5
+
6
+ def in_overlay?
7
+ params[:content_id].present?
8
+ end
9
+
10
+ def archive_overlay
11
+ @content = Content.find_by(id: params[:content_id])
12
+
13
+ respond_to do |format|
14
+ format.html { render partial: 'archive_overlay' }
15
+ format.js { render action: 'archive_overlay' }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -106,7 +106,6 @@ module Alchemy
106
106
  concat text_field_tag(nil, nil, options)
107
107
  concat render_icon(:search)
108
108
  concat link_to(render_icon(:times, size: 'xs'), '', class: 'js_filter_field_clear', title: Alchemy.t(:click_to_show_all))
109
- concat content_tag(:label, Alchemy.t(:search), for: options[:id])
110
109
  end
111
110
  end
112
111
 
@@ -215,13 +214,6 @@ module Alchemy
215
214
  "Alchemy CMS - #{title}"
216
215
  end
217
216
 
218
- # (internal) Returns max image count as integer or nil. Used for the picture editor in element editor views.
219
- def max_image_count
220
- return nil if !@options
221
- image_count = @options[:maximum_amount_of_images] || @options[:max_images]
222
- image_count.blank? ? nil : image_count.to_i
223
- end
224
-
225
217
  # Renders a toolbar button for the Alchemy toolbar
226
218
  #
227
219
  # == Example
@@ -338,9 +330,6 @@ module Alchemy
338
330
  # If you pass +'datetime'+ as +:type+ the datepicker will also have a Time select.
339
331
  # If you pass +'time'+ as +:type+ the datepicker will only have a Time select.
340
332
  #
341
- # The date value gets localized via +I18n.l+. The format on Time and Date is +datepicker+, +timepicker+
342
- # or +datetimepicker+, if you pass another +type+.
343
- #
344
333
  # This helper always renders "text" as input type because:
345
334
  # HTML5 supports input types like 'date' but Browsers are using the users OS settings
346
335
  # to validate the input format. Since Alchemy is localized in the backend the date formats
@@ -374,7 +363,7 @@ module Alchemy
374
363
  type = html_options.delete(:type) || 'date'
375
364
  date = html_options.delete(:value) || object.send(method.to_sym).presence
376
365
  date = Time.zone.parse(date) if date.is_a?(String)
377
- value = date ? l(date, format: "alchemy.#{type}picker".to_sym) : nil
366
+ value = date ? date.iso8601 : nil
378
367
 
379
368
  text_field object.class.name.demodulize.underscore.to_sym,
380
369
  method.to_sym, {type: "text", class: type, "data-datepicker-type" => type, value: value}.merge(html_options)
@@ -402,14 +391,15 @@ module Alchemy
402
391
 
403
392
  # (internal) Returns options for the clipboard select tag
404
393
  def clipboard_select_tag_options(items)
405
- if @page.persisted? && @page.can_have_cells?
406
- grouped_options_for_select(grouped_elements_for_select(items, :id))
407
- else
408
- options = items.map do |item|
409
- [item.respond_to?(:display_name_with_preview_text) ? item.display_name_with_preview_text : item.name, item.id]
394
+ options = items.map do |item|
395
+ if item.respond_to?(:display_name_with_preview_text)
396
+ name = item.display_name_with_preview_text
397
+ else
398
+ name = item.name
410
399
  end
411
- options_for_select(options)
400
+ [name, item.id]
412
401
  end
402
+ options_for_select(options)
413
403
  end
414
404
 
415
405
  # Returns the regular expression used for external url validation in link dialog.
@@ -3,42 +3,69 @@
3
3
  module Alchemy
4
4
  module Admin
5
5
  module ElementsHelper
6
- include Alchemy::ElementsHelper
7
6
  include Alchemy::ElementsBlockHelper
8
7
  include Alchemy::Admin::BaseHelper
9
8
  include Alchemy::Admin::ContentsHelper
10
9
  include Alchemy::Admin::EssencesHelper
11
10
 
12
- # Renders the element editor partial
13
- def render_editor(element)
14
- render_element(element, :editor)
15
- end
16
-
17
- # Renders a drag'n'drop picture gallery editor for all EssencePictures.
11
+ # Renders a {Alchemy::Element} editor partial.
12
+ #
13
+ # A element editor partial is the form presented to the content author in page edit mode.
14
+ #
15
+ # The partial is located in <tt>app/views/alchemy/elements</tt>.
16
+ #
17
+ # == Partial naming
18
+ #
19
+ # The partials have to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with <tt>_editor</tt>.
20
+ #
21
+ # === Example
22
+ #
23
+ # Given a headline element
24
+ #
25
+ # # elements.yml
26
+ # - name: headline
27
+ # contents:
28
+ # - name: text
29
+ # type: EssenceText
18
30
  #
19
- # It brings full functionality for adding images, deleting images and sorting them via drag'n'drop.
20
- # Just place this helper inside your element editor view, pass the element as parameter and that's it.
31
+ # Then your element editor partial has to be named:
21
32
  #
22
- # === Options:
33
+ # app/views/alchemy/elements/_headline_editor.html.{erb|haml|slim}
23
34
  #
24
- # :maximum_amount_of_images [Integer] # This option let you handle the amount of images your customer can add to this element.
35
+ # === Element partials generator
25
36
  #
26
- def render_picture_gallery_editor(element, options = {})
27
- default_options = {
28
- maximum_amount_of_images: nil,
29
- grouped: true
37
+ # You can use this handy generator to let Alchemy generate the partials for you:
38
+ #
39
+ # $ rails generate alchemy:elements --skip
40
+ #
41
+ # == Usage
42
+ #
43
+ # <%= render_editor(Alchemy::Element.published.named(:headline).first) %>
44
+ #
45
+ # @param [Alchemy::Element] element
46
+ # The element you want to render the editor for
47
+ #
48
+ # @note If the partial is not found
49
+ # <tt>alchemy/elements/_editor_not_found.html.erb</tt> gets rendered.
50
+ #
51
+ def render_editor(element)
52
+ if element.nil?
53
+ warning('Element is nil')
54
+ render "alchemy/elements/editor_not_found", {name: 'nil'}
55
+ return
56
+ end
57
+
58
+ render "alchemy/elements/#{element.name}_editor", element: element
59
+ rescue ActionView::MissingTemplate => e
60
+ warning(%(
61
+ Element editor partial not found for #{element.name}.\n
62
+ #{e}
63
+ ))
64
+ render "alchemy/elements/editor_not_found", {
65
+ name: element.name,
66
+ error: "Element editor partial not found.<br>Use <code>rails generate alchemy:elements</code> to generate it."
30
67
  }
31
- options = default_options.merge(options)
32
- render(
33
- partial: "alchemy/admin/elements/picture_gallery_editor",
34
- locals: {
35
- pictures: element.contents.gallery_pictures,
36
- element: element,
37
- options: options
38
- }
39
- )
40
68
  end
41
- alias_method :render_picture_editor, :render_picture_gallery_editor
42
69
 
43
70
  # Returns an elements array for select helper.
44
71
  #
@@ -55,57 +82,16 @@ module Alchemy
55
82
  end
56
83
  end
57
84
 
58
- # Returns all elements that can be placed on the current page.
59
- # The elements will be grouped by cell.
60
- #
61
- # @param [Array] elements
62
- # collection of element objects
63
- # @param [String] object_method
64
- # method that is called on the element objects used for the select option value
65
- #
66
- def grouped_elements_for_select(elements, object_method = 'name')
67
- return [] if elements.blank?
68
- cells_definition = @page.cell_definitions
69
- return [] if cells_definition.blank?
70
- options = {}
71
- cells_definition.each do |cell|
72
- cell_elements = elements_for_cell(elements, cell)
73
- optgroup_label = Cell.translated_label_for(cell['name'])
74
- options[optgroup_label] = cell_elements.map do |e|
75
- element_array_for_options(e, object_method, cell)
76
- end
77
- end
78
- options[Alchemy.t(:main_content)] = elements_for_main_content(elements).map do |e|
79
- element_array_for_options(e, object_method)
80
- end
81
- # Remove empty cells
82
- options.delete_if { |_c, e| e.blank? }
83
- end
84
-
85
- def element_array_for_options(element, object_method, cell = nil)
86
- case element
87
- when Alchemy::Element
88
- [
89
- element.display_name_with_preview_text,
90
- element.send(object_method).to_s + (cell ? "##{cell['name']}" : "")
91
- ]
92
- else
93
- [
94
- Element.display_name_for(element['name']),
95
- element[object_method] + (cell ? "##{cell['name']}" : "")
96
- ]
97
- end
98
- end
99
-
100
85
  # CSS classes for the element editor partial.
101
- def element_editor_classes(element, local_assigns)
86
+ def element_editor_classes(element)
102
87
  [
103
88
  'element-editor',
104
89
  element.content_definitions.present? ? 'with-contents' : 'without-contents',
105
90
  element.nestable_elements.any? ? 'nestable' : 'not-nestable',
106
91
  element.taggable? ? 'taggable' : 'not-taggable',
107
92
  element.folded ? 'folded' : 'expanded',
108
- local_assigns[:draggable] == false ? 'not-draggable' : 'draggable'
93
+ element.compact? ? 'compact' : nil,
94
+ element.fixed? ? 'is-fixed' : 'not-fixed'
109
95
  ].join(' ')
110
96
  end
111
97
 
@@ -118,22 +104,6 @@ module Alchemy
118
104
  element.nestable_elements.empty?
119
105
  end
120
106
  end
121
-
122
- private
123
-
124
- def elements_for_main_content(elements)
125
- page_definition = @page.definition['elements']
126
- elements.select do |e|
127
- page_definition.include?(e.class.name == 'Element' ? e.name : e['name'])
128
- end
129
- end
130
-
131
- def elements_for_cell(elements, cell)
132
- cell_elements = cell['elements']
133
- elements.select do |e|
134
- cell_elements.include?(e.class.name == 'Element' ? e.name : e['name'])
135
- end
136
- end
137
107
  end
138
108
  end
139
109
  end