comfy_middle_seat 3.2.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 (436) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +4 -0
  3. data/.gitattributes +3 -0
  4. data/.github/dependabot.yml +7 -0
  5. data/.github/issue_template.md +19 -0
  6. data/.github/pull_request_template.md +6 -0
  7. data/.github/workflows/claude-code-review.yml +46 -0
  8. data/.github/workflows/claude.yml +148 -0
  9. data/.github/workflows/coveralls.yml +53 -0
  10. data/.github/workflows/rubyonrails.yml +94 -0
  11. data/.gitignore +25 -0
  12. data/.rubocop.yml +82 -0
  13. data/.travis.yml +44 -0
  14. data/CHANGELOG.md +147 -0
  15. data/CONTRIBUTING.md +42 -0
  16. data/Gemfile +44 -0
  17. data/LICENSE +20 -0
  18. data/README.md +158 -0
  19. data/Rakefile +206 -0
  20. data/app/assets/builds/.keep +0 -0
  21. data/app/assets/config/manifest.js +1 -0
  22. data/app/assets/fonts/comfy/admin/cms/lib/redactor-font.eot +0 -0
  23. data/app/assets/javascripts/comfy/admin/cms/application.js +27 -0
  24. data/app/assets/javascripts/comfy/admin/cms/base.js +48 -0
  25. data/app/assets/javascripts/comfy/admin/cms/categories.js +17 -0
  26. data/app/assets/javascripts/comfy/admin/cms/codemirror.js +43 -0
  27. data/app/assets/javascripts/comfy/admin/cms/custom.js +1 -0
  28. data/app/assets/javascripts/comfy/admin/cms/diff.js +12 -0
  29. data/app/assets/javascripts/comfy/admin/cms/file_link.js +96 -0
  30. data/app/assets/javascripts/comfy/admin/cms/file_upload.js +229 -0
  31. data/app/assets/javascripts/comfy/admin/cms/files_modal.js +97 -0
  32. data/app/assets/javascripts/comfy/admin/cms/page_fragments.js +22 -0
  33. data/app/assets/javascripts/comfy/admin/cms/slugify.js +34 -0
  34. data/app/assets/javascripts/comfy/admin/cms/sortable_list.js +49 -0
  35. data/app/assets/javascripts/comfy/admin/cms/timepicker.js +38 -0
  36. data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +91 -0
  37. data/app/assets/javascripts/comfy/vendor/diff/diff_match_patch.min.js +49 -0
  38. data/app/assets/javascripts/comfy/vendor/diff/pretty_text_diff.js +88 -0
  39. data/app/assets/javascripts/comfy/vendor/flatpickr.min.js +2 -0
  40. data/app/assets/javascripts/comfy/vendor/fontawesome.js +5 -0
  41. data/app/assets/javascripts/comfy/vendor/redactor/definedlinks.js +50 -0
  42. data/app/assets/javascripts/comfy/vendor/redactor/filemanager.js +79 -0
  43. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ar.js +76 -0
  44. data/app/assets/javascripts/comfy/vendor/redactor/i18n/az.js +75 -0
  45. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ba.js +79 -0
  46. data/app/assets/javascripts/comfy/vendor/redactor/i18n/bg.js +77 -0
  47. data/app/assets/javascripts/comfy/vendor/redactor/i18n/by.js +77 -0
  48. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ca.js +75 -0
  49. data/app/assets/javascripts/comfy/vendor/redactor/i18n/cs.js +87 -0
  50. data/app/assets/javascripts/comfy/vendor/redactor/i18n/da.js +75 -0
  51. data/app/assets/javascripts/comfy/vendor/redactor/i18n/de.js +80 -0
  52. data/app/assets/javascripts/comfy/vendor/redactor/i18n/el.js +76 -0
  53. data/app/assets/javascripts/comfy/vendor/redactor/i18n/en.js +75 -0
  54. data/app/assets/javascripts/comfy/vendor/redactor/i18n/eo.js +76 -0
  55. data/app/assets/javascripts/comfy/vendor/redactor/i18n/es.js +75 -0
  56. data/app/assets/javascripts/comfy/vendor/redactor/i18n/es_AR.js +76 -0
  57. data/app/assets/javascripts/comfy/vendor/redactor/i18n/fa.js +76 -0
  58. data/app/assets/javascripts/comfy/vendor/redactor/i18n/fi.js +75 -0
  59. data/app/assets/javascripts/comfy/vendor/redactor/i18n/fr.js +75 -0
  60. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ge.js +75 -0
  61. data/app/assets/javascripts/comfy/vendor/redactor/i18n/gr.js +75 -0
  62. data/app/assets/javascripts/comfy/vendor/redactor/i18n/he.js +75 -0
  63. data/app/assets/javascripts/comfy/vendor/redactor/i18n/hr.js +78 -0
  64. data/app/assets/javascripts/comfy/vendor/redactor/i18n/hu.js +77 -0
  65. data/app/assets/javascripts/comfy/vendor/redactor/i18n/id.js +76 -0
  66. data/app/assets/javascripts/comfy/vendor/redactor/i18n/it.js +78 -0
  67. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ja.js +76 -0
  68. data/app/assets/javascripts/comfy/vendor/redactor/i18n/kn.js +75 -0
  69. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ko.js +76 -0
  70. data/app/assets/javascripts/comfy/vendor/redactor/i18n/lt.js +75 -0
  71. data/app/assets/javascripts/comfy/vendor/redactor/i18n/lv.js +75 -0
  72. data/app/assets/javascripts/comfy/vendor/redactor/i18n/mk.js +75 -0
  73. data/app/assets/javascripts/comfy/vendor/redactor/i18n/nb.js +77 -0
  74. data/app/assets/javascripts/comfy/vendor/redactor/i18n/nl.js +80 -0
  75. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pl.js +78 -0
  76. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pt-BR.js +75 -0
  77. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pt.js +75 -0
  78. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ro.js +76 -0
  79. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ru.js +76 -0
  80. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sk.js +76 -0
  81. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sl.js +79 -0
  82. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sq.js +79 -0
  83. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sr-CIR.js +79 -0
  84. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sr-LAT.js +79 -0
  85. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sv.js +74 -0
  86. data/app/assets/javascripts/comfy/vendor/redactor/i18n/th.js +74 -0
  87. data/app/assets/javascripts/comfy/vendor/redactor/i18n/tr.js +75 -0
  88. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ua.js +77 -0
  89. data/app/assets/javascripts/comfy/vendor/redactor/i18n/uk.js +77 -0
  90. data/app/assets/javascripts/comfy/vendor/redactor/i18n/vi.js +74 -0
  91. data/app/assets/javascripts/comfy/vendor/redactor/i18n/zh-CN.js +75 -0
  92. data/app/assets/javascripts/comfy/vendor/redactor/i18n/zh-TW.js +75 -0
  93. data/app/assets/javascripts/comfy/vendor/redactor/imagemanager.js +68 -0
  94. data/app/assets/javascripts/comfy/vendor/redactor/table.js +348 -0
  95. data/app/assets/javascripts/comfy/vendor/redactor/video.js +82 -0
  96. data/app/assets/javascripts/comfy/vendor/redactor.js +9563 -0
  97. data/app/assets/stylesheets/comfy/admin/cms/application.sass +11 -0
  98. data/app/assets/stylesheets/comfy/admin/cms/base.sass +256 -0
  99. data/app/assets/stylesheets/comfy/admin/cms/codemirror_overrides.sass +19 -0
  100. data/app/assets/stylesheets/comfy/admin/cms/custom.sass +1 -0
  101. data/app/assets/stylesheets/comfy/admin/cms/redactor_overrides.sass +22 -0
  102. data/app/assets/stylesheets/comfy/vendor/bootstrap/_alert.scss +51 -0
  103. data/app/assets/stylesheets/comfy/vendor/bootstrap/_badge.scss +54 -0
  104. data/app/assets/stylesheets/comfy/vendor/bootstrap/_breadcrumb.scss +41 -0
  105. data/app/assets/stylesheets/comfy/vendor/bootstrap/_button-group.scss +163 -0
  106. data/app/assets/stylesheets/comfy/vendor/bootstrap/_buttons.scss +137 -0
  107. data/app/assets/stylesheets/comfy/vendor/bootstrap/_card.scss +289 -0
  108. data/app/assets/stylesheets/comfy/vendor/bootstrap/_carousel.scss +197 -0
  109. data/app/assets/stylesheets/comfy/vendor/bootstrap/_close.scss +41 -0
  110. data/app/assets/stylesheets/comfy/vendor/bootstrap/_code.scss +48 -0
  111. data/app/assets/stylesheets/comfy/vendor/bootstrap/_custom-forms.scss +507 -0
  112. data/app/assets/stylesheets/comfy/vendor/bootstrap/_dropdown.scss +191 -0
  113. data/app/assets/stylesheets/comfy/vendor/bootstrap/_forms.scss +330 -0
  114. data/app/assets/stylesheets/comfy/vendor/bootstrap/_functions.scss +86 -0
  115. data/app/assets/stylesheets/comfy/vendor/bootstrap/_grid.scss +52 -0
  116. data/app/assets/stylesheets/comfy/vendor/bootstrap/_images.scss +42 -0
  117. data/app/assets/stylesheets/comfy/vendor/bootstrap/_input-group.scss +193 -0
  118. data/app/assets/stylesheets/comfy/vendor/bootstrap/_jumbotron.scss +17 -0
  119. data/app/assets/stylesheets/comfy/vendor/bootstrap/_list-group.scss +149 -0
  120. data/app/assets/stylesheets/comfy/vendor/bootstrap/_media.scss +8 -0
  121. data/app/assets/stylesheets/comfy/vendor/bootstrap/_mixins.scss +47 -0
  122. data/app/assets/stylesheets/comfy/vendor/bootstrap/_modal.scss +229 -0
  123. data/app/assets/stylesheets/comfy/vendor/bootstrap/_nav.scss +120 -0
  124. data/app/assets/stylesheets/comfy/vendor/bootstrap/_navbar.scss +294 -0
  125. data/app/assets/stylesheets/comfy/vendor/bootstrap/_pagination.scss +73 -0
  126. data/app/assets/stylesheets/comfy/vendor/bootstrap/_popover.scss +171 -0
  127. data/app/assets/stylesheets/comfy/vendor/bootstrap/_print.scss +141 -0
  128. data/app/assets/stylesheets/comfy/vendor/bootstrap/_progress.scss +43 -0
  129. data/app/assets/stylesheets/comfy/vendor/bootstrap/_reboot.scss +483 -0
  130. data/app/assets/stylesheets/comfy/vendor/bootstrap/_root.scss +19 -0
  131. data/app/assets/stylesheets/comfy/vendor/bootstrap/_spinners.scss +55 -0
  132. data/app/assets/stylesheets/comfy/vendor/bootstrap/_tables.scss +185 -0
  133. data/app/assets/stylesheets/comfy/vendor/bootstrap/_toasts.scss +44 -0
  134. data/app/assets/stylesheets/comfy/vendor/bootstrap/_tooltip.scss +115 -0
  135. data/app/assets/stylesheets/comfy/vendor/bootstrap/_transitions.scss +20 -0
  136. data/app/assets/stylesheets/comfy/vendor/bootstrap/_type.scss +125 -0
  137. data/app/assets/stylesheets/comfy/vendor/bootstrap/_utilities.scss +17 -0
  138. data/app/assets/stylesheets/comfy/vendor/bootstrap/_variables.scss +1123 -0
  139. data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap-grid.scss +29 -0
  140. data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap-reboot.scss +12 -0
  141. data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap.scss +44 -0
  142. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_alert.scss +13 -0
  143. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_background-variant.scss +21 -0
  144. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_badge.scss +17 -0
  145. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_border-radius.scss +63 -0
  146. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_box-shadow.scss +20 -0
  147. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_breakpoints.scss +123 -0
  148. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_buttons.scss +107 -0
  149. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_caret.scss +62 -0
  150. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_clearfix.scss +7 -0
  151. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_deprecate.scss +10 -0
  152. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_float.scss +14 -0
  153. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_forms.scss +192 -0
  154. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_gradients.scss +45 -0
  155. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_grid-framework.scss +66 -0
  156. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_grid.scss +51 -0
  157. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_hover.scss +37 -0
  158. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_image.scss +36 -0
  159. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_list-group.scss +21 -0
  160. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_lists.scss +7 -0
  161. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_nav-divider.scss +10 -0
  162. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_pagination.scss +22 -0
  163. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_reset-text.scss +17 -0
  164. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_resize.scss +6 -0
  165. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_screen-reader.scss +33 -0
  166. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_size.scss +7 -0
  167. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_table-row.scss +39 -0
  168. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-emphasis.scss +16 -0
  169. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-hide.scss +11 -0
  170. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-truncate.scss +8 -0
  171. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_transition.scss +16 -0
  172. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_visibility.scss +8 -0
  173. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_align.scss +8 -0
  174. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_background.scss +19 -0
  175. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_borders.scss +75 -0
  176. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_clearfix.scss +3 -0
  177. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_display.scss +26 -0
  178. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_embed.scss +39 -0
  179. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_flex.scss +51 -0
  180. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_float.scss +11 -0
  181. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_overflow.scss +5 -0
  182. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_position.scss +32 -0
  183. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_screenreaders.scss +11 -0
  184. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_shadows.scss +6 -0
  185. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_sizing.scss +20 -0
  186. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_spacing.scss +73 -0
  187. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_stretched-link.scss +19 -0
  188. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_text.scss +72 -0
  189. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_visibility.scss +13 -0
  190. data/app/assets/stylesheets/comfy/vendor/bootstrap/vendor/_rfs.scss +204 -0
  191. data/app/assets/stylesheets/comfy/vendor/fontawesome.css +343 -0
  192. data/app/assets/stylesheets/comfy/vendor/redactor.css +948 -0
  193. data/app/controllers/application_controller.rb +5 -0
  194. data/app/controllers/comfy/admin/base_controller.rb +20 -0
  195. data/app/controllers/comfy/admin/cms/base_controller.rb +54 -0
  196. data/app/controllers/comfy/admin/cms/categories_controller.rb +38 -0
  197. data/app/controllers/comfy/admin/cms/files_controller.rb +140 -0
  198. data/app/controllers/comfy/admin/cms/layouts_controller.rb +69 -0
  199. data/app/controllers/comfy/admin/cms/pages_controller.rb +193 -0
  200. data/app/controllers/comfy/admin/cms/revisions/base_controller.rb +48 -0
  201. data/app/controllers/comfy/admin/cms/revisions/layout_controller.rb +16 -0
  202. data/app/controllers/comfy/admin/cms/revisions/page_controller.rb +28 -0
  203. data/app/controllers/comfy/admin/cms/revisions/snippet_controller.rb +16 -0
  204. data/app/controllers/comfy/admin/cms/revisions/translation_controller.rb +29 -0
  205. data/app/controllers/comfy/admin/cms/sites_controller.rb +68 -0
  206. data/app/controllers/comfy/admin/cms/snippets_controller.rb +66 -0
  207. data/app/controllers/comfy/admin/cms/translations_controller.rb +117 -0
  208. data/app/controllers/comfy/cms/assets_controller.rb +38 -0
  209. data/app/controllers/comfy/cms/base_controller.rb +35 -0
  210. data/app/controllers/comfy/cms/content_controller.rb +90 -0
  211. data/app/controllers/concerns/comfy/paginate.rb +11 -0
  212. data/app/controllers/concerns/comfy/reorder_action.rb +19 -0
  213. data/app/helpers/comfy/admin/cms_helper.rb +50 -0
  214. data/app/helpers/comfy/cms_helper.rb +71 -0
  215. data/app/models/comfy/cms/categorization.rb +23 -0
  216. data/app/models/comfy/cms/category.rb +22 -0
  217. data/app/models/comfy/cms/file.rb +65 -0
  218. data/app/models/comfy/cms/fragment.rb +65 -0
  219. data/app/models/comfy/cms/layout.rb +119 -0
  220. data/app/models/comfy/cms/page.rb +182 -0
  221. data/app/models/comfy/cms/revision.rb +10 -0
  222. data/app/models/comfy/cms/site.rb +93 -0
  223. data/app/models/comfy/cms/snippet.rb +43 -0
  224. data/app/models/comfy/cms/translation.rb +47 -0
  225. data/app/models/concerns/comfy/cms/with_categories.rb +51 -0
  226. data/app/models/concerns/comfy/cms/with_fragments.rb +123 -0
  227. data/app/views/comfy/admin/cms/categories/_categories.html.haml +4 -0
  228. data/app/views/comfy/admin/cms/categories/_edit.html.haml +7 -0
  229. data/app/views/comfy/admin/cms/categories/_form.html.haml +5 -0
  230. data/app/views/comfy/admin/cms/categories/_index.html.haml +28 -0
  231. data/app/views/comfy/admin/cms/categories/_show.html.haml +15 -0
  232. data/app/views/comfy/admin/cms/categories/create.js.erb +7 -0
  233. data/app/views/comfy/admin/cms/categories/destroy.js.erb +8 -0
  234. data/app/views/comfy/admin/cms/categories/edit.js.erb +3 -0
  235. data/app/views/comfy/admin/cms/categories/update.js.erb +6 -0
  236. data/app/views/comfy/admin/cms/files/_file.html.haml +31 -0
  237. data/app/views/comfy/admin/cms/files/_form.html.haml +26 -0
  238. data/app/views/comfy/admin/cms/files/_modal.html.haml +3 -0
  239. data/app/views/comfy/admin/cms/files/destroy.js.erb +4 -0
  240. data/app/views/comfy/admin/cms/files/edit.html.haml +5 -0
  241. data/app/views/comfy/admin/cms/files/index.html.haml +31 -0
  242. data/app/views/comfy/admin/cms/files/new.html.haml +5 -0
  243. data/app/views/comfy/admin/cms/fragments/_form_fragment_attachments.html.haml +23 -0
  244. data/app/views/comfy/admin/cms/fragments/_form_fragments.html.haml +38 -0
  245. data/app/views/comfy/admin/cms/layouts/_form.html.haml +20 -0
  246. data/app/views/comfy/admin/cms/layouts/_index_branch.html.haml +26 -0
  247. data/app/views/comfy/admin/cms/layouts/edit.html.haml +9 -0
  248. data/app/views/comfy/admin/cms/layouts/index.html.haml +10 -0
  249. data/app/views/comfy/admin/cms/layouts/new.html.haml +5 -0
  250. data/app/views/comfy/admin/cms/pages/_form.html.haml +31 -0
  251. data/app/views/comfy/admin/cms/pages/_index_branch.html.haml +44 -0
  252. data/app/views/comfy/admin/cms/pages/edit.html.haml +14 -0
  253. data/app/views/comfy/admin/cms/pages/index.html.haml +13 -0
  254. data/app/views/comfy/admin/cms/pages/new.html.haml +5 -0
  255. data/app/views/comfy/admin/cms/pages/toggle_branch.js.erb +19 -0
  256. data/app/views/comfy/admin/cms/revisions/_sidebar.html.haml +2 -0
  257. data/app/views/comfy/admin/cms/revisions/show.html.haml +36 -0
  258. data/app/views/comfy/admin/cms/sites/_form.html.haml +15 -0
  259. data/app/views/comfy/admin/cms/sites/edit.html.haml +5 -0
  260. data/app/views/comfy/admin/cms/sites/index.html.haml +28 -0
  261. data/app/views/comfy/admin/cms/sites/new.html.haml +5 -0
  262. data/app/views/comfy/admin/cms/snippets/_form.html.haml +19 -0
  263. data/app/views/comfy/admin/cms/snippets/edit.html.haml +9 -0
  264. data/app/views/comfy/admin/cms/snippets/index.html.haml +33 -0
  265. data/app/views/comfy/admin/cms/snippets/new.html.haml +5 -0
  266. data/app/views/comfy/admin/cms/translations/_form.html.haml +20 -0
  267. data/app/views/comfy/admin/cms/translations/_sidebar.html.haml +19 -0
  268. data/app/views/comfy/admin/cms/translations/edit.html.haml +10 -0
  269. data/app/views/comfy/admin/cms/translations/new.html.haml +5 -0
  270. data/app/views/kaminari/comfy/_first_page.html.haml +3 -0
  271. data/app/views/kaminari/comfy/_gap.html.haml +2 -0
  272. data/app/views/kaminari/comfy/_last_page.html.haml +3 -0
  273. data/app/views/kaminari/comfy/_next_page.html.haml +2 -0
  274. data/app/views/kaminari/comfy/_page.html.haml +2 -0
  275. data/app/views/kaminari/comfy/_paginator.html.haml +11 -0
  276. data/app/views/kaminari/comfy/_prev_page.html.haml +2 -0
  277. data/app/views/layouts/comfy/admin/cms/_body.html.haml +14 -0
  278. data/app/views/layouts/comfy/admin/cms/_flash.html.haml +4 -0
  279. data/app/views/layouts/comfy/admin/cms/_footer_js.html.haml +6 -0
  280. data/app/views/layouts/comfy/admin/cms/_head.html.haml +19 -0
  281. data/app/views/layouts/comfy/admin/cms/_left.html.haml +46 -0
  282. data/app/views/layouts/comfy/admin/cms/_right.html.haml +5 -0
  283. data/app/views/layouts/comfy/admin/cms.html.haml +4 -0
  284. data/bin/bundle +3 -0
  285. data/bin/rails +4 -0
  286. data/bin/rake +4 -0
  287. data/bin/setup +36 -0
  288. data/bin/update +31 -0
  289. data/bin/yarn +11 -0
  290. data/comfy_middle_seat.gemspec +35 -0
  291. data/config/application.rb +62 -0
  292. data/config/boot.rb +5 -0
  293. data/config/cable.yml +10 -0
  294. data/config/cms_routes.rb +8 -0
  295. data/config/database.yml +40 -0
  296. data/config/environment.rb +7 -0
  297. data/config/environments/development.rb +81 -0
  298. data/config/environments/production.rb +93 -0
  299. data/config/environments/test.rb +74 -0
  300. data/config/initializers/comfortable_media_surfer.rb +122 -0
  301. data/config/initializers/content_security_policy.rb +27 -0
  302. data/config/initializers/filter_parameter_logging.rb +10 -0
  303. data/config/initializers/inflections.rb +18 -0
  304. data/config/initializers/json.rb +11 -0
  305. data/config/initializers/new_framework_defaults_7_0.rb +144 -0
  306. data/config/initializers/new_framework_defaults_7_1.rb +225 -0
  307. data/config/initializers/permissions_policy.rb +15 -0
  308. data/config/locales/ar.yml +268 -0
  309. data/config/locales/ca.yml +268 -0
  310. data/config/locales/cs.yml +268 -0
  311. data/config/locales/da.yml +268 -0
  312. data/config/locales/de.yml +268 -0
  313. data/config/locales/en.yml +268 -0
  314. data/config/locales/es.yml +268 -0
  315. data/config/locales/fi.yml +268 -0
  316. data/config/locales/fr.yml +268 -0
  317. data/config/locales/gr.yml +268 -0
  318. data/config/locales/hr.yml +268 -0
  319. data/config/locales/it.yml +268 -0
  320. data/config/locales/ja.yml +268 -0
  321. data/config/locales/nb.yml +268 -0
  322. data/config/locales/nl.yml +268 -0
  323. data/config/locales/pl.yml +268 -0
  324. data/config/locales/pt-BR.yml +268 -0
  325. data/config/locales/ru.yml +268 -0
  326. data/config/locales/sk.yml +268 -0
  327. data/config/locales/sv.yml +268 -0
  328. data/config/locales/tr.yml +268 -0
  329. data/config/locales/uk.yml +268 -0
  330. data/config/locales/zh-CN.yml +268 -0
  331. data/config/locales/zh-TW.yml +268 -0
  332. data/config/puma.rb +43 -0
  333. data/config/storage.yml +35 -0
  334. data/config.ru +6 -0
  335. data/db/cms_seeds/sample-site/files/_default.jpg.yml +5 -0
  336. data/db/cms_seeds/sample-site/files/default.jpg +0 -0
  337. data/db/cms_seeds/sample-site/layouts/default/content.html +16 -0
  338. data/db/cms_seeds/sample-site/layouts/default/nested/content.html +14 -0
  339. data/db/cms_seeds/sample-site/pages/index/child_a/content.html +7 -0
  340. data/db/cms_seeds/sample-site/pages/index/child_b/child_a/content.html +6 -0
  341. data/db/cms_seeds/sample-site/pages/index/child_b/content.html +6 -0
  342. data/db/cms_seeds/sample-site/pages/index/cms logo.png +0 -0
  343. data/db/cms_seeds/sample-site/pages/index/content.es.html +6 -0
  344. data/db/cms_seeds/sample-site/pages/index/content.fr.html +6 -0
  345. data/db/cms_seeds/sample-site/pages/index/content.html +25 -0
  346. data/db/cms_seeds/sample-site/pages/index/footer.png +0 -0
  347. data/db/cms_seeds/sample-site/pages/index/header.png +0 -0
  348. data/db/cms_seeds/sample-site/snippets/default.html +8 -0
  349. data/db/migrate/00_create_active_storage_tables.active_storage.rb +50 -0
  350. data/db/migrate/01_create_cms.rb +142 -0
  351. data/db/migrate/02_add_markdown_to_snippets.rb +5 -0
  352. data/gemfiles/7.2.gemfile +36 -0
  353. data/gemfiles/8.0.gemfile +36 -0
  354. data/gemfiles/8.1.gemfile +36 -0
  355. data/lib/comfortable_media_surfer/access_control/admin_authentication.rb +22 -0
  356. data/lib/comfortable_media_surfer/access_control/admin_authorization.rb +10 -0
  357. data/lib/comfortable_media_surfer/access_control/public_authentication.rb +10 -0
  358. data/lib/comfortable_media_surfer/access_control/public_authorization.rb +10 -0
  359. data/lib/comfortable_media_surfer/configuration.rb +138 -0
  360. data/lib/comfortable_media_surfer/content/block.rb +12 -0
  361. data/lib/comfortable_media_surfer/content/params_parser.rb +149 -0
  362. data/lib/comfortable_media_surfer/content/renderer.rb +146 -0
  363. data/lib/comfortable_media_surfer/content/tag.rb +48 -0
  364. data/lib/comfortable_media_surfer/content/tags/asset.rb +57 -0
  365. data/lib/comfortable_media_surfer/content/tags/audio.rb +39 -0
  366. data/lib/comfortable_media_surfer/content/tags/breadcrumbs.rb +43 -0
  367. data/lib/comfortable_media_surfer/content/tags/checkbox.rb +27 -0
  368. data/lib/comfortable_media_surfer/content/tags/children.rb +52 -0
  369. data/lib/comfortable_media_surfer/content/tags/date.rb +19 -0
  370. data/lib/comfortable_media_surfer/content/tags/datetime.rb +42 -0
  371. data/lib/comfortable_media_surfer/content/tags/file.rb +70 -0
  372. data/lib/comfortable_media_surfer/content/tags/file_link.rb +58 -0
  373. data/lib/comfortable_media_surfer/content/tags/files.rb +41 -0
  374. data/lib/comfortable_media_surfer/content/tags/fragment.rb +64 -0
  375. data/lib/comfortable_media_surfer/content/tags/helper.rb +53 -0
  376. data/lib/comfortable_media_surfer/content/tags/image.rb +56 -0
  377. data/lib/comfortable_media_surfer/content/tags/markdown.rb +22 -0
  378. data/lib/comfortable_media_surfer/content/tags/mixins/file_content.rb +42 -0
  379. data/lib/comfortable_media_surfer/content/tags/number.rb +18 -0
  380. data/lib/comfortable_media_surfer/content/tags/page_file_link.rb +86 -0
  381. data/lib/comfortable_media_surfer/content/tags/partial.rb +47 -0
  382. data/lib/comfortable_media_surfer/content/tags/siblings.rb +66 -0
  383. data/lib/comfortable_media_surfer/content/tags/snippet.rb +36 -0
  384. data/lib/comfortable_media_surfer/content/tags/template.rb +42 -0
  385. data/lib/comfortable_media_surfer/content/tags/text.rb +18 -0
  386. data/lib/comfortable_media_surfer/content/tags/textarea.rb +19 -0
  387. data/lib/comfortable_media_surfer/content/tags/wysiwyg.rb +19 -0
  388. data/lib/comfortable_media_surfer/content/tags.rb +29 -0
  389. data/lib/comfortable_media_surfer/content.rb +11 -0
  390. data/lib/comfortable_media_surfer/engine.rb +24 -0
  391. data/lib/comfortable_media_surfer/error.rb +24 -0
  392. data/lib/comfortable_media_surfer/extensions/acts_as_tree.rb +114 -0
  393. data/lib/comfortable_media_surfer/extensions/has_revisions.rb +68 -0
  394. data/lib/comfortable_media_surfer/extensions.rb +8 -0
  395. data/lib/comfortable_media_surfer/form_builder.rb +43 -0
  396. data/lib/comfortable_media_surfer/render_methods.rb +106 -0
  397. data/lib/comfortable_media_surfer/routing.rb +87 -0
  398. data/lib/comfortable_media_surfer/seeds/file/exporter.rb +37 -0
  399. data/lib/comfortable_media_surfer/seeds/file/importer.rb +55 -0
  400. data/lib/comfortable_media_surfer/seeds/layout/exporter.rb +38 -0
  401. data/lib/comfortable_media_surfer/seeds/layout/importer.rb +60 -0
  402. data/lib/comfortable_media_surfer/seeds/page/exporter.rb +88 -0
  403. data/lib/comfortable_media_surfer/seeds/page/importer.rb +245 -0
  404. data/lib/comfortable_media_surfer/seeds/snippet/exporter.rb +32 -0
  405. data/lib/comfortable_media_surfer/seeds/snippet/importer.rb +47 -0
  406. data/lib/comfortable_media_surfer/seeds.rb +110 -0
  407. data/lib/comfortable_media_surfer/version.rb +3 -0
  408. data/lib/comfortable_media_surfer/view_hooks.rb +33 -0
  409. data/lib/comfortable_media_surfer.rb +56 -0
  410. data/lib/comfy_middle_seat/version.rb +5 -0
  411. data/lib/comfy_middle_seat.rb +3 -0
  412. data/lib/generators/comfy/cms/README +21 -0
  413. data/lib/generators/comfy/cms/assets_generator.rb +16 -0
  414. data/lib/generators/comfy/cms/cms_generator.rb +69 -0
  415. data/lib/generators/comfy/cms/controllers_generator.rb +15 -0
  416. data/lib/generators/comfy/cms/models_generator.rb +15 -0
  417. data/lib/generators/comfy/cms/views_generator.rb +15 -0
  418. data/lib/generators/comfy/scaffold/scaffold_generator.rb +79 -0
  419. data/lib/generators/comfy/scaffold/templates/controller.rb.tt +62 -0
  420. data/lib/generators/comfy/scaffold/templates/migration.rb.tt +11 -0
  421. data/lib/generators/comfy/scaffold/templates/model.rb.tt +21 -0
  422. data/lib/generators/comfy/scaffold/templates/tests/controller.rb.tt +115 -0
  423. data/lib/generators/comfy/scaffold/templates/tests/fixture.yml.tt +4 -0
  424. data/lib/generators/comfy/scaffold/templates/tests/model.rb.tt +26 -0
  425. data/lib/generators/comfy/scaffold/templates/views/_form.haml.tt +7 -0
  426. data/lib/generators/comfy/scaffold/templates/views/edit.haml.tt +5 -0
  427. data/lib/generators/comfy/scaffold/templates/views/index.haml.tt +21 -0
  428. data/lib/generators/comfy/scaffold/templates/views/new.haml.tt +5 -0
  429. data/lib/generators/comfy/scaffold/templates/views/show.haml.tt +4 -0
  430. data/lib/tasks/cms_assets.rake +19 -0
  431. data/lib/tasks/cms_seeds.rake +40 -0
  432. data/package-lock.json +989 -0
  433. data/package.json +23 -0
  434. data/public/favicon.ico +0 -0
  435. data/rakelib/create_release.rake +82 -0
  436. metadata +665 -0
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationController < ActionController::Base
4
+ protect_from_forgery
5
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::BaseController < ComfortableMediaSurfer.config.admin_base_controller.to_s.constantize
4
+ include Comfy::Paginate
5
+
6
+ # Authentication module must have `authenticate` method
7
+ include ComfortableMediaSurfer.config.admin_auth.to_s.constantize
8
+
9
+ # Authorization module must have `authorize` method
10
+ include ComfortableMediaSurfer.config.admin_authorization.to_s.constantize
11
+
12
+ helper Comfy::Admin::CmsHelper
13
+ helper Comfy::CmsHelper
14
+
15
+ protect_from_forgery with: :exception
16
+
17
+ before_action :authenticate
18
+
19
+ layout 'comfy/admin/cms'
20
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::BaseController < Comfy::Admin::BaseController
4
+ before_action :load_admin_site,
5
+ :set_locale?,
6
+ :load_seeds,
7
+ except: :jump
8
+
9
+ layout :infer_layout
10
+
11
+ if ComfortableMediaSurfer.config.admin_cache_sweeper.present?
12
+ cache_sweeper(*ComfortableMediaSurfer.config.admin_cache_sweeper)
13
+ end
14
+
15
+ def jump
16
+ path = ComfortableMediaSurfer.config.admin_route_redirect
17
+ return redirect_to(path) unless path.blank?
18
+
19
+ load_admin_site
20
+ redirect_to comfy_admin_cms_site_pages_path(@site) if @site
21
+ end
22
+
23
+ protected
24
+
25
+ def load_admin_site
26
+ id_param = params[:site_id] || session[:site_id]
27
+ if (@site = ::Comfy::Cms::Site.find_by(id: id_param) || ::Comfy::Cms::Site.first)
28
+ session[:site_id] = @site.id
29
+ else
30
+ I18n.locale = ComfortableMediaSurfer.config.admin_locale || I18n.default_locale
31
+ flash[:danger] = I18n.t('comfy.admin.cms.base.site_not_found')
32
+ redirect_to(new_comfy_admin_cms_site_path)
33
+ end
34
+ end
35
+
36
+ def set_locale?
37
+ I18n.locale = ComfortableMediaSurfer.config.admin_locale || @site&.locale
38
+ true
39
+ end
40
+
41
+ def load_seeds
42
+ return unless ComfortableMediaSurfer.config.enable_seeds
43
+
44
+ controllers = %w[layouts pages snippets files].collect { |c| "comfy/admin/cms/#{c}" }
45
+ return unless controllers.member?(params[:controller]) && params[:action] == 'index'
46
+
47
+ ComfortableMediaSurfer::Seeds::Importer.new(@site.identifier).import!
48
+ flash.now[:warning] = I18n.t('comfy.admin.cms.base.seeds_enabled')
49
+ end
50
+
51
+ def infer_layout
52
+ false if params[:layout] == 'false'
53
+ end
54
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::CategoriesController < Comfy::Admin::Cms::BaseController
4
+ before_action :load_category, only: %i[edit update destroy]
5
+ before_action :authorize
6
+
7
+ def edit
8
+ render
9
+ end
10
+
11
+ def create
12
+ @category = @site.categories.create!(category_params)
13
+ rescue ActiveRecord::RecordInvalid
14
+ head :ok
15
+ end
16
+
17
+ def update
18
+ @category.update!(category_params)
19
+ rescue ActiveRecord::RecordInvalid
20
+ head :ok
21
+ end
22
+
23
+ def destroy
24
+ @category.destroy
25
+ end
26
+
27
+ protected
28
+
29
+ def load_category
30
+ @category = @site.categories.find(params[:id])
31
+ rescue ActiveRecord::RecordNotFound
32
+ head :ok
33
+ end
34
+
35
+ def category_params
36
+ params.fetch(:category, {}).permit(:label, :categorized_type)
37
+ end
38
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::FilesController < Comfy::Admin::Cms::BaseController
4
+ include ::Comfy::ReorderAction
5
+
6
+ self.reorder_action_resource = ::Comfy::Cms::File
7
+
8
+ include ActionView::Helpers::NumberHelper
9
+
10
+ before_action :build_file, only: %i[new create]
11
+ before_action :load_file, only: %i[edit update destroy]
12
+ before_action :authorize
13
+
14
+ def index
15
+ files_scope = @site.files.with_attached_attachment
16
+
17
+ case params[:source]
18
+
19
+ # Integration with Redactor 1.0 Wysiwyg
20
+ when 'redactor'
21
+ file_scope = files_scope.limit(100).order(:position)
22
+ file_hashes =
23
+ case params[:type]
24
+ when 'image'
25
+ file_scope.with_images.collect do |file|
26
+ { thumb: url_for(file.attachment.variant(combine_options: Comfy::Cms::File::VARIANT_SIZE[:redactor])),
27
+ image: url_for(file.attachment),
28
+ title: file.label }
29
+ end
30
+ else
31
+ file_scope.collect do |file|
32
+ { title: file.label,
33
+ name: file.attachment.filename,
34
+ link: url_for(file.attachment),
35
+ size: number_to_human_size(file.attachment.byte_size) }
36
+ end
37
+ end
38
+
39
+ render json: file_hashes
40
+
41
+ else
42
+ files_scope = files_scope
43
+ .includes(:categories)
44
+ .for_category(params[:categories])
45
+ .order('comfy_cms_files.position')
46
+ @files = comfy_paginate(files_scope, per_page: 50)
47
+ end
48
+ end
49
+
50
+ def new
51
+ render
52
+ end
53
+
54
+ def create
55
+ categories_scope = @site.categories.of_type('Comfy::Cms::File')
56
+
57
+ if params[:categories]
58
+ ids = categories_scope.where(label: params[:categories]).pluck(:id)
59
+ @file.category_ids = ids
60
+ end
61
+
62
+ # Automatically tagging upload if it's done through redactor
63
+ if params[:source] == 'redactor'
64
+ category = categories_scope.find_or_create_by(label: 'wysiwyg')
65
+ @file.category_ids = [category.id]
66
+ end
67
+
68
+ @file.save!
69
+
70
+ case params[:source]
71
+ when 'plupload'
72
+ render partial: 'file', object: @file
73
+ when 'redactor'
74
+ render json: {
75
+ filelink: url_for(@file.attachment),
76
+ filename: @file.attachment.filename
77
+ }
78
+ else
79
+ flash[:success] = I18n.t('comfy.admin.cms.files.created')
80
+ redirect_to action: :edit, id: @file
81
+ end
82
+ rescue ActiveRecord::RecordInvalid
83
+ case params[:source]
84
+ when 'plupload'
85
+ render body: @file.errors.full_messages.to_sentence, status: :unprocessable_content
86
+ when 'redactor'
87
+ render body: nil, status: :unprocessable_content
88
+ else
89
+ flash.now[:danger] = I18n.t('comfy.admin.cms.files.creation_failure')
90
+ render action: :new
91
+ end
92
+ end
93
+
94
+ def edit
95
+ render
96
+ end
97
+
98
+ def update
99
+ if @file.update(file_params)
100
+ flash[:success] = I18n.t('comfy.admin.cms.files.updated')
101
+ redirect_to action: :edit, id: @file
102
+ else
103
+ flash.now[:danger] = I18n.t('comfy.admin.cms.files.update_failure')
104
+ render action: :edit
105
+ end
106
+ end
107
+
108
+ def destroy
109
+ @file.destroy
110
+ respond_to do |format|
111
+ format.js
112
+ format.html do
113
+ flash[:success] = I18n.t('comfy.admin.cms.files.deleted')
114
+ redirect_to action: :index
115
+ end
116
+ end
117
+ end
118
+
119
+ protected
120
+
121
+ def build_file
122
+ @file = @site.files.new(file_params)
123
+ end
124
+
125
+ def load_file
126
+ @file = @site.files.find(params[:id])
127
+ rescue ActiveRecord::RecordNotFound
128
+ flash[:danger] = I18n.t('comfy.admin.cms.files.not_found')
129
+ redirect_to action: :index
130
+ end
131
+
132
+ def file_params
133
+ file = params[:file]
134
+ unless file.is_a?(Hash) || file.respond_to?(:to_unsafe_hash)
135
+ params[:file] = {}
136
+ params[:file][:file] = file
137
+ end
138
+ params.fetch(:file, {}).permit(:label, :description, :file, category_ids: [])
139
+ end
140
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::LayoutsController < Comfy::Admin::Cms::BaseController
4
+ include ::Comfy::ReorderAction
5
+
6
+ self.reorder_action_resource = ::Comfy::Cms::Layout
7
+
8
+ before_action :build_layout, only: %i[new create]
9
+ before_action :load_layout, only: %i[edit update destroy]
10
+ before_action :authorize
11
+
12
+ def index
13
+ return redirect_to action: :new if @site.layouts.none?
14
+
15
+ @layouts = @site.layouts.roots.order(:position)
16
+ end
17
+
18
+ def new
19
+ render
20
+ end
21
+
22
+ def edit
23
+ render
24
+ end
25
+
26
+ def create
27
+ @layout.save!
28
+ flash[:success] = I18n.t('comfy.admin.cms.layouts.created')
29
+ redirect_to action: :edit, id: @layout
30
+ rescue ActiveRecord::RecordInvalid
31
+ flash.now[:danger] = I18n.t('comfy.admin.cms.layouts.creation_failure')
32
+ render action: :new
33
+ end
34
+
35
+ def update
36
+ @layout.update!(layout_params)
37
+ flash[:success] = I18n.t('comfy.admin.cms.layouts.updated')
38
+ redirect_to action: :edit, id: @layout
39
+ rescue ActiveRecord::RecordInvalid
40
+ flash.now[:danger] = I18n.t('comfy.admin.cms.layouts.update_failure')
41
+ render action: :edit
42
+ end
43
+
44
+ def destroy
45
+ @layout.destroy
46
+ flash[:success] = I18n.t('comfy.admin.cms.layouts.deleted')
47
+ redirect_to action: :index
48
+ end
49
+
50
+ protected
51
+
52
+ def build_layout
53
+ @layout = @site.layouts.new(layout_params)
54
+ @layout.parent ||= ::Comfy::Cms::Layout.find_by_id(params[:parent_id])
55
+ @layout.app_layout ||= @layout.parent.try(:app_layout)
56
+ @layout.content ||= '{{ cms:wysiwyg content }}'
57
+ end
58
+
59
+ def load_layout
60
+ @layout = @site.layouts.find(params[:id])
61
+ rescue ActiveRecord::RecordNotFound
62
+ flash[:danger] = I18n.t('comfy.admin.cms.layouts.not_found')
63
+ redirect_to action: :index
64
+ end
65
+
66
+ def layout_params
67
+ params.fetch(:layout, {}).permit(:label, :identifier, :parent_id, :app_layout, :content, :css, :js)
68
+ end
69
+ end
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::PagesController < Comfy::Admin::Cms::BaseController
4
+ FRAGMENT_PARAMS = [
5
+ :identifier, :tag, :content, :datetime, :boolean, :files,
6
+ { files: [], file_ids_destroy: [] }
7
+ ].freeze
8
+
9
+ include ::Comfy::ReorderAction
10
+
11
+ self.reorder_action_resource = ::Comfy::Cms::Page
12
+
13
+ before_action :check_for_layouts, only: %i[new edit]
14
+ before_action :build_page, only: %i[new create]
15
+ before_action :load_page, only: %i[edit update destroy publish_children unpublish_children]
16
+
17
+ before_action :authorize
18
+ before_action :assign_page_params, only: :update
19
+ before_action :preview_page, only: %i[create update]
20
+
21
+ def index
22
+ return redirect_to action: :new if site_has_no_pages?
23
+
24
+ return index_for_redactor if params[:source] == 'redactor'
25
+
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
34
+ end
35
+
36
+ def new
37
+ render
38
+ end
39
+
40
+ def edit
41
+ render
42
+ end
43
+
44
+ def update_family
45
+ @page.siblings.each(&:save!) if @page.siblings
46
+ @page.parent.save! if @page.parent
47
+ end
48
+
49
+ def create
50
+ @page.save!
51
+ update_family
52
+ flash[:success] = I18n.t('comfy.admin.cms.pages.created')
53
+ redirect_to action: :edit, id: @page
54
+ rescue ActiveRecord::RecordInvalid
55
+ flash.now[:danger] = I18n.t('comfy.admin.cms.pages.creation_failure')
56
+ render action: :new
57
+ end
58
+
59
+ def update
60
+ @page.save!
61
+ update_family
62
+ flash[:success] = I18n.t('comfy.admin.cms.pages.updated')
63
+ redirect_to action: :edit, id: @page
64
+ rescue ActiveRecord::RecordInvalid
65
+ flash.now[:danger] = I18n.t('comfy.admin.cms.pages.update_failure')
66
+ render action: :edit
67
+ end
68
+
69
+ def destroy
70
+ @page.destroy
71
+ update_family
72
+ flash[:success] = I18n.t('comfy.admin.cms.pages.deleted')
73
+ redirect_to action: :index
74
+ end
75
+
76
+ def form_fragments
77
+ @page = @site.pages.find_by(id: params[:id]) || @site.pages.new
78
+ @page.layout = @site.layouts.find_by(id: params[:layout_id])
79
+
80
+ render(
81
+ partial: 'comfy/admin/cms/fragments/form_fragments',
82
+ locals: { record: @page, scope: :page },
83
+ layout: false
84
+ )
85
+ end
86
+
87
+ def toggle_branch
88
+ @pages_by_parent = pages_grouped_by_parent
89
+ @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
93
+ rescue ActiveRecord::RecordNotFound
94
+ render nothing: true
95
+ end
96
+
97
+ def publish_children
98
+ update_children_publication(true, :children_published)
99
+ end
100
+
101
+ def unpublish_children
102
+ update_children_publication(false, :children_unpublished)
103
+ end
104
+
105
+ protected
106
+
107
+ def update_children_publication(is_published, message)
108
+ descendant_ids = @page.descendants.map(&:id)
109
+ @site.pages
110
+ .where(id: descendant_ids)
111
+ .update_all(is_published: is_published, updated_at: Time.current)
112
+ default = is_published ? 'Child pages published' : 'Child pages unpublished'
113
+ flash[:success] = I18n.t("comfy.admin.cms.pages.#{message}", default: default)
114
+ redirect_to action: :edit, id: @page
115
+ end
116
+
117
+ def index_for_redactor
118
+ tree_walker = ->(page, list, offset) do
119
+ return unless page.present?
120
+
121
+ label = "#{'. . ' * offset}#{page.label}"
122
+ list << { name: label, url: page.url(relative: true) }
123
+ page.children.each do |child_page|
124
+ tree_walker.call(child_page, list, offset + 1)
125
+ end
126
+ list
127
+ end
128
+
129
+ page_select_options = [{
130
+ name: I18n.t('comfy.admin.cms.pages.form.choose_link'),
131
+ url: false
132
+ }] + tree_walker.call(@site.pages.root, [], 0)
133
+
134
+ render json: page_select_options
135
+ end
136
+
137
+ def site_has_no_pages?
138
+ @site.pages.none?
139
+ end
140
+
141
+ def pages_grouped_by_parent
142
+ @site.pages.order(:position).includes(:categories).group_by(&:parent_id)
143
+ end
144
+
145
+ def check_for_layouts
146
+ return unless @site.layouts.none?
147
+
148
+ flash[:danger] = I18n.t('comfy.admin.cms.pages.layout_not_found')
149
+ redirect_to new_comfy_admin_cms_site_layout_path(@site)
150
+ end
151
+
152
+ def build_page
153
+ @page = @site.pages.new(page_params)
154
+ @page.parent ||= @site.pages.find_by_id(params[:parent_id]) || @site.pages.root
155
+ @page.layout ||= @page.parent&.layout || @site.layouts.first
156
+ end
157
+
158
+ def load_page
159
+ @page = @site.pages.find(params[:id])
160
+ rescue ActiveRecord::RecordNotFound
161
+ flash[:danger] = I18n.t('comfy.admin.cms.pages.not_found')
162
+ redirect_to action: :index
163
+ end
164
+
165
+ def assign_page_params
166
+ @page.assign_attributes(page_params)
167
+ end
168
+
169
+ def preview_page
170
+ return unless params[:preview]
171
+
172
+ layout = @page.layout.app_layout.blank? ? false : @page.layout.app_layout
173
+ @cms_site = @page.site
174
+ @cms_layout = @page.layout
175
+ @cms_page = @page
176
+
177
+ # Make sure to use the site locale to render the preview becaue it might
178
+ # be different from the admin locale.
179
+ I18n.locale = @cms_site.locale
180
+
181
+ # Chrome chokes on content with iframes. Issue #434
182
+ response.headers['X-XSS-Protection'] = '0'
183
+
184
+ render inline: @page.render, layout: layout, content_type: 'text/html'
185
+ end
186
+
187
+ def page_params
188
+ params.fetch(:page, {}).permit(
189
+ :label, :slug, :parent_id, :layout_id, :target_page_id, :is_published,
190
+ category_ids: [], fragments_attributes: FRAGMENT_PARAMS
191
+ )
192
+ end
193
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::Revisions::BaseController < Comfy::Admin::Cms::BaseController
4
+ helper_method :record_path
5
+
6
+ before_action :load_record
7
+ before_action :load_revision, except: :index
8
+ before_action :authorize
9
+
10
+ def index
11
+ revision = @record.revisions.order(created_at: :desc).first
12
+ if revision
13
+ redirect_to action: :show, id: revision.id
14
+ else
15
+ redirect_to record_path
16
+ end
17
+ end
18
+
19
+ def show
20
+ @current_content = @record.revision_fields.to_h { |field| [field, @record.send(field)] }
21
+ @versioned_content = @record.revision_fields.to_h { |field| [field, @revision.data[field]] }
22
+
23
+ render 'comfy/admin/cms/revisions/show'
24
+ end
25
+
26
+ def revert
27
+ @record.restore_from_revision(@revision)
28
+ flash[:success] = I18n.t('comfy.admin.cms.revisions.reverted')
29
+ redirect_to record_path
30
+ end
31
+
32
+ protected
33
+
34
+ def load_record
35
+ raise 'not implemented'
36
+ end
37
+
38
+ def load_revision
39
+ @revision = @record.revisions.find(params[:id])
40
+ rescue ActiveRecord::RecordNotFound
41
+ flash[:danger] = I18n.t('comfy.admin.cms.revisions.not_found')
42
+ redirect_to record_path
43
+ end
44
+
45
+ def record_path
46
+ raise 'not implemented'
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::Revisions::LayoutController < Comfy::Admin::Cms::Revisions::BaseController
4
+ private
5
+
6
+ def load_record
7
+ @record = @site.layouts.find(params[:layout_id])
8
+ rescue ActiveRecord::RecordNotFound
9
+ flash[:danger] = I18n.t('comfy.admin.cms.revisions.record_not_found')
10
+ redirect_to comfy_admin_cms_site_layouts_path(@site)
11
+ end
12
+
13
+ def record_path
14
+ edit_comfy_admin_cms_site_layout_path(@site, @record)
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::Revisions::PageController < Comfy::Admin::Cms::Revisions::BaseController
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
+
13
+ render 'comfy/admin/cms/revisions/show'
14
+ end
15
+
16
+ private
17
+
18
+ def load_record
19
+ @record = @site.pages.find(params[:page_id])
20
+ rescue ActiveRecord::RecordNotFound
21
+ flash[:danger] = I18n.t('comfy.admin.cms.revisions.record_not_found')
22
+ redirect_to comfy_admin_cms_site_pages_path(@site)
23
+ end
24
+
25
+ def record_path
26
+ edit_comfy_admin_cms_site_page_path(@site, @record)
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::Revisions::SnippetController < Comfy::Admin::Cms::Revisions::BaseController
4
+ private
5
+
6
+ def load_record
7
+ @record = @site.snippets.find(params[:snippet_id])
8
+ rescue ActiveRecord::RecordNotFound
9
+ flash[:danger] = I18n.t('comfy.admin.cms.revisions.record_not_found')
10
+ redirect_to comfy_admin_cms_site_snippets_path(@site)
11
+ end
12
+
13
+ def record_path
14
+ edit_comfy_admin_cms_site_snippet_path(@site, @record)
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comfy::Admin::Cms::Revisions::TranslationController < Comfy::Admin::Cms::Revisions::BaseController
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
+
13
+ render 'comfy/admin/cms/revisions/show'
14
+ end
15
+
16
+ private
17
+
18
+ def load_record
19
+ @page = @site.pages.find(params[:page_id])
20
+ @record = @page.translations.find(params[:translation_id])
21
+ rescue ActiveRecord::RecordNotFound
22
+ flash[:danger] = I18n.t('comfy.admin.cms.revisions.record_not_found')
23
+ redirect_to comfy_admin_cms_site_pages_path(@site)
24
+ end
25
+
26
+ def record_path
27
+ edit_comfy_admin_cms_site_page_translation_path(@site, @page, @record)
28
+ end
29
+ end