alchemy_cms 4.1.2 → 4.2.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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