comfy_middle_seat 3.2.0 → 4.0.0

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/coveralls.yml +4 -0
  3. data/CHANGELOG.md +56 -3
  4. data/CONTRIBUTING.md +8 -5
  5. data/Gemfile +1 -1
  6. data/README.md +66 -29
  7. data/Rakefile +3 -3
  8. data/app/assets/javascripts/comfy/admin/cms/application.js +2 -0
  9. data/app/assets/javascripts/comfy/admin/cms/base.js +6 -1
  10. data/app/assets/javascripts/comfy/admin/cms/codemirror.js +17 -0
  11. data/app/assets/javascripts/comfy/admin/cms/dirty_forms.js +201 -0
  12. data/app/assets/javascripts/comfy/admin/cms/draft_forms.js +468 -0
  13. data/app/assets/javascripts/comfy/admin/cms/page_fragments.js +393 -22
  14. data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +21 -0
  15. data/app/assets/javascripts/comfy/vendor/redactor/filemanager.js +48 -30
  16. data/app/assets/javascripts/comfy/vendor/redactor/imagemanager.js +43 -25
  17. data/app/assets/stylesheets/comfy/admin/cms/base.sass +23 -0
  18. data/app/controllers/comfy/admin/base_controller.rb +3 -3
  19. data/app/controllers/comfy/admin/cms/base_controller.rb +12 -7
  20. data/app/controllers/comfy/admin/cms/files_controller.rb +1 -1
  21. data/app/controllers/comfy/admin/cms/pages_controller.rb +76 -16
  22. data/app/controllers/comfy/admin/cms/revisions/base_controller.rb +39 -1
  23. data/app/controllers/comfy/admin/cms/revisions/page_controller.rb +9 -8
  24. data/app/controllers/comfy/admin/cms/revisions/translation_controller.rb +14 -8
  25. data/app/controllers/comfy/admin/cms/sites_controller.rb +1 -1
  26. data/app/controllers/comfy/admin/cms/translations_controller.rb +3 -1
  27. data/app/controllers/comfy/cms/base_controller.rb +1 -1
  28. data/app/controllers/comfy/cms/content_controller.rb +5 -5
  29. data/app/controllers/concerns/comfy/reorder_action.rb +24 -4
  30. data/app/helpers/comfy/admin/cms_helper.rb +28 -3
  31. data/app/helpers/comfy/cms_helper.rb +1 -1
  32. data/app/models/comfy/cms/file.rb +25 -3
  33. data/app/models/comfy/cms/layout.rb +8 -6
  34. data/app/models/comfy/cms/page.rb +22 -0
  35. data/app/models/comfy/cms/site.rb +3 -3
  36. data/app/models/comfy/cms/snippet.rb +8 -3
  37. data/app/models/concerns/comfy/cms/with_fragments.rb +2 -2
  38. data/app/views/comfy/admin/cms/categories/_index.html.haml +1 -1
  39. data/app/views/comfy/admin/cms/categories/_show.html.haml +1 -1
  40. data/app/views/comfy/admin/cms/files/_file.html.haml +1 -1
  41. data/app/views/comfy/admin/cms/files/index.html.haml +9 -2
  42. data/app/views/comfy/admin/cms/fragments/_form_fragments.html.haml +2 -2
  43. data/app/views/comfy/admin/cms/pages/_form.html.haml +2 -1
  44. data/app/views/comfy/admin/cms/pages/_index_branch.html.haml +11 -10
  45. data/app/views/comfy/admin/cms/pages/edit.html.haml +3 -1
  46. data/app/views/comfy/admin/cms/pages/index.html.haml +9 -2
  47. data/app/views/comfy/admin/cms/pages/new.html.haml +3 -1
  48. data/app/views/comfy/admin/cms/pages/toggle_branch.js.erb +2 -2
  49. data/app/views/comfy/admin/cms/revisions/show.html.haml +25 -7
  50. data/app/views/comfy/admin/cms/shared/_search.html.haml +9 -0
  51. data/app/views/comfy/admin/cms/sites/_form.html.haml +1 -1
  52. data/app/views/comfy/admin/cms/translations/_form.html.haml +2 -1
  53. data/app/views/comfy/admin/cms/translations/edit.html.haml +3 -1
  54. data/app/views/comfy/admin/cms/translations/new.html.haml +3 -1
  55. data/app/views/layouts/comfy/admin/cms/_flash.html.haml +1 -1
  56. data/app/views/layouts/comfy/admin/cms/_head.html.haml +3 -1
  57. data/app/views/layouts/comfy/admin/cms/_left.html.haml +2 -2
  58. data/comfy_middle_seat.gemspec +10 -5
  59. data/config/application.rb +3 -2
  60. data/config/cms_routes.rb +1 -1
  61. data/config/environment.rb +1 -1
  62. data/config/environments/development.rb +1 -1
  63. data/config/environments/production.rb +1 -1
  64. data/config/environments/test.rb +1 -1
  65. data/config/initializers/{comfortable_media_surfer.rb → comfy_middle_seat.rb} +4 -4
  66. data/config/locales/ar.yml +14 -0
  67. data/config/locales/ca.yml +14 -0
  68. data/config/locales/cs.yml +14 -0
  69. data/config/locales/da.yml +14 -0
  70. data/config/locales/de.yml +14 -0
  71. data/config/locales/en.yml +14 -0
  72. data/config/locales/es.yml +14 -0
  73. data/config/locales/fi.yml +14 -0
  74. data/config/locales/fr.yml +14 -0
  75. data/config/locales/gr.yml +14 -0
  76. data/config/locales/hr.yml +14 -0
  77. data/config/locales/it.yml +14 -0
  78. data/config/locales/ja.yml +14 -0
  79. data/config/locales/nb.yml +14 -0
  80. data/config/locales/nl.yml +14 -0
  81. data/config/locales/pl.yml +14 -0
  82. data/config/locales/pt-BR.yml +14 -0
  83. data/config/locales/ru.yml +14 -0
  84. data/config/locales/sk.yml +14 -0
  85. data/config/locales/sv.yml +14 -0
  86. data/config/locales/tr.yml +14 -0
  87. data/config/locales/uk.yml +14 -0
  88. data/config/locales/zh-CN.yml +14 -0
  89. data/config/locales/zh-TW.yml +14 -0
  90. data/config.ru +1 -1
  91. data/exe/comfy-middle-seat-upgrade +34 -0
  92. data/lib/{comfortable_media_surfer → comfy_middle_seat}/access_control/admin_authentication.rb +4 -4
  93. data/lib/{comfortable_media_surfer → comfy_middle_seat}/access_control/admin_authorization.rb +1 -1
  94. data/lib/{comfortable_media_surfer → comfy_middle_seat}/access_control/public_authentication.rb +1 -1
  95. data/lib/{comfortable_media_surfer → comfy_middle_seat}/access_control/public_authorization.rb +1 -1
  96. data/lib/{comfortable_media_surfer → comfy_middle_seat}/configuration.rb +7 -7
  97. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/block.rb +1 -1
  98. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/params_parser.rb +1 -1
  99. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/renderer.rb +10 -10
  100. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tag.rb +4 -4
  101. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/asset.rb +4 -4
  102. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/audio.rb +3 -3
  103. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/breadcrumbs.rb +3 -3
  104. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/checkbox.rb +3 -3
  105. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/children.rb +3 -3
  106. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/date.rb +3 -3
  107. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/datetime.rb +3 -3
  108. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/file.rb +5 -5
  109. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/file_link.rb +4 -4
  110. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/files.rb +3 -3
  111. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/fragment.rb +2 -2
  112. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/helper.rb +4 -4
  113. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/image.rb +4 -4
  114. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/markdown.rb +3 -3
  115. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/mixins/file_content.rb +1 -1
  116. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/number.rb +3 -3
  117. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/page_file_link.rb +5 -5
  118. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/partial.rb +4 -4
  119. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/siblings.rb +3 -3
  120. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/snippet.rb +3 -3
  121. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/template.rb +4 -4
  122. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/text.rb +3 -3
  123. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/textarea.rb +3 -3
  124. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags/wysiwyg.rb +3 -3
  125. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content/tags.rb +1 -1
  126. data/lib/{comfortable_media_surfer → comfy_middle_seat}/content.rb +1 -1
  127. data/lib/{comfortable_media_surfer → comfy_middle_seat}/engine.rb +4 -4
  128. data/lib/{comfortable_media_surfer → comfy_middle_seat}/error.rb +4 -4
  129. data/lib/{comfortable_media_surfer → comfy_middle_seat}/extensions/acts_as_tree.rb +3 -3
  130. data/lib/{comfortable_media_surfer → comfy_middle_seat}/extensions/has_revisions.rb +4 -4
  131. data/lib/{comfortable_media_surfer → comfy_middle_seat}/extensions.rb +1 -1
  132. data/lib/{comfortable_media_surfer → comfy_middle_seat}/form_builder.rb +2 -2
  133. data/lib/comfy_middle_seat/initializer_upgrader.rb +115 -0
  134. data/lib/{comfortable_media_surfer → comfy_middle_seat}/render_methods.rb +7 -7
  135. data/lib/{comfortable_media_surfer → comfy_middle_seat}/routing.rb +3 -2
  136. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/file/exporter.rb +5 -5
  137. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/file/importer.rb +5 -5
  138. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/layout/exporter.rb +4 -4
  139. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/layout/importer.rb +5 -5
  140. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/page/exporter.rb +5 -5
  141. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/page/importer.rb +7 -7
  142. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/snippet/exporter.rb +4 -4
  143. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds/snippet/importer.rb +5 -5
  144. data/lib/{comfortable_media_surfer → comfy_middle_seat}/seeds.rb +4 -4
  145. data/lib/comfy_middle_seat/version.rb +2 -2
  146. data/lib/{comfortable_media_surfer → comfy_middle_seat}/view_hooks.rb +2 -2
  147. data/lib/comfy_middle_seat.rb +54 -1
  148. data/lib/generators/comfy/cms/README +3 -11
  149. data/lib/generators/comfy/cms/cms_generator.rb +2 -2
  150. data/lib/generators/comfy/scaffold/templates/tests/controller.rb.tt +2 -2
  151. data/lib/tasks/cms_seeds.rake +8 -8
  152. data/package-lock.json +2 -2
  153. data/package.json +1 -1
  154. metadata +68 -62
  155. data/lib/comfortable_media_surfer/version.rb +0 -3
  156. data/lib/comfortable_media_surfer.rb +0 -56
@@ -8,12 +8,12 @@ class Comfy::Admin::Cms::BaseController < Comfy::Admin::BaseController
8
8
 
9
9
  layout :infer_layout
10
10
 
11
- if ComfortableMediaSurfer.config.admin_cache_sweeper.present?
12
- cache_sweeper(*ComfortableMediaSurfer.config.admin_cache_sweeper)
11
+ if ComfyMiddleSeat.config.admin_cache_sweeper.present?
12
+ cache_sweeper(*ComfyMiddleSeat.config.admin_cache_sweeper)
13
13
  end
14
14
 
15
15
  def jump
16
- path = ComfortableMediaSurfer.config.admin_route_redirect
16
+ path = ComfyMiddleSeat.config.admin_route_redirect
17
17
  return redirect_to(path) unless path.blank?
18
18
 
19
19
  load_admin_site
@@ -27,24 +27,29 @@ protected
27
27
  if (@site = ::Comfy::Cms::Site.find_by(id: id_param) || ::Comfy::Cms::Site.first)
28
28
  session[:site_id] = @site.id
29
29
  else
30
- I18n.locale = ComfortableMediaSurfer.config.admin_locale || I18n.default_locale
30
+ I18n.locale = ComfyMiddleSeat.config.admin_locale || I18n.default_locale
31
31
  flash[:danger] = I18n.t('comfy.admin.cms.base.site_not_found')
32
32
  redirect_to(new_comfy_admin_cms_site_path)
33
33
  end
34
34
  end
35
35
 
36
36
  def set_locale?
37
- I18n.locale = ComfortableMediaSurfer.config.admin_locale || @site&.locale
37
+ I18n.locale = ComfyMiddleSeat.config.admin_locale || @site&.locale
38
38
  true
39
39
  end
40
40
 
41
+ def acknowledge_draft_save
42
+ key = params[:cms_draft_key].to_s
43
+ flash[:cms_saved_draft_key] = key if key.start_with?('comfy-cms:draft:v1:')
44
+ end
45
+
41
46
  def load_seeds
42
- return unless ComfortableMediaSurfer.config.enable_seeds
47
+ return unless ComfyMiddleSeat.config.enable_seeds
43
48
 
44
49
  controllers = %w[layouts pages snippets files].collect { |c| "comfy/admin/cms/#{c}" }
45
50
  return unless controllers.member?(params[:controller]) && params[:action] == 'index'
46
51
 
47
- ComfortableMediaSurfer::Seeds::Importer.new(@site.identifier).import!
52
+ ComfyMiddleSeat::Seeds::Importer.new(@site.identifier).import!
48
53
  flash.now[:warning] = I18n.t('comfy.admin.cms.base.seeds_enabled')
49
54
  end
50
55
 
@@ -12,7 +12,7 @@ class Comfy::Admin::Cms::FilesController < Comfy::Admin::Cms::BaseController
12
12
  before_action :authorize
13
13
 
14
14
  def index
15
- files_scope = @site.files.with_attached_attachment
15
+ files_scope = @site.files.with_attached_attachment.search(params[:q])
16
16
 
17
17
  case params[:source]
18
18
 
@@ -8,6 +8,8 @@ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
8
8
 
9
9
  include ::Comfy::ReorderAction
10
10
 
11
+ helper_method :page_branch_open?
12
+
11
13
  self.reorder_action_resource = ::Comfy::Cms::Page
12
14
 
13
15
  before_action :check_for_layouts, only: %i[new edit]
@@ -23,14 +25,18 @@ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
23
25
 
24
26
  return index_for_redactor if params[:source] == 'redactor'
25
27
 
26
- @pages_by_parent = pages_grouped_by_parent
27
-
28
- @pages =
29
- if params[:categories].present?
30
- @site.pages.includes(:categories).for_category(params[:categories]).order(:label)
31
- else
32
- [@site.pages.root].compact
33
- end
28
+ if page_filters?
29
+ @pages_by_parent = {}
30
+ @pages = @site.pages
31
+ .includes(:categories)
32
+ .for_category(params[:categories])
33
+ .search(params[:q])
34
+ .order(:label)
35
+ else
36
+ root = @site.pages.roots.includes(:categories).first
37
+ @pages = [root].compact
38
+ @pages_by_parent = pages_grouped_for_open_tree(root)
39
+ end
34
40
  end
35
41
 
36
42
  def new
@@ -49,6 +55,7 @@ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
49
55
  def create
50
56
  @page.save!
51
57
  update_family
58
+ acknowledge_draft_save
52
59
  flash[:success] = I18n.t('comfy.admin.cms.pages.created')
53
60
  redirect_to action: :edit, id: @page
54
61
  rescue ActiveRecord::RecordInvalid
@@ -59,6 +66,7 @@ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
59
66
  def update
60
67
  @page.save!
61
68
  update_family
69
+ acknowledge_draft_save
62
70
  flash[:success] = I18n.t('comfy.admin.cms.pages.updated')
63
71
  redirect_to action: :edit, id: @page
64
72
  rescue ActiveRecord::RecordInvalid
@@ -67,7 +75,15 @@ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
67
75
  end
68
76
 
69
77
  def destroy
70
- @page.destroy
78
+ if @page.root?
79
+ flash[:danger] = I18n.t(
80
+ 'comfy.admin.cms.pages.root_delete_failure',
81
+ default: 'The root page cannot be deleted.'
82
+ )
83
+ return redirect_to action: :index
84
+ end
85
+
86
+ @page.destroy!
71
87
  update_family
72
88
  flash[:success] = I18n.t('comfy.admin.cms.pages.deleted')
73
89
  redirect_to action: :index
@@ -85,13 +101,21 @@ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
85
101
  end
86
102
 
87
103
  def toggle_branch
88
- @pages_by_parent = pages_grouped_by_parent
89
104
  @page = @site.pages.find(params[:id])
90
- s = (session[:cms_page_tree] ||= [])
91
- id = @page.id.to_s
92
- s.member?(id) ? s.delete(id) : s << id
105
+ tree = page_tree_session
106
+ id = @page.id.to_s
107
+
108
+ if tree.member?(id)
109
+ tree.delete(id)
110
+ @branch_open = false
111
+ @pages_by_parent = {}
112
+ else
113
+ tree << id
114
+ @branch_open = true
115
+ @pages_by_parent = pages_grouped_for_open_tree(@page)
116
+ end
93
117
  rescue ActiveRecord::RecordNotFound
94
- render nothing: true
118
+ head :not_found
95
119
  end
96
120
 
97
121
  def publish_children
@@ -138,8 +162,44 @@ protected
138
162
  @site.pages.none?
139
163
  end
140
164
 
141
- def pages_grouped_by_parent
142
- @site.pages.order(:position).includes(:categories).group_by(&:parent_id)
165
+ def pages_grouped_for_open_tree(parent)
166
+ return {} unless parent
167
+
168
+ pages_by_parent = {}
169
+ open_ids = session_open_page_ids
170
+ parent_ids = [parent.id]
171
+
172
+ while parent_ids.present?
173
+ children = @site.pages
174
+ .where(parent_id: parent_ids)
175
+ .includes(:categories)
176
+ .order(:parent_id, :position, :id)
177
+ .to_a
178
+ pages_by_parent.merge!(children.group_by(&:parent_id))
179
+ parent_ids = children.filter_map { |page| page.id if open_ids.include?(page.id) }
180
+ end
181
+
182
+ pages_by_parent
183
+ end
184
+
185
+ def page_branch_open?(page)
186
+ page.root? || page_tree_session.member?(page.id.to_s)
187
+ end
188
+
189
+ def page_tree_session
190
+ trees = session[:cms_page_tree]
191
+ trees = session[:cms_page_tree] = {} unless trees.is_a?(Hash)
192
+ trees[@site.id.to_s] ||= []
193
+ end
194
+
195
+ def session_open_page_ids
196
+ page_tree_session.filter_map do |id|
197
+ id.to_i if id.to_s.match?(%r{\A[1-9]\d*\z})
198
+ end.to_set
199
+ end
200
+
201
+ def page_filters?
202
+ params[:categories].present? || params[:q].present?
143
203
  end
144
204
 
145
205
  def check_for_layouts
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Comfy::Admin::Cms::Revisions::BaseController < Comfy::Admin::Cms::BaseController
4
- helper_method :record_path
4
+ helper_method :record_path, :preview_path
5
5
 
6
6
  before_action :load_record
7
7
  before_action :load_revision, except: :index
@@ -31,6 +31,40 @@ class Comfy::Admin::Cms::Revisions::BaseController < Comfy::Admin::Cms::BaseCont
31
31
 
32
32
  protected
33
33
 
34
+ def load_fragment_content
35
+ current_content = @record.fragments.to_h do |fragment|
36
+ [fragment.identifier, fragment.content]
37
+ end
38
+ versioned_content = @revision.data.fetch('fragments_attributes', []).to_h do |attributes|
39
+ attributes = attributes.with_indifferent_access
40
+ [attributes[:identifier], attributes[:content]]
41
+ end
42
+ identifiers = current_content.keys | versioned_content.keys
43
+
44
+ @current_content = identifiers.to_h { |identifier| [identifier, current_content[identifier]] }
45
+ @versioned_content = identifiers.to_h { |identifier| [identifier, versioned_content[identifier]] }
46
+ end
47
+
48
+ def render_fragment_preview(cms_page:, locale:)
49
+ apply_revision_in_memory
50
+
51
+ @cms_site = @record.site
52
+ @cms_layout = @record.layout
53
+ @cms_page = cms_page
54
+
55
+ I18n.locale = locale
56
+ response.headers['X-XSS-Protection'] = '0'
57
+
58
+ app_layout = @cms_layout.app_layout.presence || false
59
+ render inline: @record.render, layout: app_layout, content_type: 'text/html'
60
+ end
61
+
62
+ def apply_revision_in_memory
63
+ @record.fragments.load_target
64
+ @record.fragments.target.clear
65
+ @record.assign_attributes(@revision.data.deep_dup)
66
+ end
67
+
34
68
  def load_record
35
69
  raise 'not implemented'
36
70
  end
@@ -45,4 +79,8 @@ protected
45
79
  def record_path
46
80
  raise 'not implemented'
47
81
  end
82
+
83
+ def preview_path
84
+ nil
85
+ end
48
86
  end
@@ -2,17 +2,14 @@
2
2
 
3
3
  class Comfy::Admin::Cms::Revisions::PageController < Comfy::Admin::Cms::Revisions::BaseController
4
4
  def show
5
- @current_content = @record.fragments.to_h do |fragment|
6
- [fragment.identifier, fragment.content]
7
- end
8
- @versioned_content = @record.fragments.to_h do |fragment|
9
- data = @revision.data['fragments_attributes'].detect { |item| item[:identifier] == fragment.identifier }
10
- [fragment.identifier, data.try(:[], :content)]
11
- end
12
-
5
+ load_fragment_content
13
6
  render 'comfy/admin/cms/revisions/show'
14
7
  end
15
8
 
9
+ def preview
10
+ render_fragment_preview(cms_page: @record, locale: @site.locale)
11
+ end
12
+
16
13
  private
17
14
 
18
15
  def load_record
@@ -25,4 +22,8 @@ private
25
22
  def record_path
26
23
  edit_comfy_admin_cms_site_page_path(@site, @record)
27
24
  end
25
+
26
+ def preview_path
27
+ preview_comfy_admin_cms_site_page_revision_path(@site, @record, @revision)
28
+ end
28
29
  end
@@ -2,17 +2,14 @@
2
2
 
3
3
  class Comfy::Admin::Cms::Revisions::TranslationController < Comfy::Admin::Cms::Revisions::BaseController
4
4
  def show
5
- @current_content = @record.fragments.to_h do |fragment|
6
- [fragment.identifier, fragment.content]
7
- end
8
- @versioned_content = @record.fragments.to_h do |fragment|
9
- data = @revision.data['fragments_attributes'].detect { |item| item[:identifier] == fragment.identifier }
10
- [fragment.identifier, data.try(:[], :content)]
11
- end
12
-
5
+ load_fragment_content
13
6
  render 'comfy/admin/cms/revisions/show'
14
7
  end
15
8
 
9
+ def preview
10
+ render_fragment_preview(cms_page: @page, locale: @record.locale)
11
+ end
12
+
16
13
  private
17
14
 
18
15
  def load_record
@@ -26,4 +23,13 @@ private
26
23
  def record_path
27
24
  edit_comfy_admin_cms_site_page_translation_path(@site, @page, @record)
28
25
  end
26
+
27
+ def preview_path
28
+ preview_comfy_admin_cms_site_page_translation_revision_path(
29
+ @site,
30
+ @page,
31
+ @record,
32
+ @revision
33
+ )
34
+ end
29
35
  end
@@ -56,7 +56,7 @@ protected
56
56
 
57
57
  def load_site
58
58
  @site = ::Comfy::Cms::Site.find(params[:id])
59
- I18n.locale = ComfortableMediaSurfer.config.admin_locale || @site.locale
59
+ I18n.locale = ComfyMiddleSeat.config.admin_locale || @site.locale
60
60
  rescue ActiveRecord::RecordNotFound
61
61
  flash[:danger] = I18n.t('comfy.admin.cms.sites.not_found')
62
62
  redirect_to action: :index
@@ -25,6 +25,7 @@ class Comfy::Admin::Cms::TranslationsController < Comfy::Admin::Cms::BaseControl
25
25
 
26
26
  def create
27
27
  @translation.save!
28
+ acknowledge_draft_save
28
29
  flash[:success] = I18n.t('comfy.admin.cms.translations.created')
29
30
  redirect_to action: :edit, id: @translation
30
31
  rescue ActiveRecord::RecordInvalid
@@ -34,6 +35,7 @@ class Comfy::Admin::Cms::TranslationsController < Comfy::Admin::Cms::BaseControl
34
35
 
35
36
  def update
36
37
  @translation.save!
38
+ acknowledge_draft_save
37
39
  flash[:success] = I18n.t('comfy.admin.cms.translations.updated')
38
40
  redirect_to action: :edit, id: @translation
39
41
  rescue ActiveRecord::RecordInvalid
@@ -61,7 +63,7 @@ class Comfy::Admin::Cms::TranslationsController < Comfy::Admin::Cms::BaseControl
61
63
  private
62
64
 
63
65
  def translation_select_options
64
- all = ComfortableMediaSurfer.config.locales
66
+ all = ComfyMiddleSeat.config.locales
65
67
  taken = @page.translations.pluck(:locale) + [@site.locale] - [@translation.locale]
66
68
  all.except(*taken).map { |k, v| ["#{v} (#{k})", k] }
67
69
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Comfy::Cms::BaseController < ComfortableMediaSurfer.config.public_base_controller.to_s.constantize
3
+ class Comfy::Cms::BaseController < ComfyMiddleSeat.config.public_base_controller.to_s.constantize
4
4
  before_action :load_cms_site
5
5
 
6
6
  helper Comfy::CmsHelper
@@ -2,10 +2,10 @@
2
2
 
3
3
  class Comfy::Cms::ContentController < Comfy::Cms::BaseController
4
4
  # Authentication module must have `authenticate` method
5
- include ComfortableMediaSurfer.config.public_auth.to_s.constantize
5
+ include ComfyMiddleSeat.config.public_auth.to_s.constantize
6
6
 
7
7
  # Authorization module must have `authorize` method
8
- include ComfortableMediaSurfer.config.public_authorization.to_s.constantize
8
+ include ComfyMiddleSeat.config.public_authorization.to_s.constantize
9
9
 
10
10
  before_action :load_seeds
11
11
  before_action :load_cms_page,
@@ -24,7 +24,7 @@ class Comfy::Cms::ContentController < Comfy::Cms::BaseController
24
24
  inline: @cms_page.content_cache,
25
25
  layout: false
26
26
  )
27
- json_page = @cms_page.as_json(ComfortableMediaSurfer.config.page_to_json_options)
27
+ json_page = @cms_page.as_json(ComfyMiddleSeat.config.page_to_json_options)
28
28
  render json: json_page
29
29
  end
30
30
  end
@@ -53,9 +53,9 @@ protected
53
53
  end
54
54
 
55
55
  def load_seeds
56
- return unless ComfortableMediaSurfer.config.enable_seeds
56
+ return unless ComfyMiddleSeat.config.enable_seeds
57
57
 
58
- ComfortableMediaSurfer::Seeds::Importer.new(@cms_site.identifier).import!
58
+ ComfyMiddleSeat::Seeds::Importer.new(@cms_site.identifier).import!
59
59
  end
60
60
 
61
61
  # Attempting to populate @cms_page and @cms_layout instance variables so they
@@ -9,11 +9,31 @@ module Comfy::ReorderAction
9
9
 
10
10
  def reorder
11
11
  resource_class = self.class.reorder_action_resource
12
- site_resources = resource_class.where(site_id: @site.id)
13
- (params.permit(order: [])[:order] || []).each_with_index do |id, index|
14
- site_resources.where(id: id).update_all(position: index)
12
+ positions = (params.permit(order: [])[:order] || []).each_with_index.to_h
13
+
14
+ if positions.present?
15
+ site_resources = resource_class.where(site_id: @site.id)
16
+ reordered_resources = site_resources.where(id: positions.keys)
17
+ position = Arel::Nodes::Case.new(resource_class.arel_table[:id])
18
+ positions.each do |id, index|
19
+ position.when(id).then(index)
20
+ end
21
+
22
+ reordered_resources.update_all(position: position)
23
+ if resource_class == Comfy::Cms::Page
24
+ clear_reordered_page_content_cache(site_resources, reordered_resources)
25
+ end
15
26
  end
16
- @site.pages.each(&:save!) if resource_class == ::Comfy::Cms::Page
27
+
17
28
  head :ok
18
29
  end
30
+
31
+ private
32
+
33
+ def clear_reordered_page_content_cache(site_pages, reordered_pages)
34
+ affected_pages = site_pages.where(id: reordered_pages.select(:id)).or(
35
+ site_pages.where(id: reordered_pages.select(:parent_id))
36
+ )
37
+ affected_pages.update_all(content_cache: nil)
38
+ end
19
39
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'securerandom'
4
+
3
5
  module Comfy
4
6
  module Admin
5
7
  module CmsHelper
6
8
  # Wrapper around Comfy::FormBuilder
7
9
  def comfy_form_with(**options, &)
8
- form_options = options.merge(builder: ComfortableMediaSurfer::FormBuilder)
10
+ form_options = options.merge(builder: ComfyMiddleSeat::FormBuilder)
9
11
  form_options[:bootstrap] = { layout: :horizontal }
10
12
  form_options[:local] = true
11
13
  bootstrap_form_with(**form_options, &)
@@ -14,16 +16,39 @@ module Comfy
14
16
  def comfy_admin_partial(path, params = {})
15
17
  render path, params
16
18
  rescue ActionView::MissingTemplate
17
- if ComfortableMediaSurfer.config.reveal_cms_partials
19
+ if ComfyMiddleSeat.config.reveal_cms_partials
18
20
  content_tag(:div, class: 'comfy-admin-partial') do
19
21
  path
20
22
  end
21
23
  end
22
24
  end
23
25
 
26
+ def cms_draft_form_data(*key_parts, record:)
27
+ namespace = session[:comfy_cms_draft_namespace] ||= SecureRandom.hex(16)
28
+ {
29
+ cms_unsaved_message: t(
30
+ 'comfy.admin.cms.forms.unsaved_changes',
31
+ default: 'You have unsaved changes. Are you sure you want to leave this page?'
32
+ ),
33
+ cms_draft_key: ['comfy-cms:draft:v1', namespace, *key_parts].join(':'),
34
+ cms_draft_title: t('comfy.admin.cms.drafts.title', default: 'Unsaved draft found'),
35
+ cms_draft_message: t(
36
+ 'comfy.admin.cms.drafts.message',
37
+ default: 'A locally saved draft is available. Restore it or discard it?'
38
+ ),
39
+ cms_draft_files_message: t(
40
+ 'comfy.admin.cms.drafts.files_message',
41
+ default: 'Selected files are not stored and must be selected again.'
42
+ ),
43
+ cms_draft_restore: t('comfy.admin.cms.drafts.restore', default: 'Restore draft'),
44
+ cms_draft_discard: t('comfy.admin.cms.drafts.discard', default: 'Discard draft'),
45
+ cms_save_failed: record.errors.any?
46
+ }
47
+ end
48
+
24
49
  # Injects some content somewhere inside cms admin area
25
50
  def cms_hook(name, options = {})
26
- ComfortableMediaSurfer::ViewHooks.render(name, self, options)
51
+ ComfyMiddleSeat::ViewHooks.render(name, self, options)
27
52
  end
28
53
 
29
54
  # @param [String] fragment_id
@@ -52,7 +52,7 @@ module Comfy
52
52
  snippet = cms_site&.snippets&.find_by_identifier(identifier)
53
53
  return '' unless snippet
54
54
 
55
- r = ComfortableMediaSurfer::Content::Renderer.new(snippet)
55
+ r = ComfyMiddleSeat::Content::Renderer.new(snippet)
56
56
  render inline: r.render(r.nodes(r.tokenize(snippet.content)))
57
57
  end
58
58
 
@@ -24,7 +24,9 @@ class Comfy::Cms::File < ActiveRecord::Base
24
24
  before_create :assign_position
25
25
  # active_storage attachment behavior changed in rails 6
26
26
  before_save :process_attachment
27
- after_save :clear_page_content_cache
27
+ after_commit :clear_page_content_cache,
28
+ on: %i[create update destroy],
29
+ if: :page_content_cache_stale?
28
30
 
29
31
  # -- Validations -------------------------------------------------------------
30
32
  validates :label, presence: true
@@ -36,17 +38,37 @@ class Comfy::Cms::File < ActiveRecord::Base
36
38
  scope :with_images, -> {
37
39
  where("active_storage_blobs.content_type LIKE 'image/%'").references(:blob)
38
40
  }
41
+ scope :search, ->(query) {
42
+ term = query.to_s.strip
43
+ if term.present?
44
+ pattern = "%#{sanitize_sql_like(term.downcase)}%"
45
+ left_joins(attachment_attachment: :blob)
46
+ .where(
47
+ <<~SQL.squish,
48
+ LOWER(comfy_cms_files.label) LIKE :pattern OR
49
+ LOWER(comfy_cms_files.description) LIKE :pattern OR
50
+ LOWER(active_storage_blobs.filename) LIKE :pattern
51
+ SQL
52
+ pattern: pattern
53
+ )
54
+ .distinct
55
+ end
56
+ }
39
57
 
40
58
  private
41
59
 
42
60
  def clear_page_content_cache
43
- Comfy::Cms::Page.where(id: site.pages.pluck(:id)).update_all(content_cache: nil)
61
+ site.pages.update_all(content_cache: nil)
62
+ end
63
+
64
+ def page_content_cache_stale?
65
+ destroyed? || saved_changes? || @file.present?
44
66
  end
45
67
 
46
68
  protected
47
69
 
48
70
  def assign_position
49
- max = Comfy::Cms::File.maximum(:position)
71
+ max = site.files.maximum(:position)
50
72
  self.position = max ? max + 1 : 0
51
73
  end
52
74
 
@@ -3,7 +3,7 @@
3
3
  class Comfy::Cms::Layout < ActiveRecord::Base
4
4
  self.table_name = 'comfy_cms_layouts'
5
5
 
6
- require_relative '../../../../lib/comfortable_media_surfer/extensions/acts_as_tree'
6
+ require_relative '../../../../lib/comfy_middle_seat/extensions/acts_as_tree'
7
7
 
8
8
  cms_acts_as_tree
9
9
  cms_has_revisions_for :content, :css, :js
@@ -15,7 +15,9 @@ class Comfy::Cms::Layout < ActiveRecord::Base
15
15
  # -- Callbacks ---------------------------------------------------------------
16
16
  before_validation :assign_label
17
17
  before_create :assign_position
18
- after_save :clear_page_content_cache
18
+ after_commit :clear_page_content_cache,
19
+ on: %i[create update],
20
+ if: :saved_changes?
19
21
  after_destroy :clear_page_content_cache
20
22
 
21
23
  # -- Validations -------------------------------------------------------------
@@ -66,12 +68,12 @@ class Comfy::Cms::Layout < ActiveRecord::Base
66
68
  # and merges on the {{cms:tag_type content}} tag (if parent layout has that).
67
69
  # Returns a list of tokens that can be fed into the renderer.
68
70
  def content_tokens
69
- renderer = ComfortableMediaSurfer::Content::Renderer.new(nil)
71
+ renderer = ComfyMiddleSeat::Content::Renderer.new(nil)
70
72
  tokens = renderer.tokenize(content)
71
73
 
72
74
  if parent
73
- fragment_tags = ComfortableMediaSurfer::Content::Tags::Fragment.subclasses.map do |c|
74
- ComfortableMediaSurfer::Content::Renderer.tags.key(c)
75
+ fragment_tags = ComfyMiddleSeat::Content::Tags::Fragment.subclasses.map do |c|
76
+ ComfyMiddleSeat::Content::Renderer.tags.key(c)
75
77
  end
76
78
 
77
79
  parent_tokens = parent.content_tokens
@@ -96,7 +98,7 @@ class Comfy::Cms::Layout < ActiveRecord::Base
96
98
 
97
99
  # Forcing page content reload
98
100
  def clear_page_content_cache
99
- Comfy::Cms::Page.where(id: pages.pluck(:id)).update_all(content_cache: nil)
101
+ pages.update_all(content_cache: nil)
100
102
  children.each(&:clear_page_content_cache)
101
103
  end
102
104
 
@@ -44,6 +44,28 @@ class Comfy::Cms::Page < ActiveRecord::Base
44
44
 
45
45
  # -- Scopes ------------------------------------------------------------------
46
46
  scope :published, -> { where(is_published: true) }
47
+ scope :search, ->(query) {
48
+ term = query.to_s.strip
49
+ if term.present?
50
+ pattern = "%#{sanitize_sql_like(term.downcase)}%"
51
+ where(
52
+ <<~SQL.squish,
53
+ LOWER(comfy_cms_pages.label) LIKE :pattern OR
54
+ LOWER(comfy_cms_pages.slug) LIKE :pattern OR
55
+ LOWER(comfy_cms_pages.full_path) LIKE :pattern OR
56
+ EXISTS (
57
+ SELECT 1
58
+ FROM comfy_cms_fragments
59
+ WHERE comfy_cms_fragments.record_type = :record_type
60
+ AND comfy_cms_fragments.record_id = comfy_cms_pages.id
61
+ AND LOWER(comfy_cms_fragments.content) LIKE :pattern
62
+ )
63
+ SQL
64
+ pattern: pattern,
65
+ record_type: polymorphic_name
66
+ )
67
+ end
68
+ }
47
69
 
48
70
  # -- Class Methods -----------------------------------------------------------
49
71
  # Tree-like structure for pages
@@ -37,7 +37,7 @@ class Comfy::Cms::Site < ActiveRecord::Base
37
37
 
38
38
  cms_site = nil
39
39
 
40
- public_cms_path = ComfortableMediaSurfer.configuration.public_cms_path
40
+ public_cms_path = ComfyMiddleSeat.configuration.public_cms_path
41
41
  if path && public_cms_path != '/'
42
42
  path = path.sub(%r{\A#{public_cms_path}}, '')
43
43
  end
@@ -54,7 +54,7 @@ class Comfy::Cms::Site < ActiveRecord::Base
54
54
  end
55
55
 
56
56
  def self.real_host_from_aliases(host)
57
- if (aliases = ComfortableMediaSurfer.config.hostname_aliases)
57
+ if (aliases = ComfyMiddleSeat.config.hostname_aliases)
58
58
  aliases.each do |alias_host, hosts|
59
59
  return alias_host if hosts.include?(host)
60
60
  end
@@ -64,7 +64,7 @@ class Comfy::Cms::Site < ActiveRecord::Base
64
64
 
65
65
  # -- Instance Methods --------------------------------------------------------
66
66
  def url(relative: false)
67
- public_cms_path = ComfortableMediaSurfer.config.public_cms_path || '/'
67
+ public_cms_path = ComfyMiddleSeat.config.public_cms_path || '/'
68
68
  host = "//#{hostname}"
69
69
  path = ['/', public_cms_path, self.path].compact.join('/').squeeze('/').chomp('/')
70
70
  relative ? path.presence : [host, path].join