camaleon_cms 2.9.2 → 2.9.4

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 (216) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -4
  3. data/Rakefile +3 -16
  4. data/app/apps/plugins/attack/admin_controller.rb +9 -6
  5. data/app/apps/plugins/attack/attack_helper.rb +35 -25
  6. data/app/apps/plugins/authoring_post/authoring_post_helper.rb +23 -16
  7. data/app/apps/plugins/front_cache/admin_controller.rb +14 -10
  8. data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
  9. data/app/apps/plugins/front_cache/config/locales/translation.yml +0 -7
  10. data/app/apps/plugins/front_cache/front_cache_helper.rb +109 -37
  11. data/app/apps/plugins/front_cache/views/admin/settings.html.erb +0 -5
  12. data/app/apps/plugins/visibility_post/config/config.json +1 -0
  13. data/app/apps/plugins/visibility_post/config/routes_front.txt +1 -0
  14. data/app/apps/plugins/visibility_post/front_controller.rb +23 -0
  15. data/app/apps/plugins/visibility_post/visibility_post_helper.rb +141 -70
  16. data/app/apps/themes/camaleon_first/main_helper.rb +18 -12
  17. data/app/apps/themes/default/assets/css/style.css.scss +24 -0
  18. data/app/apps/themes/default/assets/genericons/genericons.css +3 -8
  19. data/app/apps/themes/default/default_helper.rb +2 -1
  20. data/app/apps/themes/default/views/layouts/index.html.erb +3 -1
  21. data/app/apps/themes/new/assets/css/styles.css.scss +24 -0
  22. data/app/apps/themes/new/custom_helper.rb +5 -9
  23. data/app/apps/themes/new/views/layouts/_header.html.erb +3 -1
  24. data/app/assets/javascripts/camaleon_cms/admin/_data.js +16 -0
  25. data/app/assets/javascripts/camaleon_cms/admin/_post.js +5 -2
  26. data/app/assets/javascripts/camaleon_cms/admin/nav_menu.js +14 -3
  27. data/app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js +5 -0
  28. data/app/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +8 -6
  29. data/app/controllers/camaleon_cms/admin/appearances/themes_controller.rb +8 -5
  30. data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +7 -2
  31. data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +2 -1
  32. data/app/controllers/camaleon_cms/admin/categories_controller.rb +19 -4
  33. data/app/controllers/camaleon_cms/admin/comments_controller.rb +0 -1
  34. data/app/controllers/camaleon_cms/admin/installers_controller.rb +32 -1
  35. data/app/controllers/camaleon_cms/admin/media_controller.rb +66 -14
  36. data/app/controllers/camaleon_cms/admin/plugins_controller.rb +1 -3
  37. data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +10 -4
  38. data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +40 -11
  39. data/app/controllers/camaleon_cms/admin/posts_controller.rb +55 -22
  40. data/app/controllers/camaleon_cms/admin/sessions_controller.rb +237 -44
  41. data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +80 -13
  42. data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +5 -2
  43. data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +26 -3
  44. data/app/controllers/camaleon_cms/admin/settings_controller.rb +5 -3
  45. data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +7 -5
  46. data/app/controllers/camaleon_cms/admin/users_controller.rb +78 -11
  47. data/app/controllers/camaleon_cms/admin_controller.rb +136 -26
  48. data/app/controllers/camaleon_cms/camaleon_controller.rb +37 -92
  49. data/app/controllers/camaleon_cms/frontend_controller.rb +146 -74
  50. data/app/controllers/concerns/camaleon_cms/admin/custom_fields_concern.rb +20 -5
  51. data/app/controllers/concerns/camaleon_cms/frontend_concern.rb +46 -17
  52. data/app/controllers/concerns/camaleon_cms/frontend_visited_state_concern.rb +72 -0
  53. data/app/controllers/concerns/camaleon_cms/hook_lifecycle_concern.rb +104 -0
  54. data/app/controllers/concerns/camaleon_cms/request_context_concern.rb +113 -0
  55. data/app/controllers/concerns/camaleon_cms/runtime_admin_menu_concern.rb +237 -0
  56. data/app/controllers/concerns/camaleon_cms/runtime_captcha_image_concern.rb +13 -0
  57. data/app/controllers/concerns/camaleon_cms/runtime_html_content_concern.rb +143 -0
  58. data/app/controllers/concerns/camaleon_cms/runtime_shortcode_theme_concern.rb +246 -0
  59. data/app/controllers/concerns/camaleon_cms/runtime_state_concern.rb +13 -0
  60. data/app/controllers/concerns/camaleon_cms/runtime_uploader_concern.rb +54 -0
  61. data/app/controllers/concerns/camaleon_cms/session_captcha_runtime_concern.rb +19 -0
  62. data/app/controllers/concerns/camaleon_cms/session_runtime_concern.rb +40 -0
  63. data/app/decorators/camaleon_cms/application_decorator.rb +11 -8
  64. data/app/decorators/camaleon_cms/category_decorator.rb +3 -2
  65. data/app/decorators/camaleon_cms/post_comment_decorator.rb +13 -5
  66. data/app/decorators/camaleon_cms/post_decorator.rb +68 -50
  67. data/app/decorators/camaleon_cms/post_type_decorator.rb +1 -1
  68. data/app/decorators/camaleon_cms/site_decorator.rb +33 -25
  69. data/app/decorators/camaleon_cms/term_taxonomy_decorator.rb +21 -10
  70. data/app/decorators/camaleon_cms/theme_decorator.rb +3 -3
  71. data/app/decorators/camaleon_cms/user_decorator.rb +26 -5
  72. data/app/helpers/camaleon_cms/admin/application_helper.rb +5 -8
  73. data/app/helpers/camaleon_cms/admin/breadcrumb_helper.rb +1 -1
  74. data/app/helpers/camaleon_cms/admin/custom_fields_helper.rb +24 -23
  75. data/app/helpers/camaleon_cms/admin/menus_helper.rb +249 -139
  76. data/app/helpers/camaleon_cms/admin/post_type_helper.rb +34 -17
  77. data/app/helpers/camaleon_cms/camaleon_helper.rb +31 -39
  78. data/app/helpers/camaleon_cms/captcha_helper.rb +73 -53
  79. data/app/helpers/camaleon_cms/comment_helper.rb +19 -7
  80. data/app/helpers/camaleon_cms/content_helper.rb +13 -6
  81. data/app/helpers/camaleon_cms/email_helper.rb +7 -3
  82. data/app/helpers/camaleon_cms/frontend/application_helper.rb +6 -1
  83. data/app/helpers/camaleon_cms/frontend/content_select_helper.rb +34 -20
  84. data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +143 -66
  85. data/app/helpers/camaleon_cms/frontend/seo_helper.rb +39 -28
  86. data/app/helpers/camaleon_cms/frontend/site_helper.rb +32 -12
  87. data/app/helpers/camaleon_cms/hooks_helper.rb +14 -4
  88. data/app/helpers/camaleon_cms/html_helper.rb +58 -37
  89. data/app/helpers/camaleon_cms/plugins_helper.rb +23 -24
  90. data/app/helpers/camaleon_cms/session_helper.rb +188 -44
  91. data/app/helpers/camaleon_cms/short_code_helper.rb +181 -85
  92. data/app/helpers/camaleon_cms/site_helper.rb +34 -13
  93. data/app/helpers/camaleon_cms/theme_helper.rb +35 -19
  94. data/app/helpers/camaleon_cms/uploader_helper.rb +19 -473
  95. data/app/helpers/camaleon_cms/user_roles_helper.rb +5 -4
  96. data/app/mailers/camaleon_cms/html_mailer.rb +4 -4
  97. data/app/models/camaleon_cms/ability.rb +15 -7
  98. data/app/models/camaleon_cms/category.rb +6 -6
  99. data/app/models/camaleon_cms/custom_field.rb +15 -6
  100. data/app/models/camaleon_cms/custom_field_group.rb +39 -22
  101. data/app/models/camaleon_cms/custom_fields_relationship.rb +140 -2
  102. data/app/models/camaleon_cms/media.rb +8 -2
  103. data/app/models/camaleon_cms/meta.rb +2 -2
  104. data/app/models/camaleon_cms/nav_menu.rb +5 -3
  105. data/app/models/camaleon_cms/nav_menu_item.rb +16 -8
  106. data/app/models/camaleon_cms/plugin.rb +3 -4
  107. data/app/models/camaleon_cms/post.rb +137 -27
  108. data/app/models/camaleon_cms/post_comment.rb +10 -6
  109. data/app/models/camaleon_cms/post_default.rb +42 -12
  110. data/app/models/camaleon_cms/post_relationship.rb +6 -4
  111. data/app/models/camaleon_cms/post_tag.rb +4 -5
  112. data/app/models/camaleon_cms/post_type.rb +21 -13
  113. data/app/models/camaleon_cms/site.rb +39 -29
  114. data/app/models/camaleon_cms/term_relationship.rb +10 -7
  115. data/app/models/camaleon_cms/term_taxonomy.rb +58 -4
  116. data/app/models/camaleon_cms/theme.rb +2 -4
  117. data/app/models/camaleon_cms/user.rb +17 -5
  118. data/app/models/camaleon_cms/user_role.rb +81 -6
  119. data/app/models/camaleon_cms/widget/assigned.rb +11 -6
  120. data/app/models/camaleon_cms/widget/main.rb +12 -8
  121. data/app/models/camaleon_cms/widget/sidebar.rb +3 -8
  122. data/app/models/camaleon_record.rb +89 -5
  123. data/app/models/concerns/camaleon_cms/categories_tags_for_posts.rb +36 -42
  124. data/app/models/concerns/camaleon_cms/common_relationships.rb +18 -5
  125. data/app/models/concerns/camaleon_cms/content_shortcode_gate.rb +73 -0
  126. data/app/models/concerns/camaleon_cms/custom_fields_read.rb +111 -54
  127. data/app/models/concerns/camaleon_cms/metas.rb +31 -6
  128. data/app/models/concerns/camaleon_cms/normalize_attrs.rb +2 -8
  129. data/app/models/concerns/camaleon_cms/site_default_settings.rb +120 -16
  130. data/app/models/concerns/camaleon_cms/user_methods.rb +44 -19
  131. data/app/models/current_request.rb +8 -1
  132. data/app/uploaders/camaleon_cms_aws_uploader.rb +31 -10
  133. data/app/uploaders/camaleon_cms_local_uploader.rb +76 -19
  134. data/app/uploaders/camaleon_cms_uploader.rb +23 -10
  135. data/app/validators/camaleon_cms/post_uniq_validator.rb +5 -4
  136. data/app/validators/camaleon_cms/uniq_validator.rb +1 -1
  137. data/app/validators/camaleon_cms/user_url_validator.rb +215 -36
  138. data/app/views/camaleon_cms/admin/categories/index.html.erb +2 -2
  139. data/app/views/camaleon_cms/admin/installers/form.html.erb +5 -0
  140. data/app/views/camaleon_cms/admin/installers/welcome.html.erb +30 -6
  141. data/app/views/camaleon_cms/admin/plugins/_plugins_list.html.erb +2 -2
  142. data/app/views/camaleon_cms/admin/post_tags/index.html.erb +2 -2
  143. data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +1 -1
  144. data/app/views/camaleon_cms/admin/posts/form.html.erb +3 -2
  145. data/app/views/camaleon_cms/admin/posts/index.html.erb +5 -5
  146. data/app/views/camaleon_cms/admin/sessions/back_to_parent.html.erb +39 -0
  147. data/app/views/camaleon_cms/admin/sessions/logout_confirm.html.erb +27 -0
  148. data/app/views/camaleon_cms/admin/settings/_email_settings.html.erb +4 -1
  149. data/app/views/camaleon_cms/admin/settings/custom_fields/_get_items.html.erb +1 -1
  150. data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +19 -4
  151. data/app/views/camaleon_cms/admin/settings/custom_fields/_render_category_simple.html.erb +1 -1
  152. data/app/views/camaleon_cms/admin/settings/custom_fields/form.html.erb +4 -3
  153. data/app/views/camaleon_cms/admin/settings/shortcodes.html.erb +4 -4
  154. data/app/views/camaleon_cms/admin/settings/site.html.erb +1 -1
  155. data/app/views/camaleon_cms/admin/settings/sites/form.html.erb +1 -1
  156. data/app/views/camaleon_cms/admin/user_roles/form.html.erb +24 -3
  157. data/app/views/camaleon_cms/admin/users/form.html.erb +8 -4
  158. data/app/views/camaleon_cms/admin/users/index.html.erb +1 -1
  159. data/app/views/camaleon_cms/default_theme/partials/_render_custom_field.html.erb +8 -2
  160. data/app/views/camaleon_cms/default_theme/sitemap.html.erb +1 -1
  161. data/app/views/camaleon_cms/default_theme/sitemap.xml.builder +1 -1
  162. data/app/views/layouts/camaleon_cms/admin/_header.html.erb +1 -1
  163. data/config/initializers/action_view.rb +42 -5
  164. data/config/initializers/active_record_extension.rb +13 -27
  165. data/config/initializers/assets.rb +52 -23
  166. data/config/initializers/custom_initializers.rb +1 -1
  167. data/config/locales/camaleon_cms/admin/ar.yml +1 -0
  168. data/config/locales/camaleon_cms/admin/de.yml +1 -0
  169. data/config/locales/camaleon_cms/admin/en.yml +36 -0
  170. data/config/locales/camaleon_cms/admin/es.yml +1 -0
  171. data/config/locales/camaleon_cms/admin/fr.yml +1 -0
  172. data/config/locales/camaleon_cms/admin/it.yml +1 -0
  173. data/config/locales/camaleon_cms/admin/nl.yml +1 -0
  174. data/config/locales/camaleon_cms/admin/pt-BR.yml +1 -0
  175. data/config/locales/camaleon_cms/admin/pt.yml +1 -0
  176. data/config/locales/camaleon_cms/admin/ru.yml +1 -0
  177. data/config/locales/camaleon_cms/admin/uk.yml +1 -0
  178. data/config/locales/camaleon_cms/admin/zh-CH.yml +1 -0
  179. data/config/routes/admin.rb +33 -15
  180. data/config/routes/frontend.rb +21 -15
  181. data/lib/camaleon_cms/assets_precompile.rb +86 -0
  182. data/lib/camaleon_cms/captcha_image_generation.rb +65 -0
  183. data/lib/camaleon_cms/content_security.rb +158 -0
  184. data/lib/camaleon_cms/engine.rb +45 -21
  185. data/lib/camaleon_cms/media_security_headers.rb +27 -0
  186. data/lib/camaleon_cms/setup_token.rb +69 -0
  187. data/lib/camaleon_cms/shortcode_registry.rb +102 -0
  188. data/lib/camaleon_cms/svg_content_checker.rb +123 -0
  189. data/lib/camaleon_cms/task_reporter.rb +14 -0
  190. data/lib/camaleon_cms/unsafe_markup.rb +207 -0
  191. data/lib/camaleon_cms/uploader_content_security.rb +248 -0
  192. data/lib/camaleon_cms/uploader_image_processing.rb +166 -0
  193. data/lib/camaleon_cms/uploader_path_security.rb +146 -0
  194. data/lib/camaleon_cms/uploader_pipeline.rb +350 -0
  195. data/lib/camaleon_cms/uploader_support.rb +86 -0
  196. data/lib/camaleon_cms/version.rb +1 -1
  197. data/lib/camaleon_cms.rb +23 -0
  198. data/lib/ext/hash.rb +28 -2
  199. data/lib/ext/string.rb +10 -5
  200. data/lib/ext/translator.rb +10 -2
  201. data/lib/generators/camaleon_cms/gem_plugin_template/app/controllers/plugins/my_plugin/admin_controller.rb +5 -1
  202. data/lib/generators/camaleon_cms/install_generator.rb +7 -4
  203. data/lib/generators/camaleon_cms/install_template/plugin_routes.rb +5 -12
  204. data/lib/generators/camaleon_cms/theme_generator.rb +5 -10
  205. data/lib/generators/camaleon_cms/theme_template/views/layouts/index.html.erb +3 -1
  206. data/lib/plugin_routes.rb +412 -368
  207. data/lib/tasks/camaleon_cms/camaleon_tasks.rake +2 -1
  208. data/lib/tasks/cross_site_field_groups.rake +74 -0
  209. data/lib/tasks/custom_fields_roles.rake +15 -13
  210. data/lib/tasks/orphaned_comments.rake +42 -0
  211. data/lib/tasks/private_upload_acls.rake +31 -0
  212. data/lib/tasks/site_custom_field_groups.rake +36 -0
  213. data/lib/tasks/unsafe_stored_content.rake +42 -0
  214. data/lib/tasks/unsafe_stored_uploads.rake +70 -0
  215. data/lib/tasks/user_field_groups.rake +27 -0
  216. metadata +125 -4
@@ -1,34 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CamaleonCms
2
4
  module Admin
3
5
  module MenusHelper
4
6
  include CamaleonCms::Admin::BreadcrumbHelper
7
+ include ActionView::Helpers::TagHelper
8
+ include ActionView::Helpers::OutputSafetyHelper
5
9
 
6
10
  def admin_menus_add_commons
7
- admin_menu_add_menu('dashboard',
8
- { icon: 'dashboard', title: t('camaleon_cms.admin.sidebar.dashboard'),
9
- url: cama_admin_dashboard_path })
10
- items = []
11
+ admin_menu_add_menu(
12
+ 'dashboard',
13
+ { icon: 'dashboard', title: t('camaleon_cms.admin.sidebar.dashboard'), url: cama_admin_dashboard_path }
14
+ )
11
15
 
12
- current_site.post_types.eager_load(:metas).visible_menu.all.each do |pt|
16
+ items = []
17
+ current_site.post_types.eager_load(:metas).visible_menu.find_each do |pt|
13
18
  pt = pt.decorate
14
19
  items_i = []
15
- if can? :posts,
16
- pt
20
+ if can? :posts, pt
17
21
  items_i << { icon: 'list', title: t('camaleon_cms.admin.post_type.all').to_s,
18
22
  url: cama_admin_post_type_posts_path(pt.id) }
19
23
  end
20
- if can? :create_post,
21
- pt
24
+ if can? :create_post, pt
22
25
  items_i << { icon: 'plus', title: t('camaleon_cms.admin.post_type.add_new', type_title: pt.the_title).to_s,
23
26
  url: new_cama_admin_post_type_post_path(pt.id) }
24
27
  end
25
- if pt.manage_categories? && (can? :categories,
26
- pt)
28
+ if pt.manage_categories? && (can? :categories, pt)
27
29
  items_i << { icon: 'folder-open', title: t('camaleon_cms.admin.post_type.categories'),
28
30
  url: cama_admin_post_type_categories_path(pt.id) }
29
31
  end
30
- if pt.manage_tags? && (can? :post_tags,
31
- pt)
32
+ if pt.manage_tags? && (can? :post_tags, pt)
32
33
  items_i << { icon: 'tags', title: t('camaleon_cms.admin.post_type.tags'),
33
34
  url: cama_admin_post_type_post_tags_path(pt.id) }
34
35
  end
@@ -36,58 +37,93 @@ module CamaleonCms
36
37
  items << { icon: pt.get_option('icon', 'copy'), title: pt.the_title, url: '', items: items_i }
37
38
  end
38
39
  end
40
+
39
41
  if items.present?
40
- admin_menu_add_menu('content',
41
- { icon: 'database', title: t('camaleon_cms.admin.sidebar.contents'), url: '', items: items,
42
- datas: "data-intro='#{t('camaleon_cms.admin.intro.content')}' data-position='right' data-wait='600'" })
42
+ admin_menu_add_menu(
43
+ 'content',
44
+ {
45
+ icon: 'database', title: t('camaleon_cms.admin.sidebar.contents'), url: '', items: items,
46
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.content')}' data-position='right' data-wait='600'"
47
+ }
48
+ )
43
49
  end
44
50
  # end
45
51
 
46
- if can? :manage,
47
- :media
48
- admin_menu_add_menu('media',
49
- { icon: 'picture-o', title: t('camaleon_cms.admin.sidebar.media'), url: cama_admin_media_path,
50
- datas: "data-intro='#{t('camaleon_cms.admin.intro.media')}' data-position='right'" })
52
+ if can? :manage, :media
53
+ admin_menu_add_menu(
54
+ 'media',
55
+ {
56
+ icon: 'picture-o', title: t('camaleon_cms.admin.sidebar.media'), url: cama_admin_media_path,
57
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.media')}' data-position='right'"
58
+ }
59
+ )
51
60
  end
52
- if can? :manage,
53
- :comments
54
- admin_menu_add_menu('comments',
55
- { icon: 'comments', title: t('camaleon_cms.admin.sidebar.comments'), url: cama_admin_comments_path,
56
- datas: "data-intro='#{t('camaleon_cms.admin.intro.comments')}' data-position='right'" })
61
+ if can? :manage, :comments
62
+ admin_menu_add_menu(
63
+ 'comments',
64
+ {
65
+ icon: 'comments', title: t('camaleon_cms.admin.sidebar.comments'), url: cama_admin_comments_path,
66
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.comments')}' data-position='right'"
67
+ }
68
+ )
57
69
  end
58
70
 
59
71
  items = []
60
- if can? :manage,
61
- :themes
62
- items << { icon: 'desktop', title: t('camaleon_cms.admin.sidebar.themes'), url: cama_admin_appearances_themes_path,
63
- datas: "data-intro='#{t('camaleon_cms.admin.intro.themes')}' data-position='right'" }
72
+ if can? :manage, :themes
73
+ items << {
74
+ icon: 'desktop', title: t('camaleon_cms.admin.sidebar.themes'), url: cama_admin_appearances_themes_path,
75
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.themes')}' data-position='right'"
76
+ }
64
77
  end
65
- if can? :manage,
66
- :widgets
67
- items << { icon: 'archive', title: t('camaleon_cms.admin.sidebar.widgets'),
68
- url: cama_admin_appearances_widgets_main_index_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.widgets')}' data-position='right'" }
78
+ if can? :manage, :widgets
79
+ items << {
80
+ icon: 'archive', title: t('camaleon_cms.admin.sidebar.widgets'),
81
+ url: cama_admin_appearances_widgets_main_index_path,
82
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.widgets')}' data-position='right'"
83
+ }
69
84
  end
70
- if can? :manage,
71
- :nav_menu
72
- items << { icon: 'list', title: t('camaleon_cms.admin.sidebar.menus'), url: cama_admin_appearances_nav_menus_path,
73
- datas: "data-intro='#{t('camaleon_cms.admin.intro.menus', image: view_context.asset_path('camaleon_cms/admin/intro/menus.png'))}' data-position='right'" }
85
+ if can? :manage, :nav_menu
86
+ intro_menus_data =
87
+ t('camaleon_cms.admin.intro.menus', image: view_context.asset_path('camaleon_cms/admin/intro/menus.png'))
88
+ items << {
89
+ icon: 'list', title: t('camaleon_cms.admin.sidebar.menus'), url: cama_admin_appearances_nav_menus_path,
90
+ datas: "data-intro='#{intro_menus_data}' data-position='right'"
91
+ }
74
92
  end
75
- if can? :manage,
76
- :shortcodes
77
- items << { icon: 'code', title: t('camaleon_cms.admin.sidebar.shortcodes', default: 'Shortcodes'),
78
- url: cama_admin_settings_shortcodes_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.shortcodes')}' data-position='right'" }
93
+ if can? :manage, :shortcodes
94
+ items << {
95
+ icon: 'code', title: t('camaleon_cms.admin.sidebar.shortcodes', default: 'Shortcodes'),
96
+ url: cama_admin_settings_shortcodes_path,
97
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.shortcodes')}' data-position='right'"
98
+ }
79
99
  end
80
100
  if items.present?
81
- admin_menu_add_menu('appearance',
82
- { icon: 'paint-brush', title: t('camaleon_cms.admin.sidebar.appearance'), url: '', items: items,
83
- datas: "data-intro='#{t('camaleon_cms.admin.intro.appearance')}' data-position='right' data-wait='500'" })
101
+ admin_menu_add_menu(
102
+ 'appearance',
103
+ {
104
+ icon: 'paint-brush', title: t('camaleon_cms.admin.sidebar.appearance'), url: '', items: items,
105
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.appearance')}' data-position='right' data-wait='500'"
106
+ }
107
+ )
84
108
  end
85
109
 
86
- if can? :manage,
87
- :plugins
88
- admin_menu_add_menu('plugins', { icon: 'plug', title: "#{t('camaleon_cms.admin.sidebar.plugins')} <small class='label label-primary'>#{PluginRoutes.all_plugins.clone.delete_if do |plugin|
89
- plugin[:domain].present? && !plugin[:domain].split(',').include?(current_site.the_slug)
90
- end.size}</small>", url: cama_admin_plugins_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.plugins')}' data-position='right'" })
110
+ if can? :manage, :plugins
111
+ plugin_count = PluginRoutes.all_plugins.count do |plugin|
112
+ !(plugin[:domain].present? && !plugin[:domain].split(',').include?(current_site.the_slug))
113
+ end
114
+ admin_menu_add_menu(
115
+ 'plugins',
116
+ {
117
+ icon: 'plug',
118
+ title: safe_join([
119
+ t('camaleon_cms.admin.sidebar.plugins'),
120
+ ' ',
121
+ content_tag(:small, plugin_count, class: 'label label-primary')
122
+ ]),
123
+ url: cama_admin_plugins_path,
124
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.plugins')}' data-position='right'"
125
+ }
126
+ )
91
127
  end
92
128
 
93
129
  if can? :manage, :users
@@ -95,117 +131,154 @@ module CamaleonCms
95
131
  items << { icon: 'list', title: t('camaleon_cms.admin.users.all_users'), url: cama_admin_users_path }
96
132
  items << { icon: 'plus', title: t('camaleon_cms.admin.users.add_user'), url: new_cama_admin_user_path }
97
133
  items << { icon: 'group', title: t('camaleon_cms.admin.users.user_roles'), url: cama_admin_user_roles_path }
98
- admin_menu_add_menu('users',
99
- { icon: 'users', title: t('camaleon_cms.admin.sidebar.users'), url: '', items: items,
100
- datas: "data-intro='#{t('camaleon_cms.admin.intro.users')}' data-position='right' data-wait='500'" })
134
+ admin_menu_add_menu(
135
+ 'users',
136
+ {
137
+ icon: 'users', title: t('camaleon_cms.admin.sidebar.users'), url: '', items: items,
138
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.users')}' data-position='right' data-wait='500'"
139
+ }
140
+ )
101
141
  end
102
142
 
103
143
  items = []
104
144
  if can? :manage, :settings
105
- items << { icon: 'desktop', title: t('camaleon_cms.admin.sidebar.general_site'),
106
- url: cama_admin_settings_site_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.gral_site')}' data-position='right'" }
145
+ items << {
146
+ icon: 'desktop', title: t('camaleon_cms.admin.sidebar.general_site'),
147
+ url: cama_admin_settings_site_path,
148
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.gral_site')}' data-position='right'"
149
+ }
107
150
  if current_site.manage_sites?
108
- items << { icon: 'cog', title: t('camaleon_cms.admin.sidebar.sites'), url: cama_admin_settings_sites_path,
109
- datas: "data-intro='#{t('camaleon_cms.admin.intro.sites')}' data-position='right'" }
151
+ items << {
152
+ icon: 'cog', title: t('camaleon_cms.admin.sidebar.sites'),
153
+ url: cama_admin_settings_sites_path,
154
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.sites')}' data-position='right'"
155
+ }
110
156
  end
111
- items << { icon: 'files-o', title: t('camaleon_cms.admin.sidebar.content_groups'),
112
- url: cama_admin_settings_post_types_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.post_type')}' data-position='right'" }
113
- items << { icon: 'cog', title: t('camaleon_cms.admin.sidebar.custom_fields'),
114
- url: cama_admin_settings_custom_fields_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.custom_fields')}' data-position='right'" }
115
- items << { icon: 'language', title: t('camaleon_cms.admin.sidebar.languages'),
116
- url: cama_admin_settings_languages_path, datas: "data-intro='#{t('camaleon_cms.admin.intro.languages')}' data-position='right'" }
157
+ items << {
158
+ icon: 'files-o', title: t('camaleon_cms.admin.sidebar.content_groups'),
159
+ url: cama_admin_settings_post_types_path,
160
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.post_type')}' data-position='right'"
161
+ }
162
+ items << {
163
+ icon: 'cog', title: t('camaleon_cms.admin.sidebar.custom_fields'),
164
+ url: cama_admin_settings_custom_fields_path,
165
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.custom_fields')}' data-position='right'"
166
+ }
167
+ items << {
168
+ icon: 'language', title: t('camaleon_cms.admin.sidebar.languages'),
169
+ url: cama_admin_settings_languages_path,
170
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.languages')}' data-position='right'"
171
+ }
117
172
  end
118
173
 
119
- if can? :manage,
120
- :theme_settings
121
- items << { icon: 'windows', title: t('camaleon_cms.admin.settings.theme_setting', default: 'Theme Settings'),
122
- url: cama_admin_settings_theme_path }
174
+ if can? :manage, :theme_settings
175
+ items << {
176
+ icon: 'windows', title: t('camaleon_cms.admin.settings.theme_setting', default: 'Theme Settings'),
177
+ url: cama_admin_settings_theme_path
178
+ }
123
179
  end
124
- return unless items.present?
180
+ return if items.blank?
125
181
 
126
- admin_menu_add_menu('settings',
127
- { icon: 'cogs', title: t('camaleon_cms.admin.sidebar.settings'), url: '', items: items,
128
- datas: "data-intro='#{t('camaleon_cms.admin.intro.settings')}' data-position='right' data-wait='500'" })
182
+ admin_menu_add_menu(
183
+ 'settings',
184
+ {
185
+ icon: 'cogs', title: t('camaleon_cms.admin.sidebar.settings'), url: '', items: items,
186
+ datas: "data-intro='#{t('camaleon_cms.admin.intro.settings')}' data-position='right' data-wait='500'"
187
+ }
188
+ )
129
189
  end
130
190
 
131
- # add menu item to admin menu at the the end
132
- # key: key for menu
133
- # menu: is hash like this: {icon: "dashboard", title: "My title", url: my_path, items: [sub menus]}
191
+ # add a menu item to the menu at the end
192
+ # key: key for the menu
193
+ # menu: is hash like this: { icon: "dashboard", title: "My title", url: my_path, items: [sub menus] }
134
194
  # - icon: font-awesome icon (it is already included "fa fa-")
135
195
  # - title: title for the menu
136
196
  # - url: url for the menu
137
- # - items: is an recursive array of the menus without a key
138
- # - datas: html data text for this menu item
197
+ # - items: is a recursive array of the menus without a key
198
+ # - datas: HTML data text for this menu item
139
199
  def admin_menu_add_menu(key, menu)
140
- @_admin_menus[key] = menu
200
+ CurrentRequest.admin_menu_items ||= {}
201
+ CurrentRequest.admin_menu_items[key] = menu
141
202
  end
142
203
 
143
- # append sub menu to menu with key = key
204
+ # append sub menu to menu with a key = key
144
205
  # menu: is hash like this: {icon: "dashboard", title: "My title", url: my_path, items: [sub menus]}
145
206
  def admin_menu_append_menu_item(key, menu)
146
- return unless @_admin_menus[key].present?
207
+ CurrentRequest.admin_menu_items ||= {}
208
+ return if CurrentRequest.admin_menu_items[key].blank?
147
209
 
148
- @_admin_menus[key][:items] = [] unless @_admin_menus[key].key?(:items)
149
- @_admin_menus[key][:items] << menu
210
+ CurrentRequest.admin_menu_items[key][:items] = [] unless CurrentRequest.admin_menu_items[key].key?(:items)
211
+ CurrentRequest.admin_menu_items[key][:items] << menu
150
212
  end
151
213
 
152
- # prepend sub menu to menu with key = key
153
- # menu: is hash like this: {icon: "dashboard", title: "My title", url: my_path, items: [sub menus]}
214
+ # prepend submenu to menu with key = key
215
+ # menu: is hash like this: { icon: "dashboard", title: "My title", url: my_path, items: [sub menus] }
154
216
  def admin_menu_prepend_menu_item(key, menu)
155
- return unless @_admin_menus[key].present?
217
+ CurrentRequest.admin_menu_items ||= {}
218
+ return if CurrentRequest.admin_menu_items[key].blank?
156
219
 
157
- @_admin_menus[key][:items] = [] unless @_admin_menus[key].key?(:items)
158
- @_admin_menus[key][:items] = [menu] + @_admin_menus[key][:items]
220
+ CurrentRequest.admin_menu_items[key][:items] = [] unless CurrentRequest.admin_menu_items[key].key?(:items)
221
+ CurrentRequest.admin_menu_items[key][:items] = [menu] + CurrentRequest.admin_menu_items[key][:items]
159
222
  end
160
223
 
161
- # add menu before menu with key = key_target
224
+ # add the menu before the menu with key = key_target
162
225
  # key_menu: key for menu
163
- # menu: is hash like this: {icon: "dashboard", title: "My title", url: my_path, items: [sub menus]}
226
+ # menu: is hash like this: { icon: "dashboard", title: "My title", url: my_path, items: [sub menus] }
164
227
  def admin_menu_insert_menu_before(key_target, key_menu, menu)
165
- res = {}
166
- @_admin_menus.each do |key, val|
167
- res[key_menu] = menu if key == key_target
168
- res[key] = val
228
+ CurrentRequest.admin_menu_items ||= {}
229
+ res = CurrentRequest.admin_menu_items.each_with_object({}) do |(key, val), hsh|
230
+ hsh[key_menu] = menu if key == key_target
231
+ hsh[key] = val
169
232
  end
170
- @_admin_menus = res
233
+ CurrentRequest.admin_menu_items.replace(res) # mutate in place so @_admin_menus stays a live alias (M19)
171
234
  end
172
235
 
173
236
  # add menu after menu with key = key_target
174
237
  # key_menu: key for menu
175
238
  # menu: is hash like this: {icon: "dashboard", title: "My title", url: my_path, items: [sub menus]}
176
239
  def admin_menu_insert_menu_after(key_target, key_menu, menu)
177
- res = {}
178
- @_admin_menus.each do |key, val|
179
- res[key] = val
180
- res[key_menu] = menu if key == key_target
240
+ CurrentRequest.admin_menu_items ||= {}
241
+ res = CurrentRequest.admin_menu_items.each_with_object({}) do |(key, val), hsh|
242
+ hsh[key] = val
243
+ hsh[key_menu] = menu if key == key_target
181
244
  end
182
- @_admin_menus = res
245
+ CurrentRequest.admin_menu_items.replace(res) # mutate in place so @_admin_menus stays a live alias (M19)
183
246
  end
184
247
 
185
248
  # draw admin menu as html
186
249
  def admin_menu_draw
187
- res = []
188
- @_tmp_menu_parents = []
189
- menus = _get_url_current
190
- menus.each do |menu|
191
- res << "<li data-key='#{menu[:key]}' class='#{if menu.key?(:items)
192
- 'treeview'
193
- end} #{if is_active_menu(menu[:key])
194
- 'active'
195
- end}' #{menu[:datas]}>
196
- <a href='#{menu[:url]}'><i class='fa fa-#{menu[:icon]}'></i> <span class=''>#{menu[:title]}</span> #{if menu.key?(:items)
197
- '<i class="fa fa-angle-left pull-right"></i>'
198
- end}</a>
199
- #{_admin_menu_draw(menu[:items]) if menu.key?(:items)}
200
- </li>"
201
- end
202
- res.join
250
+ CurrentRequest.admin_menu_items ||= {}
251
+ menu_parents = []
252
+ menus = _get_url_current(CurrentRequest.admin_menu_items, menu_parents)
253
+ safe_join(menus.map do |menu|
254
+ css_class = +''
255
+ css_class << 'treeview ' if menu.key?(:items)
256
+ css_class << 'active' if is_active_menu(menu[:key], menu_parents)
257
+ css_class.strip!
258
+ data_attrs = parse_datas(menu[:datas])
259
+ content_tag(
260
+ :li, ''.html_safe,
261
+ class: css_class.presence, data: { key: menu[:key] }.merge!(data_attrs.presence || {})
262
+ ) do
263
+ safe_join([
264
+ content_tag(:a, href: menu[:url]) do
265
+ safe_join([
266
+ content_tag(:i, nil, class: "fa fa-#{menu[:icon]}"),
267
+ ' ',
268
+ content_tag(:span, cama_admin_menu_title(menu[:title])),
269
+ (content_tag(:i, nil, class: 'fa fa-angle-left pull-right') if menu.key?(:items))
270
+ ].compact)
271
+ end,
272
+ (_admin_menu_draw(menu[:items], menu_parents) if menu.key?(:items))
273
+ ].compact)
274
+ end
275
+ end)
203
276
  end
204
277
 
205
278
  private
206
279
 
207
- def _get_url_current
208
- menus = @_admin_menus.map do |key, menu|
280
+ def _get_url_current(menus, menu_parents)
281
+ menus = menus.map do |key, menu|
209
282
  menu[:key] = key
210
283
  menu
211
284
  end
@@ -213,7 +286,7 @@ module CamaleonCms
213
286
  current_path_array = current_path.split('/')
214
287
  a_size = current_path_array.size
215
288
  (0..a_size).each do |i|
216
- resp = _search_in_menus(menus, current_path_array[0..a_size - i].join('/'))
289
+ resp = _search_in_menus(menus, current_path_array[0..a_size - i].join('/'), 0, menu_parents)
217
290
  bool = resp[:bool]
218
291
  menus = resp[:menus]
219
292
  break if bool
@@ -221,11 +294,11 @@ module CamaleonCms
221
294
  menus
222
295
  end
223
296
 
224
- def is_active_menu(key)
225
- @_tmp_menu_parents.map { |item| item[:key] == key }.include?(true)
297
+ def is_active_menu(key, menu_parents)
298
+ menu_parents.map { |item| item[:key] == key }.include?(true)
226
299
  end
227
300
 
228
- def _search_in_menus(menus, _url, parent_index = 0)
301
+ def _search_in_menus(menus, _url, parent_index = 0, menu_parents = [])
229
302
  bool = false
230
303
  menus.each_with_index do |menu, _index_menu|
231
304
  menu[:key] = "#{parent_index}__#{rand(999...99_999)}" if menu[:key].nil?
@@ -235,38 +308,75 @@ module CamaleonCms
235
308
  bool = url_path.to_s == _url.to_s && url_path.present?
236
309
  # params compare
237
310
  if url_query.present?
238
- bool &&= Rack::Utils.parse_nested_query(url_query.to_s) == Rack::Utils.parse_nested_query(URI(site_current_url).query.to_s)
311
+ menu_params = Rack::Utils.parse_nested_query(url_query.to_s)
312
+ current_params = Rack::Utils.parse_nested_query(URI(site_current_url).query.to_s)
313
+ bool &&= menu_params == current_params
239
314
  end
240
315
  if menu.key?(:items)
241
- resp = _search_in_menus(menu[:items], _url, parent_index + 1)
316
+ resp = _search_in_menus(menu[:items], _url, parent_index + 1, menu_parents)
242
317
  bool ||= resp[:bool]
243
318
  menu[:items] = resp[:menus]
244
319
  end
245
320
  if bool
246
- @_tmp_menu_parents[parent_index] = { url: menu[:url], title: menu[:title], key: menu[:key] }
321
+ menu_parents[parent_index] = { url: menu[:url], title: menu[:title], key: menu[:key] }
247
322
  break
248
323
  end
249
324
  end
250
325
  { menus: menus, bool: bool }
251
326
  end
252
327
 
253
- def _admin_menu_draw(items)
254
- res = []
255
- res << "<ul class='treeview-menu'>"
256
- items.each_with_index do |item, index|
257
- res << "<li class='#{if item.key?(:items)
258
- 'xn-openable'
259
- end} item_#{index + 1} #{if is_active_menu(item[:key])
260
- 'active'
261
- end}' #{item[:datas]}>
262
- <a href='#{item[:url]}'><i class='fa fa-#{item[:icon]}'></i> #{item[:title]} #{if item.key?(:items)
263
- '<i class="fa fa-angle-left pull-right"></i>'
264
- end}</a>
265
- #{_admin_menu_draw(item[:items]) if item.key?(:items)}
266
- </li>"
328
+ def _admin_menu_draw(items, menu_parents)
329
+ return ''.html_safe if items.blank?
330
+
331
+ content_tag(:ul, class: 'treeview-menu') do
332
+ safe_join(items.each_with_index.map do |item, index|
333
+ css_class = +"item_#{index + 1} "
334
+ css_class << 'xn-openable ' if item.key?(:items)
335
+ css_class << 'active ' if is_active_menu(item[:key], menu_parents)
336
+ css_class.strip!
337
+ data_attrs = parse_datas(item[:datas])
338
+ content_tag(
339
+ :li, ''.html_safe,
340
+ class: css_class.presence,
341
+ data: { key: item[:key] }.merge!(data_attrs.presence || {})
342
+ ) do
343
+ safe_join([
344
+ content_tag(:a, href: item[:url]) do
345
+ safe_join([
346
+ content_tag(:i, nil, class: "fa fa-#{item[:icon]}"),
347
+ ' ',
348
+ cama_admin_menu_title(item[:title]),
349
+ (content_tag(:i, nil, class: 'fa fa-angle-left pull-right') if item.key?(:items))
350
+ ].compact)
351
+ end,
352
+ (item.key?(:items) ? _admin_menu_draw(item[:items], menu_parents) : nil)
353
+ ].compact)
354
+ end
355
+ end)
356
+ end
357
+ end
358
+
359
+ # Menu titles may carry inline formatting (e.g. camaleon-ecommerce's count badge). Core builds its
360
+ # titles as SafeBuffers via safe_join/content_tag and those pass through untouched; a plain-String
361
+ # title from a plugin is sanitized to a safe inline subset — the badge renders, scripts and event
362
+ # handlers are stripped — rather than escaped whole. Regression M22.
363
+ def cama_admin_menu_title(title)
364
+ return title if title.is_a?(ActiveSupport::SafeBuffer)
365
+
366
+ sanitize(title.to_s, tags: %w[span small i b strong em], attributes: %w[class])
367
+ end
368
+
369
+ def parse_datas(datas_string)
370
+ return {} if datas_string.blank?
371
+
372
+ result = {}
373
+ # Match single- or double-quoted values so a value may contain the other quote character. The
374
+ # old /['"]([^'"]*)['"]/ stopped at the first quote of either kind, truncating data-intro
375
+ # strings that carry HTML (e.g. the Menus tooltip's <img ... style="...">). Regression M22.
376
+ datas_string.scan(/data-([\w-]+)=(?:'([^']*)'|"([^"]*)")/).each do |key, single, double|
377
+ result[key.to_sym] = single || double
267
378
  end
268
- res << '</ul>'
269
- res.join
379
+ result
270
380
  end
271
381
  end
272
382
  end
@@ -15,33 +15,41 @@ module CamaleonCms
15
15
  end
16
16
 
17
17
  # taxonomies -> (categories || post_tags)
18
- def post_type_list_taxonomy(taxonomies, color = 'primary')
19
- taxonomies.decorate.map do |f|
20
- link_to(cama_admin_post_type_taxonomy_posts_path(@post_type.id, f.taxonomy, f.id), class: 'cama_ajax_request') do
18
+ def post_type_list_taxonomy(taxonomies, color = 'primary', post_type = nil)
19
+ # Legacy 2-arg call sites (e.g. overridden admin posts-index views, camaleon-ecommerce) omit
20
+ # post_type and expect the controller's @post_type. Restored from #1178; see regression M23.
21
+ post_type ||= controller.instance_variable_get(:@post_type) if respond_to?(:controller)
22
+ return safe_join([]) if post_type.blank?
23
+
24
+ safe_join(taxonomies.decorate.map do |f|
25
+ link_to(
26
+ cama_admin_post_type_taxonomy_posts_path(post_type.id, f.taxonomy, f.id), class: 'cama_ajax_request'
27
+ ) do
21
28
  content_tag(:span, f.the_title, class: "label label-#{color} label-form")
22
29
  end
23
- end.join(' ').html_safe
30
+ end, ' ')
24
31
  end
25
32
 
26
33
  # sort array of posts to build post's tree
27
34
  # skip_non_parent_posts: don't include post's where root post doesn't exist
28
35
  # internal control for recursive items
29
- def cama_hierarchy_post_list(posts_list, parent_id = nil, skip_non_parent_posts = false)
36
+ def cama_hierarchy_post_list(posts_list, parent_id = nil, skip_non_parent_posts = false,
37
+ no_parent_accumulator = nil)
38
+ no_parent_accumulator ||= posts_list.clone
30
39
  res = []
31
- @_cama_hierarchy_post_list_no_parent ||= posts_list.clone
32
40
  posts_list.each do |element|
33
41
  next unless element.post_parent.to_s == parent_id.to_s
34
42
 
35
43
  res << element
36
- @_cama_hierarchy_post_list_no_parent.delete_item(element)
37
- res += cama_hierarchy_post_list(posts_list, element.id)
44
+ no_parent_accumulator.delete_item(element)
45
+ res += cama_hierarchy_post_list(posts_list, element.id, false, no_parent_accumulator)
38
46
  end
39
47
 
40
- if !parent_id.present? && !skip_non_parent_posts
41
- @_cama_hierarchy_post_list_no_parent.each do |element|
48
+ if parent_id.blank? && !skip_non_parent_posts
49
+ no_parent_accumulator.each do |element|
42
50
  element.show_title_with_parent = true
43
51
  res << element
44
- res += cama_hierarchy_post_list(posts_list, element.id)
52
+ res += cama_hierarchy_post_list(posts_list, element.id, false, no_parent_accumulator)
45
53
  end
46
54
  end
47
55
  res
@@ -52,27 +60,36 @@ module CamaleonCms
52
60
  def post_type_taxonomy_html_(categories, taxonomy = 'categories', name = 'categories', type = 'checkbox',
53
61
  values = [], class_cat = '', required = false)
54
62
  if categories.count < 1
55
- return t('camaleon_cms.admin.post_type.message.no_created_html',
56
- taxonomy: taxonomy == 'categories' ? t('camaleon_cms.admin.table.categories') : t('camaleon_cms.admin.table.tags'))
63
+ # Interpolate the translated taxonomy label, not the raw 'categories'/'post_tags' slug
64
+ # (the label was computed here and discarded before).
65
+ taxonomy_label = if taxonomy == 'categories'
66
+ t('camaleon_cms.admin.table.categories')
67
+ else
68
+ t('camaleon_cms.admin.table.tags')
69
+ end
70
+ return t('camaleon_cms.admin.post_type.message.no_created_html', taxonomy: taxonomy_label)
57
71
  end
58
72
 
59
73
  content_tag(:ul, class: class_cat) do
60
- categories.decorate.map do |f|
74
+ items = categories.decorate.map do |f|
61
75
  content_tag(:li) do
62
76
  is_checked = Array(values).map(&:to_s).include?(f.id.to_s)
63
- input_options = { class: (required ? 'required' : ''), data: { error_place: "#validation_error_list_#{name}" } }
77
+ input_options = {
78
+ class: (required ? 'required' : ''), data: { error_place: "#validation_error_list_#{name}" }
79
+ }
64
80
  input_tag = if type == 'radio'
65
81
  radio_button_tag("#{name}[]", f.id, is_checked, input_options)
66
82
  else
67
83
  check_box_tag("#{name}[]", f.id, is_checked, input_options)
68
84
  end
69
85
  res = content_tag(:label, class: 'class_slug', data: { post_link_edit: f.the_edit_url }) do
70
- "#{input_tag} #{f.the_title} ".html_safe
86
+ safe_join([input_tag, ' ', f.the_title.to_s, ' '])
71
87
  end
72
88
  res << post_type_html_inputs(f, 'children', name, type, values, 'children') if f.children.present?
73
89
  res
74
90
  end
75
- end.join.html_safe
91
+ end
92
+ safe_join(items)
76
93
  end + content_tag(:div, '', id: "validation_error_list_#{name}")
77
94
  end
78
95
  end